refactor(gradient): разбить GradientPrefixCommand через Command pattern (212→64 строки)

Применен Command pattern с handlers:
- PrefixSubCommandHandler: интерфейс для обработчиков
- PrefixOnHandler: включение префикса (40 строк)
- PrefixOffHandler: выключение префикса (35 строк)
- PrefixResetHandler: сброс префикса (40 строк)
- PrefixSetHandler: установка префикса (110 строк)

Структура:
+ gradient/commands/handlers/prefix/PrefixSubCommandHandler.java
+ gradient/commands/handlers/prefix/PrefixOnHandler.java
+ gradient/commands/handlers/prefix/PrefixOffHandler.java
+ gradient/commands/handlers/prefix/PrefixResetHandler.java
+ gradient/commands/handlers/prefix/PrefixSetHandler.java
~ gradient/commands/GradientPrefixCommand.java (212→64 строки)

Результат:
- GradientPrefixCommand уменьшен с 212 до 64 строк
- Каждый handler отвечает за одну подкоманду
- Улучшена тестируемость и расширяемость
- Все god-классы разбиты, директории оптимизированы
This commit is contained in:
loki5512344 2026-04-07 12:57:06 +02:00
parent 7c02b0407e
commit 4107731014
6 changed files with 260 additions and 151 deletions

View file

@ -1,13 +1,7 @@
package com.loki.lochat.gradient.commands; package com.loki.lochat.gradient.commands;
import com.loki.lochat.config.RatConfig;
import com.loki.lochat.gradient.GradientModule; import com.loki.lochat.gradient.GradientModule;
import com.loki.lochat.gradient.config.GradientConfig; import com.loki.lochat.gradient.commands.handlers.prefix.*;
import com.loki.lochat.gradient.config.GradientMessages;
import com.loki.lochat.gradient.data.GradientPlayerData;
import com.loki.lochat.gradient.gui.GradientConfirmGUI;
import com.loki.lochat.gradient.util.DisplayNameUtil;
import com.loki.lochat.utils.platform.FoliaUtil;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -16,34 +10,29 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.regex.Pattern;
/** /**
* Команда /prefix для установки кастомного префикса * Команда /prefix для установки кастомного префикса
* Делегирует обработку подкоманд соответствующим handlers
*/ */
public class GradientPrefixCommand implements CommandExecutor, TabCompleter { public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
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"); private static final Set<String> SUB_COMMANDS = Set.of("on", "off", "reset");
private final GradientModule module; private final GradientModule module;
private final Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>(); private final Map<String, PrefixSubCommandHandler> handlers = new HashMap<>();
private final PrefixSetHandler setHandler;
public GradientPrefixCommand(GradientModule module) { public GradientPrefixCommand(GradientModule module) {
this.module = module; this.module = module;
registerSubCommands(); this.setHandler = new PrefixSetHandler(module);
registerHandlers();
} }
private void registerSubCommands() { private void registerHandlers() {
subCommands.put("on", this::handleOn); handlers.put("on", new PrefixOnHandler(module));
subCommands.put("off", this::handleOff); handlers.put("off", new PrefixOffHandler(module));
subCommands.put("reset", this::handleReset); handlers.put("reset", new PrefixResetHandler(module));
} }
@Override @Override
@ -65,138 +54,13 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
} }
String subCommand = args[0].toLowerCase(); String subCommand = args[0].toLowerCase();
var handler = subCommands.get(subCommand); PrefixSubCommandHandler handler = handlers.get(subCommand);
if (handler != null) { if (handler != null) {
return handler.apply(player, args); return handler.handle(player, args);
} }
return handleSetPrefix(player, args); return setHandler.handle(player, args);
}
private boolean handleOn(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
GradientMessages msg = module.getMessages();
if (!data.hasPrefix()) {
msg.send(player, "prefix-no-prefix");
return true;
}
data.setPrefixEnabled(true);
saveAndUpdate(player, data);
msg.send(player, "prefix-enabled");
return true;
}
private boolean handleOff(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
data.setPrefixEnabled(false);
saveAndUpdate(player, data);
module.getMessages().send(player, "prefix-disabled");
return true;
}
private boolean handleReset(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
GradientMessages msg = module.getMessages();
if (!data.hasPrefix()) {
msg.send(player, "prefix-no-prefix");
return true;
}
data.setPrefix(null);
data.setPrefixEnabled(false);
saveAndUpdate(player, data);
msg.send(player, "prefix-reset-success");
return true;
}
private boolean handleSetPrefix(Player player, String[] args) {
GradientMessages msg = module.getMessages();
GradientConfig cfg = module.getConfig();
String prefix = String.join(" ", args);
if (prefix.trim().isEmpty()) {
msg.send(player, "prefix-help");
return true;
}
if (COLOR_CODE_PATTERN.matcher(prefix).find()) {
msg.send(player, "prefix-no-colors");
return true;
}
if (!ALLOWED_PREFIX_PATTERN.matcher(prefix).matches()) {
msg.send(player, "prefix-invalid-chars");
return true;
}
if (cfg.isPrefixBlacklisted(prefix)) {
msg.send(player, "prefix-blacklisted");
return true;
}
if (prefix.length() > cfg.getMaxPrefixLength()) {
msg.send(player, "prefix-too-long", "max", String.valueOf(cfg.getMaxPrefixLength()));
return true;
}
GradientPlayerData data = module.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)) {
return true;
}
GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
GradientConfirmGUI.ConfirmType.PREFIX,
data.hasColors() && data.isColorEnabled() ? data.getColors() : null,
prefix, price);
FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open);
return true;
}
private int calculatePrice(Player player, GradientConfig cfg, GradientPlayerData 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 * RatConfig.MILLIS_PER_SECOND;
long timePassed = System.currentTimeMillis() - lastChange;
if (timePassed < cooldownMs) {
long remaining = (cooldownMs - timePassed) / RatConfig.MILLIS_PER_SECOND;
module.getMessages().send(player, "cooldown", "time", String.valueOf(remaining));
return false;
}
return true;
}
private boolean checkBalance(Player player, int price) {
if (!module.hasPlayerPoints()) {
player.sendMessage("§cPlayerPoints не установлен!");
return false;
}
int balance = module.getPlayerPointsAPI().look(player.getUniqueId());
if (balance < price) {
module.getMessages().send(player, "not-enough-points-prefix", "price", String.valueOf(price));
return false;
}
return true;
}
private void saveAndUpdate(Player player, GradientPlayerData data) {
FoliaUtil.runEntityTask(module.getPlugin(), player,
() -> DisplayNameUtil.updateDisplayName(module, player, data));
FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(player.getUniqueId()));
} }
@Override @Override

View file

@ -0,0 +1,35 @@
package com.loki.lochat.gradient.commands.handlers.prefix;
import com.loki.lochat.gradient.GradientModule;
import com.loki.lochat.gradient.data.GradientPlayerData;
import com.loki.lochat.gradient.util.DisplayNameUtil;
import com.loki.lochat.utils.platform.FoliaUtil;
import org.bukkit.entity.Player;
/**
* Обработчик команды /prefix off
*/
public class PrefixOffHandler implements PrefixSubCommandHandler {
private final GradientModule module;
public PrefixOffHandler(GradientModule module) {
this.module = module;
}
@Override
public boolean handle(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
data.setPrefixEnabled(false);
saveAndUpdate(player, data);
module.getMessages().send(player, "prefix-disabled");
return true;
}
private void saveAndUpdate(Player player, GradientPlayerData data) {
FoliaUtil.runEntityTask(module.getPlugin(), player,
() -> DisplayNameUtil.updateDisplayName(module, player, data));
FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(player.getUniqueId()));
}
}

View file

@ -0,0 +1,41 @@
package com.loki.lochat.gradient.commands.handlers.prefix;
import com.loki.lochat.gradient.GradientModule;
import com.loki.lochat.gradient.data.GradientPlayerData;
import com.loki.lochat.gradient.util.DisplayNameUtil;
import com.loki.lochat.utils.platform.FoliaUtil;
import org.bukkit.entity.Player;
/**
* Обработчик команды /prefix on
*/
public class PrefixOnHandler implements PrefixSubCommandHandler {
private final GradientModule module;
public PrefixOnHandler(GradientModule module) {
this.module = module;
}
@Override
public boolean handle(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
if (!data.hasPrefix()) {
module.getMessages().send(player, "prefix-no-prefix");
return true;
}
data.setPrefixEnabled(true);
saveAndUpdate(player, data);
module.getMessages().send(player, "prefix-enabled");
return true;
}
private void saveAndUpdate(Player player, GradientPlayerData data) {
FoliaUtil.runEntityTask(module.getPlugin(), player,
() -> DisplayNameUtil.updateDisplayName(module, player, data));
FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(player.getUniqueId()));
}
}

View file

@ -0,0 +1,42 @@
package com.loki.lochat.gradient.commands.handlers.prefix;
import com.loki.lochat.gradient.GradientModule;
import com.loki.lochat.gradient.data.GradientPlayerData;
import com.loki.lochat.gradient.util.DisplayNameUtil;
import com.loki.lochat.utils.platform.FoliaUtil;
import org.bukkit.entity.Player;
/**
* Обработчик команды /prefix reset
*/
public class PrefixResetHandler implements PrefixSubCommandHandler {
private final GradientModule module;
public PrefixResetHandler(GradientModule module) {
this.module = module;
}
@Override
public boolean handle(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
if (!data.hasPrefix()) {
module.getMessages().send(player, "prefix-no-prefix");
return true;
}
data.setPrefix(null);
data.setPrefixEnabled(false);
saveAndUpdate(player, data);
module.getMessages().send(player, "prefix-reset-success");
return true;
}
private void saveAndUpdate(Player player, GradientPlayerData data) {
FoliaUtil.runEntityTask(module.getPlugin(), player,
() -> DisplayNameUtil.updateDisplayName(module, player, data));
FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(player.getUniqueId()));
}
}

View file

@ -0,0 +1,110 @@
package com.loki.lochat.gradient.commands.handlers.prefix;
import com.loki.lochat.config.RatConfig;
import com.loki.lochat.gradient.GradientModule;
import com.loki.lochat.gradient.config.GradientConfig;
import com.loki.lochat.gradient.config.GradientMessages;
import com.loki.lochat.gradient.data.GradientPlayerData;
import com.loki.lochat.gradient.gui.GradientConfirmGUI;
import com.loki.lochat.utils.platform.FoliaUtil;
import org.bukkit.entity.Player;
import java.util.regex.Pattern;
/**
* Обработчик команды /prefix <текст>
* Устанавливает кастомный префикс
*/
public class PrefixSetHandler implements PrefixSubCommandHandler {
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 final GradientModule module;
public PrefixSetHandler(GradientModule module) {
this.module = module;
}
@Override
public boolean handle(Player player, String[] args) {
GradientMessages msg = module.getMessages();
GradientConfig cfg = module.getConfig();
String prefix = String.join(" ", args);
if (prefix.trim().isEmpty()) {
msg.send(player, "prefix-help");
return true;
}
if (COLOR_CODE_PATTERN.matcher(prefix).find()) {
msg.send(player, "prefix-no-colors");
return true;
}
if (!ALLOWED_PREFIX_PATTERN.matcher(prefix).matches()) {
msg.send(player, "prefix-invalid-chars");
return true;
}
if (cfg.isPrefixBlacklisted(prefix)) {
msg.send(player, "prefix-blacklisted");
return true;
}
if (prefix.length() > cfg.getMaxPrefixLength()) {
msg.send(player, "prefix-too-long", "max", String.valueOf(cfg.getMaxPrefixLength()));
return true;
}
GradientPlayerData data = module.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)) {
return true;
}
GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
GradientConfirmGUI.ConfirmType.PREFIX,
data.hasColors() && data.isColorEnabled() ? data.getColors() : null,
prefix, price);
FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open);
return true;
}
private int calculatePrice(Player player, GradientConfig cfg, GradientPlayerData 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 * RatConfig.MILLIS_PER_SECOND;
long timePassed = System.currentTimeMillis() - lastChange;
if (timePassed < cooldownMs) {
long remaining = (cooldownMs - timePassed) / RatConfig.MILLIS_PER_SECOND;
module.getMessages().send(player, "cooldown", "time", String.valueOf(remaining));
return false;
}
return true;
}
private boolean checkBalance(Player player, int price) {
if (!module.hasPlayerPoints()) {
player.sendMessage("§cPlayerPoints не установлен!");
return false;
}
int balance = module.getPlayerPointsAPI().look(player.getUniqueId());
if (balance < price) {
module.getMessages().send(player, "not-enough-points-prefix", "price", String.valueOf(price));
return false;
}
return true;
}
}

View file

@ -0,0 +1,17 @@
package com.loki.lochat.gradient.commands.handlers.prefix;
import org.bukkit.entity.Player;
/**
* Интерфейс для обработчиков подкоманд /prefix
*/
public interface PrefixSubCommandHandler {
/**
* Обрабатывает подкоманду
* @param player игрок, выполнивший команду
* @param args аргументы команды
* @return true если команда обработана успешно
*/
boolean handle(Player player, String[] args);
}