feat: add mute/unmute commands with MuteManager
This commit is contained in:
parent
55c965603f
commit
c4d2768423
27 changed files with 559 additions and 2352 deletions
|
|
@ -28,6 +28,7 @@ public final class LoChat extends JavaPlugin {
|
|||
private EmojiManager emojiManager;
|
||||
private ChatColorManager chatColorManager;
|
||||
private CustomCommandManager customCommandManager;
|
||||
private MuteManager muteManager;
|
||||
private GradientModule gradientModule;
|
||||
private com.loki.lochat.listeners.DisplayNameListener displayNameListener;
|
||||
|
||||
|
|
@ -50,6 +51,7 @@ public final class LoChat extends JavaPlugin {
|
|||
spyManager = new SpyManager(this);
|
||||
chatColorManager = new ChatColorManager(this);
|
||||
customCommandManager = new CustomCommandManager(this);
|
||||
muteManager = new MuteManager(this);
|
||||
chatManager = new ChatManager(this);
|
||||
autoMessageManager = new AutoMessageManager(this);
|
||||
|
||||
|
|
@ -90,6 +92,9 @@ public final class LoChat extends JavaPlugin {
|
|||
if (chatColorManager != null) {
|
||||
chatColorManager.saveData();
|
||||
}
|
||||
if (muteManager != null) {
|
||||
muteManager.saveData();
|
||||
}
|
||||
if (gradientModule != null) {
|
||||
gradientModule.shutdown();
|
||||
}
|
||||
|
|
@ -107,6 +112,8 @@ public final class LoChat extends JavaPlugin {
|
|||
getCommand("announce").setExecutor(new AnnounceCommand(this));
|
||||
getCommand("chatspy").setExecutor(new ChatSpyCommand(this));
|
||||
getCommand("clearchat").setExecutor(new ClearChatCommand(this));
|
||||
getCommand("mute").setExecutor(new MuteCommand(this));
|
||||
getCommand("unmute").setExecutor(new UnmuteCommand(this));
|
||||
getCommand("chatcolor").setExecutor(new ChatColorCommand(this));
|
||||
|
||||
LoChatCommand loChatCommand = new LoChatCommand(this);
|
||||
|
|
@ -195,6 +202,10 @@ public final class LoChat extends JavaPlugin {
|
|||
return customCommandManager;
|
||||
}
|
||||
|
||||
public MuteManager getMuteManager() {
|
||||
return muteManager;
|
||||
}
|
||||
|
||||
public com.loki.lochat.listeners.DisplayNameListener getDisplayNameListener() {
|
||||
return displayNameListener;
|
||||
}
|
||||
|
|
|
|||
122
src/main/java/com/loki/lochat/commands/MuteCommand.java
Normal file
122
src/main/java/com/loki/lochat/commands/MuteCommand.java
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
package com.loki.lochat.commands;
|
||||
|
||||
import com.loki.lochat.LoChat;
|
||||
import com.loki.lochat.utils.ChatFormatter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MuteCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final LoChat plugin;
|
||||
|
||||
public MuteCommand(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (!sender.hasPermission("chat.mute")) {
|
||||
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getNoPermission()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getInvalidUsage("/mute <игрок> <время> [причина]")));
|
||||
sender.sendMessage(ChatFormatter.parse("<gray>Время: 1m, 1h, 1d, permanent"));
|
||||
return true;
|
||||
}
|
||||
|
||||
String playerName = args[0];
|
||||
String timeStr = args[1];
|
||||
String reason = args.length > 2 ? String.join(" ", Arrays.copyOfRange(args, 2, args.length)) : "Нарушение правил чата";
|
||||
|
||||
Player target = Bukkit.getPlayer(playerName);
|
||||
if (target == null) {
|
||||
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getPlayerNotFound()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Парсим время
|
||||
long duration = parseTime(timeStr);
|
||||
if (duration == -1) {
|
||||
sender.sendMessage(ChatFormatter.parse("<red>Неверный формат времени! Используйте: 1m, 1h, 1d, permanent"));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Мутим игрока
|
||||
plugin.getMuteManager().mutePlayer(target.getUniqueId(), duration, reason, sender.getName());
|
||||
|
||||
// Уведомления
|
||||
String timeDisplay = duration == 0 ? "навсегда" : formatTime(duration);
|
||||
sender.sendMessage(ChatFormatter.parse(
|
||||
plugin.getMessageConfig().get("mute.muted", "{player}", target.getName(), "{time}", timeDisplay)
|
||||
));
|
||||
|
||||
if (target.isOnline()) {
|
||||
target.sendMessage(ChatFormatter.parse(
|
||||
plugin.getMessageConfig().get("mute.you-muted", "{time}", timeDisplay)
|
||||
));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private long parseTime(String timeStr) {
|
||||
if (timeStr.equalsIgnoreCase("permanent") || timeStr.equalsIgnoreCase("perm")) {
|
||||
return 0; // 0 = permanent
|
||||
}
|
||||
|
||||
try {
|
||||
char unit = timeStr.charAt(timeStr.length() - 1);
|
||||
int amount = Integer.parseInt(timeStr.substring(0, timeStr.length() - 1));
|
||||
|
||||
return switch (unit) {
|
||||
case 'm' -> amount * 60L * 1000L; // минуты
|
||||
case 'h' -> amount * 60L * 60L * 1000L; // часы
|
||||
case 'd' -> amount * 24L * 60L * 60L * 1000L; // дни
|
||||
default -> -1;
|
||||
};
|
||||
} catch (NumberFormatException | StringIndexOutOfBoundsException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private String formatTime(long millis) {
|
||||
long seconds = millis / 1000;
|
||||
long minutes = seconds / 60;
|
||||
long hours = minutes / 60;
|
||||
long days = hours / 24;
|
||||
|
||||
if (days > 0) return days + "д";
|
||||
if (hours > 0) return hours + "ч";
|
||||
if (minutes > 0) return minutes + "м";
|
||||
return seconds + "с";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Bukkit.getOnlinePlayers().stream()
|
||||
.map(Player::getName)
|
||||
.filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
} else if (args.length == 2) {
|
||||
List<String> times = Arrays.asList("1m", "5m", "10m", "30m", "1h", "2h", "6h", "12h", "1d", "3d", "7d", "permanent");
|
||||
return times.stream()
|
||||
.filter(time -> time.toLowerCase().startsWith(args[1].toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
76
src/main/java/com/loki/lochat/commands/UnmuteCommand.java
Normal file
76
src/main/java/com/loki/lochat/commands/UnmuteCommand.java
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package com.loki.lochat.commands;
|
||||
|
||||
import com.loki.lochat.LoChat;
|
||||
import com.loki.lochat.utils.ChatFormatter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class UnmuteCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final LoChat plugin;
|
||||
|
||||
public UnmuteCommand(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (!sender.hasPermission("chat.mute")) {
|
||||
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getNoPermission()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length != 1) {
|
||||
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getInvalidUsage("/unmute <игрок>")));
|
||||
return true;
|
||||
}
|
||||
|
||||
String playerName = args[0];
|
||||
Player target = Bukkit.getPlayer(playerName);
|
||||
if (target == null) {
|
||||
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getPlayerNotFound()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!plugin.getMuteManager().isMuted(target.getUniqueId())) {
|
||||
sender.sendMessage(ChatFormatter.parse(
|
||||
plugin.getMessageConfig().get("mute.not-muted", "{player}", target.getName())
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Размучиваем
|
||||
plugin.getMuteManager().unmutePlayer(target.getUniqueId());
|
||||
|
||||
// Уведомления
|
||||
sender.sendMessage(ChatFormatter.parse(
|
||||
plugin.getMessageConfig().get("mute.unmuted", "{player}", target.getName())
|
||||
));
|
||||
|
||||
if (target.isOnline()) {
|
||||
target.sendMessage(ChatFormatter.parse("<green>Вы были размучены!"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Bukkit.getOnlinePlayers().stream()
|
||||
.map(Player::getName)
|
||||
.filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -57,6 +57,17 @@ public class PlaceholderAPIHook extends PlaceholderExpansion {
|
|||
}
|
||||
case "spy_enabled" -> String.valueOf(plugin.getSpyManager().isSpying(uuid));
|
||||
|
||||
// Mute placeholders
|
||||
case "muted" -> String.valueOf(plugin.getMuteManager().isMuted(uuid));
|
||||
case "mute_time" -> {
|
||||
if (!plugin.getMuteManager().isMuted(uuid)) yield "";
|
||||
yield plugin.getMuteManager().formatRemainingTime(uuid);
|
||||
}
|
||||
case "mute_reason" -> {
|
||||
var muteData = plugin.getMuteManager().getMuteData(uuid);
|
||||
yield muteData != null ? muteData.reason : "";
|
||||
}
|
||||
|
||||
// Gradient placeholders (совместимость с LoPreff)
|
||||
case "gradient_full", "full" -> {
|
||||
Player onlinePlayer = player.getPlayer();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,19 @@ public class ChatListener implements Listener {
|
|||
}
|
||||
|
||||
private void processChat(Player player, String message) {
|
||||
// Проверка мута
|
||||
if (plugin.getMuteManager().isMuted(player.getUniqueId())) {
|
||||
String timeLeft = plugin.getMuteManager().formatRemainingTime(player.getUniqueId());
|
||||
if (timeLeft.equals("навсегда")) {
|
||||
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("mute.permanent")));
|
||||
} else {
|
||||
player.sendMessage(ChatFormatter.parse(
|
||||
plugin.getMessageConfig().get("mute.you-muted", "{time}", timeLeft)
|
||||
));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String globalSymbol = plugin.getConfigManager().getGlobalSymbol();
|
||||
boolean isGlobal = message.startsWith(globalSymbol) && player.hasPermission("chat.global.use");
|
||||
String chatType = isGlobal ? "global" : "local";
|
||||
|
|
|
|||
147
src/main/java/com/loki/lochat/managers/MuteManager.java
Normal file
147
src/main/java/com/loki/lochat/managers/MuteManager.java
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
package com.loki.lochat.managers;
|
||||
|
||||
import com.loki.lochat.LoChat;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MuteManager {
|
||||
|
||||
private final LoChat plugin;
|
||||
private final Map<UUID, MuteData> mutedPlayers;
|
||||
private File dataFile;
|
||||
private FileConfiguration dataConfig;
|
||||
|
||||
public MuteManager(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
this.mutedPlayers = new HashMap<>();
|
||||
loadData();
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
dataFile = new File(plugin.getDataFolder(), "mutes.yml");
|
||||
if (!dataFile.exists()) {
|
||||
try {
|
||||
dataFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().severe("Не удалось создать файл mutes.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
|
||||
|
||||
// Загружаем муты из файла
|
||||
for (String key : dataConfig.getKeys(false)) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(key);
|
||||
long expiry = dataConfig.getLong(key + ".expiry");
|
||||
String reason = dataConfig.getString(key + ".reason", "Нарушение правил");
|
||||
String mutedBy = dataConfig.getString(key + ".muted_by", "Система");
|
||||
|
||||
// Проверяем не истёк ли мут
|
||||
if (expiry > 0 && System.currentTimeMillis() > expiry) {
|
||||
dataConfig.set(key, null);
|
||||
continue;
|
||||
}
|
||||
|
||||
mutedPlayers.put(uuid, new MuteData(expiry, reason, mutedBy));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// Неверный UUID, пропускаем
|
||||
}
|
||||
}
|
||||
|
||||
saveData();
|
||||
}
|
||||
|
||||
public void saveData() {
|
||||
for (Map.Entry<UUID, MuteData> entry : mutedPlayers.entrySet()) {
|
||||
String key = entry.getKey().toString();
|
||||
MuteData data = entry.getValue();
|
||||
|
||||
dataConfig.set(key + ".expiry", data.expiry);
|
||||
dataConfig.set(key + ".reason", data.reason);
|
||||
dataConfig.set(key + ".muted_by", data.mutedBy);
|
||||
}
|
||||
|
||||
try {
|
||||
dataConfig.save(dataFile);
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().severe("Не удалось сохранить mutes.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void mutePlayer(UUID playerId, long duration, String reason, String mutedBy) {
|
||||
long expiry = duration == 0 ? 0 : System.currentTimeMillis() + duration;
|
||||
mutedPlayers.put(playerId, new MuteData(expiry, reason, mutedBy));
|
||||
saveData();
|
||||
}
|
||||
|
||||
public void unmutePlayer(UUID playerId) {
|
||||
mutedPlayers.remove(playerId);
|
||||
dataConfig.set(playerId.toString(), null);
|
||||
saveData();
|
||||
}
|
||||
|
||||
public boolean isMuted(UUID playerId) {
|
||||
MuteData data = mutedPlayers.get(playerId);
|
||||
if (data == null) return false;
|
||||
|
||||
// Проверяем не истёк ли мут
|
||||
if (data.expiry > 0 && System.currentTimeMillis() > data.expiry) {
|
||||
unmutePlayer(playerId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public MuteData getMuteData(UUID playerId) {
|
||||
return mutedPlayers.get(playerId);
|
||||
}
|
||||
|
||||
public long getRemainingTime(UUID playerId) {
|
||||
MuteData data = mutedPlayers.get(playerId);
|
||||
if (data == null || data.expiry == 0) return 0;
|
||||
|
||||
long remaining = data.expiry - System.currentTimeMillis();
|
||||
return Math.max(0, remaining);
|
||||
}
|
||||
|
||||
public String formatRemainingTime(UUID playerId) {
|
||||
long remaining = getRemainingTime(playerId);
|
||||
if (remaining == 0) {
|
||||
MuteData data = getMuteData(playerId);
|
||||
if (data != null && data.expiry == 0) {
|
||||
return "навсегда";
|
||||
}
|
||||
return "0с";
|
||||
}
|
||||
|
||||
long seconds = remaining / 1000;
|
||||
long minutes = seconds / 60;
|
||||
long hours = minutes / 60;
|
||||
long days = hours / 24;
|
||||
|
||||
if (days > 0) return days + "д " + (hours % 24) + "ч";
|
||||
if (hours > 0) return hours + "ч " + (minutes % 60) + "м";
|
||||
if (minutes > 0) return minutes + "м " + (seconds % 60) + "с";
|
||||
return seconds + "с";
|
||||
}
|
||||
|
||||
public static class MuteData {
|
||||
public final long expiry; // 0 = permanent
|
||||
public final String reason;
|
||||
public final String mutedBy;
|
||||
|
||||
public MuteData(long expiry, String reason, String mutedBy) {
|
||||
this.expiry = expiry;
|
||||
this.reason = reason;
|
||||
this.mutedBy = mutedBy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,19 +40,106 @@ mentions:
|
|||
sound: true
|
||||
sound-type: "BLOCK_NOTE_BLOCK_PLING"
|
||||
# Выделение при @ник
|
||||
highlight: "<yellow>@{player}</yellow>"
|
||||
highlight: "<#04CADF>@{player}</#04CADF>"
|
||||
# Выделение когда твой ник написали (без @)
|
||||
self-highlight: "<gold><bold>{player}</bold></gold>"
|
||||
self-highlight: "<#04CADF>{player}</#04CADF>"
|
||||
|
||||
# Фильтр мата
|
||||
filter:
|
||||
enabled: true
|
||||
# Регулярные выражения для обнаружения мата с обходами
|
||||
patterns:
|
||||
# Основные корни с вариациями
|
||||
- "х\\s*у\\s*[йяёе]" # хуй, хуя, хуё, хуе
|
||||
- "[хx]\\s*у\\s*[йяёе]" # латиница: xuй
|
||||
- "п\\s*[иi]\\s*з\\s*д" # пизд, пiзд
|
||||
- "п\\s*[иi]\\s*д\\s*[оа]\\s*р" # пидор, пидар
|
||||
- "[еeё]\\s*б\\s*[аоуыи]" # ебать, ебут, ебал
|
||||
- "б\\s*л\\s*я\\s*[тдь]" # блять, блядь
|
||||
- "с\\s*у\\s*к\\s*[аи]" # сука, суки
|
||||
- "м\\s*у\\s*д\\s*[аи]" # муда, муди
|
||||
- "г\\s*а\\s*н\\s*д\\s*о\\s*н" # гандон
|
||||
- "д\\s*р\\s*о\\s*ч" # дрочить
|
||||
- "с\\s*с\\s*а\\s*т\\s*ь" # ссать
|
||||
- "с\\s*р\\s*а\\s*т\\s*ь" # срать
|
||||
- "ш\\s*м\\s*а\\s*р\\s*[аи]" # шмара
|
||||
- "ч\\s*м\\s*[оы]" # чмо, чмы
|
||||
- "г\\s*н\\s*и\\s*д\\s*[аы]" # гнида
|
||||
|
||||
# Простые слова (для быстрой проверки)
|
||||
words:
|
||||
# Основные
|
||||
- "хуй"
|
||||
- "пизд"
|
||||
- "блять"
|
||||
- "хуя"
|
||||
- "хуё"
|
||||
- "хуе"
|
||||
- "хуёк"
|
||||
- "хуёчек"
|
||||
- "хуесос"
|
||||
- "хуеплёт"
|
||||
- "пизда"
|
||||
- "пизде"
|
||||
- "пизду"
|
||||
- "пиздец"
|
||||
- "пиздюк"
|
||||
- "пиздюшка"
|
||||
- "пиздануть"
|
||||
- "спиздить"
|
||||
- "пиздоглазый"
|
||||
- "ебать"
|
||||
- "ебал"
|
||||
- "ебут"
|
||||
- "ебись"
|
||||
- "ебитесь"
|
||||
- "ебашить"
|
||||
- "уёбывать"
|
||||
- "заёбывать"
|
||||
- "ебашка"
|
||||
- "ебанарот"
|
||||
- "блять"
|
||||
- "блядь"
|
||||
- "блядина"
|
||||
- "сука"
|
||||
- "суки"
|
||||
- "сучка"
|
||||
- "мудак"
|
||||
- "мудила"
|
||||
- "мудачок"
|
||||
- "гандон"
|
||||
- "гандоник"
|
||||
- "пидор"
|
||||
- "пидорас"
|
||||
- "дрочить"
|
||||
- "дрочка"
|
||||
- "онанист"
|
||||
- "ссать"
|
||||
- "срать"
|
||||
- "говно"
|
||||
- "говнюк"
|
||||
- "шмара"
|
||||
- "шлюха"
|
||||
- "проститутка"
|
||||
- "чмо"
|
||||
- "чмошник"
|
||||
- "чмырь"
|
||||
- "гнида"
|
||||
- "тварь"
|
||||
- "падла"
|
||||
- "сволочь"
|
||||
- "охуеть"
|
||||
- "ахуеть"
|
||||
- "нихуя"
|
||||
- "кончепизд"
|
||||
|
||||
# Обходы с символами
|
||||
- "х*й"
|
||||
- "п@зда"
|
||||
- "б#ять"
|
||||
- "хуй"
|
||||
- "ebat"
|
||||
- "pidar"
|
||||
- "mudak"
|
||||
|
||||
action: "censor" # censor/block/warn
|
||||
replacement: "***"
|
||||
|
||||
|
|
@ -69,14 +156,14 @@ automessages:
|
|||
random: false
|
||||
|
||||
formats:
|
||||
announcement: "<gold>[ОБЪЯВЛЕНИЕ]</gold> <message>"
|
||||
announcement: "<#04CADF>[ОБЪЯВЛЕНИЕ]</#04CADF> <message>"
|
||||
|
||||
# Настройки объявлений
|
||||
announcements:
|
||||
# Показывать title при объявлении
|
||||
show-title: true
|
||||
# Заголовок title
|
||||
title-header: "<gold>ОБЪЯВЛЕНИЕ</gold>"
|
||||
title-header: "<#04CADF>ОБЪЯВЛЕНИЕ</#04CADF>"
|
||||
# Показывать actionbar при объявлении
|
||||
show-actionbar: true
|
||||
# Время показа title (в секундах)
|
||||
|
|
|
|||
|
|
@ -2,56 +2,56 @@
|
|||
# Сообщения модуля градиентных ников
|
||||
|
||||
# Общие
|
||||
only-player: "§cЭта команда только для игроков!"
|
||||
no-permission: "§cУ вас нет прав на это действие!"
|
||||
player-not-found: "§cИгрок не найден!"
|
||||
reload-success: "§aКонфигурация градиентов перезагружена!"
|
||||
cooldown: "§cПодождите ещё {time} секунд!"
|
||||
only-player: "<#04CADF>Эта команда только для игроков!</#04CADF>"
|
||||
no-permission: "<#04CADF>У вас нет прав на это действие!</#04CADF>"
|
||||
player-not-found: "<#04CADF>Игрок не найден!</#04CADF>"
|
||||
reload-success: "<#04CADF>Конфигурация градиентов перезагружена!</#04CADF>"
|
||||
cooldown: "<#04CADF>Подождите ещё {time} секунд!</#04CADF>"
|
||||
|
||||
# Цвета
|
||||
color-help: |
|
||||
§e=== Команда /color ===
|
||||
§e/color <цвет1> [цвет2] ... §7— установить градиент
|
||||
§e/color on §7— включить цвет
|
||||
§e/color off §7— выключить цвет
|
||||
§e/color reset §7— сбросить цвет
|
||||
§e/color copy <игрок> §7— скопировать цвет
|
||||
§7Пример: /color #FF0000 #00FF00 #0000FF
|
||||
color-enabled: "§aЦвет ника включён!"
|
||||
color-disabled: "§cЦвет ника выключен!"
|
||||
color-reset: "§aЦвет ника сброшен!"
|
||||
color-no-colors: "§cУ вас нет установленных цветов!"
|
||||
color-success: "§aЦвет успешно установлен! Списано: {price} PP"
|
||||
color-copy-usage: "§cИспользование: /color copy <игрок>"
|
||||
color-copy-no-colors: "§cУ игрока {player} нет цветов!"
|
||||
invalid-color: "§cНеверный формат цвета: {color}. Используйте #RRGGBB"
|
||||
too-many-colors: "§cМаксимум {max} цветов!"
|
||||
not-enough-colors: "§cМинимум {min} цветов!"
|
||||
not-enough-points-color: "§cНедостаточно поинтов! Нужно: {price} PP"
|
||||
<#04CADF>=== Команда /color ===</#04CADF>
|
||||
<#04CADF>/color <цвет1> [цвет2] ... <gray>— установить градиент</gray>
|
||||
<#04CADF>/color on <gray>— включить цвет</gray>
|
||||
<#04CADF>/color off <gray>— выключить цвет</gray>
|
||||
<#04CADF>/color reset <gray>— сбросить цвет</gray>
|
||||
<#04CADF>/color copy <игрок> <gray>— скопировать цвет</gray>
|
||||
<gray>Пример: /color #FF0000 #00FF00 #0000FF</gray>
|
||||
color-enabled: "<#04CADF>Цвет ника включён!</#04CADF>"
|
||||
color-disabled: "<#04CADF>Цвет ника выключен!</#04CADF>"
|
||||
color-reset: "<#04CADF>Цвет ника сброшен!</#04CADF>"
|
||||
color-no-colors: "<#04CADF>У вас нет установленных цветов!</#04CADF>"
|
||||
color-success: "<#04CADF>Цвет успешно установлен! Списано: {price} PP</#04CADF>"
|
||||
color-copy-usage: "<#04CADF>Использование: /color copy <игрок></#04CADF>"
|
||||
color-copy-no-colors: "<#04CADF>У игрока {player} нет цветов!</#04CADF>"
|
||||
invalid-color: "<#04CADF>Неверный формат цвета: {color}. Используйте #RRGGBB</#04CADF>"
|
||||
too-many-colors: "<#04CADF>Максимум {max} цветов!</#04CADF>"
|
||||
not-enough-colors: "<#04CADF>Минимум {min} цветов!</#04CADF>"
|
||||
not-enough-points-color: "<#04CADF>Недостаточно поинтов! Нужно: {price} PP</#04CADF>"
|
||||
|
||||
# Префикс
|
||||
prefix-help: |
|
||||
§e=== Команда /prefix ===
|
||||
§e/prefix <текст> §7— установить префикс
|
||||
§e/prefix on §7— включить префикс
|
||||
§e/prefix off §7— выключить префикс
|
||||
§e/prefix reset §7— сбросить префикс
|
||||
prefix-enabled: "§aПрефикс включён!"
|
||||
prefix-disabled: "§cПрефикс выключен!"
|
||||
prefix-reset-success: "§aПрефикс сброшен!"
|
||||
prefix-no-prefix: "§cУ вас нет установленного префикса!"
|
||||
prefix-success: "§aПрефикс успешно установлен! Списано: {price} PP"
|
||||
prefix-success-free: "§aПрефикс успешно изменён!"
|
||||
prefix-no-colors: "§cПрефикс не может содержать цветовые коды!"
|
||||
prefix-invalid-chars: "§cПрефикс содержит недопустимые символы!"
|
||||
prefix-blacklisted: "§cЭтот префикс запрещён!"
|
||||
prefix-too-long: "§cПрефикс слишком длинный! Максимум: {max} символов"
|
||||
not-enough-points-prefix: "§cНедостаточно поинтов! Нужно: {price} PP"
|
||||
<#04CADF>=== Команда /prefix ===</#04CADF>
|
||||
<#04CADF>/prefix <текст> <gray>— установить префикс</gray>
|
||||
<#04CADF>/prefix on <gray>— включить префикс</gray>
|
||||
<#04CADF>/prefix off <gray>— выключить префикс</gray>
|
||||
<#04CADF>/prefix reset <gray>— сбросить префикс</gray>
|
||||
prefix-enabled: "<#04CADF>Префикс включён!</#04CADF>"
|
||||
prefix-disabled: "<#04CADF>Префикс выключен!</#04CADF>"
|
||||
prefix-reset-success: "<#04CADF>Префикс сброшен!</#04CADF>"
|
||||
prefix-no-prefix: "<#04CADF>У вас нет установленного префикса!</#04CADF>"
|
||||
prefix-success: "<#04CADF>Префикс успешно установлен! Списано: {price} PP</#04CADF>"
|
||||
prefix-success-free: "<#04CADF>Префикс успешно изменён!</#04CADF>"
|
||||
prefix-no-colors: "<#04CADF>Префикс не может содержать цветовые коды!</#04CADF>"
|
||||
prefix-invalid-chars: "<#04CADF>Префикс содержит недопустимые символы!</#04CADF>"
|
||||
prefix-blacklisted: "<#04CADF>Этот префикс запрещён!</#04CADF>"
|
||||
prefix-too-long: "<#04CADF>Префикс слишком длинный! Максимум: {max} символов</#04CADF>"
|
||||
not-enough-points-prefix: "<#04CADF>Недостаточно поинтов! Нужно: {price} PP</#04CADF>"
|
||||
|
||||
# Админ информация
|
||||
info-header: "§e=== Информация об игроке {player} ==="
|
||||
info-prefix: "§7Префикс: §f{prefix}"
|
||||
info-prefix-enabled: "§7Префикс включён: §f{enabled}"
|
||||
info-colors: "§7Цвета: §f{colors}"
|
||||
info-color-enabled: "§7Цвет включён: §f{enabled}"
|
||||
info-prefix-purchased: "§7Префикс куплен: §f{purchased}"
|
||||
info-header: "<#04CADF>=== Информация об игроке {player} ===</#04CADF>"
|
||||
info-prefix: "<gray>Префикс: <white>{prefix}</white></gray>"
|
||||
info-prefix-enabled: "<gray>Префикс включён: <white>{enabled}</white></gray>"
|
||||
info-colors: "<gray>Цвета: <white>{colors}</white></gray>"
|
||||
info-color-enabled: "<gray>Цвет включён: <white>{enabled}</white></gray>"
|
||||
info-prefix-purchased: "<gray>Префикс куплен: <white>{purchased}</white></gray>"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
prefix: "<gold>[LoChat]</gold>"
|
||||
prefix: "<#04CADF>[LoChat]</#04CADF>"
|
||||
|
||||
global:
|
||||
disabled: "<red>Глобальный чат отключен</red>"
|
||||
toggled-on: "<green>Глобальный чат включен</green>"
|
||||
toggled-off: "<red>Глобальный чат отключен</red>"
|
||||
disabled: "<#04CADF>Глобальный чат отключен</#04CADF>"
|
||||
toggled-on: "<#04CADF>Глобальный чат включен</#04CADF>"
|
||||
toggled-off: "<#04CADF>Глобальный чат отключен</#04CADF>"
|
||||
|
||||
local:
|
||||
no-players: "<red>Рядом нет игроков</red>"
|
||||
no-players: "<#04CADF>Рядом нет игроков</#04CADF>"
|
||||
|
||||
pm:
|
||||
# Форматы личных сообщений
|
||||
|
|
@ -20,42 +20,42 @@ pm:
|
|||
# Старые форматы (для совместимости)
|
||||
sent: "<gray>[PM] Ты → {player}: {message}</gray>"
|
||||
received: "<gray>[PM] {player} → Ты: {message}</gray>"
|
||||
no-reply: "<red>Некому ответить</red>"
|
||||
ignored: "<red>Этот игрок вас игнорирует</red>"
|
||||
player-offline: "<red>Игрок не в сети</red>"
|
||||
self: "<red>Нельзя писать самому себе</red>"
|
||||
no-reply: "<#04CADF>Некому ответить</#04CADF>"
|
||||
ignored: "<#04CADF>Этот игрок вас игнорирует</#04CADF>"
|
||||
player-offline: "<#04CADF>Игрок не в сети</#04CADF>"
|
||||
self: "<#04CADF>Нельзя писать самому себе</#04CADF>"
|
||||
|
||||
ignore:
|
||||
added: "<green>Игрок {player} добавлен в игнор</green>"
|
||||
removed: "<green>Игрок {player} убран из игнора</green>"
|
||||
already-ignored: "<red>Игрок уже в игноре</red>"
|
||||
not-ignored: "<red>Игрок не в игноре</red>"
|
||||
self: "<red>Нельзя игнорировать себя</red>"
|
||||
added: "<#04CADF>Игрок {player} добавлен в игнор</#04CADF>"
|
||||
removed: "<#04CADF>Игрок {player} убран из игнора</#04CADF>"
|
||||
already-ignored: "<#04CADF>Игрок уже в игноре</#04CADF>"
|
||||
not-ignored: "<#04CADF>Игрок не в игноре</#04CADF>"
|
||||
self: "<#04CADF>Нельзя игнорировать себя</#04CADF>"
|
||||
|
||||
announce:
|
||||
reloaded: "<green>Конфигурация перезагружена</green>"
|
||||
reloaded: "<#04CADF>Конфигурация перезагружена</#04CADF>"
|
||||
|
||||
spy:
|
||||
enabled: "<green>Шпион режим включен</green>"
|
||||
disabled: "<red>Шпион режим выключен</red>"
|
||||
enabled: "<#04CADF>Шпион режим включен</#04CADF>"
|
||||
disabled: "<#04CADF>Шпион режим выключен</#04CADF>"
|
||||
format: "<gray>[SPY] {sender} → {receiver}: {message}</gray>"
|
||||
|
||||
filter:
|
||||
blocked: "<red>Сообщение заблокировано (мат)</red>"
|
||||
warned: "<yellow>Предупреждение: не используйте мат!</yellow>"
|
||||
blocked: "<#04CADF>Сообщение заблокировано (мат)</#04CADF>"
|
||||
warned: "<#04CADF>Предупреждение: не используйте мат!</#04CADF>"
|
||||
|
||||
cooldown:
|
||||
wait: "<red>Подождите {time} сек перед следующим сообщением</red>"
|
||||
wait: "<#04CADF>Подождите {time} сек перед следующим сообщением</#04CADF>"
|
||||
|
||||
antispam:
|
||||
caps: "<red>Слишком много заглавных букв!</red>"
|
||||
repeat: "<red>Не повторяйте символы!</red>"
|
||||
similar: "<red>Не отправляйте одинаковые сообщения!</red>"
|
||||
caps: "<#04CADF>Слишком много заглавных букв!</#04CADF>"
|
||||
repeat: "<#04CADF>Не повторяйте символы!</#04CADF>"
|
||||
similar: "<#04CADF>Не отправляйте одинаковые сообщения!</#04CADF>"
|
||||
|
||||
clearchat:
|
||||
cleared: "<green>Чат очищен администратором {player}</green>"
|
||||
cleared: "<#04CADF>Чат очищен администратором {player}</#04CADF>"
|
||||
|
||||
errors:
|
||||
no-permission: "<red>Нет прав!</red>"
|
||||
player-not-found: "<red>Игрок не найден</red>"
|
||||
invalid-usage: "<red>Использование: {usage}</red>"
|
||||
no-permission: "<#04CADF>Нет прав!</#04CADF>"
|
||||
player-not-found: "<#04CADF>Игрок не найден</#04CADF>"
|
||||
invalid-usage: "<#04CADF>Использование: {usage}</#04CADF>"
|
||||
|
|
|
|||
|
|
@ -72,6 +72,18 @@ commands:
|
|||
permission: chat.clear
|
||||
aliases: [cc, очиститьчат, сдуфксрфе, сс]
|
||||
|
||||
mute:
|
||||
description: Mute player
|
||||
usage: /mute <player> <time> [reason]
|
||||
permission: chat.mute
|
||||
aliases: [мут, ьгеу]
|
||||
|
||||
unmute:
|
||||
description: Unmute player
|
||||
usage: /unmute <player>
|
||||
permission: chat.mute
|
||||
aliases: [размут, гтьгеу]
|
||||
|
||||
chatcolor:
|
||||
description: Set chat color
|
||||
usage: /chatcolor <color>
|
||||
|
|
@ -125,6 +137,8 @@ permissions:
|
|||
default: op
|
||||
chat.clear:
|
||||
default: op
|
||||
chat.mute:
|
||||
default: op
|
||||
chat.bypass.cooldown:
|
||||
default: op
|
||||
chat.bypass.filter:
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
package ru.lovar.gradientnick;
|
||||
|
||||
import org.black_ixx.playerpoints.PlayerPoints;
|
||||
import org.black_ixx.playerpoints.PlayerPointsAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import ru.lovar.gradientnick.commands.ColorCommand;
|
||||
import ru.lovar.gradientnick.commands.GradientCommand;
|
||||
import ru.lovar.gradientnick.commands.PrefixCommand;
|
||||
import ru.lovar.gradientnick.config.ConfigManager;
|
||||
import ru.lovar.gradientnick.config.MessagesManager;
|
||||
import ru.lovar.gradientnick.data.DataManager;
|
||||
import ru.lovar.gradientnick.hooks.LuckPermsHook;
|
||||
import ru.lovar.gradientnick.hooks.PlaceholderAPIHook;
|
||||
import ru.lovar.gradientnick.listeners.GUIListener;
|
||||
import ru.lovar.gradientnick.listeners.PlayerListener;
|
||||
|
||||
public class GradientNick extends JavaPlugin {
|
||||
|
||||
private static GradientNick instance;
|
||||
private PlayerPointsAPI playerPointsAPI;
|
||||
private ConfigManager configManager;
|
||||
private MessagesManager messagesManager;
|
||||
private DataManager dataManager;
|
||||
private LuckPermsHook luckPermsHook;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
|
||||
// Инициализация конфигов
|
||||
this.configManager = new ConfigManager(this);
|
||||
this.messagesManager = new MessagesManager(this);
|
||||
|
||||
// Инициализация хранилища данных
|
||||
this.dataManager = new DataManager(this);
|
||||
|
||||
// Подключение PlayerPoints
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) {
|
||||
this.playerPointsAPI = PlayerPoints.getInstance().getAPI();
|
||||
getLogger().info("PlayerPoints подключен!");
|
||||
} else {
|
||||
getLogger().severe("PlayerPoints не найден! Плагин отключается.");
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Подключение LuckPerms
|
||||
this.luckPermsHook = new LuckPermsHook(this);
|
||||
|
||||
// Подключение PlaceholderAPI
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
|
||||
new PlaceholderAPIHook(this).register();
|
||||
getLogger().info("PlaceholderAPI подключен!");
|
||||
}
|
||||
|
||||
// Регистрация команд
|
||||
ColorCommand colorCommand = new ColorCommand(this);
|
||||
getCommand("color").setExecutor(colorCommand);
|
||||
getCommand("color").setTabCompleter(colorCommand);
|
||||
|
||||
PrefixCommand prefixCommand = new PrefixCommand(this);
|
||||
getCommand("prefix").setExecutor(prefixCommand);
|
||||
getCommand("prefix").setTabCompleter(prefixCommand);
|
||||
|
||||
GradientCommand gradientCommand = new GradientCommand(this);
|
||||
getCommand("aprefix").setExecutor(gradientCommand);
|
||||
getCommand("aprefix").setTabCompleter(gradientCommand);
|
||||
|
||||
// Регистрация слушателей
|
||||
Bukkit.getPluginManager().registerEvents(new PlayerListener(this), this);
|
||||
Bukkit.getPluginManager().registerEvents(new GUIListener(this), this);
|
||||
|
||||
getLogger().info("LoPreff успешно запущен!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (dataManager != null) {
|
||||
dataManager.saveAll();
|
||||
}
|
||||
getLogger().info("LoPreff отключен!");
|
||||
}
|
||||
|
||||
public static GradientNick getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public PlayerPointsAPI getPlayerPointsAPI() {
|
||||
return playerPointsAPI;
|
||||
}
|
||||
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
public MessagesManager getMessagesManager() {
|
||||
return messagesManager;
|
||||
}
|
||||
|
||||
public DataManager getDataManager() {
|
||||
return dataManager;
|
||||
}
|
||||
|
||||
public LuckPermsHook getLuckPermsHook() {
|
||||
return luckPermsHook;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
configManager.reload();
|
||||
messagesManager.reload();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
package ru.lovar.gradientnick.commands;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.config.ConfigManager;
|
||||
import ru.lovar.gradientnick.config.MessagesManager;
|
||||
import ru.lovar.gradientnick.data.PlayerData;
|
||||
import ru.lovar.gradientnick.gui.ConfirmGUI;
|
||||
import ru.lovar.gradientnick.util.Constants;
|
||||
import ru.lovar.gradientnick.util.DisplayNameUtil;
|
||||
import ru.lovar.gradientnick.util.FoliaUtil;
|
||||
import ru.lovar.gradientnick.util.GradientUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class ColorCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final GradientNick plugin;
|
||||
private final Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>();
|
||||
|
||||
private static final List<String> PRESET_COLORS = List.of(
|
||||
"#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3",
|
||||
"#FF69B4", "#00FFFF", "#FFD700", "#FFFFFF", "#000000"
|
||||
);
|
||||
private static final Set<String> SUB_COMMANDS = Set.of("on", "off", "reset", "copy");
|
||||
|
||||
public ColorCommand(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
registerSubCommands();
|
||||
}
|
||||
|
||||
private void registerSubCommands() {
|
||||
subCommands.put("on", this::handleOn);
|
||||
subCommands.put("off", this::handleOff);
|
||||
subCommands.put("reset", this::handleReset);
|
||||
subCommands.put("copy", this::handleCopy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String label, @NotNull String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(plugin.getMessagesManager().get("only-player"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("gradient.color")) {
|
||||
player.sendMessage(plugin.getMessagesManager().get("no-permission"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
player.sendMessage(plugin.getMessagesManager().get("color-help"));
|
||||
return true;
|
||||
}
|
||||
|
||||
String subCommand = args[0].toLowerCase();
|
||||
var handler = subCommands.get(subCommand);
|
||||
if (handler != null) {
|
||||
return handler.apply(player, args);
|
||||
}
|
||||
|
||||
return handleSetColors(player, args);
|
||||
}
|
||||
|
||||
private boolean handleOn(Player player, String[] args) {
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
|
||||
if (!data.hasColors()) {
|
||||
player.sendMessage(msg.get("color-no-colors"));
|
||||
return true;
|
||||
}
|
||||
|
||||
data.setColorEnabled(true);
|
||||
saveAndUpdate(player, data);
|
||||
player.sendMessage(msg.get("color-enabled"));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleOff(Player player, String[] args) {
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
data.setColorEnabled(false);
|
||||
saveAndUpdate(player, data);
|
||||
player.sendMessage(plugin.getMessagesManager().get("color-disabled"));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleReset(Player player, String[] args) {
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
|
||||
if (!data.hasColors()) {
|
||||
player.sendMessage(msg.get("color-no-colors"));
|
||||
return true;
|
||||
}
|
||||
|
||||
data.setColors(new ArrayList<>());
|
||||
data.setColorEnabled(false);
|
||||
saveAndUpdate(player, data);
|
||||
player.sendMessage(msg.get("color-reset"));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleCopy(Player player, String[] args) {
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
ConfigManager cfg = plugin.getConfigManager();
|
||||
|
||||
if (args.length < 2) {
|
||||
player.sendMessage(msg.get("color-copy-usage"));
|
||||
return true;
|
||||
}
|
||||
|
||||
Player target = Bukkit.getPlayer(args[1]);
|
||||
if (target == null) {
|
||||
player.sendMessage(msg.get("player-not-found"));
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerData targetData = plugin.getDataManager().getPlayerData(target.getUniqueId());
|
||||
if (!targetData.hasColors()) {
|
||||
player.sendMessage(msg.get("color-copy-no-colors", "player", target.getName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
|
||||
if (!player.hasPermission("gradient.bypass.cooldown") && !checkCooldown(player, cfg.getColorCooldown(), data.getLastColorChange())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<String> colors = new ArrayList<>(targetData.getColors());
|
||||
int price = player.hasPermission("gradient.bypass.cost") ? 0 : colors.size() * cfg.getPricePerColor();
|
||||
|
||||
if (price > 0 && !checkBalance(player, price)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ConfirmGUI gui = new ConfirmGUI(plugin, player, ConfirmGUI.ConfirmType.COLOR, colors, data.getPrefix(), price);
|
||||
FoliaUtil.runEntityTask(plugin, player, gui::open);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleSetColors(Player player, String[] args) {
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
ConfigManager cfg = plugin.getConfigManager();
|
||||
|
||||
if (args.length > cfg.getMaxColors()) {
|
||||
player.sendMessage(msg.get("too-many-colors", "max", String.valueOf(cfg.getMaxColors())));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < cfg.getMinColors()) {
|
||||
player.sendMessage(msg.get("not-enough-colors", "min", String.valueOf(cfg.getMinColors())));
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
|
||||
if (!player.hasPermission("gradient.bypass.cooldown") && !checkCooldown(player, cfg.getColorCooldown(), data.getLastColorChange())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<String> colors = new ArrayList<>();
|
||||
for (String arg : args) {
|
||||
String color = arg.startsWith("#") ? arg : "#" + arg;
|
||||
if (!GradientUtil.isValidHex(color)) {
|
||||
player.sendMessage(msg.get("invalid-color", "color", arg));
|
||||
return true;
|
||||
}
|
||||
colors.add(color.toUpperCase());
|
||||
}
|
||||
|
||||
int price = player.hasPermission("gradient.bypass.cost") ? 0 : colors.size() * cfg.getPricePerColor();
|
||||
|
||||
if (price > 0 && !checkBalance(player, price)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ConfirmGUI gui = new ConfirmGUI(plugin, player, ConfirmGUI.ConfirmType.COLOR, colors, data.getPrefix(), price);
|
||||
FoliaUtil.runEntityTask(plugin, player, gui::open);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkCooldown(Player player, int cooldownSec, long lastChange) {
|
||||
long cooldownMs = cooldownSec * Constants.MILLIS_PER_SECOND;
|
||||
long timePassed = System.currentTimeMillis() - lastChange;
|
||||
if (timePassed < cooldownMs) {
|
||||
long remaining = (cooldownMs - timePassed) / Constants.MILLIS_PER_SECOND;
|
||||
player.sendMessage(plugin.getMessagesManager().get("cooldown", "time", String.valueOf(remaining)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkBalance(Player player, int price) {
|
||||
int balance = plugin.getPlayerPointsAPI().look(player.getUniqueId());
|
||||
if (balance < price) {
|
||||
player.sendMessage(plugin.getMessagesManager().get("not-enough-points-color", "price", String.valueOf(price)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void saveAndUpdate(Player player, PlayerData data) {
|
||||
FoliaUtil.runEntityTask(plugin, player, () -> DisplayNameUtil.updateDisplayName(plugin, player, data));
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(player.getUniqueId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String alias, @NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
String input = args[0].toLowerCase();
|
||||
List<String> completions = new ArrayList<>(SUB_COMMANDS);
|
||||
completions.addAll(PRESET_COLORS);
|
||||
return completions.stream().filter(s -> s.toLowerCase().startsWith(input)).toList();
|
||||
}
|
||||
|
||||
String firstArg = args[0].toLowerCase();
|
||||
|
||||
if (args.length == 2 && firstArg.equals("copy")) {
|
||||
return Bukkit.getOnlinePlayers().stream().map(Player::getName)
|
||||
.filter(s -> s.toLowerCase().startsWith(args[1].toLowerCase())).toList();
|
||||
}
|
||||
|
||||
// Для цветов — показываем пресеты
|
||||
if (!SUB_COMMANDS.contains(firstArg) && args.length <= plugin.getConfigManager().getMaxColors()) {
|
||||
return PRESET_COLORS.stream()
|
||||
.filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,347 +0,0 @@
|
|||
package ru.lovar.gradientnick.commands;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.config.ConfigManager;
|
||||
import ru.lovar.gradientnick.config.MessagesManager;
|
||||
import ru.lovar.gradientnick.data.PlayerData;
|
||||
import ru.lovar.gradientnick.util.DisplayNameUtil;
|
||||
import ru.lovar.gradientnick.util.FoliaUtil;
|
||||
import ru.lovar.gradientnick.util.GradientUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class GradientCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final GradientNick plugin;
|
||||
private static final List<String> PRESET_COLORS = Arrays.asList(
|
||||
"#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3"
|
||||
);
|
||||
|
||||
public GradientCommand(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String label, @NotNull String[] args) {
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
ConfigManager cfg = plugin.getConfigManager();
|
||||
|
||||
if (!sender.hasPermission("gradient.admin")) {
|
||||
sender.sendMessage(msg.get("no-permission"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
sendHelp(sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
String subCommand = args[0].toLowerCase();
|
||||
|
||||
switch (subCommand) {
|
||||
case "reload" -> {
|
||||
plugin.reload();
|
||||
sender.sendMessage(msg.get("reload-success"));
|
||||
}
|
||||
case "info" -> {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix info <игрок>");
|
||||
return true;
|
||||
}
|
||||
handleInfo(sender, args[1], msg);
|
||||
}
|
||||
case "setcolor" -> {
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage("§cИспользование: /aprefix setcolor <игрок> <цвет1> [цвет2] ...");
|
||||
return true;
|
||||
}
|
||||
handleSetColor(sender, args, msg, cfg);
|
||||
}
|
||||
case "setprefix" -> {
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage("§cИспользование: /aprefix setprefix <игрок> <префикс>");
|
||||
return true;
|
||||
}
|
||||
handleSetPrefix(sender, args, msg, cfg);
|
||||
}
|
||||
case "coloron" -> {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix coloron <игрок>");
|
||||
return true;
|
||||
}
|
||||
handleColorToggle(sender, args[1], true, msg);
|
||||
}
|
||||
case "coloroff" -> {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix coloroff <игрок>");
|
||||
return true;
|
||||
}
|
||||
handleColorToggle(sender, args[1], false, msg);
|
||||
}
|
||||
case "prefixon" -> {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix prefixon <игрок>");
|
||||
return true;
|
||||
}
|
||||
handlePrefixToggle(sender, args[1], true, msg);
|
||||
}
|
||||
case "prefixoff" -> {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix prefixoff <игрок>");
|
||||
return true;
|
||||
}
|
||||
handlePrefixToggle(sender, args[1], false, msg);
|
||||
}
|
||||
case "resetcolor" -> {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix resetcolor <игрок>");
|
||||
return true;
|
||||
}
|
||||
handleResetColor(sender, args[1], msg);
|
||||
}
|
||||
case "resetprefix" -> {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("§cИспользование: /aprefix resetprefix <игрок>");
|
||||
return true;
|
||||
}
|
||||
handleResetPrefix(sender, args[1], msg);
|
||||
}
|
||||
default -> sendHelp(sender);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sendHelp(CommandSender sender) {
|
||||
sender.sendMessage("§e=== LoPreff Admin ===");
|
||||
sender.sendMessage("§e/aprefix reload §7— перезагрузить конфиг");
|
||||
sender.sendMessage("§e/aprefix info <игрок> §7— информация об игроке");
|
||||
sender.sendMessage("§e/aprefix setcolor <игрок> <цвета> §7— установить цвет");
|
||||
sender.sendMessage("§e/aprefix setprefix <игрок> <префикс> §7— установить префикс");
|
||||
sender.sendMessage("§e/aprefix coloron/coloroff <игрок> §7— вкл/выкл цвет");
|
||||
sender.sendMessage("§e/aprefix prefixon/prefixoff <игрок> §7— вкл/выкл префикс");
|
||||
sender.sendMessage("§e/aprefix resetcolor <игрок> §7— сбросить цвет");
|
||||
sender.sendMessage("§e/aprefix resetprefix <игрок> §7— сбросить префикс");
|
||||
}
|
||||
|
||||
private void handleInfo(CommandSender sender, String playerName, MessagesManager msg) {
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(playerName);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
sender.sendMessage(msg.get("player-not-found"));
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(target.getUniqueId());
|
||||
|
||||
sender.sendMessage(msg.get("info-header", "player", playerName));
|
||||
sender.sendMessage(msg.get("info-prefix", "prefix", data.hasPrefix() ? data.getPrefix() : "нет"));
|
||||
sender.sendMessage(msg.get("info-prefix-enabled", "enabled", data.isPrefixEnabled() ? "да" : "нет"));
|
||||
sender.sendMessage(msg.get("info-colors", "colors", data.hasColors() ? String.join(", ", data.getColors()) : "нет"));
|
||||
sender.sendMessage(msg.get("info-color-enabled", "enabled", data.isColorEnabled() ? "да" : "нет"));
|
||||
sender.sendMessage(msg.get("info-prefix-purchased", "purchased", data.isPrefixPurchased() ? "да" : "нет"));
|
||||
}
|
||||
|
||||
private void handleSetColor(CommandSender sender, String[] args, MessagesManager msg, ConfigManager cfg) {
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
sender.sendMessage(msg.get("player-not-found"));
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> colors = new ArrayList<>();
|
||||
for (int i = 2; i < args.length; i++) {
|
||||
String color = args[i].startsWith("#") ? args[i] : "#" + args[i];
|
||||
if (!GradientUtil.isValidHex(color)) {
|
||||
sender.sendMessage(msg.get("invalid-color", "color", args[i]));
|
||||
return;
|
||||
}
|
||||
colors.add(color.toUpperCase());
|
||||
}
|
||||
|
||||
if (colors.size() > cfg.getMaxColors()) {
|
||||
sender.sendMessage(msg.get("too-many-colors", "max", String.valueOf(cfg.getMaxColors())));
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(target.getUniqueId());
|
||||
data.setColors(colors);
|
||||
data.setColorEnabled(true);
|
||||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(plugin, onlineTarget, () -> DisplayNameUtil.updateDisplayName(plugin, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aЦвет для игрока §f" + args[1] + " §aустановлен: §f" + String.join(" ", colors));
|
||||
}
|
||||
|
||||
private void handleSetPrefix(CommandSender sender, String[] args, MessagesManager msg, ConfigManager cfg) {
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
sender.sendMessage(msg.get("player-not-found"));
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder prefixBuilder = new StringBuilder();
|
||||
for (int i = 2; i < args.length; i++) {
|
||||
if (i > 2) prefixBuilder.append(" ");
|
||||
prefixBuilder.append(args[i]);
|
||||
}
|
||||
String prefix = prefixBuilder.toString();
|
||||
|
||||
if (prefix.length() > cfg.getMaxPrefixLength()) {
|
||||
sender.sendMessage(msg.get("prefix-too-long", "max", String.valueOf(cfg.getMaxPrefixLength())));
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(target.getUniqueId());
|
||||
data.setPrefix(prefix);
|
||||
data.setPrefixEnabled(true);
|
||||
data.setPrefixPurchased(true);
|
||||
|
||||
plugin.getLuckPermsHook().setPrefix(target.getUniqueId(), DisplayNameUtil.buildColoredPrefix(plugin, data));
|
||||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(plugin, onlineTarget, () -> DisplayNameUtil.updateDisplayName(plugin, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aПрефикс для игрока §f" + args[1] + " §aустановлен: §f" + prefix);
|
||||
}
|
||||
|
||||
private void handleColorToggle(CommandSender sender, String playerName, boolean enable, MessagesManager msg) {
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(playerName);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
sender.sendMessage(msg.get("player-not-found"));
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(target.getUniqueId());
|
||||
data.setColorEnabled(enable);
|
||||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(plugin, onlineTarget, () -> DisplayNameUtil.updateDisplayName(plugin, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aЦвет для игрока §f" + playerName + (enable ? " §aвключён" : " §cвыключен"));
|
||||
}
|
||||
|
||||
private void handlePrefixToggle(CommandSender sender, String playerName, boolean enable, MessagesManager msg) {
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(playerName);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
sender.sendMessage(msg.get("player-not-found"));
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(target.getUniqueId());
|
||||
data.setPrefixEnabled(enable);
|
||||
|
||||
if (enable && data.hasPrefix()) {
|
||||
plugin.getLuckPermsHook().setPrefix(target.getUniqueId(), DisplayNameUtil.buildColoredPrefix(plugin, data));
|
||||
} else {
|
||||
plugin.getLuckPermsHook().removePrefix(target.getUniqueId());
|
||||
}
|
||||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(plugin, onlineTarget, () -> DisplayNameUtil.updateDisplayName(plugin, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aПрефикс для игрока §f" + playerName + (enable ? " §aвключён" : " §cвыключен"));
|
||||
}
|
||||
|
||||
private void handleResetColor(CommandSender sender, String playerName, MessagesManager msg) {
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(playerName);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
sender.sendMessage(msg.get("player-not-found"));
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(target.getUniqueId());
|
||||
data.setColors(new ArrayList<>());
|
||||
data.setColorEnabled(false);
|
||||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(plugin, onlineTarget, () -> DisplayNameUtil.updateDisplayName(plugin, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aЦвет для игрока §f" + playerName + " §aсброшен");
|
||||
}
|
||||
|
||||
private void handleResetPrefix(CommandSender sender, String playerName, MessagesManager msg) {
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(playerName);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
sender.sendMessage(msg.get("player-not-found"));
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(target.getUniqueId());
|
||||
data.setPrefix(null);
|
||||
data.setPrefixEnabled(false);
|
||||
|
||||
plugin.getLuckPermsHook().removePrefix(target.getUniqueId());
|
||||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(plugin, onlineTarget, () -> DisplayNameUtil.updateDisplayName(plugin, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aПрефикс для игрока §f" + playerName + " §aсброшен");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String alias, @NotNull String[] args) {
|
||||
if (!sender.hasPermission("gradient.admin")) return new ArrayList<>();
|
||||
|
||||
if (args.length == 1) {
|
||||
return Arrays.asList("reload", "info", "setcolor", "setprefix", "coloron", "coloroff", "prefixon", "prefixoff", "resetcolor", "resetprefix").stream()
|
||||
.filter(s -> s.startsWith(args[0].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
if (args.length == 2) {
|
||||
String sub = args[0].toLowerCase();
|
||||
if (Arrays.asList("info", "setcolor", "setprefix", "coloron", "coloroff", "prefixon", "prefixoff", "resetcolor", "resetprefix").contains(sub)) {
|
||||
return Bukkit.getOnlinePlayers().stream()
|
||||
.map(Player::getName)
|
||||
.filter(s -> s.toLowerCase().startsWith(args[1].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length >= 3 && args[0].equalsIgnoreCase("setcolor")) {
|
||||
return PRESET_COLORS.stream()
|
||||
.filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,199 +0,0 @@
|
|||
package ru.lovar.gradientnick.commands;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.config.ConfigManager;
|
||||
import ru.lovar.gradientnick.config.MessagesManager;
|
||||
import ru.lovar.gradientnick.data.PlayerData;
|
||||
import ru.lovar.gradientnick.gui.ConfirmGUI;
|
||||
import ru.lovar.gradientnick.util.Constants;
|
||||
import ru.lovar.gradientnick.util.DisplayNameUtil;
|
||||
import ru.lovar.gradientnick.util.FoliaUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PrefixCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final GradientNick plugin;
|
||||
private final Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>();
|
||||
|
||||
private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("(?i)(&[0-9a-fk-or]|§[0-9a-fk-or]|#[0-9a-f]{6}|&#[0-9a-f]{6}|<#[0-9a-f]{6}>)");
|
||||
private static final Pattern ALLOWED_PREFIX_PATTERN = Pattern.compile("^[a-zA-Zа-яА-ЯёЁ0-9 _\\-]+$");
|
||||
private static final Set<String> SUB_COMMANDS = Set.of("on", "off", "reset");
|
||||
|
||||
public PrefixCommand(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
registerSubCommands();
|
||||
}
|
||||
|
||||
private void registerSubCommands() {
|
||||
subCommands.put("on", this::handleOn);
|
||||
subCommands.put("off", this::handleOff);
|
||||
subCommands.put("reset", this::handleReset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String label, @NotNull String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(plugin.getMessagesManager().get("only-player"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("gradient.prefix")) {
|
||||
player.sendMessage(plugin.getMessagesManager().get("no-permission"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
player.sendMessage(plugin.getMessagesManager().get("prefix-help"));
|
||||
return true;
|
||||
}
|
||||
|
||||
String subCommand = args[0].toLowerCase();
|
||||
var handler = subCommands.get(subCommand);
|
||||
if (handler != null) {
|
||||
return handler.apply(player, args);
|
||||
}
|
||||
|
||||
return handleSetPrefix(player, args);
|
||||
}
|
||||
|
||||
private boolean handleOn(Player player, String[] args) {
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
|
||||
if (!data.hasPrefix()) {
|
||||
player.sendMessage(msg.get("prefix-no-prefix"));
|
||||
return true;
|
||||
}
|
||||
|
||||
data.setPrefixEnabled(true);
|
||||
plugin.getLuckPermsHook().setPrefix(player, DisplayNameUtil.buildColoredPrefix(plugin, data));
|
||||
saveAndUpdate(player, data);
|
||||
player.sendMessage(msg.get("prefix-enabled"));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleOff(Player player, String[] args) {
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
data.setPrefixEnabled(false);
|
||||
plugin.getLuckPermsHook().removePrefix(player);
|
||||
saveAndUpdate(player, data);
|
||||
player.sendMessage(plugin.getMessagesManager().get("prefix-disabled"));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleReset(Player player, String[] args) {
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
|
||||
if (!data.hasPrefix()) {
|
||||
player.sendMessage(msg.get("prefix-no-prefix"));
|
||||
return true;
|
||||
}
|
||||
|
||||
data.setPrefix(null);
|
||||
data.setPrefixEnabled(false);
|
||||
plugin.getLuckPermsHook().removePrefix(player);
|
||||
saveAndUpdate(player, data);
|
||||
player.sendMessage(msg.get("prefix-reset-success"));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleSetPrefix(Player player, String[] args) {
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
ConfigManager cfg = plugin.getConfigManager();
|
||||
String prefix = String.join(" ", args);
|
||||
|
||||
if (prefix.trim().isEmpty()) {
|
||||
player.sendMessage(msg.get("prefix-help"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (COLOR_CODE_PATTERN.matcher(prefix).find()) {
|
||||
player.sendMessage(msg.get("prefix-no-colors"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ALLOWED_PREFIX_PATTERN.matcher(prefix).matches()) {
|
||||
player.sendMessage(msg.get("prefix-invalid-chars"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cfg.isPrefixBlacklisted(prefix)) {
|
||||
player.sendMessage(msg.get("prefix-blacklisted"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (prefix.length() > cfg.getMaxPrefixLength()) {
|
||||
player.sendMessage(msg.get("prefix-too-long", "max", String.valueOf(cfg.getMaxPrefixLength())));
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
|
||||
if (!player.hasPermission("gradient.bypass.cooldown") && !checkCooldown(player, cfg.getPrefixCooldown(), data.getLastPrefixChange())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int price = calculatePrice(player, cfg, data);
|
||||
|
||||
if (price > 0 && !checkBalance(player, price, "not-enough-points-prefix")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ConfirmGUI gui = new ConfirmGUI(plugin, player, ConfirmGUI.ConfirmType.PREFIX, data.getColors(), prefix, price);
|
||||
FoliaUtil.runEntityTask(plugin, player, gui::open);
|
||||
return true;
|
||||
}
|
||||
|
||||
private int calculatePrice(Player player, ConfigManager cfg, PlayerData data) {
|
||||
if (player.hasPermission("gradient.bypass.cost")) return 0;
|
||||
return (cfg.isPrefixOneTimePurchase() && data.isPrefixPurchased()) ? 0 : cfg.getPrefixPrice();
|
||||
}
|
||||
|
||||
private boolean checkCooldown(Player player, int cooldownSec, long lastChange) {
|
||||
long cooldownMs = cooldownSec * Constants.MILLIS_PER_SECOND;
|
||||
long timePassed = System.currentTimeMillis() - lastChange;
|
||||
if (timePassed < cooldownMs) {
|
||||
long remaining = (cooldownMs - timePassed) / Constants.MILLIS_PER_SECOND;
|
||||
player.sendMessage(plugin.getMessagesManager().get("cooldown", "time", String.valueOf(remaining)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkBalance(Player player, int price, String msgKey) {
|
||||
int balance = plugin.getPlayerPointsAPI().look(player.getUniqueId());
|
||||
if (balance < price) {
|
||||
player.sendMessage(plugin.getMessagesManager().get(msgKey, "price", String.valueOf(price)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void saveAndUpdate(Player player, PlayerData data) {
|
||||
FoliaUtil.runEntityTask(plugin, player, () -> DisplayNameUtil.updateDisplayName(plugin, player, data));
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(player.getUniqueId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String alias, @NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
return SUB_COMMANDS.stream()
|
||||
.filter(s -> s.startsWith(args[0].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
package ru.lovar.gradientnick.config;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
private final GradientNick plugin;
|
||||
private FileConfiguration config;
|
||||
|
||||
public ConfigManager(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
plugin.saveDefaultConfig();
|
||||
this.config = plugin.getConfig();
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
plugin.reloadConfig();
|
||||
this.config = plugin.getConfig();
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
private void updateConfig() {
|
||||
boolean needsSave = false;
|
||||
|
||||
// Автодополнение новых параметров
|
||||
if (!config.contains("prefix-blacklist")) {
|
||||
config.set("prefix-blacklist", List.of("admin", "owner", "moder", "helper", "staff"));
|
||||
needsSave = true;
|
||||
}
|
||||
if (!config.contains("history-max-entries")) {
|
||||
config.set("history-max-entries", 10);
|
||||
needsSave = true;
|
||||
}
|
||||
if (!config.contains("history-free-apply")) {
|
||||
config.set("history-free-apply", true);
|
||||
needsSave = true;
|
||||
}
|
||||
|
||||
if (needsSave) {
|
||||
plugin.saveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxColors() {
|
||||
return config.getInt("max-colors", 7);
|
||||
}
|
||||
|
||||
public int getMinColors() {
|
||||
return config.getInt("min-colors", 1);
|
||||
}
|
||||
|
||||
public int getPricePerColor() {
|
||||
return config.getInt("price-per-color", 50);
|
||||
}
|
||||
|
||||
public int getPrefixPrice() {
|
||||
return config.getInt("prefix-price", 500);
|
||||
}
|
||||
|
||||
public boolean isPrefixOneTimePurchase() {
|
||||
return config.getBoolean("prefix-one-time-purchase", true);
|
||||
}
|
||||
|
||||
public int getAnimatedPrice() {
|
||||
return config.getInt("animated-price", 1000);
|
||||
}
|
||||
|
||||
public int getAnimatedIntervalTicks() {
|
||||
return config.getInt("animated-interval-ticks", 5);
|
||||
}
|
||||
|
||||
public int getColorCooldown() {
|
||||
return config.getInt("color-cooldown", 60);
|
||||
}
|
||||
|
||||
public int getPrefixCooldown() {
|
||||
return config.getInt("prefix-cooldown", 300);
|
||||
}
|
||||
|
||||
public int getMaxPrefixLength() {
|
||||
return config.getInt("max-prefix-length", 7);
|
||||
}
|
||||
|
||||
public String getPrefixFormat() {
|
||||
return config.getString("prefix-format", "[{prefix}] ");
|
||||
}
|
||||
|
||||
public boolean isGradientOnPrefix() {
|
||||
return config.getBoolean("gradient-on-prefix", true);
|
||||
}
|
||||
|
||||
public boolean isContinuousGradient() {
|
||||
return config.getBoolean("continuous-gradient", true);
|
||||
}
|
||||
|
||||
public boolean isUseLegacyRgbFormat() {
|
||||
return config.getBoolean("use-legacy-rgb-format", true);
|
||||
}
|
||||
|
||||
public String getStorageType() {
|
||||
return config.getString("storage-type", "YAML");
|
||||
}
|
||||
|
||||
public String getSqliteFile() {
|
||||
return config.getString("sqlite-file", "data.db");
|
||||
}
|
||||
|
||||
public List<String> getPrefixBlacklist() {
|
||||
return config.getStringList("prefix-blacklist");
|
||||
}
|
||||
|
||||
public boolean isPrefixBlacklisted(String prefix) {
|
||||
String lowerPrefix = prefix.toLowerCase();
|
||||
return getPrefixBlacklist().stream()
|
||||
.anyMatch(blacklisted -> lowerPrefix.contains(blacklisted.toLowerCase()));
|
||||
}
|
||||
|
||||
public int getHistoryMaxEntries() {
|
||||
return config.getInt("history-max-entries", 10);
|
||||
}
|
||||
|
||||
public boolean isHistoryFreeApply() {
|
||||
return config.getBoolean("history-free-apply", true);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package ru.lovar.gradientnick.config;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class MessagesManager {
|
||||
|
||||
private final GradientNick plugin;
|
||||
private FileConfiguration messages;
|
||||
private File messagesFile;
|
||||
|
||||
public MessagesManager(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
loadMessages();
|
||||
}
|
||||
|
||||
private void loadMessages() {
|
||||
messagesFile = new File(plugin.getDataFolder(), "messages.yml");
|
||||
if (!messagesFile.exists()) {
|
||||
plugin.saveResource("messages.yml", false);
|
||||
}
|
||||
messages = YamlConfiguration.loadConfiguration(messagesFile);
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
loadMessages();
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
return messages.getString(key, "§cСообщение не найдено: " + key);
|
||||
}
|
||||
|
||||
public String get(String key, String... replacements) {
|
||||
String message = get(key);
|
||||
for (int i = 0; i < replacements.length; i += 2) {
|
||||
if (i + 1 < replacements.length) {
|
||||
message = message.replace("{" + replacements[i] + "}", replacements[i + 1]);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
package ru.lovar.gradientnick.data;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class DataManager {
|
||||
|
||||
private final GradientNick plugin;
|
||||
private final Map<UUID, PlayerData> cache = new ConcurrentHashMap<>();
|
||||
private Connection sqliteConnection;
|
||||
private boolean useSqlite;
|
||||
|
||||
public DataManager(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
this.useSqlite = plugin.getConfigManager().getStorageType().equalsIgnoreCase("SQLITE");
|
||||
|
||||
if (useSqlite) {
|
||||
initSqlite();
|
||||
} else {
|
||||
loadYamlData();
|
||||
}
|
||||
}
|
||||
|
||||
private void initSqlite() {
|
||||
try {
|
||||
File dbFile = new File(plugin.getDataFolder(), plugin.getConfigManager().getSqliteFile());
|
||||
sqliteConnection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
|
||||
|
||||
try (Statement stmt = sqliteConnection.createStatement()) {
|
||||
stmt.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS player_data (
|
||||
uuid TEXT PRIMARY KEY,
|
||||
prefix TEXT,
|
||||
colors TEXT,
|
||||
color_enabled INTEGER DEFAULT 1,
|
||||
prefix_enabled INTEGER DEFAULT 1,
|
||||
prefix_purchased INTEGER DEFAULT 0,
|
||||
last_color_change INTEGER DEFAULT 0,
|
||||
last_prefix_change INTEGER DEFAULT 0
|
||||
)
|
||||
""");
|
||||
}
|
||||
plugin.getLogger().info("SQLite база данных инициализирована.");
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().severe("Ошибка инициализации SQLite: " + e.getMessage());
|
||||
useSqlite = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadYamlData() {
|
||||
File dataFile = new File(plugin.getDataFolder(), "data.yml");
|
||||
if (!dataFile.exists()) return;
|
||||
|
||||
FileConfiguration data = YamlConfiguration.loadConfiguration(dataFile);
|
||||
for (String uuidStr : data.getKeys(false)) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(uuidStr);
|
||||
PlayerData playerData = new PlayerData(uuid);
|
||||
playerData.setPrefix(data.getString(uuidStr + ".prefix"));
|
||||
playerData.setColors(data.getStringList(uuidStr + ".colors"));
|
||||
playerData.setColorEnabled(data.getBoolean(uuidStr + ".color-enabled", true));
|
||||
playerData.setPrefixEnabled(data.getBoolean(uuidStr + ".prefix-enabled", true));
|
||||
playerData.setPrefixPurchased(data.getBoolean(uuidStr + ".prefix-purchased", false));
|
||||
playerData.setLastColorChange(data.getLong(uuidStr + ".last-color-change", 0));
|
||||
playerData.setLastPrefixChange(data.getLong(uuidStr + ".last-prefix-change", 0));
|
||||
cache.put(uuid, playerData);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerData getPlayerData(UUID uuid) {
|
||||
return cache.computeIfAbsent(uuid, this::loadPlayerData);
|
||||
}
|
||||
|
||||
private PlayerData loadPlayerData(UUID uuid) {
|
||||
PlayerData data = new PlayerData(uuid);
|
||||
|
||||
if (useSqlite && sqliteConnection != null) {
|
||||
try (PreparedStatement stmt = sqliteConnection.prepareStatement(
|
||||
"SELECT prefix, colors, color_enabled, prefix_enabled, prefix_purchased, last_color_change, last_prefix_change FROM player_data WHERE uuid = ?")) {
|
||||
stmt.setString(1, uuid.toString());
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
if (rs.next()) {
|
||||
data.setPrefix(rs.getString("prefix"));
|
||||
String colorsStr = rs.getString("colors");
|
||||
if (colorsStr != null && !colorsStr.isEmpty()) {
|
||||
data.setColors(List.of(colorsStr.split(",")));
|
||||
}
|
||||
data.setColorEnabled(rs.getBoolean("color_enabled"));
|
||||
data.setPrefixEnabled(rs.getBoolean("prefix_enabled"));
|
||||
data.setPrefixPurchased(rs.getBoolean("prefix_purchased"));
|
||||
data.setLastColorChange(rs.getLong("last_color_change"));
|
||||
data.setLastPrefixChange(rs.getLong("last_prefix_change"));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Ошибка загрузки данных игрока: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public void savePlayerData(UUID uuid) {
|
||||
PlayerData data = cache.get(uuid);
|
||||
if (data == null) return;
|
||||
|
||||
if (useSqlite && sqliteConnection != null) {
|
||||
try (PreparedStatement stmt = sqliteConnection.prepareStatement(
|
||||
"INSERT OR REPLACE INTO player_data (uuid, prefix, colors, color_enabled, prefix_enabled, prefix_purchased, last_color_change, last_prefix_change) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")) {
|
||||
stmt.setString(1, uuid.toString());
|
||||
stmt.setString(2, data.getPrefix());
|
||||
stmt.setString(3, data.hasColors() ? String.join(",", data.getColors()) : "");
|
||||
stmt.setBoolean(4, data.isColorEnabled());
|
||||
stmt.setBoolean(5, data.isPrefixEnabled());
|
||||
stmt.setBoolean(6, data.isPrefixPurchased());
|
||||
stmt.setLong(7, data.getLastColorChange());
|
||||
stmt.setLong(8, data.getLastPrefixChange());
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Ошибка сохранения данных игрока: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
if (useSqlite) {
|
||||
for (UUID uuid : cache.keySet()) {
|
||||
savePlayerData(uuid);
|
||||
}
|
||||
} else {
|
||||
saveYamlData();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveYamlData() {
|
||||
File dataFile = new File(plugin.getDataFolder(), "data.yml");
|
||||
FileConfiguration data = new YamlConfiguration();
|
||||
|
||||
for (Map.Entry<UUID, PlayerData> entry : cache.entrySet()) {
|
||||
String path = entry.getKey().toString();
|
||||
PlayerData pd = entry.getValue();
|
||||
data.set(path + ".prefix", pd.getPrefix());
|
||||
data.set(path + ".colors", pd.getColors());
|
||||
data.set(path + ".color-enabled", pd.isColorEnabled());
|
||||
data.set(path + ".prefix-enabled", pd.isPrefixEnabled());
|
||||
data.set(path + ".prefix-purchased", pd.isPrefixPurchased());
|
||||
data.set(path + ".last-color-change", pd.getLastColorChange());
|
||||
data.set(path + ".last-prefix-change", pd.getLastPrefixChange());
|
||||
}
|
||||
|
||||
try {
|
||||
data.save(dataFile);
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().warning("Ошибка сохранения data.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
package ru.lovar.gradientnick.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerData {
|
||||
|
||||
private final UUID uuid;
|
||||
private String prefix;
|
||||
private List<String> colors;
|
||||
private boolean colorEnabled;
|
||||
private boolean prefixEnabled;
|
||||
private boolean prefixPurchased;
|
||||
private long lastColorChange;
|
||||
private long lastPrefixChange;
|
||||
|
||||
public PlayerData(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
this.prefix = null;
|
||||
this.colors = new ArrayList<>();
|
||||
this.colorEnabled = true;
|
||||
this.prefixEnabled = true;
|
||||
this.prefixPurchased = false;
|
||||
this.lastColorChange = 0;
|
||||
this.lastPrefixChange = 0;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public List<String> getColors() {
|
||||
return colors;
|
||||
}
|
||||
|
||||
public void setColors(List<String> colors) {
|
||||
this.colors = colors != null ? new ArrayList<>(colors) : new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean hasPrefix() {
|
||||
return prefix != null && !prefix.isEmpty();
|
||||
}
|
||||
|
||||
public boolean hasColors() {
|
||||
return colors != null && !colors.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isColorEnabled() {
|
||||
return colorEnabled;
|
||||
}
|
||||
|
||||
public void setColorEnabled(boolean colorEnabled) {
|
||||
this.colorEnabled = colorEnabled;
|
||||
}
|
||||
|
||||
public boolean isPrefixEnabled() {
|
||||
return prefixEnabled;
|
||||
}
|
||||
|
||||
public void setPrefixEnabled(boolean prefixEnabled) {
|
||||
this.prefixEnabled = prefixEnabled;
|
||||
}
|
||||
|
||||
public boolean isPrefixPurchased() {
|
||||
return prefixPurchased;
|
||||
}
|
||||
|
||||
public void setPrefixPurchased(boolean prefixPurchased) {
|
||||
this.prefixPurchased = prefixPurchased;
|
||||
}
|
||||
|
||||
public long getLastColorChange() {
|
||||
return lastColorChange;
|
||||
}
|
||||
|
||||
public void setLastColorChange(long lastColorChange) {
|
||||
this.lastColorChange = lastColorChange;
|
||||
}
|
||||
|
||||
public long getLastPrefixChange() {
|
||||
return lastPrefixChange;
|
||||
}
|
||||
|
||||
public void setLastPrefixChange(long lastPrefixChange) {
|
||||
this.lastPrefixChange = lastPrefixChange;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
package ru.lovar.gradientnick.gui;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.util.Constants;
|
||||
import ru.lovar.gradientnick.util.GradientUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ConfirmGUI implements InventoryHolder {
|
||||
|
||||
public enum ConfirmType {
|
||||
COLOR, PREFIX
|
||||
}
|
||||
|
||||
private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.hexCharacter('#')
|
||||
.hexColors()
|
||||
.build();
|
||||
|
||||
private final GradientNick plugin;
|
||||
private final Player player;
|
||||
private final Inventory inventory;
|
||||
private final ConfirmType type;
|
||||
private final List<String> colors;
|
||||
private final String prefix;
|
||||
private final int price;
|
||||
|
||||
public ConfirmGUI(GradientNick plugin, Player player, ConfirmType type, List<String> colors, String prefix, int price) {
|
||||
this.plugin = plugin;
|
||||
this.player = player;
|
||||
this.type = type;
|
||||
this.colors = colors;
|
||||
this.prefix = prefix;
|
||||
this.price = price;
|
||||
this.inventory = Bukkit.createInventory(this, 27, Component.text("Подтверждение", NamedTextColor.DARK_GRAY));
|
||||
setupItems();
|
||||
}
|
||||
|
||||
private void setupItems() {
|
||||
ItemStack glass = createItem(Material.GRAY_STAINED_GLASS_PANE, " ");
|
||||
for (int i = 0; i < 27; i++) {
|
||||
inventory.setItem(i, glass);
|
||||
}
|
||||
|
||||
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
|
||||
SkullMeta skullMeta = (SkullMeta) head.getItemMeta();
|
||||
skullMeta.setOwningPlayer(player);
|
||||
|
||||
String preview = buildPreview();
|
||||
Component previewComponent = SERIALIZER.deserialize(preview);
|
||||
skullMeta.displayName(previewComponent.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
List<Component> lore = new ArrayList<>();
|
||||
lore.add(Component.empty());
|
||||
lore.add(Component.text("Так будет выглядеть ваш ник", NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, false));
|
||||
if (price > 0) {
|
||||
lore.add(Component.text("Стоимость: ", NamedTextColor.GRAY)
|
||||
.append(Component.text(price + " PP", NamedTextColor.GOLD))
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
}
|
||||
skullMeta.lore(lore);
|
||||
head.setItemMeta(skullMeta);
|
||||
inventory.setItem(Constants.GUI_PREVIEW_SLOT, head);
|
||||
|
||||
ItemStack confirm = createItem(Material.LIME_WOOL, "§a§lПодтвердить");
|
||||
ItemMeta confirmMeta = confirm.getItemMeta();
|
||||
List<Component> confirmLore = new ArrayList<>();
|
||||
confirmLore.add(Component.empty());
|
||||
confirmLore.add(Component.text("Нажмите для подтверждения", NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false));
|
||||
confirmMeta.lore(confirmLore);
|
||||
confirm.setItemMeta(confirmMeta);
|
||||
inventory.setItem(Constants.GUI_CONFIRM_SLOT, confirm);
|
||||
|
||||
ItemStack cancel = createItem(Material.RED_WOOL, "§c§lОтменить");
|
||||
ItemMeta cancelMeta = cancel.getItemMeta();
|
||||
List<Component> cancelLore = new ArrayList<>();
|
||||
cancelLore.add(Component.empty());
|
||||
cancelLore.add(Component.text("Нажмите для отмены", NamedTextColor.RED).decoration(TextDecoration.ITALIC, false));
|
||||
cancelMeta.lore(cancelLore);
|
||||
cancel.setItemMeta(cancelMeta);
|
||||
inventory.setItem(Constants.GUI_CANCEL_SLOT, cancel);
|
||||
}
|
||||
|
||||
private String buildPreview() {
|
||||
String nick = player.getName();
|
||||
String prefixToUse = this.prefix;
|
||||
List<String> colorsToUse = this.colors;
|
||||
|
||||
if (type == ConfirmType.PREFIX && (colorsToUse == null || colorsToUse.isEmpty())) {
|
||||
var data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
if (data.hasColors() && data.isColorEnabled()) {
|
||||
colorsToUse = data.getColors();
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ConfirmType.COLOR && (prefixToUse == null || prefixToUse.isEmpty())) {
|
||||
var data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
if (data.hasPrefix() && data.isPrefixEnabled()) {
|
||||
prefixToUse = data.getPrefix();
|
||||
}
|
||||
}
|
||||
|
||||
return GradientUtil.buildDisplayName(
|
||||
prefixToUse,
|
||||
nick,
|
||||
colorsToUse,
|
||||
plugin.getConfigManager().isGradientOnPrefix(),
|
||||
plugin.getConfigManager().isContinuousGradient(),
|
||||
plugin.getConfigManager().getPrefixFormat(),
|
||||
plugin.getConfigManager().isUseLegacyRgbFormat()
|
||||
);
|
||||
}
|
||||
|
||||
private ItemStack createItem(Material material, String name) {
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.displayName(LegacyComponentSerializer.legacySection().deserialize(name).decoration(TextDecoration.ITALIC, false));
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public ConfirmType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public List<String> getColors() {
|
||||
return colors;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public int getPrice() {
|
||||
return price;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
package ru.lovar.gradientnick.hooks;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.util.Constants;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class LuckPermsHook {
|
||||
|
||||
private LuckPerms luckPerms;
|
||||
private boolean enabled;
|
||||
|
||||
public LuckPermsHook(GradientNick plugin) {
|
||||
this.enabled = false;
|
||||
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) {
|
||||
try {
|
||||
this.luckPerms = LuckPermsProvider.get();
|
||||
this.enabled = true;
|
||||
plugin.getLogger().info("LuckPerms подключен!");
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Не удалось подключить LuckPerms: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled && luckPerms != null;
|
||||
}
|
||||
|
||||
public LuckPerms getApi() {
|
||||
return luckPerms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает кастомный префикс игроку (приоритет 100 — выше групповых)
|
||||
*/
|
||||
public void setPrefix(Player player, String prefix) {
|
||||
if (!isEnabled()) return;
|
||||
|
||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
if (user == null) return;
|
||||
|
||||
// Удаляем старые кастомные префиксы (приоритет 100)
|
||||
user.data().clear(node ->
|
||||
node instanceof PrefixNode && ((PrefixNode) node).getPriority() == Constants.LUCKPERMS_PREFIX_PRIORITY
|
||||
);
|
||||
|
||||
// Добавляем новый префикс если есть
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
PrefixNode prefixNode = PrefixNode.builder(prefix, Constants.LUCKPERMS_PREFIX_PRIORITY).build();
|
||||
user.data().add(prefixNode);
|
||||
}
|
||||
|
||||
luckPerms.getUserManager().saveUser(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает кастомный префикс по UUID (асинхронно)
|
||||
*/
|
||||
public void setPrefix(UUID uuid, String prefix) {
|
||||
if (!isEnabled()) return;
|
||||
|
||||
luckPerms.getUserManager().loadUser(uuid).thenAccept(user -> {
|
||||
if (user == null) return;
|
||||
|
||||
user.data().clear(node ->
|
||||
node instanceof PrefixNode && ((PrefixNode) node).getPriority() == Constants.LUCKPERMS_PREFIX_PRIORITY
|
||||
);
|
||||
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
PrefixNode prefixNode = PrefixNode.builder(prefix, Constants.LUCKPERMS_PREFIX_PRIORITY).build();
|
||||
user.data().add(prefixNode);
|
||||
}
|
||||
|
||||
luckPerms.getUserManager().saveUser(user);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет кастомный префикс — будет показываться префикс от группы
|
||||
*/
|
||||
public void removePrefix(Player player) {
|
||||
setPrefix(player, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет кастомный префикс по UUID
|
||||
*/
|
||||
public void removePrefix(UUID uuid) {
|
||||
setPrefix(uuid, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает текущий активный префикс игрока (включая групповой)
|
||||
*/
|
||||
public String getActivePrefix(Player player) {
|
||||
if (!isEnabled()) return null;
|
||||
|
||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
if (user == null) return null;
|
||||
|
||||
CachedMetaData metaData = user.getCachedData().getMetaData();
|
||||
return metaData.getPrefix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает префикс от группы (без кастомного)
|
||||
*/
|
||||
public String getGroupPrefix(Player player) {
|
||||
if (!isEnabled()) return null;
|
||||
|
||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
if (user == null) return null;
|
||||
|
||||
// Временно убираем кастомный префикс чтобы получить групповой
|
||||
// Это сложно сделать правильно, поэтому просто возвращаем активный
|
||||
// Групповой префикс будет показан когда кастомный удалён
|
||||
CachedMetaData metaData = user.getCachedData().getMetaData();
|
||||
return metaData.getPrefix();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
package ru.lovar.gradientnick.hooks;
|
||||
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.data.PlayerData;
|
||||
import ru.lovar.gradientnick.util.GradientUtil;
|
||||
|
||||
public class PlaceholderAPIHook extends PlaceholderExpansion {
|
||||
|
||||
private final GradientNick plugin;
|
||||
|
||||
public PlaceholderAPIHook(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return "lopreff";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor() {
|
||||
return "loki";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return "1.0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persist() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) {
|
||||
if (player == null) return null;
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
org.bukkit.entity.Player onlinePlayer = player.getPlayer();
|
||||
|
||||
return switch (params.toLowerCase()) {
|
||||
case "name" -> {
|
||||
if (!data.isColorEnabled() || !data.hasColors()) {
|
||||
yield player.getName();
|
||||
}
|
||||
yield GradientUtil.applyGradient(
|
||||
player.getName(),
|
||||
data.getColors(),
|
||||
plugin.getConfigManager().isUseLegacyRgbFormat()
|
||||
);
|
||||
}
|
||||
case "prefix" -> {
|
||||
if (!data.isPrefixEnabled() || !data.hasPrefix()) {
|
||||
yield "";
|
||||
}
|
||||
String format = plugin.getConfigManager().getPrefixFormat();
|
||||
String prefix = format.replace("{prefix}", data.getPrefix());
|
||||
if (data.isColorEnabled() && data.hasColors() && plugin.getConfigManager().isGradientOnPrefix()) {
|
||||
yield GradientUtil.applyGradient(prefix, data.getColors(), plugin.getConfigManager().isUseLegacyRgbFormat());
|
||||
}
|
||||
yield prefix;
|
||||
}
|
||||
case "full", "displayname" -> {
|
||||
yield GradientUtil.buildDisplayName(
|
||||
data.isPrefixEnabled() ? data.getPrefix() : null,
|
||||
player.getName(),
|
||||
data.isColorEnabled() ? data.getColors() : null,
|
||||
plugin.getConfigManager().isGradientOnPrefix(),
|
||||
plugin.getConfigManager().isContinuousGradient(),
|
||||
plugin.getConfigManager().getPrefixFormat(),
|
||||
plugin.getConfigManager().isUseLegacyRgbFormat()
|
||||
);
|
||||
}
|
||||
case "tabname" -> {
|
||||
if (!data.isColorEnabled() || !data.hasColors()) {
|
||||
yield player.getName();
|
||||
}
|
||||
yield GradientUtil.applyGradient(
|
||||
player.getName(),
|
||||
data.getColors(),
|
||||
plugin.getConfigManager().isUseLegacyRgbFormat()
|
||||
);
|
||||
}
|
||||
case "tab" -> {
|
||||
String prefix = null;
|
||||
boolean hasCustomPrefix = data.isPrefixEnabled() && data.hasPrefix();
|
||||
|
||||
if (hasCustomPrefix) {
|
||||
prefix = plugin.getConfigManager().getPrefixFormat()
|
||||
.replace("{prefix}", data.getPrefix());
|
||||
} else if (onlinePlayer != null) {
|
||||
String lpPrefix = plugin.getLuckPermsHook().getActivePrefix(onlinePlayer);
|
||||
if (lpPrefix != null && !lpPrefix.isEmpty()) {
|
||||
prefix = stripColors(lpPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
String nick = player.getName();
|
||||
|
||||
if (data.isColorEnabled() && data.hasColors()) {
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
String fullText = prefix + nick;
|
||||
yield GradientUtil.applyGradient(fullText, data.getColors(),
|
||||
plugin.getConfigManager().isUseLegacyRgbFormat());
|
||||
} else {
|
||||
yield GradientUtil.applyGradient(nick, data.getColors(),
|
||||
plugin.getConfigManager().isUseLegacyRgbFormat());
|
||||
}
|
||||
} else {
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
if (!hasCustomPrefix && onlinePlayer != null) {
|
||||
String lpPrefix = plugin.getLuckPermsHook().getActivePrefix(onlinePlayer);
|
||||
if (lpPrefix != null) {
|
||||
yield lpPrefix + nick;
|
||||
}
|
||||
}
|
||||
yield prefix + nick;
|
||||
}
|
||||
yield nick;
|
||||
}
|
||||
}
|
||||
case "hasprefix" -> (data.isPrefixEnabled() && data.hasPrefix()) ? "true" : "false";
|
||||
case "colors" -> data.hasColors() ? String.join(", ", data.getColors()) : "нет";
|
||||
case "color_enabled" -> data.isColorEnabled() ? "да" : "нет";
|
||||
case "prefix_enabled" -> data.isPrefixEnabled() ? "да" : "нет";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private String stripColors(String text) {
|
||||
if (text == null) return null;
|
||||
return text.replaceAll("(?i)(§x(§[0-9a-f]){6}|§[0-9a-fk-or]|&[0-9a-fk-or]|&#[0-9a-f]{6})", "");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
package ru.lovar.gradientnick.listeners;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.config.MessagesManager;
|
||||
import ru.lovar.gradientnick.data.PlayerData;
|
||||
import ru.lovar.gradientnick.gui.ConfirmGUI;
|
||||
import ru.lovar.gradientnick.util.Constants;
|
||||
import ru.lovar.gradientnick.util.DisplayNameUtil;
|
||||
import ru.lovar.gradientnick.util.FoliaUtil;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class GUIListener implements Listener {
|
||||
|
||||
private final GradientNick plugin;
|
||||
|
||||
private static final Map<ConfirmGUI.ConfirmType, String> PRICE_MSG_KEYS = Map.of(
|
||||
ConfirmGUI.ConfirmType.COLOR, "not-enough-points-color",
|
||||
ConfirmGUI.ConfirmType.PREFIX, "not-enough-points-prefix"
|
||||
);
|
||||
|
||||
public GUIListener(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (!(event.getInventory().getHolder() instanceof ConfirmGUI gui)) return;
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
if (!(event.getWhoClicked() instanceof Player player) || !player.equals(gui.getPlayer())) return;
|
||||
|
||||
switch (event.getRawSlot()) {
|
||||
case Constants.GUI_CONFIRM_SLOT -> handleConfirm(player, gui);
|
||||
case Constants.GUI_CANCEL_SLOT -> handleCancel(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleConfirm(Player player, ConfirmGUI gui) {
|
||||
player.closeInventory();
|
||||
|
||||
MessagesManager msg = plugin.getMessagesManager();
|
||||
int price = gui.getPrice();
|
||||
|
||||
if (price > 0 && !player.hasPermission("gradient.bypass.cost")) {
|
||||
int balance = plugin.getPlayerPointsAPI().look(player.getUniqueId());
|
||||
if (balance < price) {
|
||||
player.sendMessage(msg.get(PRICE_MSG_KEYS.get(gui.getType()), "price", String.valueOf(price)));
|
||||
return;
|
||||
}
|
||||
plugin.getPlayerPointsAPI().take(player.getUniqueId(), price);
|
||||
}
|
||||
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
|
||||
switch (gui.getType()) {
|
||||
case COLOR -> {
|
||||
data.setColors(gui.getColors());
|
||||
data.setColorEnabled(true);
|
||||
data.setLastColorChange(System.currentTimeMillis());
|
||||
player.sendMessage(msg.get("color-success", "price", String.valueOf(price)));
|
||||
}
|
||||
case PREFIX -> {
|
||||
data.setPrefix(gui.getPrefix());
|
||||
data.setPrefixEnabled(true);
|
||||
data.setPrefixPurchased(true);
|
||||
data.setLastPrefixChange(System.currentTimeMillis());
|
||||
plugin.getLuckPermsHook().setPrefix(player, DisplayNameUtil.buildColoredPrefix(plugin, data));
|
||||
player.sendMessage(msg.get(price > 0 ? "prefix-success" : "prefix-success-free", "price", String.valueOf(price)));
|
||||
}
|
||||
}
|
||||
|
||||
FoliaUtil.runEntityTask(plugin, player, () -> DisplayNameUtil.updateDisplayName(plugin, player, data));
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(player.getUniqueId()));
|
||||
}
|
||||
|
||||
private void handleCancel(Player player) {
|
||||
player.closeInventory();
|
||||
player.sendMessage("§7Действие отменено.");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
package ru.lovar.gradientnick.listeners;
|
||||
|
||||
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;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.data.PlayerData;
|
||||
import ru.lovar.gradientnick.util.DisplayNameUtil;
|
||||
import ru.lovar.gradientnick.util.FoliaUtil;
|
||||
|
||||
public class PlayerListener implements Listener {
|
||||
|
||||
private final GradientNick plugin;
|
||||
|
||||
public PlayerListener(GradientNick plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Загружаем данные асинхронно, применяем синхронно
|
||||
FoliaUtil.runAsync(plugin, () -> {
|
||||
PlayerData data = plugin.getDataManager().getPlayerData(player.getUniqueId());
|
||||
|
||||
FoliaUtil.runEntityTask(plugin, player, () -> {
|
||||
if (!player.isOnline()) return;
|
||||
|
||||
// Всегда обновляем displayName при заходе
|
||||
DisplayNameUtil.updateDisplayName(plugin, player, data);
|
||||
|
||||
// Устанавливаем кастомный префикс в LuckPerms если включён
|
||||
if (data.hasPrefix() && data.isPrefixEnabled()) {
|
||||
plugin.getLuckPermsHook().setPrefix(player, DisplayNameUtil.buildColoredPrefix(plugin, data));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Сохраняем данные при выходе
|
||||
FoliaUtil.runAsync(plugin, () -> plugin.getDataManager().savePlayerData(player.getUniqueId()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package ru.lovar.gradientnick.util;
|
||||
|
||||
/**
|
||||
* Константы плагина
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
private Constants() {}
|
||||
|
||||
// Время
|
||||
public static final long MILLIS_PER_SECOND = 1000L;
|
||||
|
||||
// GUI слоты
|
||||
public static final int GUI_CONFIRM_SLOT = 11;
|
||||
public static final int GUI_CANCEL_SLOT = 15;
|
||||
public static final int GUI_PREVIEW_SLOT = 13;
|
||||
|
||||
// LuckPerms
|
||||
public static final int LUCKPERMS_PREFIX_PRIORITY = 100;
|
||||
}
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
package ru.lovar.gradientnick.util;
|
||||
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.bukkit.entity.Player;
|
||||
import ru.lovar.gradientnick.GradientNick;
|
||||
import ru.lovar.gradientnick.config.ConfigManager;
|
||||
import ru.lovar.gradientnick.data.PlayerData;
|
||||
|
||||
/**
|
||||
* Утилита для обновления отображаемого имени игрока
|
||||
*/
|
||||
public final class DisplayNameUtil {
|
||||
|
||||
private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.hexCharacter('#')
|
||||
.hexColors()
|
||||
.build();
|
||||
|
||||
private DisplayNameUtil() {}
|
||||
|
||||
/**
|
||||
* Обновляет displayName и playerListName игрока
|
||||
*/
|
||||
public static void updateDisplayName(GradientNick plugin, Player player, PlayerData data) {
|
||||
ConfigManager cfg = plugin.getConfigManager();
|
||||
|
||||
// Определяем префикс: кастомный или групповой от LuckPerms
|
||||
String prefix = null;
|
||||
String prefixFormat = cfg.getPrefixFormat();
|
||||
|
||||
if (data.isPrefixEnabled() && data.hasPrefix()) {
|
||||
// Кастомный префикс включён
|
||||
prefix = data.getPrefix();
|
||||
} else {
|
||||
// Кастомный выключен — берём групповой из LuckPerms
|
||||
String lpPrefix = plugin.getLuckPermsHook().getActivePrefix(player);
|
||||
if (lpPrefix != null && !lpPrefix.isEmpty()) {
|
||||
// Групповой префикс — применяем градиент на всё (префикс + ник)
|
||||
String displayName = buildWithLuckPermsPrefix(
|
||||
lpPrefix,
|
||||
player.getName(),
|
||||
data.isColorEnabled() ? data.getColors() : null,
|
||||
cfg.isUseLegacyRgbFormat(),
|
||||
cfg.isContinuousGradient()
|
||||
);
|
||||
var component = SERIALIZER.deserialize(displayName);
|
||||
player.displayName(component);
|
||||
player.playerListName(component);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String displayName = GradientUtil.buildDisplayName(
|
||||
prefix,
|
||||
player.getName(),
|
||||
data.isColorEnabled() ? data.getColors() : null,
|
||||
cfg.isGradientOnPrefix(),
|
||||
cfg.isContinuousGradient(),
|
||||
prefixFormat,
|
||||
cfg.isUseLegacyRgbFormat()
|
||||
);
|
||||
var component = SERIALIZER.deserialize(displayName);
|
||||
player.displayName(component);
|
||||
player.playerListName(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Строит displayName с префиксом от LuckPerms
|
||||
* Если есть цвета и continuousGradient — применяем единый градиент на всё
|
||||
*/
|
||||
private static String buildWithLuckPermsPrefix(String lpPrefix, String nick,
|
||||
java.util.List<String> colors,
|
||||
boolean useLegacyFormat,
|
||||
boolean continuousGradient) {
|
||||
if (colors == null || colors.isEmpty()) {
|
||||
// Нет цветов — просто префикс + ник
|
||||
return lpPrefix + nick;
|
||||
}
|
||||
|
||||
if (continuousGradient) {
|
||||
// Единый градиент на префикс + ник
|
||||
// Убираем цветовые коды из LP префикса чтобы применить наш градиент
|
||||
String cleanPrefix = stripColors(lpPrefix);
|
||||
String fullText = cleanPrefix + nick;
|
||||
return GradientUtil.applyGradient(fullText, colors, useLegacyFormat);
|
||||
} else {
|
||||
// Градиент только на ник, префикс от LP оставляем
|
||||
return lpPrefix + GradientUtil.applyGradient(nick, colors, useLegacyFormat);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает цветовые коды из строки
|
||||
*/
|
||||
private static String stripColors(String text) {
|
||||
if (text == null) return null;
|
||||
// Убираем §x§R§R§G§G§B§B, §c, &c, &#RRGGBB форматы
|
||||
return text.replaceAll("(?i)(§x(§[0-9a-f]){6}|§[0-9a-fk-or]|&[0-9a-fk-or]|&#[0-9a-f]{6})", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Строит цветной префикс для LuckPerms
|
||||
*/
|
||||
public static String buildColoredPrefix(GradientNick plugin, PlayerData data) {
|
||||
if (!data.hasPrefix() || !data.isPrefixEnabled()) return null;
|
||||
|
||||
ConfigManager cfg = plugin.getConfigManager();
|
||||
String prefix = cfg.getPrefixFormat().replace("{prefix}", data.getPrefix()).stripTrailing();
|
||||
|
||||
return (data.hasColors() && data.isColorEnabled() && cfg.isGradientOnPrefix())
|
||||
? GradientUtil.applyGradient(prefix, data.getColors(), cfg.isUseLegacyRgbFormat())
|
||||
: prefix;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
package ru.lovar.gradientnick.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Утилита для работы с Folia и Paper 1.21.8+
|
||||
* Обеспечивает потокобезопасность при работе с игроками
|
||||
*/
|
||||
public final class FoliaUtil {
|
||||
|
||||
private static final boolean IS_FOLIA;
|
||||
|
||||
static {
|
||||
IS_FOLIA = checkFolia();
|
||||
}
|
||||
|
||||
private FoliaUtil() {}
|
||||
|
||||
private static boolean checkFolia() {
|
||||
try {
|
||||
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFolia() {
|
||||
return IS_FOLIA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет задачу в контексте сущности (потокобезопасно для Folia)
|
||||
*/
|
||||
public static void runEntityTask(Plugin plugin, Entity entity, Runnable task) {
|
||||
if (IS_FOLIA) {
|
||||
entity.getScheduler().run(plugin, scheduledTask -> task.run(), null);
|
||||
} else {
|
||||
Bukkit.getScheduler().runTask(plugin, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет задачу в контексте сущности с задержкой
|
||||
*/
|
||||
public static void runEntityTaskLater(Plugin plugin, Entity entity, Runnable task, long delayTicks) {
|
||||
if (IS_FOLIA) {
|
||||
entity.getScheduler().runDelayed(plugin, scheduledTask -> task.run(), null, delayTicks);
|
||||
} else {
|
||||
Bukkit.getScheduler().runTaskLater(plugin, task, delayTicks);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет задачу асинхронно
|
||||
*/
|
||||
public static void runAsync(Plugin plugin, Runnable task) {
|
||||
if (IS_FOLIA) {
|
||||
Bukkit.getAsyncScheduler().runNow(plugin, scheduledTask -> task.run());
|
||||
} else {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет задачу асинхронно с задержкой
|
||||
*/
|
||||
public static void runAsyncLater(Plugin plugin, Runnable task, long delayMs) {
|
||||
if (IS_FOLIA) {
|
||||
Bukkit.getAsyncScheduler().runDelayed(plugin, scheduledTask -> task.run(), delayMs, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, task, delayMs / 50);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет глобальную задачу (для Folia — на глобальном регионе)
|
||||
*/
|
||||
public static void runGlobalTask(Plugin plugin, Runnable task) {
|
||||
if (IS_FOLIA) {
|
||||
Bukkit.getGlobalRegionScheduler().run(plugin, scheduledTask -> task.run());
|
||||
} else {
|
||||
Bukkit.getScheduler().runTask(plugin, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет глобальную задачу с задержкой
|
||||
*/
|
||||
public static void runGlobalTaskLater(Plugin plugin, Runnable task, long delayTicks) {
|
||||
if (IS_FOLIA) {
|
||||
Bukkit.getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> task.run(), delayTicks);
|
||||
} else {
|
||||
Bukkit.getScheduler().runTaskLater(plugin, task, delayTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
package ru.lovar.gradientnick.util;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class GradientUtil {
|
||||
|
||||
private static final Pattern HEX_PATTERN = Pattern.compile("^#[0-9A-Fa-f]{6}$");
|
||||
|
||||
public static boolean isValidHex(String color) {
|
||||
return HEX_PATTERN.matcher(color).matches();
|
||||
}
|
||||
|
||||
public static String applyGradient(String text, List<String> hexColors, boolean useLegacyFormat) {
|
||||
if (text == null || text.isEmpty() || hexColors == null || hexColors.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
|
||||
char[] chars = text.toCharArray();
|
||||
int length = chars.length;
|
||||
|
||||
if (length == 0) return text;
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
if (hexColors.size() == 1) {
|
||||
// Один цвет — весь текст одним цветом
|
||||
String colorCode = formatHex(hexColors.get(0), useLegacyFormat);
|
||||
for (char c : chars) {
|
||||
result.append(colorCode).append(c);
|
||||
}
|
||||
} else {
|
||||
// Градиент из нескольких цветов
|
||||
Color[] colors = hexColors.stream()
|
||||
.map(GradientUtil::parseHex)
|
||||
.toArray(Color[]::new);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
Color interpolated = interpolateMultiColor(colors, (double) i / Math.max(1, length - 1));
|
||||
String hex = String.format("#%02x%02x%02x",
|
||||
interpolated.getRed(), interpolated.getGreen(), interpolated.getBlue());
|
||||
result.append(formatHex(hex, useLegacyFormat)).append(chars[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static Color interpolateMultiColor(Color[] colors, double ratio) {
|
||||
if (colors.length == 1) return colors[0];
|
||||
if (ratio <= 0) return colors[0];
|
||||
if (ratio >= 1) return colors[colors.length - 1];
|
||||
|
||||
// Определяем между какими двумя цветами находимся
|
||||
double scaledRatio = ratio * (colors.length - 1);
|
||||
int index = (int) scaledRatio;
|
||||
double localRatio = scaledRatio - index;
|
||||
|
||||
if (index >= colors.length - 1) {
|
||||
return colors[colors.length - 1];
|
||||
}
|
||||
|
||||
return interpolate(colors[index], colors[index + 1], localRatio);
|
||||
}
|
||||
|
||||
private static Color interpolate(Color c1, Color c2, double ratio) {
|
||||
int r = (int) (c1.getRed() + (c2.getRed() - c1.getRed()) * ratio);
|
||||
int g = (int) (c1.getGreen() + (c2.getGreen() - c1.getGreen()) * ratio);
|
||||
int b = (int) (c1.getBlue() + (c2.getBlue() - c1.getBlue()) * ratio);
|
||||
return new Color(
|
||||
Math.max(0, Math.min(255, r)),
|
||||
Math.max(0, Math.min(255, g)),
|
||||
Math.max(0, Math.min(255, b))
|
||||
);
|
||||
}
|
||||
|
||||
private static Color parseHex(String hex) {
|
||||
hex = hex.replace("#", "");
|
||||
return new Color(
|
||||
Integer.parseInt(hex.substring(0, 2), 16),
|
||||
Integer.parseInt(hex.substring(2, 4), 16),
|
||||
Integer.parseInt(hex.substring(4, 6), 16)
|
||||
);
|
||||
}
|
||||
|
||||
private static String formatHex(String hex, boolean useLegacyFormat) {
|
||||
hex = hex.replace("#", "").toLowerCase();
|
||||
if (useLegacyFormat) {
|
||||
// &#RRGGBB формат
|
||||
return "&#" + hex;
|
||||
} else {
|
||||
// <#RRGGBB> формат для MiniMessage
|
||||
return "<#" + hex + ">";
|
||||
}
|
||||
}
|
||||
|
||||
public static String buildDisplayName(String prefix, String nick, List<String> colors,
|
||||
boolean gradientOnPrefix, boolean continuousGradient,
|
||||
String prefixFormat, boolean useLegacyFormat) {
|
||||
if (colors == null || colors.isEmpty()) {
|
||||
// Нет цветов — возвращаем как есть
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
return prefixFormat.replace("{prefix}", prefix) + nick;
|
||||
}
|
||||
return nick;
|
||||
}
|
||||
|
||||
if (prefix == null || prefix.isEmpty()) {
|
||||
// Нет префикса — градиент только на ник
|
||||
return applyGradient(nick, colors, useLegacyFormat);
|
||||
}
|
||||
|
||||
if (continuousGradient && gradientOnPrefix) {
|
||||
// Единый градиент на префикс + ник
|
||||
String fullText = prefixFormat.replace("{prefix}", prefix) + nick;
|
||||
return applyGradient(fullText, colors, useLegacyFormat);
|
||||
} else if (gradientOnPrefix) {
|
||||
// Градиент отдельно на префикс и ник
|
||||
String coloredPrefix = applyGradient(prefixFormat.replace("{prefix}", prefix), colors, useLegacyFormat);
|
||||
String coloredNick = applyGradient(nick, colors, useLegacyFormat);
|
||||
return coloredPrefix + coloredNick;
|
||||
} else {
|
||||
// Градиент только на ник
|
||||
String formattedPrefix = prefixFormat.replace("{prefix}", prefix);
|
||||
return formattedPrefix + applyGradient(nick, colors, useLegacyFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue