Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7bc25e168 | |||
| 0a06223f7c | |||
| 578a1d0d55 | |||
| 0e18a64054 |
@@ -15,6 +15,7 @@ allprojects {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven("https://repo.papermc.io/repository/maven-public/")
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
maven("https://repo.extendedclip.com/releases/") // PlaceholderAPI
|
maven("https://repo.extendedclip.com/releases/") // PlaceholderAPI
|
||||||
|
maven("https://repo.selixe.com/repository/api/") // Atlantis Disguises
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,9 +23,8 @@ subprojects {
|
|||||||
apply(plugin = "java")
|
apply(plugin = "java")
|
||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
sourceCompatibility = JavaVersion.toVersion(javaVersion.toInt())
|
||||||
languageVersion.set(JavaLanguageVersion.of(javaVersion.toInt()))
|
targetCompatibility = JavaVersion.toVersion(javaVersion.toInt())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<JavaCompile> {
|
tasks.withType<JavaCompile> {
|
||||||
|
|||||||
@@ -16,11 +16,15 @@ dependencies {
|
|||||||
|
|
||||||
compileOnly("net.luckperms:api:$luckpermsVersion")
|
compileOnly("net.luckperms:api:$luckpermsVersion")
|
||||||
compileOnly("me.clip:placeholderapi:$placeholderApiVersion")
|
compileOnly("me.clip:placeholderapi:$placeholderApiVersion")
|
||||||
|
compileOnly("net.atlantismc.disguises:api:1.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.jar {
|
||||||
|
enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.shadowJar {
|
tasks.shadowJar {
|
||||||
archiveClassifier.set("")
|
archiveFileName.set("NickCore-Paper-${project.version}.jar")
|
||||||
archiveBaseName.set("NickCore-Paper")
|
|
||||||
|
|
||||||
relocate("com.zaxxer.hikari", "com.nickcore.lib.hikari")
|
relocate("com.zaxxer.hikari", "com.nickcore.lib.hikari")
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.nickcore.common.validation.NicknameValidator;
|
|||||||
import com.nickcore.paper.cache.ProfileCache;
|
import com.nickcore.paper.cache.ProfileCache;
|
||||||
import com.nickcore.paper.command.NickCommand;
|
import com.nickcore.paper.command.NickCommand;
|
||||||
import com.nickcore.paper.gui.GuiManager;
|
import com.nickcore.paper.gui.GuiManager;
|
||||||
|
import com.nickcore.paper.integration.AtlantisDisguiseIntegration;
|
||||||
import com.nickcore.paper.integration.NickCoreExpansion;
|
import com.nickcore.paper.integration.NickCoreExpansion;
|
||||||
import com.nickcore.paper.integration.VelocityMessaging;
|
import com.nickcore.paper.integration.VelocityMessaging;
|
||||||
import com.nickcore.paper.listener.CommandPreprocessListener;
|
import com.nickcore.paper.listener.CommandPreprocessListener;
|
||||||
@@ -15,7 +16,13 @@ import com.nickcore.paper.listener.TabCompleteListener;
|
|||||||
import com.nickcore.paper.repository.DatabaseManager;
|
import com.nickcore.paper.repository.DatabaseManager;
|
||||||
import com.nickcore.paper.repository.SqlNickRepository;
|
import com.nickcore.paper.repository.SqlNickRepository;
|
||||||
import com.nickcore.paper.scheduler.SchedulerAdapter;
|
import com.nickcore.paper.scheduler.SchedulerAdapter;
|
||||||
import com.nickcore.paper.service.*;
|
import com.nickcore.paper.service.ChatService;
|
||||||
|
import com.nickcore.paper.service.NameOverrideService;
|
||||||
|
import com.nickcore.paper.service.NametagService;
|
||||||
|
import com.nickcore.paper.service.NickService;
|
||||||
|
import com.nickcore.paper.service.PlaceholderService;
|
||||||
|
import com.nickcore.paper.service.RankService;
|
||||||
|
import com.nickcore.paper.service.SkinService;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
@@ -24,7 +31,11 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,6 +103,9 @@ public final class NickCorePlugin extends JavaPlugin {
|
|||||||
chatService = new ChatService(profileCache, rankService, getLogger());
|
chatService = new ChatService(profileCache, rankService, getLogger());
|
||||||
nameOverrideService = new NameOverrideService(profileCache);
|
nameOverrideService = new NameOverrideService(profileCache);
|
||||||
|
|
||||||
|
// Hook into Atlantis Disguises for packet-level nick/skin support
|
||||||
|
hookAtlantisDisguises();
|
||||||
|
|
||||||
// Load data files
|
// Load data files
|
||||||
loadNames();
|
loadNames();
|
||||||
loadRanks();
|
loadRanks();
|
||||||
@@ -125,7 +139,7 @@ public final class NickCorePlugin extends JavaPlugin {
|
|||||||
Bukkit.getPluginManager().registerEvents(chatService, this);
|
Bukkit.getPluginManager().registerEvents(chatService, this);
|
||||||
Bukkit.getPluginManager().registerEvents(guiManager, this);
|
Bukkit.getPluginManager().registerEvents(guiManager, this);
|
||||||
Bukkit.getPluginManager().registerEvents(
|
Bukkit.getPluginManager().registerEvents(
|
||||||
new CommandPreprocessListener(nameOverrideService, getLogger()), this);
|
new CommandPreprocessListener(nameOverrideService), this);
|
||||||
Bukkit.getPluginManager().registerEvents(
|
Bukkit.getPluginManager().registerEvents(
|
||||||
new TabCompleteListener(nameOverrideService), this);
|
new TabCompleteListener(nameOverrideService), this);
|
||||||
|
|
||||||
@@ -291,6 +305,18 @@ public final class NickCorePlugin extends JavaPlugin {
|
|||||||
skinService.loadConfiguredSkins(skins);
|
skinService.loadConfiguredSkins(skins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hookAtlantisDisguises() {
|
||||||
|
if (Bukkit.getPluginManager().getPlugin("AtlantisDisguises") != null) {
|
||||||
|
AtlantisDisguiseIntegration atlantis = new AtlantisDisguiseIntegration(getLogger());
|
||||||
|
if (atlantis.hook()) {
|
||||||
|
nameOverrideService.setAtlantis(atlantis);
|
||||||
|
getLogger().info("Atlantis Disguises integration enabled — using packet-level disguises");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getLogger().info("Atlantis Disguises not found — using built-in name overrides");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void registerPlaceholderAPI() {
|
private void registerPlaceholderAPI() {
|
||||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||||
placeholderExpansion = new NickCoreExpansion(this, placeholderService);
|
placeholderExpansion = new NickCoreExpansion(this, placeholderService);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.nickcore.paper.command;
|
package com.nickcore.paper.command;
|
||||||
|
|
||||||
import com.nickcore.common.model.NickHistory;
|
|
||||||
import com.nickcore.common.model.NickProfile;
|
import com.nickcore.common.model.NickProfile;
|
||||||
import com.nickcore.common.validation.InputSanitizer;
|
import com.nickcore.common.validation.InputSanitizer;
|
||||||
import com.nickcore.paper.gui.GuiManager;
|
import com.nickcore.paper.gui.GuiManager;
|
||||||
@@ -23,7 +22,8 @@ import org.bukkit.command.CommandSender;
|
|||||||
import org.bukkit.command.TabCompleter;
|
import org.bukkit.command.TabCompleter;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -39,7 +39,6 @@ public final class NickCommand implements CommandExecutor, TabCompleter {
|
|||||||
private static final String PERM_RESET = "nickcore.reset";
|
private static final String PERM_RESET = "nickcore.reset";
|
||||||
private static final String PERM_RANK = "nickcore.rank.select";
|
private static final String PERM_RANK = "nickcore.rank.select";
|
||||||
private static final String PERM_SKIN = "nickcore.skin.select";
|
private static final String PERM_SKIN = "nickcore.skin.select";
|
||||||
private static final String PERM_ADMIN = "nickcore.admin";
|
|
||||||
private static final String PERM_RELOAD = "nickcore.reload";
|
private static final String PERM_RELOAD = "nickcore.reload";
|
||||||
private static final String PERM_FORCE = "nickcore.force";
|
private static final String PERM_FORCE = "nickcore.force";
|
||||||
private static final String PERM_INFO = "nickcore.info";
|
private static final String PERM_INFO = "nickcore.info";
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import org.bukkit.inventory.InventoryHolder;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package com.nickcore.paper.gui;
|
package com.nickcore.paper.gui;
|
||||||
|
|
||||||
import com.nickcore.paper.cache.ProfileCache;
|
import com.nickcore.paper.cache.ProfileCache;
|
||||||
import com.nickcore.paper.service.*;
|
import com.nickcore.paper.service.NickService;
|
||||||
|
import com.nickcore.paper.service.NametagService;
|
||||||
|
import com.nickcore.paper.service.PlaceholderService;
|
||||||
|
import com.nickcore.paper.service.RankService;
|
||||||
|
import com.nickcore.paper.service.SkinService;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
@@ -10,7 +14,7 @@ import org.bukkit.event.inventory.InventoryCloseEvent;
|
|||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,7 +58,7 @@ public final class GuiManager implements Listener {
|
|||||||
|
|
||||||
public void openRankMenu(Player player) {
|
public void openRankMenu(Player player) {
|
||||||
RankMenuGui gui = new RankMenuGui(player, this, nickService, rankService,
|
RankMenuGui gui = new RankMenuGui(player, this, nickService, rankService,
|
||||||
profileCache, placeholderService, nametagService);
|
placeholderService, nametagService);
|
||||||
openGuis.put(player.getUniqueId(), gui);
|
openGuis.put(player.getUniqueId(), gui);
|
||||||
gui.open();
|
gui.open();
|
||||||
}
|
}
|
||||||
@@ -67,7 +71,7 @@ public final class GuiManager implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClick(InventoryClickEvent event) {
|
public void onInventoryClick(InventoryClickEvent event) {
|
||||||
if (!(event.getWhoClicked() instanceof Player player)) return;
|
if (!(event.getWhoClicked() instanceof Player)) return;
|
||||||
if (!(event.getInventory().getHolder() instanceof AbstractGui gui)) return;
|
if (!(event.getInventory().getHolder() instanceof AbstractGui gui)) return;
|
||||||
gui.handleClick(event);
|
gui.handleClick(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.nickcore.paper.gui;
|
package com.nickcore.paper.gui;
|
||||||
|
|
||||||
import com.nickcore.common.validation.InputSanitizer;
|
|
||||||
import com.nickcore.paper.service.NickService;
|
import com.nickcore.paper.service.NickService;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.nickcore.paper.gui;
|
package com.nickcore.paper.gui;
|
||||||
|
|
||||||
import com.nickcore.common.model.NickProfile;
|
|
||||||
import com.nickcore.common.model.RankDefinition;
|
import com.nickcore.common.model.RankDefinition;
|
||||||
import com.nickcore.paper.cache.ProfileCache;
|
|
||||||
import com.nickcore.paper.service.NickService;
|
import com.nickcore.paper.service.NickService;
|
||||||
import com.nickcore.paper.service.NametagService;
|
import com.nickcore.paper.service.NametagService;
|
||||||
import com.nickcore.paper.service.PlaceholderService;
|
import com.nickcore.paper.service.PlaceholderService;
|
||||||
@@ -24,20 +22,18 @@ public final class RankMenuGui extends AbstractGui {
|
|||||||
private final GuiManager guiManager;
|
private final GuiManager guiManager;
|
||||||
private final NickService nickService;
|
private final NickService nickService;
|
||||||
private final RankService rankService;
|
private final RankService rankService;
|
||||||
private final ProfileCache profileCache;
|
|
||||||
private final PlaceholderService placeholderService;
|
private final PlaceholderService placeholderService;
|
||||||
private final NametagService nametagService;
|
private final NametagService nametagService;
|
||||||
private final MiniMessage mm = MiniMessage.miniMessage();
|
private final MiniMessage mm = MiniMessage.miniMessage();
|
||||||
private int page = 0;
|
private int page = 0;
|
||||||
|
|
||||||
public RankMenuGui(Player viewer, GuiManager guiManager, NickService nickService,
|
public RankMenuGui(Player viewer, GuiManager guiManager, NickService nickService,
|
||||||
RankService rankService, ProfileCache profileCache,
|
RankService rankService, PlaceholderService placeholderService,
|
||||||
PlaceholderService placeholderService, NametagService nametagService) {
|
NametagService nametagService) {
|
||||||
super(viewer, 54, Component.text("Select Rank", NamedTextColor.GOLD, TextDecoration.BOLD));
|
super(viewer, 54, Component.text("Select Rank", NamedTextColor.GOLD, TextDecoration.BOLD));
|
||||||
this.guiManager = guiManager;
|
this.guiManager = guiManager;
|
||||||
this.nickService = nickService;
|
this.nickService = nickService;
|
||||||
this.rankService = rankService;
|
this.rankService = rankService;
|
||||||
this.profileCache = profileCache;
|
|
||||||
this.placeholderService = placeholderService;
|
this.placeholderService = placeholderService;
|
||||||
this.nametagService = nametagService;
|
this.nametagService = nametagService;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package com.nickcore.paper.integration;
|
||||||
|
|
||||||
|
import net.atlantismc.disguises.api.API;
|
||||||
|
import net.atlantismc.disguises.api.DisguiseProvider;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration bridge for the Atlantis Disguises plugin.
|
||||||
|
*
|
||||||
|
* <p>When Atlantis Disguises is present on the server, NickCore delegates
|
||||||
|
* all name-change and skin operations to it. Atlantis handles packet-level
|
||||||
|
* name injection, skin application, and GameProfile rewriting — producing
|
||||||
|
* a much more seamless disguise than NickCore's built-in display-name approach.</p>
|
||||||
|
*
|
||||||
|
* <p>All methods are safe to call even if Atlantis is not loaded; they will
|
||||||
|
* return false/null gracefully.</p>
|
||||||
|
*/
|
||||||
|
public final class AtlantisDisguiseIntegration {
|
||||||
|
|
||||||
|
private final Logger logger;
|
||||||
|
private volatile boolean available;
|
||||||
|
|
||||||
|
public AtlantisDisguiseIntegration(Logger logger) {
|
||||||
|
this.logger = Objects.requireNonNull(logger);
|
||||||
|
this.available = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to hook into the Atlantis Disguises API.
|
||||||
|
* Call this during plugin enable after soft-depend loads.
|
||||||
|
*
|
||||||
|
* @return true if the API was successfully hooked
|
||||||
|
*/
|
||||||
|
public boolean hook() {
|
||||||
|
try {
|
||||||
|
API api = DisguiseProvider.get();
|
||||||
|
if (api != null) {
|
||||||
|
available = true;
|
||||||
|
logger.info("[NickCore] Hooked into Atlantis Disguises API");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (NoClassDefFoundError | Exception e) {
|
||||||
|
logger.log(Level.FINE, "Atlantis Disguises not available, using built-in name overrides", e);
|
||||||
|
}
|
||||||
|
available = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if Atlantis Disguises is available and hooked.
|
||||||
|
*/
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disguises a player with the given name via Atlantis.
|
||||||
|
* This handles packet-level GameProfile rewriting, skin changes, and
|
||||||
|
* nametag updates — all at the protocol level.
|
||||||
|
*
|
||||||
|
* @param player the player to disguise
|
||||||
|
* @param name the disguise name
|
||||||
|
* @return true if the disguise was applied successfully
|
||||||
|
*/
|
||||||
|
public boolean disguise(Player player, String name) {
|
||||||
|
if (!available || player == null || name == null) return false;
|
||||||
|
try {
|
||||||
|
API api = DisguiseProvider.get();
|
||||||
|
if (api != null) {
|
||||||
|
return api.disguise(player, name);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, "Failed to apply Atlantis disguise for " + player.getName(), e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a player's disguise via Atlantis.
|
||||||
|
*
|
||||||
|
* @param player the player to undisguise
|
||||||
|
* @return true if the disguise was removed
|
||||||
|
*/
|
||||||
|
public boolean undisguise(Player player) {
|
||||||
|
if (!available || player == null) return false;
|
||||||
|
try {
|
||||||
|
API api = DisguiseProvider.get();
|
||||||
|
if (api != null) {
|
||||||
|
return api.undisguise(player);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, "Failed to remove Atlantis disguise for " + player.getName(), e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a player is currently disguised via Atlantis.
|
||||||
|
*/
|
||||||
|
public boolean isDisguised(Player player) {
|
||||||
|
if (!available || player == null) return false;
|
||||||
|
try {
|
||||||
|
API api = DisguiseProvider.get();
|
||||||
|
return api != null && api.isDisguised(player);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current disguise name for a player via Atlantis.
|
||||||
|
*
|
||||||
|
* @return the disguise name, or null if not disguised
|
||||||
|
*/
|
||||||
|
public String getDisguiseName(Player player) {
|
||||||
|
if (!available || player == null) return null;
|
||||||
|
try {
|
||||||
|
API api = DisguiseProvider.get();
|
||||||
|
return api != null ? api.getDisguise(player) : null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ public final class NickCoreExpansion extends PlaceholderExpansion {
|
|||||||
public @NotNull String getIdentifier() { return "nickcore"; }
|
public @NotNull String getIdentifier() { return "nickcore"; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull String getAuthor() { return "NickCore Team"; }
|
public @NotNull String getAuthor() { return "BaileyCodes"; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull String getVersion() { return plugin.getPluginMeta().getVersion(); }
|
public @NotNull String getVersion() { return plugin.getPluginMeta().getVersion(); }
|
||||||
|
|||||||
@@ -9,9 +9,6 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intercepts player commands and replaces nick names with real names before dispatch.
|
* Intercepts player commands and replaces nick names with real names before dispatch.
|
||||||
@@ -25,14 +22,9 @@ import java.util.regex.Pattern;
|
|||||||
public final class CommandPreprocessListener implements Listener {
|
public final class CommandPreprocessListener implements Listener {
|
||||||
|
|
||||||
private final NameOverrideService nameOverrideService;
|
private final NameOverrideService nameOverrideService;
|
||||||
private final Logger logger;
|
|
||||||
|
|
||||||
/** Pattern to split command into parts while preserving structure. */
|
public CommandPreprocessListener(NameOverrideService nameOverrideService) {
|
||||||
private static final Pattern WORD_BOUNDARY = Pattern.compile("\\s+");
|
|
||||||
|
|
||||||
public CommandPreprocessListener(NameOverrideService nameOverrideService, Logger logger) {
|
|
||||||
this.nameOverrideService = Objects.requireNonNull(nameOverrideService);
|
this.nameOverrideService = Objects.requireNonNull(nameOverrideService);
|
||||||
this.logger = Objects.requireNonNull(logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package com.nickcore.paper.listener;
|
package com.nickcore.paper.listener;
|
||||||
|
|
||||||
import com.nickcore.common.model.NickProfile;
|
import com.nickcore.common.model.NickProfile;
|
||||||
import com.nickcore.common.validation.InputSanitizer;
|
import com.nickcore.paper.service.NameOverrideService;
|
||||||
import com.nickcore.paper.service.*;
|
import com.nickcore.paper.service.NametagService;
|
||||||
|
import com.nickcore.paper.service.NickService;
|
||||||
|
import com.nickcore.paper.service.PlaceholderService;
|
||||||
|
import com.nickcore.paper.service.SkinService;
|
||||||
import com.nickcore.paper.scheduler.SchedulerAdapter;
|
import com.nickcore.paper.scheduler.SchedulerAdapter;
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
@@ -29,7 +30,6 @@ public final class PlayerConnectionListener implements Listener {
|
|||||||
private final NameOverrideService nameOverrideService;
|
private final NameOverrideService nameOverrideService;
|
||||||
private final SchedulerAdapter scheduler;
|
private final SchedulerAdapter scheduler;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final MiniMessage mm = MiniMessage.miniMessage();
|
|
||||||
|
|
||||||
public PlayerConnectionListener(Plugin plugin, NickService nickService,
|
public PlayerConnectionListener(Plugin plugin, NickService nickService,
|
||||||
SkinService skinService, PlaceholderService placeholderService,
|
SkinService skinService, PlaceholderService placeholderService,
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import com.zaxxer.hikari.HikariConfig;
|
|||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package com.nickcore.paper.service;
|
|||||||
|
|
||||||
import com.nickcore.common.model.NickProfile;
|
import com.nickcore.common.model.NickProfile;
|
||||||
import com.nickcore.paper.cache.ProfileCache;
|
import com.nickcore.paper.cache.ProfileCache;
|
||||||
|
import com.nickcore.paper.integration.AtlantisDisguiseIntegration;
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -20,6 +20,10 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
* tab completion, /tpa, /msg, player list, nametags, and any plugin that resolves
|
* tab completion, /tpa, /msg, player list, nametags, and any plugin that resolves
|
||||||
* players by display name.
|
* players by display name.
|
||||||
*
|
*
|
||||||
|
* <p>When Atlantis Disguises is available, delegates to it for packet-level
|
||||||
|
* GameProfile rewriting (the most thorough approach). Otherwise, falls back to
|
||||||
|
* Bukkit display name + custom name overrides.</p>
|
||||||
|
*
|
||||||
* <p>Maintains a bidirectional mapping between nick names and real names so that
|
* <p>Maintains a bidirectional mapping between nick names and real names so that
|
||||||
* commands referencing a nick name can be resolved back to the actual player.</p>
|
* commands referencing a nick name can be resolved back to the actual player.</p>
|
||||||
*
|
*
|
||||||
@@ -28,7 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
public final class NameOverrideService {
|
public final class NameOverrideService {
|
||||||
|
|
||||||
private final ProfileCache profileCache;
|
private final ProfileCache profileCache;
|
||||||
private final MiniMessage miniMessage = MiniMessage.miniMessage();
|
private volatile AtlantisDisguiseIntegration atlantis;
|
||||||
|
|
||||||
/** nick (lowercase) -> real player UUID */
|
/** nick (lowercase) -> real player UUID */
|
||||||
private final ConcurrentHashMap<String, UUID> nickToUuid = new ConcurrentHashMap<>(512);
|
private final ConcurrentHashMap<String, UUID> nickToUuid = new ConcurrentHashMap<>(512);
|
||||||
@@ -40,9 +44,21 @@ public final class NameOverrideService {
|
|||||||
this.profileCache = Objects.requireNonNull(profileCache);
|
this.profileCache = Objects.requireNonNull(profileCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Atlantis Disguises integration. When set and available,
|
||||||
|
* disguise/undisguise operations are delegated to Atlantis for
|
||||||
|
* packet-level name rewriting.
|
||||||
|
*/
|
||||||
|
public void setAtlantis(AtlantisDisguiseIntegration atlantis) {
|
||||||
|
this.atlantis = atlantis;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies a full name override to a player: display name, player list name,
|
* Applies a full name override to a player: display name, player list name,
|
||||||
* custom name, and registers the nick in lookup maps.
|
* custom name, and registers the nick in lookup maps.
|
||||||
|
*
|
||||||
|
* <p>If Atlantis Disguises is available, uses its packet-level disguise system
|
||||||
|
* which rewrites the GameProfile and handles skin + nametag automatically.</p>
|
||||||
*/
|
*/
|
||||||
public void applyFullOverride(Player player) {
|
public void applyFullOverride(Player player) {
|
||||||
NickProfile profile = profileCache.get(player.getUniqueId()).orElse(null);
|
NickProfile profile = profileCache.get(player.getUniqueId()).orElse(null);
|
||||||
@@ -52,16 +68,21 @@ public final class NameOverrideService {
|
|||||||
|
|
||||||
if (profile == null || !profile.nicked() || profile.nickname() == null) {
|
if (profile == null || !profile.nicked() || profile.nickname() == null) {
|
||||||
// Not nicked — restore real identity
|
// Not nicked — restore real identity
|
||||||
player.displayName(Component.text(player.getName()));
|
undisguisePlayer(player);
|
||||||
player.playerListName(Component.text(player.getName()));
|
|
||||||
player.customName(null);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String nick = profile.nickname();
|
String nick = profile.nickname();
|
||||||
Component nickComponent = Component.text(nick);
|
|
||||||
|
|
||||||
// Set all name surfaces
|
// Try Atlantis Disguises first (packet-level, most thorough)
|
||||||
|
boolean atlantisApplied = false;
|
||||||
|
AtlantisDisguiseIntegration atl = this.atlantis;
|
||||||
|
if (atl != null && atl.isAvailable()) {
|
||||||
|
atlantisApplied = atl.disguise(player, nick);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always set Bukkit-level names as fallback/supplement
|
||||||
|
Component nickComponent = Component.text(nick);
|
||||||
player.displayName(nickComponent);
|
player.displayName(nickComponent);
|
||||||
player.playerListName(nickComponent);
|
player.playerListName(nickComponent);
|
||||||
player.customName(nickComponent);
|
player.customName(nickComponent);
|
||||||
@@ -71,6 +92,22 @@ public final class NameOverrideService {
|
|||||||
realToNick.put(player.getName().toLowerCase(), nick);
|
realToNick.put(player.getName().toLowerCase(), nick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all name overrides from a player.
|
||||||
|
*/
|
||||||
|
private void undisguisePlayer(Player player) {
|
||||||
|
// Undo Atlantis disguise if active
|
||||||
|
AtlantisDisguiseIntegration atl = this.atlantis;
|
||||||
|
if (atl != null && atl.isAvailable() && atl.isDisguised(player)) {
|
||||||
|
atl.undisguise(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Bukkit-level names
|
||||||
|
player.displayName(Component.text(player.getName()));
|
||||||
|
player.playerListName(Component.text(player.getName()));
|
||||||
|
player.customName(null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all name mappings for a player. Called on quit or reset.
|
* Clears all name mappings for a player. Called on quit or reset.
|
||||||
*/
|
*/
|
||||||
@@ -82,6 +119,15 @@ public final class NameOverrideService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fully resets a player's identity — clears mappings and undisguises.
|
||||||
|
* Called on /nick reset or when a player quits.
|
||||||
|
*/
|
||||||
|
public void resetPlayer(Player player) {
|
||||||
|
clearMapping(player);
|
||||||
|
undisguisePlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a player by either their nick name or real name.
|
* Resolves a player by either their nick name or real name.
|
||||||
* This is the key method that allows /tpa, /msg, etc. to work with nicks.
|
* This is the key method that allows /tpa, /msg, etc. to work with nicks.
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import com.nickcore.paper.cache.ProfileCache;
|
|||||||
import com.nickcore.paper.integration.VelocityMessaging;
|
import com.nickcore.paper.integration.VelocityMessaging;
|
||||||
import com.nickcore.paper.repository.NickRepository;
|
import com.nickcore.paper.repository.NickRepository;
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -37,7 +36,6 @@ public final class NickService {
|
|||||||
private final ProfileCache cache;
|
private final ProfileCache cache;
|
||||||
private final NicknameValidator validator;
|
private final NicknameValidator validator;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final MiniMessage miniMessage;
|
|
||||||
|
|
||||||
// Configurable name pool — loaded from names.yml, swapped atomically on reload
|
// Configurable name pool — loaded from names.yml, swapped atomically on reload
|
||||||
private volatile List<String> namePool = List.of();
|
private volatile List<String> namePool = List.of();
|
||||||
@@ -55,7 +53,6 @@ public final class NickService {
|
|||||||
this.cache = Objects.requireNonNull(cache);
|
this.cache = Objects.requireNonNull(cache);
|
||||||
this.validator = Objects.requireNonNull(validator);
|
this.validator = Objects.requireNonNull(validator);
|
||||||
this.logger = Objects.requireNonNull(logger);
|
this.logger = Objects.requireNonNull(logger);
|
||||||
this.miniMessage = MiniMessage.miniMessage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.nickcore.paper.service;
|
|||||||
import com.nickcore.common.model.NickProfile;
|
import com.nickcore.common.model.NickProfile;
|
||||||
import com.nickcore.common.model.RankDefinition;
|
import com.nickcore.common.model.RankDefinition;
|
||||||
import com.nickcore.paper.cache.ProfileCache;
|
import com.nickcore.paper.cache.ProfileCache;
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|||||||
@@ -5,7 +5,13 @@ import net.kyori.adventure.text.Component;
|
|||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,15 +6,19 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
import java.util.concurrent.*;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ main: com.nickcore.paper.NickCorePlugin
|
|||||||
api-version: '1.21'
|
api-version: '1.21'
|
||||||
description: Enterprise Minecraft Nickname Plugin
|
description: Enterprise Minecraft Nickname Plugin
|
||||||
author: BaileyCodes
|
author: BaileyCodes
|
||||||
website: https://nickcore.com
|
website: https://balls.studio
|
||||||
folia-supported: true
|
folia-supported: true
|
||||||
|
|
||||||
softdepend:
|
softdepend:
|
||||||
@@ -12,6 +12,7 @@ softdepend:
|
|||||||
- LuckPerms
|
- LuckPerms
|
||||||
- TAB
|
- TAB
|
||||||
- Essentials
|
- Essentials
|
||||||
|
- AtlantisDisguises
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
nick:
|
nick:
|
||||||
|
|||||||
@@ -11,9 +11,12 @@ dependencies {
|
|||||||
annotationProcessor("com.velocitypowered:velocity-api:$velocityApiVersion")
|
annotationProcessor("com.velocitypowered:velocity-api:$velocityApiVersion")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.jar {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
tasks.shadowJar {
|
tasks.shadowJar {
|
||||||
archiveClassifier.set("")
|
archiveFileName.set("NickCore-Velocity-${project.version}.jar")
|
||||||
archiveBaseName.set("NickCore-Velocity")
|
|
||||||
minimize()
|
minimize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.slf4j.Logger;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -108,10 +107,12 @@ public final class NickCoreVelocity {
|
|||||||
(uuid, p) -> p.withNickname(message.nickname()));
|
(uuid, p) -> p.withNickname(message.nickname()));
|
||||||
case RANK_UPDATE -> proxyCache.computeIfPresent(message.playerUuid(),
|
case RANK_UPDATE -> proxyCache.computeIfPresent(message.playerUuid(),
|
||||||
(uuid, p) -> p.withRank(message.rankId()));
|
(uuid, p) -> p.withRank(message.rankId()));
|
||||||
|
case SKIN_UPDATE -> proxyCache.computeIfPresent(message.playerUuid(),
|
||||||
|
(uuid, p) -> p.withSkin(message.skinId(), message.skinValue(), message.skinSignature()));
|
||||||
case RESET -> proxyCache.computeIfPresent(message.playerUuid(),
|
case RESET -> proxyCache.computeIfPresent(message.playerUuid(),
|
||||||
(uuid, p) -> p.reset());
|
(uuid, p) -> p.reset());
|
||||||
case CACHE_INVALIDATE -> proxyCache.remove(message.playerUuid());
|
case CACHE_INVALIDATE -> proxyCache.remove(message.playerUuid());
|
||||||
default -> { /* ignore */ }
|
default -> { /* PLAYER_JOIN, PLAYER_QUIT — no proxy-side action needed */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward to all OTHER servers
|
// Forward to all OTHER servers
|
||||||
|
|||||||
Reference in New Issue
Block a user