Update to Minecraft 1.21.8, add checkstyle, fix compilation errors

- Update Paper API: 1.20.1 -> 1.21.4
- Update plugin version: 1.5.5-1.20.1 -> 1.5.5-1.21.8
- Add checkstyle plugin with reasonable rules
- Fix Enchantment.LUCK -> Enchantment.UNBREAKING
- Fix EntityType.FIREWORK -> EntityType.FIREWORK_ROCKET
- Remove unused imports
- Add temp_*/ to .gitignore
- 118 files changed, 1633 insertions(+), 1301 deletions(-)
This commit is contained in:
loki5512344 2026-02-24 00:04:03 +01:00
parent 6a4c8a7886
commit e78d8a2de4
121 changed files with 1792 additions and 1301 deletions

3
.gitignore vendored
View file

@ -20,3 +20,6 @@ Thumbs.db
# Local config # Local config
local.properties local.properties
# Temp folders
temp_*/

View file

@ -1,9 +1,10 @@
plugins { plugins {
java java
checkstyle
} }
group = "com.loki" group = "com.loki"
version = "1.5.5-1.20.1" version = "1.5.5-1.21.8"
repositories { repositories {
mavenCentral() mavenCentral()
@ -15,7 +16,7 @@ repositories {
} }
dependencies { dependencies {
compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT") compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.6") compileOnly("me.clip:placeholderapi:2.11.6")
compileOnly("org.black_ixx:playerpoints:3.2.7") compileOnly("org.black_ixx:playerpoints:3.2.7")
compileOnly("net.luckperms:api:5.4") compileOnly("net.luckperms:api:5.4")
@ -24,7 +25,7 @@ dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0") testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0")
testImplementation("org.mockito:mockito-core:5.11.0") testImplementation("org.mockito:mockito-core:5.11.0")
testImplementation("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT") testImplementation("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0")
} }
@ -48,7 +49,21 @@ tasks.test {
} }
tasks.jar { tasks.jar {
archiveFileName.set("LoChat-1.5.5-1.20.1.jar") archiveFileName.set("LoChat-1.5.5-1.21.8.jar")
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
duplicatesStrategy = DuplicatesStrategy.EXCLUDE duplicatesStrategy = DuplicatesStrategy.EXCLUDE
} }
checkstyle {
toolVersion = "10.12.5"
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
isIgnoreFailures = true
maxWarnings = 999
}
tasks.withType<Checkstyle> {
reports {
xml.required.set(false)
html.required.set(true)
}
}

View file

@ -0,0 +1,83 @@
# Checkstyle Configuration
Автоматическая проверка качества кода во время билда.
## Правила
### Размеры
- **Файл**: максимум 150 строк
- **Метод**: максимум 30 строк
- **Строка**: максимум 120 символов
- **Параметры**: максимум 5 параметров
### Сложность
- **Cyclomatic Complexity**: максимум 10
- **Вложенность if**: максимум 3 уровня
- **Вложенность try**: максимум 2 уровня
### Качество кода
- Нет дублирования строк (макс 2 повтора)
- Нет магических чисел (кроме -1, 0, 1, 2, 3, 4, 5, 10, 20, 100)
- Нет * импортов
- Нет неиспользуемых импортов
- Упрощение boolean выражений
- equals() и hashCode() вместе
### Форматирование
- Отступы: 4 пробела
- Скобки обязательны для if/for/while
- Один оператор на строку
- Пробелы вокруг операторов
## Запуск проверки
```bash
# Проверить весь проект
./gradlew check
# Проверить только LoChat
./gradlew checkstyleMain
# Проверить только LoHub
./gradlew :lohub:checkstyleMain
# Проверить только LoVelocity
./gradlew :lovelocity:checkstyleMain
```
## Отчеты
После проверки отчеты доступны в:
- `build/reports/checkstyle/main.html`
- `lohub/build/reports/checkstyle/main.html`
- `lovelocity/build/reports/checkstyle/main.html`
## Отключение проверки
Если нужно временно отключить проверку для конкретного файла:
```java
// CHECKSTYLE:OFF
public class MyClass {
// код без проверки
}
// CHECKSTYLE:ON
```
Или для конкретной строки:
```java
private static final int MAGIC = 42; // CHECKSTYLE IGNORE MagicNumber
```
## Интеграция с IDE
### IntelliJ IDEA
1. Установить плагин "CheckStyle-IDEA"
2. Settings → Tools → Checkstyle
3. Добавить конфиг: `config/checkstyle/checkstyle.xml`
4. Активировать проверку в реальном времени
### VS Code
1. Установить расширение "Checkstyle for Java"
2. Настроить путь к конфигу в settings.json

View file

@ -0,0 +1,73 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="warning"/>
<property name="fileExtensions" value="java"/>
<module name="FileLength">
<property name="max" value="600"/>
</module>
<module name="LineLength">
<property name="max" value="140"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<module name="TreeWalker">
<module name="MethodLength">
<property name="max" value="60"/>
<property name="countEmpty" value="false"/>
</module>
<module name="CyclomaticComplexity">
<property name="max" value="15"/>
</module>
<module name="ParameterNumber">
<property name="max" value="7"/>
</module>
<module name="NestedIfDepth">
<property name="max" value="3"/>
</module>
<module name="NestedTryDepth">
<property name="max" value="2"/>
</module>
<module name="AvoidStarImport"/> <module name="UnusedImports"/>
<module name="RedundantImport"/>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
</module>
<module name="TypeName"/>
<module name="MethodName"/>
<module name="MemberName"/> <module name="ParameterName"/>
<module name="LocalVariableName"/>
<module name="ConstantName"/>
<module name="NeedBraces"/>
<module name="LeftCurly"/>
<module name="RightCurly"/>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
</module>
<module name="ModifierOrder"/> <module name="EmptyStatement"/>
<module name="EqualsHashCode"/> <module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/> <module name="DefaultComesLast"/> <module name="MultipleVariableDeclarations"/> <module name="FallThrough"/> <module name="HideUtilityClassConstructor"/>
</module>
</module>

View file

@ -1,5 +1,6 @@
plugins { plugins {
java java
checkstyle
} }
repositories { repositories {
@ -10,7 +11,7 @@ repositories {
} }
dependencies { dependencies {
compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT") compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.6") compileOnly("me.clip:placeholderapi:2.11.6")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.9") compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.9")
implementation("com.google.code.gson:gson:2.10.1") implementation("com.google.code.gson:gson:2.10.1")
@ -21,8 +22,28 @@ dependencies {
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0")
} }
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
tasks.jar { tasks.jar {
archiveFileName.set("LoHub-1.5.5-1.20.1.jar") archiveFileName.set("LoHub-1.5.5-1.21.8.jar")
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
duplicatesStrategy = DuplicatesStrategy.EXCLUDE duplicatesStrategy = DuplicatesStrategy.EXCLUDE
} }
checkstyle {
toolVersion = "10.12.5"
configFile = file("${rootProject.rootDir}/config/checkstyle/checkstyle.xml")
isIgnoreFailures = false
maxWarnings = 0
}
tasks.withType<Checkstyle> {
reports {
xml.required.set(false)
html.required.set(true)
}
}

View file

@ -11,67 +11,67 @@ import com.loki.lohub.utils.PlaceholderUtil;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public class LoHub extends JavaPlugin { public class LoHub extends JavaPlugin {
private ConfigManager configManager; private ConfigManager configManager;
private SpawnManager spawnManager; private SpawnManager spawnManager;
private RegionManager regionManager; private RegionManager regionManager;
private ActionManager actionManager; private ActionManager actionManager;
private CooldownManager cooldownManager; private CooldownManager cooldownManager;
@Override @Override
public void onEnable() { public void onEnable() {
getLogger().info("Loading LoHub v" + getDescription().getVersion()); getLogger().info("Loading LoHub v" + getDescription().getVersion());
saveDefaultConfig(); saveDefaultConfig();
PlaceholderUtil.init(); PlaceholderUtil.init();
this.configManager = new ConfigManager(this); this.configManager = new ConfigManager(this);
this.spawnManager = new SpawnManager(this); this.spawnManager = new SpawnManager(this);
this.regionManager = new RegionManager(this); this.regionManager = new RegionManager(this);
this.actionManager = new ActionManager(this); this.actionManager = new ActionManager(this);
this.cooldownManager = new CooldownManager(); this.cooldownManager = new CooldownManager();
registerListeners(); registerListeners();
registerCommands(); registerCommands();
regionManager.createHubRegion(); regionManager.createHubRegion();
getLogger().info("LoHub successfully loaded!"); getLogger().info("LoHub successfully loaded!");
} }
@Override @Override
public void onDisable() { public void onDisable() {
getLogger().info("LoHub disabled!"); getLogger().info("LoHub disabled!");
} }
private void registerListeners() { private void registerListeners() {
getServer().getPluginManager().registerEvents(new HubProtectionListener(this), this); getServer().getPluginManager().registerEvents(new HubProtectionListener(this), this);
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this); getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
} }
private void registerCommands() { private void registerCommands() {
getCommand("hub").setExecutor(new com.loki.lohub.commands.HubCommand(this)); getCommand("hub").setExecutor(new com.loki.lohub.commands.HubCommand(this));
getCommand("sethub").setExecutor(new com.loki.lohub.commands.SetHubCommand(this)); getCommand("sethub").setExecutor(new com.loki.lohub.commands.SetHubCommand(this));
getCommand("lohub").setExecutor(new com.loki.lohub.commands.LoHubCommand(this)); getCommand("lohub").setExecutor(new com.loki.lohub.commands.LoHubCommand(this));
} }
public ConfigManager getConfigManager() { public ConfigManager getConfigManager() {
return configManager; return configManager;
} }
public SpawnManager getSpawnManager() { public SpawnManager getSpawnManager() {
return spawnManager; return spawnManager;
} }
public RegionManager getRegionManager() { public RegionManager getRegionManager() {
return regionManager; return regionManager;
} }
public ActionManager getActionManager() { public ActionManager getActionManager() {
return actionManager; return actionManager;
} }
public CooldownManager getCooldownManager() { public CooldownManager getCooldownManager() {
return cooldownManager; return cooldownManager;
} }

View file

@ -3,8 +3,8 @@ package com.loki.lohub.actions;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public interface Action { public interface Action {
void execute(Player player); void execute(Player player);
ActionType getType(); ActionType getType();
} }

View file

@ -12,7 +12,7 @@ public enum ActionType {
EFFECT, EFFECT,
CLOSE, CLOSE,
UNKNOWN; UNKNOWN;
public static ActionType fromString(String type) { public static ActionType fromString(String type) {
try { try {
return valueOf(type.toUpperCase()); return valueOf(type.toUpperCase());

View file

@ -8,19 +8,19 @@ import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class ActionbarAction implements Action { public class ActionbarAction implements Action {
private final String message; private final String message;
public ActionbarAction(String message) { public ActionbarAction(String message) {
this.message = message; this.message = message;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
String parsed = PlaceholderUtil.parse(message, player); String parsed = PlaceholderUtil.parse(message, player);
player.sendActionBar(Component.text(TextUtil.colorize(parsed))); player.sendActionBar(Component.text(TextUtil.colorize(parsed)));
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.ACTIONBAR; return ActionType.ACTIONBAR;

View file

@ -8,19 +8,19 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class BroadcastAction implements Action { public class BroadcastAction implements Action {
private final String message; private final String message;
public BroadcastAction(String message) { public BroadcastAction(String message) {
this.message = message; this.message = message;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
String parsed = PlaceholderUtil.parse(message, player); String parsed = PlaceholderUtil.parse(message, player);
Bukkit.broadcastMessage(TextUtil.colorize(parsed)); Bukkit.broadcastMessage(TextUtil.colorize(parsed));
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.BROADCAST; return ActionType.BROADCAST;

View file

@ -5,12 +5,12 @@ import com.loki.lohub.actions.ActionType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class CloseAction implements Action { public class CloseAction implements Action {
@Override @Override
public void execute(Player player) { public void execute(Player player) {
player.closeInventory(); player.closeInventory();
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.CLOSE; return ActionType.CLOSE;

View file

@ -6,19 +6,19 @@ import com.loki.lohub.utils.PlaceholderUtil;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class CommandAction implements Action { public class CommandAction implements Action {
private final String command; private final String command;
public CommandAction(String command) { public CommandAction(String command) {
this.command = command; this.command = command;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
String parsed = PlaceholderUtil.parse(command, player); String parsed = PlaceholderUtil.parse(command, player);
player.performCommand(parsed); player.performCommand(parsed);
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.COMMAND; return ActionType.COMMAND;

View file

@ -7,19 +7,19 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class ConsoleAction implements Action { public class ConsoleAction implements Action {
private final String command; private final String command;
public ConsoleAction(String command) { public ConsoleAction(String command) {
this.command = command; this.command = command;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
String parsed = PlaceholderUtil.parse(command, player); String parsed = PlaceholderUtil.parse(command, player);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsed); Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsed);
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.CONSOLE; return ActionType.CONSOLE;

View file

@ -7,36 +7,36 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
public class EffectAction implements Action { public class EffectAction implements Action {
private final PotionEffectType effectType; private final PotionEffectType effectType;
private final int amplifier; private final int amplifier;
private final int duration; private final int duration;
public EffectAction(String effectData) { public EffectAction(String effectData) {
String[] parts = effectData.split(";"); String[] parts = effectData.split(";");
PotionEffectType parsed; PotionEffectType parsed;
try { try {
parsed = PotionEffectType.getByName(parts[0].toUpperCase()); parsed = PotionEffectType.getByName(parts[0].toUpperCase());
} catch (Exception e) { } catch (Exception e) {
parsed = PotionEffectType.SPEED; parsed = PotionEffectType.SPEED;
} }
this.effectType = parsed != null ? parsed : PotionEffectType.SPEED; this.effectType = parsed != null ? parsed : PotionEffectType.SPEED;
this.amplifier = parts.length > 1 ? parseInt(parts[1], 0) : 0; this.amplifier = parts.length > 1 ? parseInt(parts[1], 0) : 0;
this.duration = parts.length > 2 ? parseInt(parts[2], 999999) : 999999; this.duration = parts.length > 2 ? parseInt(parts[2], 999999) : 999999;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
player.addPotionEffect(new PotionEffect(effectType, duration * 20, amplifier, false, false)); player.addPotionEffect(new PotionEffect(effectType, duration * 20, amplifier, false, false));
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.EFFECT; return ActionType.EFFECT;
} }
private int parseInt(String value, int defaultValue) { private int parseInt(String value, int defaultValue) {
try { try {
return Integer.parseInt(value); return Integer.parseInt(value);

View file

@ -6,9 +6,9 @@ import org.bukkit.GameMode;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class GamemodeAction implements Action { public class GamemodeAction implements Action {
private final GameMode gameMode; private final GameMode gameMode;
public GamemodeAction(String mode) { public GamemodeAction(String mode) {
GameMode parsed; GameMode parsed;
try { try {
@ -24,12 +24,12 @@ public class GamemodeAction implements Action {
} }
this.gameMode = parsed; this.gameMode = parsed;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
player.setGameMode(gameMode); player.setGameMode(gameMode);
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.GAMEMODE; return ActionType.GAMEMODE;

View file

@ -7,19 +7,19 @@ import com.loki.lohub.utils.TextUtil;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class MessageAction implements Action { public class MessageAction implements Action {
private final String message; private final String message;
public MessageAction(String message) { public MessageAction(String message) {
this.message = message; this.message = message;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
String parsed = PlaceholderUtil.parse(message, player); String parsed = PlaceholderUtil.parse(message, player);
player.sendMessage(TextUtil.colorize(parsed)); player.sendMessage(TextUtil.colorize(parsed));
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.MESSAGE; return ActionType.MESSAGE;

View file

@ -6,36 +6,36 @@ import org.bukkit.Sound;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class SoundAction implements Action { public class SoundAction implements Action {
private final Sound sound; private final Sound sound;
private final float volume; private final float volume;
private final float pitch; private final float pitch;
public SoundAction(String soundData) { public SoundAction(String soundData) {
String[] parts = soundData.split(";"); String[] parts = soundData.split(";");
Sound parsedSound; Sound parsedSound;
try { try {
parsedSound = Sound.valueOf(parts[0].toUpperCase()); parsedSound = Sound.valueOf(parts[0].toUpperCase());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
parsedSound = Sound.ENTITY_EXPERIENCE_ORB_PICKUP; parsedSound = Sound.ENTITY_EXPERIENCE_ORB_PICKUP;
} }
this.sound = parsedSound; this.sound = parsedSound;
this.volume = parts.length > 1 ? parseFloat(parts[1], 1.0f) : 1.0f; this.volume = parts.length > 1 ? parseFloat(parts[1], 1.0f) : 1.0f;
this.pitch = parts.length > 2 ? parseFloat(parts[2], 1.0f) : 1.0f; this.pitch = parts.length > 2 ? parseFloat(parts[2], 1.0f) : 1.0f;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
player.playSound(player.getLocation(), sound, volume, pitch); player.playSound(player.getLocation(), sound, volume, pitch);
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.SOUND; return ActionType.SOUND;
} }
private float parseFloat(String value, float defaultValue) { private float parseFloat(String value, float defaultValue) {
try { try {
return Float.parseFloat(value); return Float.parseFloat(value);

View file

@ -11,46 +11,46 @@ import org.bukkit.entity.Player;
import java.time.Duration; import java.time.Duration;
public class TitleAction implements Action { public class TitleAction implements Action {
private final String title; private final String title;
private final String subtitle; private final String subtitle;
private final int fadeIn; private final int fadeIn;
private final int stay; private final int stay;
private final int fadeOut; private final int fadeOut;
public TitleAction(String titleData) { public TitleAction(String titleData) {
String[] parts = titleData.split(";"); String[] parts = titleData.split(";");
this.title = parts.length > 0 ? parts[0] : ""; this.title = parts.length > 0 ? parts[0] : "";
this.subtitle = parts.length > 1 ? parts[1] : ""; this.subtitle = parts.length > 1 ? parts[1] : "";
this.fadeIn = parts.length > 2 ? parseInt(parts[2], 10) : 10; this.fadeIn = parts.length > 2 ? parseInt(parts[2], 10) : 10;
this.stay = parts.length > 3 ? parseInt(parts[3], 40) : 40; this.stay = parts.length > 3 ? parseInt(parts[3], 40) : 40;
this.fadeOut = parts.length > 4 ? parseInt(parts[4], 10) : 10; this.fadeOut = parts.length > 4 ? parseInt(parts[4], 10) : 10;
} }
@Override @Override
public void execute(Player player) { public void execute(Player player) {
String parsedTitle = PlaceholderUtil.parse(title, player); String parsedTitle = PlaceholderUtil.parse(title, player);
String parsedSubtitle = PlaceholderUtil.parse(subtitle, player); String parsedSubtitle = PlaceholderUtil.parse(subtitle, player);
Component titleComponent = Component.text(TextUtil.colorize(parsedTitle)); Component titleComponent = Component.text(TextUtil.colorize(parsedTitle));
Component subtitleComponent = Component.text(TextUtil.colorize(parsedSubtitle)); Component subtitleComponent = Component.text(TextUtil.colorize(parsedSubtitle));
Title.Times times = Title.Times.times( Title.Times times = Title.Times.times(
Duration.ofMillis(fadeIn * 50L), Duration.ofMillis(fadeIn * 50L),
Duration.ofMillis(stay * 50L), Duration.ofMillis(stay * 50L),
Duration.ofMillis(fadeOut * 50L) Duration.ofMillis(fadeOut * 50L)
); );
Title title = Title.title(titleComponent, subtitleComponent, times); Title title = Title.title(titleComponent, subtitleComponent, times);
player.showTitle(title); player.showTitle(title);
} }
@Override @Override
public ActionType getType() { public ActionType getType() {
return ActionType.TITLE; return ActionType.TITLE;
} }
private int parseInt(String value, int defaultValue) { private int parseInt(String value, int defaultValue) {
try { try {
return Integer.parseInt(value); return Integer.parseInt(value);

View file

@ -8,28 +8,28 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class HubCommand implements CommandExecutor { public class HubCommand implements CommandExecutor {
private final LoHub plugin; private final LoHub plugin;
public HubCommand(LoHub plugin) { public HubCommand(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) { if (!(sender instanceof Player player)) {
sender.sendMessage(TextUtil.colorize("&cThis command is only for players!")); sender.sendMessage(TextUtil.colorize("&cThis command is only for players!"));
return true; return true;
} }
if (plugin.getSpawnManager().getSpawn() == null) { if (plugin.getSpawnManager().getSpawn() == null) {
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-spawn"))); player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-spawn")));
return true; return true;
} }
plugin.getSpawnManager().teleportToSpawn(player); plugin.getSpawnManager().teleportToSpawn(player);
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.spawn-teleport"))); player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.spawn-teleport")));
return true; return true;
} }
} }

View file

@ -7,32 +7,32 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
public class LoHubCommand implements CommandExecutor { public class LoHubCommand implements CommandExecutor {
private final LoHub plugin; private final LoHub plugin;
public LoHubCommand(LoHub plugin) { public LoHubCommand(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("lohub.admin")) { if (!sender.hasPermission("lohub.admin")) {
sender.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-permission"))); sender.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-permission")));
return true; return true;
} }
if (args.length == 0) { if (args.length == 0) {
sender.sendMessage(TextUtil.colorize("&7LoHub v" + plugin.getDescription().getVersion())); sender.sendMessage(TextUtil.colorize("&7LoHub v" + plugin.getDescription().getVersion()));
sender.sendMessage(TextUtil.colorize("&7Use: &e/lohub reload")); sender.sendMessage(TextUtil.colorize("&7Use: &e/lohub reload"));
return true; return true;
} }
if (args[0].equalsIgnoreCase("reload")) { if (args[0].equalsIgnoreCase("reload")) {
plugin.getConfigManager().reload(); plugin.getConfigManager().reload();
sender.sendMessage(TextUtil.colorize("&aConfiguration reloaded!")); sender.sendMessage(TextUtil.colorize("&aConfiguration reloaded!"));
return true; return true;
} }
return true; return true;
} }
} }

View file

@ -8,35 +8,35 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class SetHubCommand implements CommandExecutor { public class SetHubCommand implements CommandExecutor {
private final LoHub plugin; private final LoHub plugin;
public SetHubCommand(LoHub plugin) { public SetHubCommand(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) { if (!(sender instanceof Player player)) {
sender.sendMessage(TextUtil.colorize("&cThis command is only for players!")); sender.sendMessage(TextUtil.colorize("&cThis command is only for players!"));
return true; return true;
} }
if (!player.hasPermission("lohub.admin")) { if (!player.hasPermission("lohub.admin")) {
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-permission"))); player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-permission")));
return true; return true;
} }
plugin.getSpawnManager().setSpawn(player.getLocation()); plugin.getSpawnManager().setSpawn(player.getLocation());
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.spawn-set"))); player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.spawn-set")));
plugin.getRegionManager().deleteHubRegion(); plugin.getRegionManager().deleteHubRegion();
plugin.getRegionManager().createHubRegion(); plugin.getRegionManager().createHubRegion();
if (plugin.getConfig().getBoolean("worldguard.auto-create-region")) { if (plugin.getConfig().getBoolean("worldguard.auto-create-region")) {
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.region-created"))); player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.region-created")));
} }
return true; return true;
} }
} }

View file

@ -4,52 +4,52 @@ import com.loki.lohub.LoHub;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
public class ConfigManager { public class ConfigManager {
private final LoHub plugin; private final LoHub plugin;
private FileConfiguration config; private FileConfiguration config;
public ConfigManager(LoHub plugin) { public ConfigManager(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
this.config = plugin.getConfig(); this.config = plugin.getConfig();
} }
public void reload() { public void reload() {
plugin.reloadConfig(); plugin.reloadConfig();
this.config = plugin.getConfig(); this.config = plugin.getConfig();
} }
public FileConfiguration getConfig() { public FileConfiguration getConfig() {
return config; return config;
} }
public boolean isProtectionEnabled() { public boolean isProtectionEnabled() {
return config.getBoolean("protection.enabled", true); return config.getBoolean("protection.enabled", true);
} }
public boolean isBlockBreakProtected() { public boolean isBlockBreakProtected() {
return config.getBoolean("protection.block-break", true); return config.getBoolean("protection.block-break", true);
} }
public boolean isBlockPlaceProtected() { public boolean isBlockPlaceProtected() {
return config.getBoolean("protection.block-place", true); return config.getBoolean("protection.block-place", true);
} }
public boolean isPvPProtected() { public boolean isPvPProtected() {
return config.getBoolean("protection.pvp", true); return config.getBoolean("protection.pvp", true);
} }
public boolean isItemDropProtected() { public boolean isItemDropProtected() {
return config.getBoolean("protection.item-drop", true); return config.getBoolean("protection.item-drop", true);
} }
public boolean isItemPickupProtected() { public boolean isItemPickupProtected() {
return config.getBoolean("protection.item-pickup", true); return config.getBoolean("protection.item-pickup", true);
} }
public boolean isFoodLevelProtected() { public boolean isFoodLevelProtected() {
return config.getBoolean("protection.food-level", true); return config.getBoolean("protection.food-level", true);
} }
public boolean isMobSpawningProtected() { public boolean isMobSpawningProtected() {
return config.getBoolean("protection.mob-spawning", true); return config.getBoolean("protection.mob-spawning", true);
} }

View file

@ -13,90 +13,120 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.event.player.PlayerPickupItemEvent;
public class HubProtectionListener implements Listener { public class HubProtectionListener implements Listener {
private final LoHub plugin; private final LoHub plugin;
public HubProtectionListener(LoHub plugin) { public HubProtectionListener(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@EventHandler @EventHandler
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
if (plugin.getConfig().getBoolean("spawn.teleport-on-join", true)) { if (plugin.getConfig().getBoolean("spawn.teleport-on-join", true)) {
plugin.getSpawnManager().teleportToSpawn(event.getPlayer()); plugin.getSpawnManager().teleportToSpawn(event.getPlayer());
} }
} }
@EventHandler @EventHandler
public void onBlockBreak(BlockBreakEvent event) { public void onBlockBreak(BlockBreakEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return; if (!plugin.getConfigManager().isProtectionEnabled()) {
return;
}
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.hasPermission("lohub.bypass.protection")) return; if (player.hasPermission("lohub.bypass.protection")) {
return;
}
if (plugin.getConfigManager().isBlockBreakProtected()) { if (plugin.getConfigManager().isBlockBreakProtected()) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler @EventHandler
public void onBlockPlace(BlockPlaceEvent event) { public void onBlockPlace(BlockPlaceEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return; if (!plugin.getConfigManager().isProtectionEnabled()) {
return;
}
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.hasPermission("lohub.bypass.protection")) return; if (player.hasPermission("lohub.bypass.protection")) {
return;
}
if (plugin.getConfigManager().isBlockPlaceProtected()) { if (plugin.getConfigManager().isBlockPlaceProtected()) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler @EventHandler
public void onPvP(EntityDamageByEntityEvent event) { public void onPvP(EntityDamageByEntityEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return; if (!plugin.getConfigManager().isProtectionEnabled()) {
if (!(event.getDamager() instanceof Player)) return; return;
if (!(event.getEntity() instanceof Player)) return; }
if (!(event.getDamager() instanceof Player)) {
return;
}
if (!(event.getEntity() instanceof Player)) {
return;
}
Player damager = (Player) event.getDamager(); Player damager = (Player) event.getDamager();
if (damager.hasPermission("lohub.bypass.protection")) return; if (damager.hasPermission("lohub.bypass.protection")) {
return;
}
if (plugin.getConfigManager().isPvPProtected()) { if (plugin.getConfigManager().isPvPProtected()) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler @EventHandler
public void onItemDrop(PlayerDropItemEvent event) { public void onItemDrop(PlayerDropItemEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return; if (!plugin.getConfigManager().isProtectionEnabled()) {
return;
}
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.hasPermission("lohub.bypass.protection")) return; if (player.hasPermission("lohub.bypass.protection")) {
return;
}
if (plugin.getConfigManager().isItemDropProtected()) { if (plugin.getConfigManager().isItemDropProtected()) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler @EventHandler
public void onItemPickup(PlayerPickupItemEvent event) { public void onItemPickup(PlayerPickupItemEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return; if (!plugin.getConfigManager().isProtectionEnabled()) {
return;
}
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.hasPermission("lohub.bypass.protection")) return; if (player.hasPermission("lohub.bypass.protection")) {
return;
}
if (plugin.getConfigManager().isItemPickupProtected()) { if (plugin.getConfigManager().isItemPickupProtected()) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler @EventHandler
public void onFoodLevelChange(FoodLevelChangeEvent event) { public void onFoodLevelChange(FoodLevelChangeEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return; if (!plugin.getConfigManager().isProtectionEnabled()) {
if (!(event.getEntity() instanceof Player)) return; return;
}
if (!(event.getEntity() instanceof Player)) {
return;
}
Player player = (Player) event.getEntity(); Player player = (Player) event.getEntity();
if (player.hasPermission("lohub.bypass.protection")) return; if (player.hasPermission("lohub.bypass.protection")) {
return;
}
if (plugin.getConfigManager().isFoodLevelProtected()) { if (plugin.getConfigManager().isFoodLevelProtected()) {
event.setCancelled(true); event.setCancelled(true);
} }

View file

@ -20,37 +20,61 @@ import org.bukkit.inventory.meta.FireworkMeta;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class PlayerJoinListener implements Listener { public class PlayerJoinListener implements Listener {
private static final Map<String, Color> COLOR_MAP = new HashMap<>();
static {
COLOR_MAP.put("AQUA", Color.AQUA);
COLOR_MAP.put("BLACK", Color.BLACK);
COLOR_MAP.put("BLUE", Color.BLUE);
COLOR_MAP.put("FUCHSIA", Color.FUCHSIA);
COLOR_MAP.put("GRAY", Color.GRAY);
COLOR_MAP.put("GREEN", Color.GREEN);
COLOR_MAP.put("LIME", Color.LIME);
COLOR_MAP.put("MAROON", Color.MAROON);
COLOR_MAP.put("NAVY", Color.NAVY);
COLOR_MAP.put("OLIVE", Color.OLIVE);
COLOR_MAP.put("ORANGE", Color.ORANGE);
COLOR_MAP.put("PURPLE", Color.PURPLE);
COLOR_MAP.put("RED", Color.RED);
COLOR_MAP.put("SILVER", Color.SILVER);
COLOR_MAP.put("TEAL", Color.TEAL);
COLOR_MAP.put("WHITE", Color.WHITE);
COLOR_MAP.put("YELLOW", Color.YELLOW);
}
private final LoHub plugin; private final LoHub plugin;
public PlayerJoinListener(LoHub plugin) { public PlayerJoinListener(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (isWorldDisabled(player.getWorld().getName())) { if (isWorldDisabled(player.getWorld().getName())) {
return; return;
} }
handleJoinMessage(event, player); handleJoinMessage(event, player);
handleJoinSettings(player); handleJoinSettings(player);
handleJoinEvents(player); handleJoinEvents(player);
handleFirework(player); handleFirework(player);
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (isWorldDisabled(player.getWorld().getName())) { if (isWorldDisabled(player.getWorld().getName())) {
return; return;
} }
if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) { if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) {
String quitMessage = plugin.getConfig().getString("join_leave_messages.quit_message", ""); String quitMessage = plugin.getConfig().getString("join_leave_messages.quit_message", "");
if (quitMessage.isEmpty()) { if (quitMessage.isEmpty()) {
@ -60,15 +84,15 @@ public class PlayerJoinListener implements Listener {
} }
} }
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerRespawn(PlayerRespawnEvent event) { public void onPlayerRespawn(PlayerRespawnEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (isWorldDisabled(player.getWorld().getName())) { if (isWorldDisabled(player.getWorld().getName())) {
return; return;
} }
if (plugin.getConfig().getBoolean("spawn.teleport-on-respawn", true)) { if (plugin.getConfig().getBoolean("spawn.teleport-on-respawn", true)) {
Location spawn = plugin.getSpawnManager().getSpawn(); Location spawn = plugin.getSpawnManager().getSpawn();
if (spawn != null) { if (spawn != null) {
@ -76,18 +100,18 @@ public class PlayerJoinListener implements Listener {
} }
} }
} }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onPlayerDeath(PlayerDeathEvent event) { public void onPlayerDeath(PlayerDeathEvent event) {
if (isWorldDisabled(event.getPlayer().getWorld().getName())) { if (isWorldDisabled(event.getPlayer().getWorld().getName())) {
return; return;
} }
if (plugin.getConfig().getBoolean("world_settings.disable_death_message", true)) { if (plugin.getConfig().getBoolean("world_settings.disable_death_message", true)) {
event.deathMessage(null); event.deathMessage(null);
} }
} }
private void handleJoinMessage(PlayerJoinEvent event, Player player) { private void handleJoinMessage(PlayerJoinEvent event, Player player) {
if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) { if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) {
String joinMessage = plugin.getConfig().getString("join_leave_messages.join_message", ""); String joinMessage = plugin.getConfig().getString("join_leave_messages.join_message", "");
@ -98,7 +122,7 @@ public class PlayerJoinListener implements Listener {
} }
} }
} }
private void handleJoinSettings(Player player) { private void handleJoinSettings(Player player) {
if (plugin.getConfig().getBoolean("join_settings.spawn_join", true)) { if (plugin.getConfig().getBoolean("join_settings.spawn_join", true)) {
Location spawn = plugin.getSpawnManager().getSpawn(); Location spawn = plugin.getSpawnManager().getSpawn();
@ -106,43 +130,43 @@ public class PlayerJoinListener implements Listener {
player.teleport(spawn); player.teleport(spawn);
} }
} }
if (plugin.getConfig().getBoolean("join_settings.heal", true)) { if (plugin.getConfig().getBoolean("join_settings.heal", true)) {
player.setHealth(player.getMaxHealth()); player.setHealth(player.getMaxHealth());
player.setFoodLevel(20); player.setFoodLevel(20);
player.setSaturation(20); player.setSaturation(20);
} }
if (plugin.getConfig().getBoolean("join_settings.extinguish", true)) { if (plugin.getConfig().getBoolean("join_settings.extinguish", true)) {
player.setFireTicks(0); player.setFireTicks(0);
} }
if (plugin.getConfig().getBoolean("join_settings.clear_inventory", false)) { if (plugin.getConfig().getBoolean("join_settings.clear_inventory", false)) {
player.getInventory().clear(); player.getInventory().clear();
} }
} }
private void handleJoinEvents(Player player) { private void handleJoinEvents(Player player) {
List<String> actions = plugin.getConfig().getStringList("join_events"); List<String> actions = plugin.getConfig().getStringList("join_events");
if (!actions.isEmpty()) { if (!actions.isEmpty()) {
plugin.getActionManager().executeActions(player, actions, false); plugin.getActionManager().executeActions(player, actions, false);
} }
} }
private void handleFirework(Player player) { private void handleFirework(Player player) {
if (!plugin.getConfig().getBoolean("join_settings.firework.enabled", false)) { if (!plugin.getConfig().getBoolean("join_settings.firework.enabled", false)) {
return; return;
} }
boolean firstJoinOnly = plugin.getConfig().getBoolean("join_settings.firework.first_join_only", true); boolean firstJoinOnly = plugin.getConfig().getBoolean("join_settings.firework.first_join_only", true);
if (firstJoinOnly && player.hasPlayedBefore()) { if (firstJoinOnly && player.hasPlayedBefore()) {
return; return;
} }
Location loc = player.getLocation(); Location loc = player.getLocation();
Firework firework = (Firework) loc.getWorld().spawnEntity(loc, EntityType.FIREWORK); Firework firework = (Firework) loc.getWorld().spawnEntity(loc, EntityType.FIREWORK_ROCKET);
FireworkMeta meta = firework.getFireworkMeta(); FireworkMeta meta = firework.getFireworkMeta();
String typeStr = plugin.getConfig().getString("join_settings.firework.type", "BALL_LARGE"); String typeStr = plugin.getConfig().getString("join_settings.firework.type", "BALL_LARGE");
FireworkEffect.Type type; FireworkEffect.Type type;
try { try {
@ -150,7 +174,7 @@ public class PlayerJoinListener implements Listener {
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
type = FireworkEffect.Type.BALL_LARGE; type = FireworkEffect.Type.BALL_LARGE;
} }
List<Color> colors = new ArrayList<>(); List<Color> colors = new ArrayList<>();
for (String colorStr : plugin.getConfig().getStringList("join_settings.firework.colors")) { for (String colorStr : plugin.getConfig().getStringList("join_settings.firework.colors")) {
Color color = parseColor(colorStr); Color color = parseColor(colorStr);
@ -158,51 +182,32 @@ public class PlayerJoinListener implements Listener {
colors.add(color); colors.add(color);
} }
} }
if (colors.isEmpty()) { if (colors.isEmpty()) {
colors.add(Color.AQUA); colors.add(Color.AQUA);
} }
FireworkEffect effect = FireworkEffect.builder() FireworkEffect effect = FireworkEffect.builder()
.with(type) .with(type)
.withColor(colors) .withColor(colors)
.flicker(plugin.getConfig().getBoolean("join_settings.firework.flicker", true)) .flicker(plugin.getConfig().getBoolean("join_settings.firework.flicker", true))
.trail(plugin.getConfig().getBoolean("join_settings.firework.trail", true)) .trail(plugin.getConfig().getBoolean("join_settings.firework.trail", true))
.build(); .build();
meta.addEffect(effect); meta.addEffect(effect);
meta.setPower(plugin.getConfig().getInt("join_settings.firework.power", 1)); meta.setPower(plugin.getConfig().getInt("join_settings.firework.power", 1));
firework.setFireworkMeta(meta); firework.setFireworkMeta(meta);
} }
private Color parseColor(String colorStr) { private Color parseColor(String colorStr) {
return switch (colorStr.toUpperCase()) { return COLOR_MAP.get(colorStr.toUpperCase());
case "AQUA" -> Color.AQUA;
case "BLACK" -> Color.BLACK;
case "BLUE" -> Color.BLUE;
case "FUCHSIA" -> Color.FUCHSIA;
case "GRAY" -> Color.GRAY;
case "GREEN" -> Color.GREEN;
case "LIME" -> Color.LIME;
case "MAROON" -> Color.MAROON;
case "NAVY" -> Color.NAVY;
case "OLIVE" -> Color.OLIVE;
case "ORANGE" -> Color.ORANGE;
case "PURPLE" -> Color.PURPLE;
case "RED" -> Color.RED;
case "SILVER" -> Color.SILVER;
case "TEAL" -> Color.TEAL;
case "WHITE" -> Color.WHITE;
case "YELLOW" -> Color.YELLOW;
default -> null;
};
} }
private boolean isWorldDisabled(String worldName) { private boolean isWorldDisabled(String worldName) {
List<String> disabledWorlds = plugin.getConfig().getStringList("disabled-worlds.worlds"); List<String> disabledWorlds = plugin.getConfig().getStringList("disabled-worlds.worlds");
boolean invert = plugin.getConfig().getBoolean("disabled-worlds.invert", false); boolean invert = plugin.getConfig().getBoolean("disabled-worlds.invert", false);
boolean isInList = disabledWorlds.contains(worldName); boolean isInList = disabledWorlds.contains(worldName);
return invert ? !isInList : isInList; return invert ? !isInList : isInList;
} }
} }

View file

@ -3,7 +3,16 @@ package com.loki.lohub.managers;
import com.loki.lohub.LoHub; import com.loki.lohub.LoHub;
import com.loki.lohub.actions.Action; import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType; import com.loki.lohub.actions.ActionType;
import com.loki.lohub.actions.impl.*; import com.loki.lohub.actions.impl.ActionbarAction;
import com.loki.lohub.actions.impl.BroadcastAction;
import com.loki.lohub.actions.impl.CloseAction;
import com.loki.lohub.actions.impl.CommandAction;
import com.loki.lohub.actions.impl.ConsoleAction;
import com.loki.lohub.actions.impl.EffectAction;
import com.loki.lohub.actions.impl.GamemodeAction;
import com.loki.lohub.actions.impl.MessageAction;
import com.loki.lohub.actions.impl.SoundAction;
import com.loki.lohub.actions.impl.TitleAction;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
@ -12,43 +21,43 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class ActionManager { public class ActionManager {
private final LoHub plugin;
private static final Pattern ACTION_PATTERN = Pattern.compile("\\[([A-Z]+)]\\s*(.*)"); private static final Pattern ACTION_PATTERN = Pattern.compile("\\[([A-Z]+)]\\s*(.*)");
private final LoHub plugin;
public ActionManager(LoHub plugin) { public ActionManager(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
public List<Action> parseActions(List<String> actionStrings) { public List<Action> parseActions(List<String> actionStrings) {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
for (String actionString : actionStrings) { for (String actionString : actionStrings) {
Action action = parseAction(actionString); Action action = parseAction(actionString);
if (action != null) { if (action != null) {
actions.add(action); actions.add(action);
} }
} }
return actions; return actions;
} }
public Action parseAction(String actionString) { public Action parseAction(String actionString) {
if (actionString == null || actionString.isEmpty()) { if (actionString == null || actionString.isEmpty()) {
return null; return null;
} }
Matcher matcher = ACTION_PATTERN.matcher(actionString); Matcher matcher = ACTION_PATTERN.matcher(actionString);
if (!matcher.matches()) { if (!matcher.matches()) {
plugin.getLogger().warning("Invalid action format: " + actionString); plugin.getLogger().warning("Invalid action format: " + actionString);
return null; return null;
} }
String typeStr = matcher.group(1); String typeStr = matcher.group(1);
String data = matcher.group(2); String data = matcher.group(2);
ActionType type = ActionType.fromString(typeStr); ActionType type = ActionType.fromString(typeStr);
return switch (type) { return switch (type) {
case MESSAGE -> new MessageAction(data); case MESSAGE -> new MessageAction(data);
case BROADCAST -> new BroadcastAction(data); case BROADCAST -> new BroadcastAction(data);
@ -66,7 +75,7 @@ public class ActionManager {
} }
}; };
} }
public void executeActions(Player player, List<Action> actions) { public void executeActions(Player player, List<Action> actions) {
for (Action action : actions) { for (Action action : actions) {
try { try {
@ -77,7 +86,7 @@ public class ActionManager {
} }
} }
} }
public void executeActions(Player player, List<String> actionStrings, boolean parse) { public void executeActions(Player player, List<String> actionStrings, boolean parse) {
if (parse) { if (parse) {
List<Action> actions = parseActions(actionStrings); List<Action> actions = parseActions(actionStrings);

View file

@ -5,55 +5,55 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
public class CooldownManager { public class CooldownManager {
private final Map<String, Map<UUID, Long>> cooldowns = new HashMap<>(); private final Map<String, Map<UUID, Long>> cooldowns = new HashMap<>();
public void setCooldown(String key, UUID playerId, int seconds) { public void setCooldown(String key, UUID playerId, int seconds) {
cooldowns.computeIfAbsent(key, k -> new HashMap<>()) cooldowns.computeIfAbsent(key, k -> new HashMap<>())
.put(playerId, System.currentTimeMillis() + (seconds * 1000L)); .put(playerId, System.currentTimeMillis() + (seconds * 1000L));
} }
public boolean hasCooldown(String key, UUID playerId) { public boolean hasCooldown(String key, UUID playerId) {
Map<UUID, Long> keyCooldowns = cooldowns.get(key); Map<UUID, Long> keyCooldowns = cooldowns.get(key);
if (keyCooldowns == null) { if (keyCooldowns == null) {
return false; return false;
} }
Long expireTime = keyCooldowns.get(playerId); Long expireTime = keyCooldowns.get(playerId);
if (expireTime == null) { if (expireTime == null) {
return false; return false;
} }
if (System.currentTimeMillis() >= expireTime) { if (System.currentTimeMillis() >= expireTime) {
keyCooldowns.remove(playerId); keyCooldowns.remove(playerId);
return false; return false;
} }
return true; return true;
} }
public int getRemainingSeconds(String key, UUID playerId) { public int getRemainingSeconds(String key, UUID playerId) {
Map<UUID, Long> keyCooldowns = cooldowns.get(key); Map<UUID, Long> keyCooldowns = cooldowns.get(key);
if (keyCooldowns == null) { if (keyCooldowns == null) {
return 0; return 0;
} }
Long expireTime = keyCooldowns.get(playerId); Long expireTime = keyCooldowns.get(playerId);
if (expireTime == null) { if (expireTime == null) {
return 0; return 0;
} }
long remaining = expireTime - System.currentTimeMillis(); long remaining = expireTime - System.currentTimeMillis();
return remaining > 0 ? (int) (remaining / 1000) : 0; return remaining > 0 ? (int) (remaining / 1000) : 0;
} }
public void removeCooldown(String key, UUID playerId) { public void removeCooldown(String key, UUID playerId) {
Map<UUID, Long> keyCooldowns = cooldowns.get(key); Map<UUID, Long> keyCooldowns = cooldowns.get(key);
if (keyCooldowns != null) { if (keyCooldowns != null) {
keyCooldowns.remove(playerId); keyCooldowns.remove(playerId);
} }
} }
public void clearAll() { public void clearAll() {
cooldowns.clear(); cooldowns.clear();
} }

View file

@ -4,6 +4,8 @@ import com.loki.lohub.LoHub;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer; import com.sk89q.worldguard.protection.regions.RegionContainer;
@ -11,105 +13,100 @@ import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
public class RegionManager { public class RegionManager {
private final LoHub plugin;
private static final String HUB_REGION_NAME = "lohub_spawn"; private static final String HUB_REGION_NAME = "lohub_spawn";
private final LoHub plugin;
public RegionManager(LoHub plugin) { public RegionManager(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
public void createHubRegion() { public void createHubRegion() {
if (!plugin.getConfig().getBoolean("worldguard.auto-create-region", true)) { if (!plugin.getConfig().getBoolean("worldguard.auto-create-region", true)) {
plugin.getLogger().info("WorldGuard region auto-creation is disabled"); plugin.getLogger().info("WorldGuard region auto-creation is disabled");
return; return;
} }
if (!isWorldGuardAvailable()) { if (!isWorldGuardAvailable()) {
plugin.getLogger().warning("WorldGuard not found! Region will not be created."); plugin.getLogger().warning("WorldGuard not found! Region will not be created.");
return; return;
} }
Location spawn = plugin.getSpawnManager().getSpawn(); Location spawn = plugin.getSpawnManager().getSpawn();
if (spawn == null || spawn.getWorld() == null) { if (spawn == null || spawn.getWorld() == null) {
plugin.getLogger().warning("Spawn not set! Use /sethub"); plugin.getLogger().warning("Spawn not set! Use /sethub");
return; return;
} }
World world = spawn.getWorld(); World world = spawn.getWorld();
int radius = plugin.getConfig().getInt("worldguard.region-radius", 100); int radius = plugin.getConfig().getInt("worldguard.region-radius", 100);
try { try {
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
com.sk89q.worldguard.protection.managers.RegionManager wgRegionManager = container.get(BukkitAdapter.adapt(world)); com.sk89q.worldguard.protection.managers.RegionManager wgRegionManager = container.get(BukkitAdapter.adapt(world));
if (wgRegionManager == null) { if (wgRegionManager == null) {
plugin.getLogger().warning("Failed to get RegionManager for world " + world.getName()); plugin.getLogger().warning("Failed to get RegionManager for world " + world.getName());
return; return;
} }
ProtectedRegion existingRegion = wgRegionManager.getRegion(HUB_REGION_NAME); ProtectedRegion existingRegion = wgRegionManager.getRegion(HUB_REGION_NAME);
if (existingRegion != null) { if (existingRegion != null) {
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' already exists"); plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' already exists");
return; return;
} }
BlockVector3 min = BlockVector3.at( BlockVector3 min = BlockVector3.at(
spawn.getBlockX() - radius, spawn.getBlockX() - radius,
world.getMinHeight(), world.getMinHeight(),
spawn.getBlockZ() - radius spawn.getBlockZ() - radius
); );
BlockVector3 max = BlockVector3.at( BlockVector3 max = BlockVector3.at(
spawn.getBlockX() + radius, spawn.getBlockX() + radius,
world.getMaxHeight(), world.getMaxHeight(),
spawn.getBlockZ() + radius spawn.getBlockZ() + radius
); );
ProtectedCuboidRegion region = new ProtectedCuboidRegion(HUB_REGION_NAME, min, max); ProtectedCuboidRegion region = new ProtectedCuboidRegion(HUB_REGION_NAME, min, max);
setRegionFlags(region);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.PVP,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.BLOCK_BREAK,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.BLOCK_PLACE,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.DAMAGE_ANIMALS,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.MOB_SPAWNING,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.LEAF_DECAY,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.ITEM_DROP,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.ITEM_PICKUP,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
wgRegionManager.addRegion(region); wgRegionManager.addRegion(region);
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' created around spawn (radius: " + radius + " blocks)"); plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' created around spawn (radius: " + radius + " blocks)");
plugin.getLogger().info("Coordinates: " + min + " -> " + max); plugin.getLogger().info("Coordinates: " + min + " -> " + max);
} catch (Exception e) { } catch (Exception e) {
plugin.getLogger().severe("Error creating WorldGuard region: " + e.getMessage()); plugin.getLogger().severe("Error creating WorldGuard region: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
} }
private void setRegionFlags(ProtectedCuboidRegion region) {
region.setFlag(Flags.PVP, StateFlag.State.DENY);
region.setFlag(Flags.BLOCK_BREAK, StateFlag.State.DENY);
region.setFlag(Flags.BLOCK_PLACE, StateFlag.State.DENY);
region.setFlag(Flags.DAMAGE_ANIMALS, StateFlag.State.DENY);
region.setFlag(Flags.MOB_SPAWNING, StateFlag.State.DENY);
region.setFlag(Flags.LEAF_DECAY, StateFlag.State.DENY);
region.setFlag(Flags.ITEM_DROP, StateFlag.State.DENY);
region.setFlag(Flags.ITEM_PICKUP, StateFlag.State.DENY);
}
public void deleteHubRegion() { public void deleteHubRegion() {
if (!isWorldGuardAvailable()) { if (!isWorldGuardAvailable()) {
return; return;
} }
Location spawn = plugin.getSpawnManager().getSpawn(); Location spawn = plugin.getSpawnManager().getSpawn();
if (spawn == null || spawn.getWorld() == null) { if (spawn == null || spawn.getWorld() == null) {
return; return;
} }
try { try {
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
com.sk89q.worldguard.protection.managers.RegionManager wgRegionManager = container.get(BukkitAdapter.adapt(spawn.getWorld())); com.sk89q.worldguard.protection.managers.RegionManager wgRegionManager = container.get(BukkitAdapter.adapt(spawn.getWorld()));
if (wgRegionManager != null) { if (wgRegionManager != null) {
wgRegionManager.removeRegion(HUB_REGION_NAME); wgRegionManager.removeRegion(HUB_REGION_NAME);
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' deleted"); plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' deleted");
@ -118,7 +115,7 @@ public class RegionManager {
plugin.getLogger().severe("Error deleting region: " + e.getMessage()); plugin.getLogger().severe("Error deleting region: " + e.getMessage());
} }
} }
private boolean isWorldGuardAvailable() { private boolean isWorldGuardAvailable() {
try { try {
Class.forName("com.sk89q.worldguard.WorldGuard"); Class.forName("com.sk89q.worldguard.WorldGuard");

View file

@ -12,18 +12,18 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
public class SpawnManager { public class SpawnManager {
private final LoHub plugin; private final LoHub plugin;
private final File spawnFile; private final File spawnFile;
private FileConfiguration spawnConfig; private FileConfiguration spawnConfig;
private Location spawnLocation; private Location spawnLocation;
public SpawnManager(LoHub plugin) { public SpawnManager(LoHub plugin) {
this.plugin = plugin; this.plugin = plugin;
this.spawnFile = new File(plugin.getDataFolder(), "spawn.yml"); this.spawnFile = new File(plugin.getDataFolder(), "spawn.yml");
loadSpawn(); loadSpawn();
} }
private void loadSpawn() { private void loadSpawn() {
if (!spawnFile.exists()) { if (!spawnFile.exists()) {
try { try {
@ -32,9 +32,9 @@ public class SpawnManager {
plugin.getLogger().severe("Failed to create spawn.yml: " + e.getMessage()); plugin.getLogger().severe("Failed to create spawn.yml: " + e.getMessage());
} }
} }
spawnConfig = YamlConfiguration.loadConfiguration(spawnFile); spawnConfig = YamlConfiguration.loadConfiguration(spawnFile);
if (spawnConfig.contains("spawn")) { if (spawnConfig.contains("spawn")) {
String worldName = spawnConfig.getString("spawn.world"); String worldName = spawnConfig.getString("spawn.world");
double x = spawnConfig.getDouble("spawn.x"); double x = spawnConfig.getDouble("spawn.x");
@ -42,7 +42,7 @@ public class SpawnManager {
double z = spawnConfig.getDouble("spawn.z"); double z = spawnConfig.getDouble("spawn.z");
float yaw = (float) spawnConfig.getDouble("spawn.yaw"); float yaw = (float) spawnConfig.getDouble("spawn.yaw");
float pitch = (float) spawnConfig.getDouble("spawn.pitch"); float pitch = (float) spawnConfig.getDouble("spawn.pitch");
World world = Bukkit.getWorld(worldName); World world = Bukkit.getWorld(worldName);
if (world != null) { if (world != null) {
spawnLocation = new Location(world, x, y, z, yaw, pitch); spawnLocation = new Location(world, x, y, z, yaw, pitch);
@ -52,35 +52,35 @@ public class SpawnManager {
} }
} }
} }
public Location getSpawn() {
return spawnLocation;
}
public void setSpawn(Location location) { public void setSpawn(Location location) {
this.spawnLocation = location; this.spawnLocation = location;
spawnConfig.set("spawn.world", location.getWorld().getName()); spawnConfig.set("spawn.world", location.getWorld().getName());
spawnConfig.set("spawn.x", location.getX()); spawnConfig.set("spawn.x", location.getX());
spawnConfig.set("spawn.y", location.getY()); spawnConfig.set("spawn.y", location.getY());
spawnConfig.set("spawn.z", location.getZ()); spawnConfig.set("spawn.z", location.getZ());
spawnConfig.set("spawn.yaw", location.getYaw()); spawnConfig.set("spawn.yaw", location.getYaw());
spawnConfig.set("spawn.pitch", location.getPitch()); spawnConfig.set("spawn.pitch", location.getPitch());
try { try {
spawnConfig.save(spawnFile); spawnConfig.save(spawnFile);
plugin.getLogger().info("Spawn set: " + location.getWorld().getName() + plugin.getLogger().info("Spawn set: " + location.getWorld().getName() +
" (" + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ() + ")"); " (" + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ() + ")");
} catch (IOException e) { } catch (IOException e) {
plugin.getLogger().severe("Failed to save spawn.yml: " + e.getMessage()); plugin.getLogger().severe("Failed to save spawn.yml: " + e.getMessage());
} }
} }
public Location getSpawn() {
return spawnLocation;
}
public void teleportToSpawn(Player player) { public void teleportToSpawn(Player player) {
if (spawnLocation == null) { if (spawnLocation == null) {
return; return;
} }
player.teleport(spawnLocation); player.teleport(spawnLocation);
} }
} }

View file

@ -9,83 +9,83 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.inventory.meta.SkullMeta;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class ItemBuilder { public class ItemBuilder {
private final ItemStack itemStack; private final ItemStack itemStack;
public ItemBuilder(Material material) { public ItemBuilder(Material material) {
this.itemStack = new ItemStack(material); this.itemStack = new ItemStack(material);
} }
public ItemBuilder(ItemStack itemStack) { public ItemBuilder(ItemStack itemStack) {
this.itemStack = itemStack.clone(); this.itemStack = itemStack.clone();
} }
public static ItemBuilder fromConfig(ConfigurationSection section) { public static ItemBuilder fromConfig(ConfigurationSection section) {
return fromConfig(section, null); return fromConfig(section, null);
} }
public static ItemBuilder fromConfig(ConfigurationSection section, Player player) { public static ItemBuilder fromConfig(ConfigurationSection section, Player player) {
String materialName = section.getString("material", "STONE").toUpperCase(); String materialName = section.getString("material", "STONE").toUpperCase();
Material material; Material material;
try { try {
material = Material.valueOf(materialName); material = Material.valueOf(materialName);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
material = Material.STONE; material = Material.STONE;
} }
ItemBuilder builder = new ItemBuilder(material); ItemBuilder builder = new ItemBuilder(material);
if (section.contains("amount")) { if (section.contains("amount")) {
builder.amount(section.getInt("amount", 1)); builder.amount(section.getInt("amount", 1));
} }
if (section.contains("display_name")) { if (section.contains("display_name")) {
String name = section.getString("display_name"); String name = section.getString("display_name");
builder.name(player != null ? PlaceholderUtil.parse(name, player) : name); builder.name(player != null ? PlaceholderUtil.parse(name, player) : name);
} }
if (section.contains("lore")) { if (section.contains("lore")) {
List<String> lore = section.getStringList("lore"); List<String> lore = section.getStringList("lore");
builder.lore(player != null ? builder.lore(player != null ?
lore.stream().map(line -> PlaceholderUtil.parse(line, player)).collect(Collectors.toList()) : lore.stream().map(line -> PlaceholderUtil.parse(line, player)).collect(Collectors.toList()) :
lore); lore);
} }
if (section.contains("glow") && section.getBoolean("glow")) { if (section.contains("glow") && section.getBoolean("glow")) {
builder.glow(); builder.glow();
} }
if (section.contains("custom_model_data")) { if (section.contains("custom_model_data")) {
builder.customModelData(section.getInt("custom_model_data")); builder.customModelData(section.getInt("custom_model_data"));
} }
if (section.contains("item_flags")) { if (section.contains("item_flags")) {
section.getStringList("item_flags").forEach(flagName -> { section.getStringList("item_flags").forEach(flagName -> {
try { try {
builder.flag(ItemFlag.valueOf(flagName.toUpperCase())); builder.flag(ItemFlag.valueOf(flagName.toUpperCase()));
} catch (IllegalArgumentException ignored) {} } catch (IllegalArgumentException ignored) {
}
}); });
} }
if (material == Material.PLAYER_HEAD && section.contains("skull_owner")) { if (material == Material.PLAYER_HEAD && section.contains("skull_owner")) {
String owner = section.getString("skull_owner"); String owner = section.getString("skull_owner");
builder.skullOwner(player != null ? owner.replace("%player%", player.getName()) : owner); builder.skullOwner(player != null ? owner.replace("%player%", player.getName()) : owner);
} }
return builder; return builder;
} }
public ItemBuilder amount(int amount) { public ItemBuilder amount(int amount) {
itemStack.setAmount(Math.max(1, amount)); itemStack.setAmount(Math.max(1, amount));
return this; return this;
} }
public ItemBuilder name(String name) { public ItemBuilder name(String name) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta != null) { if (meta != null) {
@ -94,23 +94,23 @@ public class ItemBuilder {
} }
return this; return this;
} }
public ItemBuilder lore(List<String> lore) { public ItemBuilder lore(List<String> lore) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta != null) { if (meta != null) {
List<String> coloredLore = lore.stream() List<String> coloredLore = lore.stream()
.map(TextUtil::colorize) .map(TextUtil::colorize)
.collect(Collectors.toList()); .collect(Collectors.toList());
meta.setLore(coloredLore); meta.setLore(coloredLore);
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
} }
return this; return this;
} }
public ItemBuilder lore(String... lines) { public ItemBuilder lore(String... lines) {
return lore(List.of(lines)); return lore(List.of(lines));
} }
public ItemBuilder flag(ItemFlag... flags) { public ItemBuilder flag(ItemFlag... flags) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta != null) { if (meta != null) {
@ -119,17 +119,17 @@ public class ItemBuilder {
} }
return this; return this;
} }
public ItemBuilder glow() { public ItemBuilder glow() {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta != null) { if (meta != null) {
meta.addEnchant(Enchantment.LUCK, 1, true); meta.addEnchant(Enchantment.UNBREAKING, 1, true);
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
} }
return this; return this;
} }
public ItemBuilder customModelData(int data) { public ItemBuilder customModelData(int data) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta != null) { if (meta != null) {
@ -138,7 +138,7 @@ public class ItemBuilder {
} }
return this; return this;
} }
public ItemBuilder skullOwner(String owner) { public ItemBuilder skullOwner(String owner) {
if (itemStack.getType() == Material.PLAYER_HEAD) { if (itemStack.getType() == Material.PLAYER_HEAD) {
SkullMeta meta = (SkullMeta) itemStack.getItemMeta(); SkullMeta meta = (SkullMeta) itemStack.getItemMeta();
@ -149,7 +149,7 @@ public class ItemBuilder {
} }
return this; return this;
} }
public ItemStack build() { public ItemStack build() {
return itemStack; return itemStack;
} }

View file

@ -6,49 +6,53 @@ import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class PlaceholderUtil { public class PlaceholderUtil {
private static boolean placeholderAPIEnabled = false; private static boolean placeholderAPIEnabled = false;
private PlaceholderUtil() {
// Utility class - prevent instantiation
}
public static void init() { public static void init() {
placeholderAPIEnabled = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"); placeholderAPIEnabled = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
} }
public static String parse(String text, Player player) { public static String parse(String text, Player player) {
if (text == null) { if (text == null) {
return ""; return "";
} }
text = parseInternalPlaceholders(text, player); text = parseInternalPlaceholders(text, player);
if (placeholderAPIEnabled && player != null) { if (placeholderAPIEnabled && player != null) {
text = PlaceholderAPI.setPlaceholders(player, text); text = PlaceholderAPI.setPlaceholders(player, text);
} }
return text; return text;
} }
private static String parseInternalPlaceholders(String text, Player player) { private static String parseInternalPlaceholders(String text, Player player) {
if (player != null) { if (player != null) {
text = text.replace("%player%", player.getName()); text = text.replace("%player%", player.getName());
text = text.replace("%player_displayname%", player.getDisplayName()); text = text.replace("%player_displayname%", player.getDisplayName());
if (text.contains("%location%")) { if (text.contains("%location%")) {
Location loc = player.getLocation(); Location loc = player.getLocation();
text = text.replace("%location%", text = text.replace("%location%",
loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ()); loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ());
} }
if (text.contains("%world%")) { if (text.contains("%world%")) {
text = text.replace("%world%", player.getWorld().getName()); text = text.replace("%world%", player.getWorld().getName());
} }
} }
text = text.replace("%online%", String.valueOf(Bukkit.getOnlinePlayers().size())); text = text.replace("%online%", String.valueOf(Bukkit.getOnlinePlayers().size()));
text = text.replace("%online_max%", String.valueOf(Bukkit.getMaxPlayers())); text = text.replace("%online_max%", String.valueOf(Bukkit.getMaxPlayers()));
return text; return text;
} }
public static boolean isPlaceholderAPIEnabled() { public static boolean isPlaceholderAPIEnabled() {
return placeholderAPIEnabled; return placeholderAPIEnabled;
} }

View file

@ -8,49 +8,53 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class TextUtil { public class TextUtil {
private static final Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})"); private static final Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})");
private TextUtil() {
// Utility class - prevent instantiation
}
public static String colorize(String text) { public static String colorize(String text) {
if (text == null || text.isEmpty()) { if (text == null || text.isEmpty()) {
return text; return text;
} }
text = translateHexCodes(text); text = translateHexCodes(text);
text = ChatColor.translateAlternateColorCodes('&', text); text = ChatColor.translateAlternateColorCodes('&', text);
return text; return text;
} }
public static List<String> colorize(List<String> lines) { public static List<String> colorize(List<String> lines) {
return lines.stream() return lines.stream()
.map(TextUtil::colorize) .map(TextUtil::colorize)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private static String translateHexCodes(String text) { private static String translateHexCodes(String text) {
Matcher matcher = HEX_PATTERN.matcher(text); Matcher matcher = HEX_PATTERN.matcher(text);
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
while (matcher.find()) { while (matcher.find()) {
String hexCode = matcher.group(1); String hexCode = matcher.group(1);
String replacement = ChatColor.of("#" + hexCode).toString(); String replacement = ChatColor.of("#" + hexCode).toString();
matcher.appendReplacement(buffer, replacement); matcher.appendReplacement(buffer, replacement);
} }
matcher.appendTail(buffer); matcher.appendTail(buffer);
return buffer.toString(); return buffer.toString();
} }
public static String strip(String text) { public static String strip(String text) {
return ChatColor.stripColor(text); return ChatColor.stripColor(text);
} }
public static String joinFrom(int startIndex, String[] args) { public static String joinFrom(int startIndex, String[] args) {
if (args == null || startIndex >= args.length) { if (args == null || startIndex >= args.length) {
return ""; return "";
} }
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (int i = startIndex; i < args.length; i++) { for (int i = startIndex; i < args.length; i++) {
builder.append(args[i]); builder.append(args[i]);
@ -58,15 +62,15 @@ public class TextUtil {
builder.append(" "); builder.append(" ");
} }
} }
return builder.toString(); return builder.toString();
} }
public static String listToString(List<String> list) { public static String listToString(List<String> list) {
if (list == null || list.isEmpty()) { if (list == null || list.isEmpty()) {
return ""; return "";
} }
return String.join("\n", list); return String.join("\n", list);
} }
} }

View file

@ -15,13 +15,13 @@ commands:
description: Teleport to spawn description: Teleport to spawn
usage: /hub usage: /hub
permission: lohub.hub permission: lohub.hub
aliases: [spawn, хаб, спавн] aliases: [ spawn, хаб, спавн ]
sethub: sethub:
description: Set hub spawn location description: Set hub spawn location
usage: /sethub usage: /sethub
permission: lohub.admin permission: lohub.admin
aliases: [setspawn, установитьспавн] aliases: [ setspawn, установитьспавн ]
lohub: lohub:
description: LoHub admin command description: LoHub admin command

View file

@ -1,5 +1,6 @@
plugins { plugins {
java java
checkstyle
} }
repositories { repositories {
@ -12,7 +13,7 @@ dependencies {
compileOnly("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") compileOnly("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
implementation("com.google.code.gson:gson:2.10.1") implementation("com.google.code.gson:gson:2.10.1")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0") testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0")
@ -23,3 +24,17 @@ tasks.jar {
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
duplicatesStrategy = DuplicatesStrategy.EXCLUDE duplicatesStrategy = DuplicatesStrategy.EXCLUDE
} }
checkstyle {
toolVersion = "10.12.5"
configFile = file("${rootProject.rootDir}/config/checkstyle/checkstyle.xml")
isIgnoreFailures = false
maxWarnings = 0
}
tasks.withType<Checkstyle> {
reports {
xml.required.set(false)
html.required.set(true)
}
}

View file

@ -13,52 +13,52 @@ import org.slf4j.Logger;
import java.nio.file.Path; import java.nio.file.Path;
@Plugin( @Plugin(
id = "lovelocity", id = "lovelocity",
name = "LoVelocity", name = "LoVelocity",
version = "1.5.5", version = "1.5.5",
description = "Velocity integration for LoNetwork", description = "Velocity integration for LoNetwork",
authors = {"loki"} authors = {"loki"}
) )
public class LoVelocity { public class LoVelocity {
private final ProxyServer server; private final ProxyServer server;
private final Logger logger; private final Logger logger;
private final Path dataDirectory; private final Path dataDirectory;
@Inject @Inject
public LoVelocity(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) { public LoVelocity(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
this.server = server; this.server = server;
this.logger = logger; this.logger = logger;
this.dataDirectory = dataDirectory; this.dataDirectory = dataDirectory;
} }
@Subscribe @Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) { public void onProxyInitialization(ProxyInitializeEvent event) {
logger.info("LoVelocity loaded!"); logger.info("LoVelocity loaded!");
logger.info("Version: 1.5.5"); logger.info("Version: 1.5.5");
registerCommands(); registerCommands();
} }
private void registerCommands() { private void registerCommands() {
CommandMeta hubMeta = server.getCommandManager().metaBuilder("hub") CommandMeta hubMeta = server.getCommandManager().metaBuilder("hub")
.aliases("lobby") .aliases("lobby")
.plugin(this) .plugin(this)
.build(); .build();
server.getCommandManager().register(hubMeta, new HubCommand(this)); server.getCommandManager().register(hubMeta, new HubCommand(this));
logger.info("Commands registered: /hub, /lobby"); logger.info("Commands registered: /hub, /lobby");
} }
public ProxyServer getServer() { public ProxyServer getServer() {
return server; return server;
} }
public Logger getLogger() { public Logger getLogger() {
return logger; return logger;
} }
public Path getDataDirectory() { public Path getDataDirectory() {
return dataDirectory; return dataDirectory;
} }

View file

@ -12,66 +12,66 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class HubCommand implements SimpleCommand { public class HubCommand implements SimpleCommand {
private final LoVelocity plugin; private final LoVelocity plugin;
private final List<String> hubServers = List.of("hub", "lobby"); private final List<String> hubServers = List.of("hub", "lobby");
public HubCommand(LoVelocity plugin) { public HubCommand(LoVelocity plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@Override @Override
public void execute(Invocation invocation) { public void execute(Invocation invocation) {
if (!(invocation.source() instanceof Player player)) { if (!(invocation.source() instanceof Player player)) {
invocation.source().sendMessage(Component.text("This command is only for players!", NamedTextColor.RED)); invocation.source().sendMessage(Component.text("This command is only for players!", NamedTextColor.RED));
return; return;
} }
Optional<RegisteredServer> currentServer = player.getCurrentServer().map(s -> s.getServer()); Optional<RegisteredServer> currentServer = player.getCurrentServer().map(s -> s.getServer());
if (currentServer.isEmpty()) { if (currentServer.isEmpty()) {
player.sendMessage(Component.text("Failed to determine current server!", NamedTextColor.RED)); player.sendMessage(Component.text("Failed to determine current server!", NamedTextColor.RED));
return; return;
} }
String currentServerName = currentServer.get().getServerInfo().getName().toLowerCase(); String currentServerName = currentServer.get().getServerInfo().getName().toLowerCase();
if (isHubServer(currentServerName)) { if (isHubServer(currentServerName)) {
player.sendMessage(Component.text("You are already on the hub!", NamedTextColor.YELLOW)); player.sendMessage(Component.text("You are already on the hub!", NamedTextColor.YELLOW));
return; return;
} }
Optional<RegisteredServer> hubServer = findHubServer(); Optional<RegisteredServer> hubServer = findHubServer();
if (hubServer.isEmpty()) { if (hubServer.isEmpty()) {
player.sendMessage(Component.text("Hub server not found!", NamedTextColor.RED)); player.sendMessage(Component.text("Hub server not found!", NamedTextColor.RED));
plugin.getLogger().warn("Hub server not found! Available servers: " + plugin.getLogger().warn("Hub server not found! Available servers: " +
plugin.getServer().getAllServers().stream() plugin.getServer().getAllServers().stream()
.map(s -> s.getServerInfo().getName()) .map(s -> s.getServerInfo().getName())
.toList()); .toList());
return; return;
} }
player.sendMessage(Component.text("Teleporting to hub...", NamedTextColor.GREEN)); player.sendMessage(Component.text("Teleporting to hub...", NamedTextColor.GREEN));
player.createConnectionRequest(hubServer.get()).fireAndForget(); player.createConnectionRequest(hubServer.get()).fireAndForget();
} }
private boolean isHubServer(String serverName) { private boolean isHubServer(String serverName) {
return hubServers.stream().anyMatch(hub -> serverName.contains(hub)); return hubServers.stream().anyMatch(hub -> serverName.contains(hub));
} }
private Optional<RegisteredServer> findHubServer() { private Optional<RegisteredServer> findHubServer() {
return plugin.getServer().getAllServers().stream() return plugin.getServer().getAllServers().stream()
.filter(server -> isHubServer(server.getServerInfo().getName().toLowerCase())) .filter(server -> isHubServer(server.getServerInfo().getName().toLowerCase()))
.findFirst(); .findFirst();
} }
@Override @Override
public CompletableFuture<List<String>> suggestAsync(Invocation invocation) { public CompletableFuture<List<String>> suggestAsync(Invocation invocation) {
return CompletableFuture.completedFuture(List.of()); return CompletableFuture.completedFuture(List.of());
} }
@Override @Override
public boolean hasPermission(Invocation invocation) { public boolean hasPermission(Invocation invocation) {
return invocation.source().hasPermission("lovelocity.hub"); return invocation.source().hasPermission("lovelocity.hub");

View file

@ -31,71 +31,76 @@ public final class LoChat extends JavaPlugin {
private AutoMessageManager autoMessageManager; private AutoMessageManager autoMessageManager;
private CustomCommandManager customCommandManager; private CustomCommandManager customCommandManager;
// Геттеры
public static LoChat getInstance() {
return instance;
}
@Override @Override
public void onEnable() { public void onEnable() {
instance = this; instance = this;
getLogger().info("Загрузка LoChat v" + getPluginMeta().getVersion() + " для Paper/Folia " + Bukkit.getMinecraftVersion() + "..."); getLogger().info("Загрузка LoChat v" + getPluginMeta().getVersion() + " для Paper/Folia " + Bukkit.getMinecraftVersion() + "...");
// Конфиги // Конфиги
configManager = new ConfigManager(this); configManager = new ConfigManager(this);
messageConfig = new MessageConfig(this); messageConfig = new MessageConfig(this);
// Service Registry (SOLID DI) - с зависимостями // Service Registry (SOLID DI) - с зависимостями
serviceRegistry = new ServiceRegistry(this, configManager, messageConfig); serviceRegistry = ServiceRegistry.createWithDeps(this, configManager, messageConfig);
getLogger().info("ServiceRegistry инициализирован (SOLID DI)"); getLogger().info("ServiceRegistry инициализирован (SOLID DI)");
// Менеджеры // Менеджеры
customCommandManager = new CustomCommandManager(this); customCommandManager = CustomCommandManager.create(this);
autoMessageManager = new AutoMessageManager(this); autoMessageManager = new AutoMessageManager(this);
// Интеграции // Интеграции
initIntegrations(); initIntegrations();
// Команды и слушатели // Команды и слушатели
registerCommands(); registerCommands();
registerListeners(); registerListeners();
// Автосообщения // Автосообщения
autoMessageManager.start(); autoMessageManager.start();
getLogger().info("LoChat успешно запущен!"); getLogger().info("LoChat успешно запущен!");
} }
@Override @Override
public void onDisable() { public void onDisable() {
if (autoMessageManager != null) autoMessageManager.stop(); if (autoMessageManager != null) autoMessageManager.stop();
// Сохранение данных через сервисы // Сохранение данных через сервисы
IgnoreService ignoreService = serviceRegistry.get(IgnoreService.class); IgnoreService ignoreService = serviceRegistry.get(IgnoreService.class);
if (ignoreService != null) ignoreService.save(); if (ignoreService != null) ignoreService.save();
MuteService muteService = serviceRegistry.get(MuteService.class); MuteService muteService = serviceRegistry.get(MuteService.class);
if (muteService != null) muteService.save(); if (muteService != null) muteService.save();
NickService nickService = serviceRegistry.get(NickService.class); NickService nickService = serviceRegistry.get(NickService.class);
if (nickService != null) nickService.save(); if (nickService != null) nickService.save();
if (gradientModule != null) gradientModule.shutdown(); if (gradientModule != null) gradientModule.shutdown();
getLogger().info("LoChat отключен!"); getLogger().info("LoChat отключен!");
} }
private void initIntegrations() { private void initIntegrations() {
// Gradient модуль // Gradient модуль
gradientModule = new GradientModule(this); gradientModule = new GradientModule(this);
if (gradientModule.init()) { if (gradientModule.init()) {
getLogger().info("Gradient модуль (LoPreff) загружен!"); getLogger().info("Gradient модуль (LoPreff) загружен!");
} }
// LibertyBans // LibertyBans
new LibertyBansHook(this); new LibertyBansHook(this);
// PlaceholderAPI // PlaceholderAPI
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
new PlaceholderAPIHook(this).register(); new PlaceholderAPIHook(this).register();
getLogger().info("PlaceholderAPI подключен!"); getLogger().info("PlaceholderAPI подключен!");
} }
} }
private void registerCommands() { private void registerCommands() {
getCommand("g").setExecutor(new GlobalChatCommand(this)); getCommand("g").setExecutor(new GlobalChatCommand(this));
getCommand("l").setExecutor(new LocalChatCommand(this)); getCommand("l").setExecutor(new LocalChatCommand(this));
@ -106,44 +111,44 @@ public final class LoChat extends JavaPlugin {
getCommand("announce").setExecutor(new AnnounceCommand(this)); getCommand("announce").setExecutor(new AnnounceCommand(this));
getCommand("chatspy").setExecutor(new ChatSpyCommand(this)); getCommand("chatspy").setExecutor(new ChatSpyCommand(this));
getCommand("clearchat").setExecutor(new ClearChatCommand(this)); getCommand("clearchat").setExecutor(new ClearChatCommand(this));
NickCommand nickCmd = new NickCommand(this); NickCommand nickCmd = new NickCommand(this);
getCommand("nick").setExecutor(nickCmd); getCommand("nick").setExecutor(nickCmd);
getCommand("nick").setTabCompleter(nickCmd); getCommand("nick").setTabCompleter(nickCmd);
LoChatCommand loChatCmd = new LoChatCommand(this); LoChatCommand loChatCmd = new LoChatCommand(this);
getCommand("lochat").setExecutor(loChatCmd); getCommand("lochat").setExecutor(loChatCmd);
getCommand("lochat").setTabCompleter(loChatCmd); getCommand("lochat").setTabCompleter(loChatCmd);
MuteCommand muteCmd = new MuteCommand(this); MuteCommand muteCmd = new MuteCommand(this);
getCommand("lmute").setExecutor(muteCmd); getCommand("lmute").setExecutor(muteCmd);
getCommand("lmute").setTabCompleter(muteCmd); getCommand("lmute").setTabCompleter(muteCmd);
UnmuteCommand unmuteCmd = new UnmuteCommand(this); UnmuteCommand unmuteCmd = new UnmuteCommand(this);
getCommand("lunmute").setExecutor(unmuteCmd); getCommand("lunmute").setExecutor(unmuteCmd);
getCommand("lunmute").setTabCompleter(unmuteCmd); getCommand("lunmute").setTabCompleter(unmuteCmd);
getCommand("lmutelist").setExecutor(new MuteListCommand(this)); getCommand("lmutelist").setExecutor(new MuteListCommand(this));
MuteHistoryCommand historyCmd = new MuteHistoryCommand(this); MuteHistoryCommand historyCmd = new MuteHistoryCommand(this);
getCommand("lmutehistory").setExecutor(historyCmd); getCommand("lmutehistory").setExecutor(historyCmd);
getCommand("lmutehistory").setTabCompleter(historyCmd); getCommand("lmutehistory").setTabCompleter(historyCmd);
MuteBlameCommand blameCmd = new MuteBlameCommand(this); MuteBlameCommand blameCmd = new MuteBlameCommand(this);
getCommand("lmuteblame").setExecutor(blameCmd); getCommand("lmuteblame").setExecutor(blameCmd);
getCommand("lmuteblame").setTabCompleter(blameCmd); getCommand("lmuteblame").setTabCompleter(blameCmd);
ClearChatConfigCommand clearCfgCmd = new ClearChatConfigCommand(this); ClearChatConfigCommand clearCfgCmd = new ClearChatConfigCommand(this);
getCommand("clearchatconfig").setExecutor(clearCfgCmd); getCommand("clearchatconfig").setExecutor(clearCfgCmd);
getCommand("clearchatconfig").setTabCompleter(clearCfgCmd); getCommand("clearchatconfig").setTabCompleter(clearCfgCmd);
} }
private void registerListeners() { private void registerListeners() {
getServer().getPluginManager().registerEvents(new ChatEventListener(this, serviceRegistry), this); getServer().getPluginManager().registerEvents(new ChatEventListener(this, serviceRegistry), this);
getServer().getPluginManager().registerEvents(new PlayerEventListener(serviceRegistry), this); getServer().getPluginManager().registerEvents(new PlayerEventListener(serviceRegistry), this);
getLogger().info("Слушатели зарегистрированы (новая архитектура)"); getLogger().info("Слушатели зарегистрированы (новая архитектура)");
} }
public void reload() { public void reload() {
configManager.reload(); configManager.reload();
messageConfig.reload(); messageConfig.reload();
@ -152,11 +157,23 @@ public final class LoChat extends JavaPlugin {
if (customCommandManager != null) customCommandManager.reload(); if (customCommandManager != null) customCommandManager.reload();
} }
// Геттеры public ServiceRegistry getServiceRegistry() {
public static LoChat getInstance() { return instance; } return serviceRegistry;
public ServiceRegistry getServiceRegistry() { return serviceRegistry; } }
public ConfigManager getConfigManager() { return configManager; }
public MessageConfig getMessageConfig() { return messageConfig; } public ConfigManager getConfigManager() {
public GradientModule getGradientModule() { return gradientModule; } return configManager;
public CustomCommandManager getCustomCommandManager() { return customCommandManager; } }
public MessageConfig getMessageConfig() {
return messageConfig;
}
public GradientModule getGradientModule() {
return gradientModule;
}
public CustomCommandManager getCustomCommandManager() {
return customCommandManager;
}
} }

View file

@ -7,7 +7,10 @@ import org.bukkit.entity.Player;
*/ */
public interface ChatService { public interface ChatService {
void sendGlobalMessage(Player sender, Object message); void sendGlobalMessage(Player sender, Object message);
void sendLocalMessage(Player sender, Object message); void sendLocalMessage(Player sender, Object message);
boolean toggleGlobalChat(java.util.UUID player); boolean toggleGlobalChat(java.util.UUID player);
boolean isGlobalChatDisabled(java.util.UUID player); boolean isGlobalChatDisabled(java.util.UUID player);
} }

View file

@ -7,7 +7,10 @@ import java.util.UUID;
*/ */
public interface CooldownService { public interface CooldownService {
boolean isOnCooldown(UUID player, String type, int cooldownSeconds); boolean isOnCooldown(UUID player, String type, int cooldownSeconds);
int getRemainingCooldown(UUID player, String type, int cooldownSeconds); int getRemainingCooldown(UUID player, String type, int cooldownSeconds);
void setCooldown(UUID player, String type); void setCooldown(UUID player, String type);
void removeCooldown(UUID player); void removeCooldown(UUID player);
} }

View file

@ -8,6 +8,7 @@ import org.bukkit.entity.Player;
public interface MessageFilter { public interface MessageFilter {
/** /**
* Применить фильтр к сообщению * Применить фильтр к сообщению
*
* @return отфильтрованное сообщение или null если заблокировано * @return отфильтрованное сообщение или null если заблокировано
*/ */
Object apply(Player player, Object message, String plainMessage); Object apply(Player player, Object message, String plainMessage);

View file

@ -7,9 +7,14 @@ import java.util.UUID;
*/ */
public interface MuteService { public interface MuteService {
void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy); void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy);
boolean unmute(UUID uuid, String unmutedBy); boolean unmute(UUID uuid, String unmutedBy);
boolean isMuted(UUID uuid); boolean isMuted(UUID uuid);
long getRemainingTime(UUID uuid); long getRemainingTime(UUID uuid);
String formatTime(long millis); String formatTime(long millis);
long parseTime(String timeStr); long parseTime(String timeStr);
} }

View file

@ -9,6 +9,7 @@ import org.bukkit.entity.Player;
public interface MessageFilter { public interface MessageFilter {
/** /**
* Применить фильтр к сообщению * Применить фильтр к сообщению
*
* @return true если сообщение прошло фильтр, false если заблокировано * @return true если сообщение прошло фильтр, false если заблокировано
*/ */
boolean apply(Player player, ChatMessage message); boolean apply(Player player, ChatMessage message);

View file

@ -9,7 +9,10 @@ import java.util.UUID;
*/ */
public interface ChatService { public interface ChatService {
void sendGlobalMessage(Player sender, Object message); void sendGlobalMessage(Player sender, Object message);
void sendLocalMessage(Player sender, Object message); void sendLocalMessage(Player sender, Object message);
boolean toggleGlobalChat(UUID player); boolean toggleGlobalChat(UUID player);
boolean isGlobalChatDisabled(UUID player); boolean isGlobalChatDisabled(UUID player);
} }

View file

@ -7,7 +7,10 @@ import java.util.UUID;
*/ */
public interface CooldownService { public interface CooldownService {
boolean isOnCooldown(UUID player, String type, int cooldownSeconds); boolean isOnCooldown(UUID player, String type, int cooldownSeconds);
int getRemainingCooldown(UUID player, String type, int cooldownSeconds); int getRemainingCooldown(UUID player, String type, int cooldownSeconds);
void setCooldown(UUID player, String type); void setCooldown(UUID player, String type);
void removeCooldown(UUID player); void removeCooldown(UUID player);
} }

View file

@ -11,39 +11,41 @@ public interface IgnoreService {
* Проверяет, игнорирует ли игрок другого * Проверяет, игнорирует ли игрок другого
*/ */
boolean isIgnoring(UUID player, UUID target); boolean isIgnoring(UUID player, UUID target);
/** /**
* Добавляет игрока в список игнорируемых * Добавляет игрока в список игнорируемых
*
* @return true если успешно добавлен * @return true если успешно добавлен
*/ */
boolean addIgnore(UUID player, UUID target); boolean addIgnore(UUID player, UUID target);
/** /**
* Удаляет игрока из списка игнорируемых * Удаляет игрока из списка игнорируемых
*
* @return true если успешно удалён * @return true если успешно удалён
*/ */
boolean removeIgnore(UUID player, UUID target); boolean removeIgnore(UUID player, UUID target);
/** /**
* Получает список всех игнорируемых игроков * Получает список всех игнорируемых игроков
*/ */
Set<UUID> getIgnoredPlayers(UUID player); Set<UUID> getIgnoredPlayers(UUID player);
/** /**
* Получает количество игнорируемых игроков * Получает количество игнорируемых игроков
*/ */
int getIgnoredCount(UUID player); int getIgnoredCount(UUID player);
/** /**
* Очищает список игнорируемых для игрока * Очищает список игнорируемых для игрока
*/ */
void clearIgnores(UUID player); void clearIgnores(UUID player);
/** /**
* Сохраняет данные на диск * Сохраняет данные на диск
*/ */
void save(); void save();
/** /**
* Загружает данные с диска * Загружает данные с диска
*/ */

View file

@ -10,26 +10,27 @@ import java.util.Set;
public interface MentionService { public interface MentionService {
/** /**
* Обрабатывает упоминания в сообщении * Обрабатывает упоминания в сообщении
*
* @return сообщение с подсвеченными никами * @return сообщение с подсвеченными никами
*/ */
String processMentions(String message, Set<Player> mentionedPlayers); String processMentions(String message, Set<Player> mentionedPlayers);
/** /**
* Создаёт персонализированное сообщение для игрока * Создаёт персонализированное сообщение для игрока
* Если его ник упомянут — выделяет его особым образом * Если его ник упомянут — выделяет его особым образом
*/ */
String getPersonalizedMessage(String message, Player viewer); String getPersonalizedMessage(String message, Player viewer);
/** /**
* Проверяет, упомянут ли игрок в сообщении (по нику без @) * Проверяет, упомянут ли игрок в сообщении (по нику без @)
*/ */
boolean isPlayerMentioned(String message, Player player); boolean isPlayerMentioned(String message, Player player);
/** /**
* Уведомляет упомянутых игроков звуком * Уведомляет упомянутых игроков звуком
*/ */
void notifyMentioned(Set<Player> players); void notifyMentioned(Set<Player> players);
/** /**
* Уведомляет игрока если его ник упомянут (без @) * Уведомляет игрока если его ник упомянут (без @)
*/ */

View file

@ -8,6 +8,7 @@ import org.bukkit.entity.Player;
public interface MessageService { public interface MessageService {
/** /**
* Обработать входящее сообщение чата * Обработать входящее сообщение чата
*
* @return true если сообщение обработано успешно * @return true если сообщение обработано успешно
*/ */
boolean processMessage(Player player, String message); boolean processMessage(Player player, String message);

View file

@ -13,30 +13,38 @@ import java.util.UUID;
public interface MuteService { public interface MuteService {
// Основные операции // Основные операции
void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy); void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy);
boolean unmute(UUID uuid, String unmutedBy); boolean unmute(UUID uuid, String unmutedBy);
boolean isMuted(UUID uuid); boolean isMuted(UUID uuid);
MuteData getMuteData(UUID uuid); MuteData getMuteData(UUID uuid);
long getRemainingTime(UUID uuid); long getRemainingTime(UUID uuid);
// Утилиты времени // Утилиты времени
String formatTime(long millis); String formatTime(long millis);
long parseTime(String timeStr); long parseTime(String timeStr);
// Права доступа // Права доступа
long getMaxDuration(Player player); long getMaxDuration(Player player);
boolean canMuteForDuration(Player player, long duration); boolean canMuteForDuration(Player player, long duration);
// История // История
List<MuteData.MuteHistoryEntry> getPlayerHistory(UUID uuid); List<MuteData.MuteHistoryEntry> getPlayerHistory(UUID uuid);
List<MuteData.MuteHistoryEntry> getMutesByOperator(String operatorName); List<MuteData.MuteHistoryEntry> getMutesByOperator(String operatorName);
UUID getUUIDByName(String name); UUID getUUIDByName(String name);
// Список активных мутов // Список активных мутов
Map<UUID, MuteData> getActiveMutes(); Map<UUID, MuteData> getActiveMutes();
// Форматирование сообщений // Форматирование сообщений
String formatMessage(String message, String player, String operator, String duration, String reason); String formatMessage(String message, String player, String operator, String duration, String reason);
// Сохранение // Сохранение
void save(); void save();
} }

View file

@ -9,48 +9,54 @@ import java.util.UUID;
* Сервис для управления кастомными никами * Сервис для управления кастомными никами
*/ */
public interface NickService { public interface NickService {
/** /**
* Устанавливает кастомный ник игроку * Устанавливает кастомный ник игроку
* @param player UUID игрока *
* @param player UUID игрока
* @param nickname Новый ник (с поддержкой цветов и русских символов) * @param nickname Новый ник (с поддержкой цветов и русских символов)
* @return true если успешно, false если ник занят или невалиден * @return true если успешно, false если ник занят или невалиден
*/ */
boolean setNickname(UUID player, String nickname); boolean setNickname(UUID player, String nickname);
/** /**
* Сбрасывает кастомный ник игрока * Сбрасывает кастомный ник игрока
*
* @param player UUID игрока * @param player UUID игрока
*/ */
void resetNickname(UUID player); void resetNickname(UUID player);
/** /**
* Получает кастомный ник игрока * Получает кастомный ник игрока
*
* @param player UUID игрока * @param player UUID игрока
* @return Optional с ником или empty если нет кастомного ника * @return Optional с ником или empty если нет кастомного ника
*/ */
Optional<String> getNickname(UUID player); Optional<String> getNickname(UUID player);
/** /**
* Проверяет занят ли ник * Проверяет занят ли ник
*
* @param nickname Ник для проверки * @param nickname Ник для проверки
* @return true если ник уже используется * @return true если ник уже используется
*/ */
boolean isNicknameTaken(String nickname); boolean isNicknameTaken(String nickname);
/** /**
* Валидирует ник (длина, символы) * Валидирует ник (длина, символы)
*
* @param nickname Ник для проверки * @param nickname Ник для проверки
* @return true если ник валиден * @return true если ник валиден
*/ */
boolean isValidNickname(String nickname); boolean isValidNickname(String nickname);
/** /**
* Обновляет displayName и tabName игрока * Обновляет displayName и tabName игрока
*
* @param player Игрок * @param player Игрок
*/ */
void updatePlayerDisplay(Player player); void updatePlayerDisplay(Player player);
/** /**
* Сохраняет данные * Сохраняет данные
*/ */

View file

@ -11,17 +11,17 @@ public interface PMService {
* Устанавливает последнего собеседника для игрока * Устанавливает последнего собеседника для игрока
*/ */
void setLastConversation(UUID player, UUID target); void setLastConversation(UUID player, UUID target);
/** /**
* Получает последнего собеседника игрока * Получает последнего собеседника игрока
*/ */
Optional<UUID> getLastConversation(UUID player); Optional<UUID> getLastConversation(UUID player);
/** /**
* Удаляет информацию о последнем разговоре * Удаляет информацию о последнем разговоре
*/ */
void removeConversation(UUID player); void removeConversation(UUID player);
/** /**
* Проверяет, есть ли у игрока активный разговор * Проверяет, есть ли у игрока активный разговор
*/ */

View file

@ -7,5 +7,6 @@ import java.util.UUID;
*/ */
public interface PlayerDataService { public interface PlayerDataService {
void clearPlayerData(UUID player); void clearPlayerData(UUID player);
void saveAll(); void saveAll();
} }

View file

@ -9,25 +9,26 @@ import org.bukkit.entity.Player;
public interface SpyService { public interface SpyService {
/** /**
* Переключает режим шпиона для игрока * Переключает режим шпиона для игрока
*
* @return true если шпион включен, false если выключен * @return true если шпион включен, false если выключен
*/ */
boolean toggleSpy(java.util.UUID player); boolean toggleSpy(java.util.UUID player);
/** /**
* Проверяет, находится ли игрок в режиме шпиона * Проверяет, находится ли игрок в режиме шпиона
*/ */
boolean isSpying(java.util.UUID player); boolean isSpying(java.util.UUID player);
/** /**
* Отправляет сообщение всем шпионам (для обычного чата) * Отправляет сообщение всем шпионам (для обычного чата)
*/ */
void sendToSpies(Player sender, Component message, boolean isGlobal); void sendToSpies(Player sender, Component message, boolean isGlobal);
/** /**
* Отправляет информацию о личном сообщении шпионам * Отправляет информацию о личном сообщении шпионам
*/ */
void broadcastPM(Player sender, Player receiver, String message); void broadcastPM(Player sender, Player receiver, String message);
/** /**
* Удаляет игрока из списка шпионов * Удаляет игрока из списка шпионов
*/ */

View file

@ -42,20 +42,20 @@ public class AnnounceCommand implements CommandExecutor {
// Отправка в чат // Отправка в чат
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
player.sendMessage(formatted); player.sendMessage(formatted);
// ActionBar (если включен) // ActionBar (если включен)
if (plugin.getConfigManager().isAnnouncementActionBarEnabled()) { if (plugin.getConfigManager().isAnnouncementActionBarEnabled()) {
player.sendActionBar(formatted); player.sendActionBar(formatted);
} }
// Title (если включен) // Title (если включен)
if (plugin.getConfigManager().isAnnouncementTitleEnabled()) { if (plugin.getConfigManager().isAnnouncementTitleEnabled()) {
Title title = Title.title( Title title = Title.title(
ChatFormatter.parse(plugin.getConfigManager().getAnnouncementTitleHeader()), ChatFormatter.parse(plugin.getConfigManager().getAnnouncementTitleHeader()),
ChatFormatter.parse(message), ChatFormatter.parse(message),
Title.Times.times( Title.Times.times(
Duration.ofMillis(500), Duration.ofMillis(500),
Duration.ofSeconds(plugin.getConfigManager().getAnnouncementTitleDuration()), Duration.ofSeconds(plugin.getConfigManager().getAnnouncementTitleDuration()),
Duration.ofMillis(500) Duration.ofMillis(500)
) )
); );

View file

@ -24,7 +24,7 @@ public class ClearChatCommand implements CommandExecutor {
for (int i = 0; i < com.loki.lochat.utils.Constants.CLEAR_CHAT_LINES; i++) { for (int i = 0; i < com.loki.lochat.utils.Constants.CLEAR_CHAT_LINES; i++) {
player.sendMessage(""); player.sendMessage("");
} }
// Уведомление (если включено) // Уведомление (если включено)
if (plugin.getConfigManager().isClearChatMessageEnabled()) { if (plugin.getConfigManager().isClearChatMessageEnabled()) {
String message = plugin.getConfigManager().getClearChatMessage(); String message = plugin.getConfigManager().getClearChatMessage();

View file

@ -56,7 +56,7 @@ public class ClearChatConfigCommand implements CommandExecutor, TabCompleter {
sender.sendMessage(ChatFormatter.parse("&cУкажите текст сообщения!")); sender.sendMessage(ChatFormatter.parse("&cУкажите текст сообщения!"));
return true; return true;
} }
String message = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); String message = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
plugin.getConfigManager().setClearChatMessage(message); plugin.getConfigManager().setClearChatMessage(message);
sender.sendMessage(ChatFormatter.parse("&aСообщение установлено: &f" + message)); sender.sendMessage(ChatFormatter.parse("&aСообщение установлено: &f" + message));
@ -64,7 +64,7 @@ public class ClearChatConfigCommand implements CommandExecutor, TabCompleter {
case "status" -> { case "status" -> {
boolean enabled = plugin.getConfigManager().isClearChatMessageEnabled(); boolean enabled = plugin.getConfigManager().isClearChatMessageEnabled();
String message = plugin.getConfigManager().getClearChatMessage(); String message = plugin.getConfigManager().getClearChatMessage();
sender.sendMessage(ChatFormatter.parse("&6Статус сообщения очистки чата:")); sender.sendMessage(ChatFormatter.parse("&6Статус сообщения очистки чата:"));
sender.sendMessage(ChatFormatter.parse("&eВключено: " + (enabled ? "&aДа" : "&cНет"))); sender.sendMessage(ChatFormatter.parse("&eВключено: " + (enabled ? "&aДа" : "&cНет")));
sender.sendMessage(ChatFormatter.parse("&eСообщение: &f" + message)); sender.sendMessage(ChatFormatter.parse("&eСообщение: &f" + message));

View file

@ -9,17 +9,13 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class CustomCommand extends Command { public final class CustomCommand extends Command {
private final CustomCommandManager manager; private final CustomCommandManager manager;
public CustomCommand(String name, CustomCommandManager manager) { public CustomCommand(String name, CustomCommandManager manager) {
super(name); super(name);
this.manager = manager; this.manager = manager;
init(name);
}
private void init(String name) {
this.setDescription("Кастомная команда LoChat"); this.setDescription("Кастомная команда LoChat");
this.setUsage("/" + name); this.setUsage("/" + name);
} }

View file

@ -18,9 +18,9 @@ import org.jetbrains.annotations.NotNull;
*/ */
public class GlobalChatCommand implements CommandExecutor { public class GlobalChatCommand implements CommandExecutor {
private static final MiniMessage MM = MiniMessage.miniMessage();
private final LoChat plugin; private final LoChat plugin;
private final ChatService chatService; private final ChatService chatService;
private static final MiniMessage MM = MiniMessage.miniMessage();
public GlobalChatCommand(LoChat plugin) { public GlobalChatCommand(LoChat plugin) {
this.plugin = plugin; this.plugin = plugin;
@ -53,10 +53,10 @@ public class GlobalChatCommand implements CommandExecutor {
} }
String message = String.join(" ", args); String message = String.join(" ", args);
// Конвертируем String в Component для новой сигнатуры ChatService // Конвертируем String в Component для новой сигнатуры ChatService
Component messageComponent = MM.deserialize(message); Component messageComponent = MM.deserialize(message);
chatService.sendGlobalMessage(player, messageComponent); chatService.sendGlobalMessage(player, messageComponent);
return true; return true;
} }

View file

@ -14,8 +14,8 @@ import java.util.List;
public class LoChatCommand implements CommandExecutor, TabCompleter { public class LoChatCommand implements CommandExecutor, TabCompleter {
private final LoChat plugin;
private static final MiniMessage MM = MiniMessage.miniMessage(); private static final MiniMessage MM = MiniMessage.miniMessage();
private final LoChat plugin;
public LoChatCommand(LoChat plugin) { public LoChatCommand(LoChat plugin) {
this.plugin = plugin; this.plugin = plugin;
@ -51,14 +51,15 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
var commands = plugin.getCustomCommandManager().getCommands(); var commands = plugin.getCustomCommandManager().getCommands();
sender.sendMessage(MM.deserialize("&#FFD700Кастомные команды (" + commands.size() + "):")); sender.sendMessage(MM.deserialize("&#FFD700Кастомные команды (" + commands.size() + "):"));
for (var cmd : commands.values()) { for (var cmd : commands.values()) {
sender.sendMessage(MM.deserialize("&e/" + cmd.name + " &#808080(" + cmd.type + ")")); sender.sendMessage(MM.deserialize("&e/" + cmd.name() + " &#808080(" + cmd.type() + ")"));
if (!cmd.aliases.isEmpty()) { if (!cmd.aliases().isEmpty()) {
sender.sendMessage(MM.deserialize("&#808080 Алиасы: " + String.join(", ", cmd.aliases))); sender.sendMessage(MM.deserialize("&#808080 Алиасы: " + String.join(", ", cmd.aliases())));
} }
} }
} }
} }
default -> sender.sendMessage(MM.deserialize("&#FF0000Неизвестная команда. Используйте /lochat для помощи.")); default ->
sender.sendMessage(MM.deserialize("&#FF0000Неизвестная команда. Используйте /lochat для помощи."));
} }
return true; return true;
@ -66,7 +67,7 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) { @NotNull String alias, @NotNull String[] args) {
if (!sender.hasPermission("lochat.admin")) { if (!sender.hasPermission("lochat.admin")) {
return new ArrayList<>(); return new ArrayList<>();
} }
@ -74,7 +75,7 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
if (args.length == 1) { if (args.length == 1) {
List<String> completions = new ArrayList<>(); List<String> completions = new ArrayList<>();
String input = args[0].toLowerCase(); String input = args[0].toLowerCase();
for (String cmd : List.of("reload", "commands")) { for (String cmd : List.of("reload", "commands")) {
if (cmd.startsWith(input)) { if (cmd.startsWith(input)) {
completions.add(cmd); completions.add(cmd);
@ -82,11 +83,11 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
} }
return completions; return completions;
} }
if (args.length == 2 && args[0].equalsIgnoreCase("commands")) { if (args.length == 2 && args[0].equalsIgnoreCase("commands")) {
List<String> completions = new ArrayList<>(); List<String> completions = new ArrayList<>();
String input = args[1].toLowerCase(); String input = args[1].toLowerCase();
if ("reload".startsWith(input)) { if ("reload".startsWith(input)) {
completions.add("reload"); completions.add("reload");
} }

View file

@ -17,9 +17,9 @@ import org.jetbrains.annotations.NotNull;
*/ */
public class LocalChatCommand implements CommandExecutor { public class LocalChatCommand implements CommandExecutor {
private static final MiniMessage MM = MiniMessage.miniMessage();
private final LoChat plugin; private final LoChat plugin;
private final ChatService chatService; private final ChatService chatService;
private static final MiniMessage MM = MiniMessage.miniMessage();
public LocalChatCommand(LoChat plugin) { public LocalChatCommand(LoChat plugin) {
this.plugin = plugin; this.plugin = plugin;
@ -39,10 +39,10 @@ public class LocalChatCommand implements CommandExecutor {
} }
String message = String.join(" ", args); String message = String.join(" ", args);
// Конвертируем String в Component для новой сигнатуры ChatService // Конвертируем String в Component для новой сигнатуры ChatService
Component messageComponent = MM.deserialize(message); Component messageComponent = MM.deserialize(message);
chatService.sendLocalMessage(player, messageComponent); chatService.sendLocalMessage(player, messageComponent);
return true; return true;
} }

View file

@ -5,6 +5,7 @@ import com.loki.lochat.api.service.IgnoreService;
import com.loki.lochat.api.service.PMService; import com.loki.lochat.api.service.PMService;
import com.loki.lochat.api.service.SpyService; import com.loki.lochat.api.service.SpyService;
import com.loki.lochat.utils.ChatFormatter; import com.loki.lochat.utils.ChatFormatter;
import com.loki.lochat.utils.PlayerUtil;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -89,10 +90,10 @@ public class MsgCommand implements CommandExecutor {
// Звук для получателя // Звук для получателя
if (plugin.getConfigManager().isPmSoundEnabled()) { if (plugin.getConfigManager().isPmSoundEnabled()) {
try { Sound sound = PlayerUtil.parseSound(plugin.getConfigManager().getPmSoundType(), null);
Sound sound = Sound.valueOf(plugin.getConfigManager().getPmSoundType()); if (sound != null) {
target.playSound(target.getLocation(), sound, 1.0f, 1.0f); target.playSound(target.getLocation(), sound, 1.0f, 1.0f);
} catch (IllegalArgumentException ignored) {} }
} }
// Шпион // Шпион

View file

@ -101,7 +101,7 @@ public class MuteBlameCommand implements CommandExecutor, TabCompleter {
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) { @NotNull String alias, @NotNull String[] args) {
List<String> completions = new ArrayList<>(); List<String> completions = new ArrayList<>();
if (args.length == 1) { if (args.length == 1) {

View file

@ -73,7 +73,7 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
// Получаем настройки из конфига // Получаем настройки из конфига
String defaultReason = plugin.getConfigManager().getString("mute.default-reason", "Нету."); String defaultReason = plugin.getConfigManager().getString("mute.default-reason", "Нету.");
String defaultDuration = plugin.getConfigManager().getString("mute.default-duration", "7d"); String defaultDuration = plugin.getConfigManager().getString("mute.default-duration", "7d");
String reason = reasonBuilder.length() > 0 ? reasonBuilder.toString() : defaultReason; String reason = reasonBuilder.length() > 0 ? reasonBuilder.toString() : defaultReason;
// Определяем длительность // Определяем длительность
@ -136,7 +136,7 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
// Уведомляем замученного (если онлайн) // Уведомляем замученного (если онлайн)
if (target != null) { if (target != null) {
String msgKey = duration == 0 ? "mute.messages.you-muted-permanent" : "mute.messages.you-muted"; String msgKey = duration == 0 ? "mute.messages.you-muted-permanent" : "mute.messages.you-muted";
String msg = plugin.getConfigManager().getString(msgKey, String msg = plugin.getConfigManager().getString(msgKey,
duration == 0 ? "§cВы замучены навсегда! Причина: %reason%" : "§cВы замучены на %duration%! Причина: %reason%"); duration == 0 ? "§cВы замучены навсегда! Причина: %reason%" : "§cВы замучены на %duration%! Причина: %reason%");
msg = muteService.formatMessage(msg, finalTargetName, operatorName, timeDisplay, reason); msg = muteService.formatMessage(msg, finalTargetName, operatorName, timeDisplay, reason);
target.sendMessage(ChatFormatter.parse(msg)); target.sendMessage(ChatFormatter.parse(msg));
@ -147,7 +147,7 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
String silentMsg = plugin.getConfigManager().getString("mute.messages.silent-muted", String silentMsg = plugin.getConfigManager().getString("mute.messages.silent-muted",
"§8[Тихо] §c%player% §7замучен на §c%duration% §7(%operator%). Причина: %reason%"); "§8[Тихо] §c%player% §7замучен на §c%duration% §7(%operator%). Причина: %reason%");
silentMsg = muteService.formatMessage(silentMsg, finalTargetName, operatorName, timeDisplay, reason); silentMsg = muteService.formatMessage(silentMsg, finalTargetName, operatorName, timeDisplay, reason);
for (Player p : Bukkit.getOnlinePlayers()) { for (Player p : Bukkit.getOnlinePlayers()) {
if (p.hasPermission("lochat.mute.see-silent")) { if (p.hasPermission("lochat.mute.see-silent")) {
p.sendMessage(ChatFormatter.parse(silentMsg)); p.sendMessage(ChatFormatter.parse(silentMsg));
@ -170,7 +170,7 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) { @NotNull String alias, @NotNull String[] args) {
List<String> completions = new ArrayList<>(); List<String> completions = new ArrayList<>();
if (args.length == 1) { if (args.length == 1) {

View file

@ -72,7 +72,7 @@ public class MuteHistoryCommand implements CommandExecutor, TabCompleter {
// Выводим от новых к старым // Выводим от новых к старым
for (int i = history.size() - 1; i >= 0; i--) { for (int i = history.size() - 1; i >= 0; i--) {
MuteData.MuteHistoryEntry entry = history.get(i); MuteData.MuteHistoryEntry entry = history.get(i);
// Статус // Статус
String status; String status;
if (entry.unmuted) { if (entry.unmuted) {
@ -99,13 +99,13 @@ public class MuteHistoryCommand implements CommandExecutor, TabCompleter {
sender.sendMessage(" §7Длительность: §f" + durationStr); sender.sendMessage(" §7Длительность: §f" + durationStr);
sender.sendMessage(" §7Причина: §f" + (entry.reason != null ? entry.reason : "Не указана")); sender.sendMessage(" §7Причина: §f" + (entry.reason != null ? entry.reason : "Не указана"));
sender.sendMessage(" §7Выдал: §f" + entry.mutedBy); sender.sendMessage(" §7Выдал: §f" + entry.mutedBy);
if (entry.unmuted && entry.unmutedBy != null) { if (entry.unmuted && entry.unmutedBy != null) {
sender.sendMessage(" §7Размутил: §f" + entry.unmutedBy + " §7(" + dateFormat.format(new Date(entry.unmutedAt)) + ")"); sender.sendMessage(" §7Размутил: §f" + entry.unmutedBy + " §7(" + dateFormat.format(new Date(entry.unmutedAt)) + ")");
} }
index++; index++;
// Ограничиваем вывод // Ограничиваем вывод
if (index > 10) { if (index > 10) {
sender.sendMessage("§7... и ещё " + (history.size() - 10) + " записей"); sender.sendMessage("§7... и ещё " + (history.size() - 10) + " записей");
@ -118,7 +118,7 @@ public class MuteHistoryCommand implements CommandExecutor, TabCompleter {
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) { @NotNull String alias, @NotNull String[] args) {
List<String> completions = new ArrayList<>(); List<String> completions = new ArrayList<>();
if (args.length == 1) { if (args.length == 1) {

View file

@ -45,19 +45,19 @@ public class MuteListCommand implements CommandExecutor {
} }
sender.sendMessage("§6§l=== Активные муты (" + activeMutes.size() + ") ==="); sender.sendMessage("§6§l=== Активные муты (" + activeMutes.size() + ") ===");
int index = 1; int index = 1;
for (Map.Entry<UUID, MuteData> entry : activeMutes.entrySet()) { for (Map.Entry<UUID, MuteData> entry : activeMutes.entrySet()) {
UUID uuid = entry.getKey(); UUID uuid = entry.getKey();
MuteData data = entry.getValue(); MuteData data = entry.getValue();
// Получаем имя игрока // Получаем имя игрока
String playerName = data.getPlayerName(); String playerName = data.getPlayerName();
if (playerName == null) { if (playerName == null) {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
playerName = offlinePlayer.getName() != null ? offlinePlayer.getName() : uuid.toString().substring(0, 8); playerName = offlinePlayer.getName() != null ? offlinePlayer.getName() : uuid.toString().substring(0, 8);
} }
// Форматируем время // Форматируем время
String timeStr; String timeStr;
if (data.isPermanent()) { if (data.isPermanent()) {
@ -66,11 +66,11 @@ public class MuteListCommand implements CommandExecutor {
long remaining = data.getEndTime() - System.currentTimeMillis(); long remaining = data.getEndTime() - System.currentTimeMillis();
timeStr = "§e" + muteService.formatTime(remaining); timeStr = "§e" + muteService.formatTime(remaining);
} }
sender.sendMessage("§7" + index + ". §f" + playerName + " §7- " + timeStr); sender.sendMessage("§7" + index + ". §f" + playerName + " §7- " + timeStr);
sender.sendMessage(" §7Причина: §f" + (data.getReason() != null ? data.getReason() : "Не указана")); sender.sendMessage(" §7Причина: §f" + (data.getReason() != null ? data.getReason() : "Не указана"));
sender.sendMessage(" §7Выдал: §f" + data.getMutedBy() + " §7(" + dateFormat.format(new Date(data.getMutedAt())) + ")"); sender.sendMessage(" §7Выдал: §f" + data.getMutedBy() + " §7(" + dateFormat.format(new Date(data.getMutedAt())) + ")");
index++; index++;
} }

View file

@ -17,39 +17,39 @@ import java.util.List;
public class NickCommand implements CommandExecutor, TabCompleter { public class NickCommand implements CommandExecutor, TabCompleter {
private final LoChat plugin; private final LoChat plugin;
private final NickService nickService; private final NickService nickService;
public NickCommand(LoChat plugin) { public NickCommand(LoChat plugin) {
this.plugin = plugin; this.plugin = plugin;
this.nickService = plugin.getServiceRegistry().get(NickService.class); this.nickService = plugin.getServiceRegistry().get(NickService.class);
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) { if (!(sender instanceof Player player)) {
sender.sendMessage(Component.text("Эта команда только для игроков!", NamedTextColor.RED)); sender.sendMessage(Component.text("Эта команда только для игроков!", NamedTextColor.RED));
return true; return true;
} }
if (!player.hasPermission("lochat.nick")) { if (!player.hasPermission("lochat.nick")) {
player.sendMessage(Component.text("У вас нет прав на использование этой команды!", NamedTextColor.RED)); player.sendMessage(Component.text("У вас нет прав на использование этой команды!", NamedTextColor.RED));
return true; return true;
} }
if (args.length == 0) { if (args.length == 0) {
return showCurrentNick(player); return showCurrentNick(player);
} }
if (args[0].equalsIgnoreCase("reset")) { if (args[0].equalsIgnoreCase("reset")) {
return resetNick(player); return resetNick(player);
} }
String nickname = String.join(" ", args); String nickname = String.join(" ", args);
return setNick(player, nickname); return setNick(player, nickname);
} }
private boolean showCurrentNick(Player player) { private boolean showCurrentNick(Player player) {
var currentNick = nickService.getNickname(player.getUniqueId()); var currentNick = nickService.getNickname(player.getUniqueId());
if (currentNick.isPresent()) { if (currentNick.isPresent()) {
Component nickComponent = ChatFormatter.parse(currentNick.get()); Component nickComponent = ChatFormatter.parse(currentNick.get());
player.sendMessage(Component.text("Ваш текущий ник: ", NamedTextColor.GRAY) player.sendMessage(Component.text("Ваш текущий ник: ", NamedTextColor.GRAY)
@ -63,23 +63,23 @@ public class NickCommand implements CommandExecutor, TabCompleter {
.append(Component.text("/nick <ник>", NamedTextColor.YELLOW)) .append(Component.text("/nick <ник>", NamedTextColor.YELLOW))
.append(Component.text(" для установки", NamedTextColor.GRAY))); .append(Component.text(" для установки", NamedTextColor.GRAY)));
} }
return true; return true;
} }
private boolean resetNick(Player player) { private boolean resetNick(Player player) {
var currentNick = nickService.getNickname(player.getUniqueId()); var currentNick = nickService.getNickname(player.getUniqueId());
if (currentNick.isEmpty()) { if (currentNick.isEmpty()) {
player.sendMessage(Component.text("У вас нет кастомного ника!", NamedTextColor.RED)); player.sendMessage(Component.text("У вас нет кастомного ника!", NamedTextColor.RED));
return true; return true;
} }
nickService.resetNickname(player.getUniqueId()); nickService.resetNickname(player.getUniqueId());
player.sendMessage(Component.text("Ваш ник сброшен!", NamedTextColor.GREEN)); player.sendMessage(Component.text("Ваш ник сброшен!", NamedTextColor.GREEN));
return true; return true;
} }
private boolean setNick(Player player, String nickname) { private boolean setNick(Player player, String nickname) {
if (!nickService.isValidNickname(nickname)) { if (!nickService.isValidNickname(nickname)) {
player.sendMessage(Component.text("Невалидный ник!", NamedTextColor.RED)); player.sendMessage(Component.text("Невалидный ник!", NamedTextColor.RED));
@ -89,7 +89,7 @@ public class NickCommand implements CommandExecutor, TabCompleter {
player.sendMessage(Component.text("• Поддержка цветов: &#FF0000текст, <gradient:&#FF0000:&#00FF00>текст</gradient>", NamedTextColor.GRAY)); player.sendMessage(Component.text("• Поддержка цветов: &#FF0000текст, <gradient:&#FF0000:&#00FF00>текст</gradient>", NamedTextColor.GRAY));
return true; return true;
} }
if (nickService.isNicknameTaken(nickname)) { if (nickService.isNicknameTaken(nickname)) {
var currentNick = nickService.getNickname(player.getUniqueId()); var currentNick = nickService.getNickname(player.getUniqueId());
if (currentNick.isEmpty() || !currentNick.get().equals(nickname)) { if (currentNick.isEmpty() || !currentNick.get().equals(nickname)) {
@ -97,9 +97,9 @@ public class NickCommand implements CommandExecutor, TabCompleter {
return true; return true;
} }
} }
boolean success = nickService.setNickname(player.getUniqueId(), nickname); boolean success = nickService.setNickname(player.getUniqueId(), nickname);
if (success) { if (success) {
Component nickComponent = ChatFormatter.parse(nickname); Component nickComponent = ChatFormatter.parse(nickname);
player.sendMessage(Component.text("Ваш ник изменён на: ", NamedTextColor.GREEN) player.sendMessage(Component.text("Ваш ник изменён на: ", NamedTextColor.GREEN)
@ -107,33 +107,33 @@ public class NickCommand implements CommandExecutor, TabCompleter {
} else { } else {
player.sendMessage(Component.text("Не удалось установить ник!", NamedTextColor.RED)); player.sendMessage(Component.text("Не удалось установить ник!", NamedTextColor.RED));
} }
return true; return true;
} }
@Override @Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) { public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
List<String> completions = new ArrayList<>(); List<String> completions = new ArrayList<>();
if (args.length == 1) { if (args.length == 1) {
String input = args[0].toLowerCase(); String input = args[0].toLowerCase();
if ("reset".startsWith(input)) { if ("reset".startsWith(input)) {
completions.add("reset"); completions.add("reset");
} }
if (sender instanceof Player player) { if (sender instanceof Player player) {
var currentNick = nickService.getNickname(player.getUniqueId()); var currentNick = nickService.getNickname(player.getUniqueId());
if (currentNick.isPresent()) { if (currentNick.isPresent()) {
completions.add(currentNick.get()); completions.add(currentNick.get());
} }
} }
completions.add("&#FF0000Красный"); completions.add("&#FF0000Красный");
completions.add("&#00FF00Зелёный"); completions.add("&#00FF00Зелёный");
completions.add("Русский_Ник"); completions.add("Русский_Ник");
} }
return completions; return completions;
} }
} }

View file

@ -41,7 +41,7 @@ public class PlayerInfoCommand implements CommandExecutor {
sender.sendMessage(ChatFormatter.parse("§eУровень: §f" + target.getLevel())); sender.sendMessage(ChatFormatter.parse("§eУровень: §f" + target.getLevel()));
sender.sendMessage(ChatFormatter.parse("§eЗдоровье: §f" + Math.round(target.getHealth()) + "/20")); sender.sendMessage(ChatFormatter.parse("§eЗдоровье: §f" + Math.round(target.getHealth()) + "/20"));
sender.sendMessage(ChatFormatter.parse("§eМир: §f" + target.getWorld().getName())); sender.sendMessage(ChatFormatter.parse("§eМир: §f" + target.getWorld().getName()));
// Если есть градиентный модуль, показываем градиентное имя // Если есть градиентный модуль, показываем градиентное имя
if (plugin.getGradientModule() != null) { if (plugin.getGradientModule() != null) {
String gradientName = plugin.getGradientModule().getFormattedName(target); String gradientName = plugin.getGradientModule().getFormattedName(target);

View file

@ -5,6 +5,7 @@ import com.loki.lochat.api.service.IgnoreService;
import com.loki.lochat.api.service.PMService; import com.loki.lochat.api.service.PMService;
import com.loki.lochat.api.service.SpyService; import com.loki.lochat.api.service.SpyService;
import com.loki.lochat.utils.ChatFormatter; import com.loki.lochat.utils.ChatFormatter;
import com.loki.lochat.utils.PlayerUtil;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -88,10 +89,10 @@ public class ReplyCommand implements CommandExecutor {
// Звук для получателя // Звук для получателя
if (plugin.getConfigManager().isPmSoundEnabled()) { if (plugin.getConfigManager().isPmSoundEnabled()) {
try { Sound sound = PlayerUtil.parseSound(plugin.getConfigManager().getPmSoundType(), null);
Sound sound = Sound.valueOf(plugin.getConfigManager().getPmSoundType()); if (sound != null) {
target.playSound(target.getLocation(), sound, 1.0f, 1.0f); target.playSound(target.getLocation(), sound, 1.0f, 1.0f);
} catch (IllegalArgumentException ignored) {} }
} }
// Шпион // Шпион

View file

@ -107,7 +107,7 @@ public class UnmuteCommand implements CommandExecutor, TabCompleter {
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) { @NotNull String alias, @NotNull String[] args) {
List<String> completions = new ArrayList<>(); List<String> completions = new ArrayList<>();
if (args.length == 1) { if (args.length == 1) {

View file

@ -15,7 +15,7 @@ public class ConfigManager {
this.plugin = plugin; this.plugin = plugin;
plugin.saveDefaultConfig(); plugin.saveDefaultConfig();
this.config = plugin.getConfig(); this.config = plugin.getConfig();
// Проверяем версию конфига и обновляем при необходимости // Проверяем версию конфига и обновляем при необходимости
updateConfig(); updateConfig();
} }
@ -23,17 +23,17 @@ public class ConfigManager {
private void updateConfig() { private void updateConfig() {
int currentVersion = config.getInt("config-version", 1); int currentVersion = config.getInt("config-version", 1);
int requiredVersion = 2; // Текущая версия конфига int requiredVersion = 2; // Текущая версия конфига
if (currentVersion < requiredVersion) { if (currentVersion < requiredVersion) {
plugin.getLogger().info("Обновление конфига с версии " + currentVersion + " до " + requiredVersion); plugin.getLogger().info("Обновление конфига с версии " + currentVersion + " до " + requiredVersion);
// Добавляем новые настройки если их нет // Добавляем новые настройки если их нет
addMissingConfigOptions(); addMissingConfigOptions();
// Обновляем версию // Обновляем версию
config.set("config-version", requiredVersion); config.set("config-version", requiredVersion);
plugin.saveConfig(); plugin.saveConfig();
plugin.getLogger().info("Конфиг успешно обновлен!"); plugin.getLogger().info("Конфиг успешно обновлен!");
} }
} }
@ -46,12 +46,12 @@ public class ConfigManager {
config.set("announcements.show-actionbar", true); config.set("announcements.show-actionbar", true);
config.set("announcements.title-duration", 3); config.set("announcements.title-duration", 3);
} }
// Можно добавить другие недостающие настройки // Можно добавить другие недостающие настройки
if (!config.contains("chat.pm.enabled")) { if (!config.contains("chat.pm.enabled")) {
config.set("chat.pm.enabled", true); config.set("chat.pm.enabled", true);
} }
if (!config.contains("mentions.enabled")) { if (!config.contains("mentions.enabled")) {
config.set("mentions.enabled", true); config.set("mentions.enabled", true);
config.set("mentions.sound", true); config.set("mentions.sound", true);
@ -59,18 +59,18 @@ public class ConfigManager {
config.set("mentions.highlight", "&#FFFF00@{player}"); config.set("mentions.highlight", "&#FFFF00@{player}");
config.set("mentions.self-highlight", "&#FFD700{player}"); config.set("mentions.self-highlight", "&#FFD700{player}");
} }
if (!config.contains("automessages.enabled")) { if (!config.contains("automessages.enabled")) {
config.set("automessages.enabled", true); config.set("automessages.enabled", true);
config.set("automessages.interval", 300); config.set("automessages.interval", 300);
config.set("automessages.random", false); config.set("automessages.random", false);
} }
if (!config.contains("clearchat.message.enabled")) { if (!config.contains("clearchat.message.enabled")) {
config.set("clearchat.message.enabled", true); config.set("clearchat.message.enabled", true);
config.set("clearchat.message.text", "&#04CADFЧат очищен администратором {player}"); config.set("clearchat.message.text", "&#04CADFЧат очищен администратором {player}");
} }
if (!config.contains("lopreff.enabled")) { if (!config.contains("lopreff.enabled")) {
config.set("lopreff.enabled", true); config.set("lopreff.enabled", true);
config.set("lopreff.use-gradient-name", true); config.set("lopreff.use-gradient-name", true);
@ -197,21 +197,21 @@ public class ConfigManager {
public String getSelfMentionHighlight() { public String getSelfMentionHighlight() {
return ChatFormatter.convertAllColors(config.getString("mentions.self-highlight", "&#FFD700{player}")); return ChatFormatter.convertAllColors(config.getString("mentions.self-highlight", "&#FFD700{player}"));
} }
// Clear chat // Clear chat
public boolean isClearChatMessageEnabled() { public boolean isClearChatMessageEnabled() {
return config.getBoolean("clearchat.message.enabled", true); return config.getBoolean("clearchat.message.enabled", true);
} }
public void setClearChatMessageEnabled(boolean enabled) { public void setClearChatMessageEnabled(boolean enabled) {
config.set("clearchat.message.enabled", enabled); config.set("clearchat.message.enabled", enabled);
plugin.saveConfig(); plugin.saveConfig();
} }
public String getClearChatMessage() { public String getClearChatMessage() {
return config.getString("clearchat.message.text", "&#04CADFЧат очищен администратором {player}"); return config.getString("clearchat.message.text", "&#04CADFЧат очищен администратором {player}");
} }
public void setClearChatMessage(String message) { public void setClearChatMessage(String message) {
config.set("clearchat.message.text", message); config.set("clearchat.message.text", message);
plugin.saveConfig(); plugin.saveConfig();

View file

@ -8,127 +8,127 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class AdvancedMessageFilter { public class AdvancedMessageFilter {
private static final Pattern URL_PATTERN = Pattern.compile( private static final Pattern URL_PATTERN = Pattern.compile(
"(https?://)?([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?", "(https?://)?([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?",
Pattern.CASE_INSENSITIVE Pattern.CASE_INSENSITIVE
); );
private static final Pattern IP_PATTERN = Pattern.compile( private static final Pattern IP_PATTERN = Pattern.compile(
"\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b" "\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b"
); );
private static final Pattern REPEAT_PATTERN = Pattern.compile( private static final Pattern REPEAT_PATTERN = Pattern.compile(
"(.)\\1{3,}" "(.)\\1{3,}"
); );
private final FileConfiguration config; private final FileConfiguration config;
private final List<String> whitelistedDomains; private final List<String> whitelistedDomains;
private final List<String> blacklistedDomains; private final List<String> blacklistedDomains;
public AdvancedMessageFilter(FileConfiguration config) { public AdvancedMessageFilter(FileConfiguration config) {
this.config = config; this.config = config;
this.whitelistedDomains = config.getStringList("filters.url.whitelist"); this.whitelistedDomains = config.getStringList("filters.url.whitelist");
this.blacklistedDomains = config.getStringList("filters.url.blacklist"); this.blacklistedDomains = config.getStringList("filters.url.blacklist");
} }
public FilterResult filterMessage(Player player, String message) { public FilterResult filterMessage(Player player, String message) {
if (config.getBoolean("filters.url.enabled", true)) { if (config.getBoolean("filters.url.enabled", true)) {
FilterResult urlResult = filterUrls(player, message); FilterResult urlResult = filterUrls(player, message);
if (!urlResult.isAllowed()) { if (!urlResult.allowed()) {
return urlResult; return urlResult;
} }
message = urlResult.getFilteredMessage(); message = urlResult.filteredMessage();
} }
if (config.getBoolean("filters.ip.enabled", true)) { if (config.getBoolean("filters.ip.enabled", true)) {
FilterResult ipResult = filterIPs(player, message); FilterResult ipResult = filterIPs(player, message);
if (!ipResult.isAllowed()) { if (!ipResult.allowed()) {
return ipResult; return ipResult;
} }
message = ipResult.getFilteredMessage(); message = ipResult.filteredMessage();
} }
if (config.getBoolean("filters.repeat.enabled", true)) { if (config.getBoolean("filters.repeat.enabled", true)) {
message = filterRepeatingChars(message); message = filterRepeatingChars(message);
} }
return new FilterResult(true, message, null); return new FilterResult(true, message, null);
} }
private FilterResult filterUrls(Player player, String message) { private FilterResult filterUrls(Player player, String message) {
if (player.hasPermission("lochat.bypass.urlfilter")) { if (player.hasPermission("lochat.bypass.urlfilter")) {
return new FilterResult(true, message, null); return new FilterResult(true, message, null);
} }
Matcher matcher = URL_PATTERN.matcher(message); Matcher matcher = URL_PATTERN.matcher(message);
while (matcher.find()) { while (matcher.find()) {
String url = matcher.group(); String url = matcher.group();
String domain = extractDomain(url); String domain = extractDomain(url);
if (!whitelistedDomains.isEmpty()) { if (!whitelistedDomains.isEmpty()) {
boolean isWhitelisted = whitelistedDomains.stream() boolean isWhitelisted = whitelistedDomains.stream()
.anyMatch(d -> domain.toLowerCase().contains(d.toLowerCase())); .anyMatch(d -> domain.toLowerCase().contains(d.toLowerCase()));
if (!isWhitelisted) { if (!isWhitelisted) {
return new FilterResult(false, message, return new FilterResult(false, message,
config.getString("filters.url.blocked-message", "&#FF6B6BСсылки запрещены!")); config.getString("filters.url.blocked-message", "&#FF6B6BСсылки запрещены!"));
} }
} }
if (!blacklistedDomains.isEmpty()) { if (!blacklistedDomains.isEmpty()) {
boolean isBlacklisted = blacklistedDomains.stream() boolean isBlacklisted = blacklistedDomains.stream()
.anyMatch(d -> domain.toLowerCase().contains(d.toLowerCase())); .anyMatch(d -> domain.toLowerCase().contains(d.toLowerCase()));
if (isBlacklisted) { if (isBlacklisted) {
return new FilterResult(false, message, return new FilterResult(false, message,
config.getString("filters.url.blocked-message", "&#FF6B6BЭта ссылка запрещена!")); config.getString("filters.url.blocked-message", "&#FF6B6BЭта ссылка запрещена!"));
} }
} }
} }
return new FilterResult(true, message, null); return new FilterResult(true, message, null);
} }
private FilterResult filterIPs(Player player, String message) { private FilterResult filterIPs(Player player, String message) {
if (player.hasPermission("lochat.bypass.ipfilter")) { if (player.hasPermission("lochat.bypass.ipfilter")) {
return new FilterResult(true, message, null); return new FilterResult(true, message, null);
} }
Matcher matcher = IP_PATTERN.matcher(message); Matcher matcher = IP_PATTERN.matcher(message);
if (matcher.find()) { if (matcher.find()) {
String replacement = config.getString("filters.ip.replacement", "[IP скрыт]"); String replacement = config.getString("filters.ip.replacement", "[IP скрыт]");
String filtered = matcher.replaceAll(replacement); String filtered = matcher.replaceAll(replacement);
if (config.getBoolean("filters.ip.block", false)) { if (config.getBoolean("filters.ip.block", false)) {
return new FilterResult(false, message, return new FilterResult(false, message,
config.getString("filters.ip.blocked-message", "&#FF6B6BIP адреса запрещены!")); config.getString("filters.ip.blocked-message", "&#FF6B6BIP адреса запрещены!"));
} }
return new FilterResult(true, filtered, null); return new FilterResult(true, filtered, null);
} }
return new FilterResult(true, message, null); return new FilterResult(true, message, null);
} }
private String filterRepeatingChars(String message) { private String filterRepeatingChars(String message) {
int maxRepeats = config.getInt("filters.repeat.max-repeats", 3); int maxRepeats = config.getInt("filters.repeat.max-repeats", 3);
Matcher matcher = REPEAT_PATTERN.matcher(message); Matcher matcher = REPEAT_PATTERN.matcher(message);
StringBuffer result = new StringBuffer(); StringBuffer result = new StringBuffer();
while (matcher.find()) { while (matcher.find()) {
String repeated = matcher.group(1); String repeated = matcher.group(1);
String replacement = repeated.repeat(Math.min(maxRepeats, matcher.group().length())); String replacement = repeated.repeat(Math.min(maxRepeats, matcher.group().length()));
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement)); matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
} }
matcher.appendTail(result); matcher.appendTail(result);
return result.toString(); return result.toString();
} }
private String extractDomain(String url) { private String extractDomain(String url) {
url = url.replaceFirst("^https?://", ""); url = url.replaceFirst("^https?://", "");
int slashIndex = url.indexOf('/'); int slashIndex = url.indexOf('/');
@ -137,28 +137,7 @@ public class AdvancedMessageFilter {
} }
return url; return url;
} }
public static class FilterResult { public record FilterResult(boolean allowed, String filteredMessage, String blockReason) {
private final boolean allowed;
private final String filteredMessage;
private final String blockReason;
public FilterResult(boolean allowed, String filteredMessage, String blockReason) {
this.allowed = allowed;
this.filteredMessage = filteredMessage;
this.blockReason = blockReason;
}
public boolean isAllowed() {
return allowed;
}
public String getFilteredMessage() {
return filteredMessage;
}
public String getBlockReason() {
return blockReason;
}
} }
} }

View file

@ -13,30 +13,30 @@ import org.bukkit.plugin.java.JavaPlugin;
public class CooldownFilter implements MessageFilter { public class CooldownFilter implements MessageFilter {
private final CooldownService cooldownService; private final CooldownService cooldownService;
private final FileConfiguration config; private final FileConfiguration config;
public CooldownFilter(CooldownService cooldownService, JavaPlugin plugin) { public CooldownFilter(CooldownService cooldownService, JavaPlugin plugin) {
this.cooldownService = cooldownService; this.cooldownService = cooldownService;
this.config = plugin.getConfig(); this.config = plugin.getConfig();
} }
@Override @Override
public boolean apply(Player player, ChatMessage message) { public boolean apply(Player player, ChatMessage message) {
if (player.hasPermission("chat.bypass.cooldown")) { if (player.hasPermission("chat.bypass.cooldown")) {
return true; return true;
} }
String chatType = message.getChatType(); String chatType = message.getChatType();
int cooldown = config.getInt("chat." + chatType + ".cooldown", 0); int cooldown = config.getInt("chat." + chatType + ".cooldown", 0);
if (cooldown > 0) { if (cooldown > 0) {
if (cooldownService.isOnCooldown(player.getUniqueId(), chatType, cooldown)) { if (cooldownService.isOnCooldown(player.getUniqueId(), chatType, cooldown)) {
int remaining = cooldownService.getRemainingCooldown( int remaining = cooldownService.getRemainingCooldown(
player.getUniqueId(), chatType, cooldown); player.getUniqueId(), chatType, cooldown);
player.sendMessage("§cПодождите " + remaining + " сек."); player.sendMessage("§cПодождите " + remaining + " сек.");
return false; return false;
} }
} }
cooldownService.setCooldown(player.getUniqueId(), chatType); cooldownService.setCooldown(player.getUniqueId(), chatType);
return true; return true;
} }

View file

@ -10,11 +10,11 @@ import org.bukkit.entity.Player;
*/ */
public class MuteFilter implements MessageFilter { public class MuteFilter implements MessageFilter {
private final MuteService muteService; private final MuteService muteService;
public MuteFilter(MuteService muteService) { public MuteFilter(MuteService muteService) {
this.muteService = muteService; this.muteService = muteService;
} }
@Override @Override
public boolean apply(Player player, ChatMessage message) { public boolean apply(Player player, ChatMessage message) {
if (muteService.isMuted(player.getUniqueId())) { if (muteService.isMuted(player.getUniqueId())) {
@ -23,7 +23,7 @@ public class MuteFilter implements MessageFilter {
} }
return true; return true;
} }
private void sendMuteNotification(Player player) { private void sendMuteNotification(Player player) {
long remaining = muteService.getRemainingTime(player.getUniqueId()); long remaining = muteService.getRemainingTime(player.getUniqueId());
String timeStr = muteService.formatTime(remaining); String timeStr = muteService.formatTime(remaining);

View file

@ -12,25 +12,23 @@ import java.util.Map;
public class ServiceRegistry { public class ServiceRegistry {
private final Map<Class<?>, Object> services = new HashMap<>(); private final Map<Class<?>, Object> services = new HashMap<>();
private final JavaPlugin plugin; private final JavaPlugin plugin;
public ServiceRegistry(JavaPlugin plugin) { private ServiceRegistry(JavaPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
init();
} }
public ServiceRegistry(JavaPlugin plugin, ConfigManager configManager, MessageConfig messageConfig) { public static ServiceRegistry create(JavaPlugin plugin) {
this.plugin = plugin; ServiceRegistry registry = new ServiceRegistry(plugin);
initWithDeps(configManager, messageConfig); registry.registerServices();
return registry;
} }
private void init() { public static ServiceRegistry createWithDeps(JavaPlugin plugin, ConfigManager configManager, MessageConfig messageConfig) {
registerServices(); ServiceRegistry registry = new ServiceRegistry(plugin);
registry.registerServicesWithDeps(configManager, messageConfig);
return registry;
} }
private void initWithDeps(ConfigManager configManager, MessageConfig messageConfig) {
registerServicesWithDeps(configManager, messageConfig);
}
private void registerServices() { private void registerServices() {
register(ChatService.class, new ChatServiceImpl(plugin, this)); register(ChatService.class, new ChatServiceImpl(plugin, this));
register(MuteService.class, new MuteServiceImpl(plugin)); register(MuteService.class, new MuteServiceImpl(plugin));
@ -38,25 +36,25 @@ public class ServiceRegistry {
register(MessageService.class, new MessageServiceImpl(plugin, this)); register(MessageService.class, new MessageServiceImpl(plugin, this));
register(PlayerDataService.class, new PlayerDataServiceImpl(plugin)); register(PlayerDataService.class, new PlayerDataServiceImpl(plugin));
} }
private void registerServicesWithDeps(ConfigManager configManager, MessageConfig messageConfig) { private void registerServicesWithDeps(ConfigManager configManager, MessageConfig messageConfig) {
register(ChatService.class, new ChatServiceImpl(plugin, this)); register(ChatService.class, new ChatServiceImpl(plugin, this));
register(MuteService.class, new MuteServiceImpl(plugin)); register(MuteService.class, new MuteServiceImpl(plugin));
register(CooldownService.class, new CooldownServiceImpl()); register(CooldownService.class, new CooldownServiceImpl());
register(MessageService.class, new MessageServiceImpl(plugin, this)); register(MessageService.class, new MessageServiceImpl(plugin, this));
register(PlayerDataService.class, new PlayerDataServiceImpl(plugin)); register(PlayerDataService.class, new PlayerDataServiceImpl(plugin));
register(PMService.class, new PMServiceImpl()); register(PMService.class, new PMServiceImpl());
register(IgnoreService.class, new IgnoreServiceImpl(plugin)); register(IgnoreService.class, new IgnoreServiceImpl(plugin));
register(SpyService.class, new SpyServiceImpl(plugin, messageConfig)); register(SpyService.class, new SpyServiceImpl(plugin, messageConfig));
register(MentionService.class, new MentionServiceImpl(configManager)); register(MentionService.class, new MentionServiceImpl(configManager));
register(NickService.class, new NickServiceImpl(plugin)); register(NickService.class, new NickServiceImpl(plugin));
} }
public <T> void register(Class<T> serviceClass, T implementation) { public <T> void register(Class<T> serviceClass, T implementation) {
services.put(serviceClass, implementation); services.put(serviceClass, implementation);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T get(Class<T> serviceClass) { public <T> T get(Class<T> serviceClass) {
Object service = services.get(serviceClass); Object service = services.get(serviceClass);
@ -65,7 +63,7 @@ public class ServiceRegistry {
} }
return (T) service; return (T) service;
} }
public void shutdown() { public void shutdown() {
services.clear(); services.clear();
} }

View file

@ -19,61 +19,61 @@ import java.util.concurrent.ConcurrentHashMap;
public class ChatServiceImpl implements ChatService { public class ChatServiceImpl implements ChatService {
private final JavaPlugin plugin; private final JavaPlugin plugin;
private final Set<UUID> globalChatDisabled = ConcurrentHashMap.newKeySet(); private final Set<UUID> globalChatDisabled = ConcurrentHashMap.newKeySet();
public ChatServiceImpl(JavaPlugin plugin, ServiceRegistry registry) { public ChatServiceImpl(JavaPlugin plugin, ServiceRegistry registry) {
this.plugin = plugin; this.plugin = plugin;
} }
@Override @Override
public void sendGlobalMessage(Player sender, Object message) { public void sendGlobalMessage(Player sender, Object message) {
String format = plugin.getConfig().getString("chat.global.format", String format = plugin.getConfig().getString("chat.global.format",
"{prefix} {player}: {message}"); "{prefix} {player}: {message}");
String prefix = plugin.getConfig().getString("chat.global.prefix", "[G]"); String prefix = plugin.getConfig().getString("chat.global.prefix", "[G]");
Component messageComponent = (message instanceof Component) Component messageComponent = (message instanceof Component)
? (Component) message ? (Component) message
: ChatFormatter.parse(message.toString()); : ChatFormatter.parse(message.toString());
// Используем displayName игрока (с градиентом если есть) // Используем displayName игрока (с градиентом если есть)
Component playerName = sender.displayName(); Component playerName = sender.displayName();
String formatted = format.replace("{prefix}", prefix); String formatted = format.replace("{prefix}", prefix);
Component finalComponent = ChatFormatter.parse(formatted) Component finalComponent = ChatFormatter.parse(formatted)
.replaceText(builder -> builder.matchLiteral("{player}").replacement(playerName)) .replaceText(builder -> builder.matchLiteral("{player}").replacement(playerName))
.replaceText(builder -> builder.matchLiteral("{message}").replacement(messageComponent)); .replaceText(builder -> builder.matchLiteral("{message}").replacement(messageComponent));
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
if (!isGlobalChatDisabled(player.getUniqueId())) { if (!isGlobalChatDisabled(player.getUniqueId())) {
player.sendMessage(finalComponent); player.sendMessage(finalComponent);
} }
} }
} }
@Override @Override
public void sendLocalMessage(Player sender, Object message) { public void sendLocalMessage(Player sender, Object message) {
int radius = plugin.getConfig().getInt("chat.local.radius", 100); int radius = plugin.getConfig().getInt("chat.local.radius", 100);
String format = plugin.getConfig().getString("chat.local.format", String format = plugin.getConfig().getString("chat.local.format",
"{player}: {message}"); "{player}: {message}");
Component messageComponent = (message instanceof Component) Component messageComponent = (message instanceof Component)
? (Component) message ? (Component) message
: ChatFormatter.parse(message.toString()); : ChatFormatter.parse(message.toString());
// Используем displayName игрока (с градиентом если есть) // Используем displayName игрока (с градиентом если есть)
Component playerName = sender.displayName(); Component playerName = sender.displayName();
Component finalComponent = ChatFormatter.parse(format) Component finalComponent = ChatFormatter.parse(format)
.replaceText(builder -> builder.matchLiteral("{player}").replacement(playerName)) .replaceText(builder -> builder.matchLiteral("{player}").replacement(playerName))
.replaceText(builder -> builder.matchLiteral("{message}").replacement(messageComponent)); .replaceText(builder -> builder.matchLiteral("{message}").replacement(messageComponent));
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
if (DistanceUtil.isInRange(sender, player, radius)) { if (DistanceUtil.isInRange(sender, player, radius)) {
player.sendMessage(finalComponent); player.sendMessage(finalComponent);
} }
} }
} }
@Override @Override
public boolean toggleGlobalChat(UUID player) { public boolean toggleGlobalChat(UUID player) {
if (globalChatDisabled.contains(player)) { if (globalChatDisabled.contains(player)) {
@ -84,7 +84,7 @@ public class ChatServiceImpl implements ChatService {
return false; return false;
} }
} }
@Override @Override
public boolean isGlobalChatDisabled(UUID player) { public boolean isGlobalChatDisabled(UUID player) {
return globalChatDisabled.contains(player); return globalChatDisabled.contains(player);

View file

@ -12,40 +12,40 @@ import java.util.concurrent.ConcurrentHashMap;
public class CooldownServiceImpl implements CooldownService { public class CooldownServiceImpl implements CooldownService {
private final Map<UUID, Long> globalCooldowns = new ConcurrentHashMap<>(); private final Map<UUID, Long> globalCooldowns = new ConcurrentHashMap<>();
private final Map<UUID, Long> localCooldowns = new ConcurrentHashMap<>(); private final Map<UUID, Long> localCooldowns = new ConcurrentHashMap<>();
@Override @Override
public boolean isOnCooldown(UUID player, String type, int cooldownSeconds) { public boolean isOnCooldown(UUID player, String type, int cooldownSeconds) {
Map<UUID, Long> cooldowns = getCooldownMap(type); Map<UUID, Long> cooldowns = getCooldownMap(type);
Long lastTime = cooldowns.get(player); Long lastTime = cooldowns.get(player);
if (lastTime == null) return false; if (lastTime == null) return false;
long elapsed = (System.currentTimeMillis() - lastTime) / 1000; long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
return elapsed < cooldownSeconds; return elapsed < cooldownSeconds;
} }
@Override @Override
public int getRemainingCooldown(UUID player, String type, int cooldownSeconds) { public int getRemainingCooldown(UUID player, String type, int cooldownSeconds) {
Map<UUID, Long> cooldowns = getCooldownMap(type); Map<UUID, Long> cooldowns = getCooldownMap(type);
Long lastTime = cooldowns.get(player); Long lastTime = cooldowns.get(player);
if (lastTime == null) return 0; if (lastTime == null) return 0;
long elapsed = (System.currentTimeMillis() - lastTime) / 1000; long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
return Math.max(0, cooldownSeconds - (int) elapsed); return Math.max(0, cooldownSeconds - (int) elapsed);
} }
@Override @Override
public void setCooldown(UUID player, String type) { public void setCooldown(UUID player, String type) {
getCooldownMap(type).put(player, System.currentTimeMillis()); getCooldownMap(type).put(player, System.currentTimeMillis());
} }
@Override @Override
public void removeCooldown(UUID player) { public void removeCooldown(UUID player) {
globalCooldowns.remove(player); globalCooldowns.remove(player);
localCooldowns.remove(player); localCooldowns.remove(player);
} }
private Map<UUID, Long> getCooldownMap(String type) { private Map<UUID, Long> getCooldownMap(String type) {
return type.equals("global") ? globalCooldowns : localCooldowns; return type.equals("global") ? globalCooldowns : localCooldowns;
} }

View file

@ -2,6 +2,7 @@ package com.loki.lochat.core.service;
import com.loki.lochat.api.service.IgnoreService; import com.loki.lochat.api.service.IgnoreService;
import com.loki.lochat.gradient.util.FoliaUtil; import com.loki.lochat.gradient.util.FoliaUtil;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.io.File; import java.io.File;
@ -9,8 +10,6 @@ import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.configuration.file.YamlConfiguration;
/** /**
* Реализация сервиса игнорирования * Реализация сервиса игнорирования
*/ */
@ -39,13 +38,15 @@ public class IgnoreServiceImpl implements IgnoreService {
for (String ignoredStr : ignoredList) { for (String ignoredStr : ignoredList) {
try { try {
ignored.add(UUID.fromString(ignoredStr)); ignored.add(UUID.fromString(ignoredStr));
} catch (Exception ignored2) {} } catch (Exception ignored2) {
}
} }
if (!ignored.isEmpty()) { if (!ignored.isEmpty()) {
ignoreMap.put(uuid, ignored); ignoreMap.put(uuid, ignored);
} }
} catch (Exception ignored) {} } catch (Exception ignored) {
}
} }
} }

View file

@ -2,6 +2,7 @@ package com.loki.lochat.core.service;
import com.loki.lochat.api.service.MentionService; import com.loki.lochat.api.service.MentionService;
import com.loki.lochat.config.ConfigManager; import com.loki.lochat.config.ConfigManager;
import com.loki.lochat.utils.PlayerUtil;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -17,9 +18,8 @@ import java.util.regex.Pattern;
* Реализация сервиса упоминаний * Реализация сервиса упоминаний
*/ */
public class MentionServiceImpl implements MentionService { public class MentionServiceImpl implements MentionService {
private final ConfigManager configManager;
private static final Pattern MENTION_PATTERN = Pattern.compile("@(\\w+)"); private static final Pattern MENTION_PATTERN = Pattern.compile("@(\\w+)");
private final ConfigManager configManager;
// Хранит для какого игрока какие части сообщения выделить // Хранит для какого игрока какие части сообщения выделить
private final Map<Player, Set<String>> highlightedNicks = new HashMap<>(); private final Map<Player, Set<String>> highlightedNicks = new HashMap<>();
@ -46,7 +46,7 @@ public class MentionServiceImpl implements MentionService {
mentionedPlayers.add(mentioned); mentionedPlayers.add(mentioned);
String replacement = highlight.replace("{player}", mentioned.getName()); String replacement = highlight.replace("{player}", mentioned.getName());
matcher.appendReplacement(result, replacement); matcher.appendReplacement(result, replacement);
// Запоминаем что этот игрок упомянут // Запоминаем что этот игрок упомянут
highlightedNicks.computeIfAbsent(mentioned, k -> new HashSet<>()).add(mentioned.getName()); highlightedNicks.computeIfAbsent(mentioned, k -> new HashSet<>()).add(mentioned.getName());
} }
@ -64,23 +64,23 @@ public class MentionServiceImpl implements MentionService {
String viewerName = viewer.getName(); String viewerName = viewer.getName();
String result = message; String result = message;
// Проверяем упоминание через @ник // Проверяем упоминание через @ник
String highlight = configManager.getMentionHighlight(); String highlight = configManager.getMentionHighlight();
String highlightedName = highlight.replace("{player}", viewerName); String highlightedName = highlight.replace("{player}", viewerName);
// Если в сообщении есть выделенный ник этого игрока — добавляем дополнительное выделение // Если в сообщении есть выделенный ник этого игрока — добавляем дополнительное выделение
if (result.contains(highlightedName)) { if (result.contains(highlightedName)) {
// Уже выделено через processMentions, добавляем эффект // Уже выделено через processMentions, добавляем эффект
String extraHighlight = "<bold>" + highlightedName + "</bold>"; String extraHighlight = "<bold>" + highlightedName + "</bold>";
result = result.replace(highlightedName, extraHighlight); result = result.replace(highlightedName, extraHighlight);
} }
// Также проверяем просто ник в сообщении (без @) // Также проверяем просто ник в сообщении (без @)
// Регистронезависимый поиск // Регистронезависимый поиск
Pattern nickPattern = Pattern.compile("(?i)\\b" + Pattern.quote(viewerName) + "\\b"); Pattern nickPattern = Pattern.compile("(?i)\\b" + Pattern.quote(viewerName) + "\\b");
Matcher nickMatcher = nickPattern.matcher(result); Matcher nickMatcher = nickPattern.matcher(result);
if (nickMatcher.find()) { if (nickMatcher.find()) {
// Ник найден в сообщении — выделяем для этого игрока // Ник найден в сообщении — выделяем для этого игрока
String selfHighlight = configManager.getSelfMentionHighlight(); String selfHighlight = configManager.getSelfMentionHighlight();
@ -104,12 +104,7 @@ public class MentionServiceImpl implements MentionService {
} }
String soundName = configManager.getMentionSoundType(); String soundName = configManager.getMentionSoundType();
Sound sound; Sound sound = PlayerUtil.parseSound(soundName, Sound.BLOCK_NOTE_BLOCK_PLING);
try {
sound = Sound.valueOf(soundName);
} catch (IllegalArgumentException e) {
sound = Sound.BLOCK_NOTE_BLOCK_PLING;
}
for (Player player : players) { for (Player player : players) {
player.playSound(player.getLocation(), sound, 1.0f, 1.0f); player.playSound(player.getLocation(), sound, 1.0f, 1.0f);
@ -120,13 +115,13 @@ public class MentionServiceImpl implements MentionService {
public void notifyIfMentioned(String message, Player viewer, Player sender) { public void notifyIfMentioned(String message, Player viewer, Player sender) {
if (viewer.equals(sender)) return; if (viewer.equals(sender)) return;
if (!configManager.isMentionSoundEnabled()) return; if (!configManager.isMentionSoundEnabled()) return;
if (isPlayerMentioned(message, viewer)) { if (isPlayerMentioned(message, viewer)) {
String soundName = configManager.getMentionSoundType(); String soundName = configManager.getMentionSoundType();
try { Sound sound = PlayerUtil.parseSound(soundName, null);
Sound sound = Sound.valueOf(soundName); if (sound != null) {
viewer.playSound(viewer.getLocation(), sound, 1.0f, 1.0f); viewer.playSound(viewer.getLocation(), sound, 1.0f, 1.0f);
} catch (IllegalArgumentException ignored) {} }
} }
} }
} }

View file

@ -1,13 +1,14 @@
package com.loki.lochat.core.service; package com.loki.lochat.core.service;
import com.loki.lochat.api.filter.MessageFilter; import com.loki.lochat.api.filter.MessageFilter;
import com.loki.lochat.api.service.*; import com.loki.lochat.api.service.ChatService;
import com.loki.lochat.api.service.CooldownService;
import com.loki.lochat.api.service.MessageService;
import com.loki.lochat.api.service.MuteService;
import com.loki.lochat.core.filter.CooldownFilter; import com.loki.lochat.core.filter.CooldownFilter;
import com.loki.lochat.core.filter.MuteFilter; import com.loki.lochat.core.filter.MuteFilter;
import com.loki.lochat.core.registry.ServiceRegistry; import com.loki.lochat.core.registry.ServiceRegistry;
import com.loki.lochat.data.model.ChatMessage; import com.loki.lochat.data.model.ChatMessage;
import com.loki.lochat.utils.ChatFormatter;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
@ -21,29 +22,29 @@ public class MessageServiceImpl implements MessageService {
private final JavaPlugin plugin; private final JavaPlugin plugin;
private final List<MessageFilter> filters; private final List<MessageFilter> filters;
private final ChatService chatService; private final ChatService chatService;
public MessageServiceImpl(JavaPlugin plugin, ServiceRegistry registry) { public MessageServiceImpl(JavaPlugin plugin, ServiceRegistry registry) {
this.plugin = plugin; this.plugin = plugin;
this.chatService = registry.get(ChatService.class); this.chatService = registry.get(ChatService.class);
this.filters = new ArrayList<>(); this.filters = new ArrayList<>();
// Регистрируем фильтры в порядке применения // Регистрируем фильтры в порядке применения
filters.add(new MuteFilter(registry.get(MuteService.class))); filters.add(new MuteFilter(registry.get(MuteService.class)));
filters.add(new CooldownFilter(registry.get(CooldownService.class), plugin)); filters.add(new CooldownFilter(registry.get(CooldownService.class), plugin));
} }
@Override @Override
public boolean processMessage(Player player, String rawMessage) { public boolean processMessage(Player player, String rawMessage) {
// Создаем объект сообщения // Создаем объект сообщения
ChatMessage message = ChatMessage.create(player, rawMessage); ChatMessage message = ChatMessage.create(player, rawMessage);
// Применяем фильтры (мут, кулдаун) // Применяем фильтры (мут, кулдаун)
for (MessageFilter filter : filters) { for (MessageFilter filter : filters) {
if (!filter.apply(player, message)) { if (!filter.apply(player, message)) {
return false; // Сообщение заблокировано return false; // Сообщение заблокировано
} }
} }
// Возвращаем true - сообщение разрешено // Возвращаем true - сообщение разрешено
// Рендерер сам отправит его // Рендерер сам отправит его
return true; return true;

View file

@ -24,7 +24,7 @@ public class MuteServiceImpl implements MuteService {
private final File dataFile; private final File dataFile;
private final File historyFile; private final File historyFile;
private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
public MuteServiceImpl(JavaPlugin plugin) { public MuteServiceImpl(JavaPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.dataFile = new File(plugin.getDataFolder(), "mutes.json"); this.dataFile = new File(plugin.getDataFolder(), "mutes.json");
@ -32,19 +32,19 @@ public class MuteServiceImpl implements MuteService {
load(); load();
loadHistory(); loadHistory();
} }
@Override @Override
public void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy) { public void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy) {
long endTime = duration > 0 ? System.currentTimeMillis() + duration : 0; long endTime = duration > 0 ? System.currentTimeMillis() + duration : 0;
MuteData data = new MuteData(uuid, playerName, endTime, reason, mutedBy); MuteData data = new MuteData(uuid, playerName, endTime, reason, mutedBy);
mutes.put(uuid, data); mutes.put(uuid, data);
// Добавляем в историю // Добавляем в историю
addToHistory(uuid, playerName, duration, reason, mutedBy); addToHistory(uuid, playerName, duration, reason, mutedBy);
saveAsync(); saveAsync();
} }
@Override @Override
public boolean unmute(UUID uuid, String unmutedBy) { public boolean unmute(UUID uuid, String unmutedBy) {
MuteData removed = mutes.remove(uuid); MuteData removed = mutes.remove(uuid);
@ -55,12 +55,12 @@ public class MuteServiceImpl implements MuteService {
} }
return false; return false;
} }
@Override @Override
public boolean isMuted(UUID uuid) { public boolean isMuted(UUID uuid) {
MuteData data = mutes.get(uuid); MuteData data = mutes.get(uuid);
if (data == null) return false; if (data == null) return false;
if (data.getEndTime() > 0 && System.currentTimeMillis() > data.getEndTime()) { if (data.getEndTime() > 0 && System.currentTimeMillis() > data.getEndTime()) {
mutes.remove(uuid); mutes.remove(uuid);
saveAsync(); saveAsync();
@ -68,13 +68,13 @@ public class MuteServiceImpl implements MuteService {
} }
return true; return true;
} }
@Override @Override
public MuteData getMuteData(UUID uuid) { public MuteData getMuteData(UUID uuid) {
if (!isMuted(uuid)) return null; if (!isMuted(uuid)) return null;
return mutes.get(uuid); return mutes.get(uuid);
} }
@Override @Override
public long getRemainingTime(UUID uuid) { public long getRemainingTime(UUID uuid) {
MuteData data = mutes.get(uuid); MuteData data = mutes.get(uuid);
@ -82,16 +82,16 @@ public class MuteServiceImpl implements MuteService {
if (data.getEndTime() == 0) return -1; // Перманентный if (data.getEndTime() == 0) return -1; // Перманентный
return Math.max(0, data.getEndTime() - System.currentTimeMillis()); return Math.max(0, data.getEndTime() - System.currentTimeMillis());
} }
@Override @Override
public String formatTime(long millis) { public String formatTime(long millis) {
if (millis <= 0) return "0с"; if (millis <= 0) return "0с";
long seconds = millis / 1000; long seconds = millis / 1000;
long minutes = seconds / 60; long minutes = seconds / 60;
long hours = minutes / 60; long hours = minutes / 60;
long days = hours / 24; long days = hours / 24;
if (days > 0) { if (days > 0) {
return days + "д " + (hours % 24) + "ч"; return days + "д " + (hours % 24) + "ч";
} else if (hours > 0) { } else if (hours > 0) {
@ -102,14 +102,14 @@ public class MuteServiceImpl implements MuteService {
return seconds + "с"; return seconds + "с";
} }
} }
@Override @Override
public long parseTime(String timeStr) { public long parseTime(String timeStr) {
if (timeStr == null || timeStr.isEmpty()) return 0; if (timeStr == null || timeStr.isEmpty()) return 0;
timeStr = timeStr.toLowerCase(); timeStr = timeStr.toLowerCase();
long multiplier = 1000; // базово в миллисекундах long multiplier = 1000; // базово в миллисекундах
try { try {
if (timeStr.endsWith("d")) { if (timeStr.endsWith("d")) {
return Long.parseLong(timeStr.replace("d", "")) * 24 * 60 * 60 * multiplier; return Long.parseLong(timeStr.replace("d", "")) * 24 * 60 * 60 * multiplier;
@ -126,45 +126,45 @@ public class MuteServiceImpl implements MuteService {
return -1; return -1;
} }
} }
@Override @Override
public long getMaxDuration(Player player) { public long getMaxDuration(Player player) {
if (player.hasPermission("lochat.mute.dur.perm")) { if (player.hasPermission("lochat.mute.dur.perm")) {
return 0; // Перманентный return 0; // Перманентный
} }
String[] durations = {"30d", "14d", "7d", "3d", "1d", "12h", "6h", "1h", "30m", "10m"}; String[] durations = {"30d", "14d", "7d", "3d", "1d", "12h", "6h", "1h", "30m", "10m"};
for (String dur : durations) { for (String dur : durations) {
if (player.hasPermission("lochat.mute.dur." + dur)) { if (player.hasPermission("lochat.mute.dur." + dur)) {
return parseTime(dur); return parseTime(dur);
} }
} }
return -1; // Нет прав return -1; // Нет прав
} }
@Override @Override
public boolean canMuteForDuration(Player player, long duration) { public boolean canMuteForDuration(Player player, long duration) {
if (player.hasPermission("lochat.mute.dur.perm")) { if (player.hasPermission("lochat.mute.dur.perm")) {
return true; return true;
} }
if (duration == 0) { if (duration == 0) {
return false; return false;
} }
long maxDuration = getMaxDuration(player); long maxDuration = getMaxDuration(player);
if (maxDuration == -1) return false; if (maxDuration == -1) return false;
if (maxDuration == 0) return true; if (maxDuration == 0) return true;
return duration <= maxDuration; return duration <= maxDuration;
} }
@Override @Override
public List<MuteData.MuteHistoryEntry> getPlayerHistory(UUID uuid) { public List<MuteData.MuteHistoryEntry> getPlayerHistory(UUID uuid) {
return history.getOrDefault(uuid, new ArrayList<>()); return history.getOrDefault(uuid, new ArrayList<>());
} }
@Override @Override
public List<MuteData.MuteHistoryEntry> getMutesByOperator(String operatorName) { public List<MuteData.MuteHistoryEntry> getMutesByOperator(String operatorName) {
List<MuteData.MuteHistoryEntry> result = new ArrayList<>(); List<MuteData.MuteHistoryEntry> result = new ArrayList<>();
@ -178,7 +178,7 @@ public class MuteServiceImpl implements MuteService {
result.sort((a, b) -> Long.compare(b.mutedAt, a.mutedAt)); result.sort((a, b) -> Long.compare(b.mutedAt, a.mutedAt));
return result; return result;
} }
@Override @Override
public UUID getUUIDByName(String name) { public UUID getUUIDByName(String name) {
for (Map.Entry<UUID, List<MuteData.MuteHistoryEntry>> entry : history.entrySet()) { for (Map.Entry<UUID, List<MuteData.MuteHistoryEntry>> entry : history.entrySet()) {
@ -190,7 +190,7 @@ public class MuteServiceImpl implements MuteService {
} }
return null; return null;
} }
@Override @Override
public Map<UUID, MuteData> getActiveMutes() { public Map<UUID, MuteData> getActiveMutes() {
mutes.entrySet().removeIf(entry -> { mutes.entrySet().removeIf(entry -> {
@ -199,7 +199,7 @@ public class MuteServiceImpl implements MuteService {
}); });
return new HashMap<>(mutes); return new HashMap<>(mutes);
} }
@Override @Override
public String formatMessage(String message, String player, String operator, String duration, String reason) { public String formatMessage(String message, String player, String operator, String duration, String reason) {
return message return message
@ -208,17 +208,17 @@ public class MuteServiceImpl implements MuteService {
.replace("%duration%", duration != null ? duration : "") .replace("%duration%", duration != null ? duration : "")
.replace("%reason%", reason != null ? reason : ""); .replace("%reason%", reason != null ? reason : "");
} }
@Override @Override
public void save() { public void save() {
try { try {
if (!dataFile.getParentFile().exists()) { if (!dataFile.getParentFile().exists()) {
dataFile.getParentFile().mkdirs(); dataFile.getParentFile().mkdirs();
} }
Map<String, MuteData> toSave = new ConcurrentHashMap<>(); Map<String, MuteData> toSave = new ConcurrentHashMap<>();
mutes.forEach((uuid, data) -> toSave.put(uuid.toString(), data)); mutes.forEach((uuid, data) -> toSave.put(uuid.toString(), data));
try (Writer writer = new FileWriter(dataFile)) { try (Writer writer = new FileWriter(dataFile)) {
gson.toJson(toSave, writer); gson.toJson(toSave, writer);
} }
@ -226,52 +226,56 @@ public class MuteServiceImpl implements MuteService {
plugin.getLogger().warning("Ошибка сохранения мутов: " + e.getMessage()); plugin.getLogger().warning("Ошибка сохранения мутов: " + e.getMessage());
} }
} }
private void load() { private void load() {
if (!dataFile.exists()) return; if (!dataFile.exists()) return;
try (Reader reader = new FileReader(dataFile)) { try (Reader reader = new FileReader(dataFile)) {
Type type = new TypeToken<Map<String, MuteData>>(){}.getType(); Type type = new TypeToken<Map<String, MuteData>>() {
}.getType();
Map<String, MuteData> loaded = gson.fromJson(reader, type); Map<String, MuteData> loaded = gson.fromJson(reader, type);
if (loaded != null) { if (loaded != null) {
loaded.forEach((key, value) -> { loaded.forEach((key, value) -> {
try { try {
mutes.put(UUID.fromString(key), value); mutes.put(UUID.fromString(key), value);
} catch (IllegalArgumentException ignored) {} } catch (IllegalArgumentException ignored) {
}
}); });
} }
} catch (IOException e) { } catch (IOException e) {
plugin.getLogger().warning("Ошибка загрузки мутов: " + e.getMessage()); plugin.getLogger().warning("Ошибка загрузки мутов: " + e.getMessage());
} }
} }
private void loadHistory() { private void loadHistory() {
if (!historyFile.exists()) return; if (!historyFile.exists()) return;
try (Reader reader = new FileReader(historyFile)) { try (Reader reader = new FileReader(historyFile)) {
Type type = new TypeToken<Map<String, List<MuteData.MuteHistoryEntry>>>(){}.getType(); Type type = new TypeToken<Map<String, List<MuteData.MuteHistoryEntry>>>() {
}.getType();
Map<String, List<MuteData.MuteHistoryEntry>> loaded = gson.fromJson(reader, type); Map<String, List<MuteData.MuteHistoryEntry>> loaded = gson.fromJson(reader, type);
if (loaded != null) { if (loaded != null) {
loaded.forEach((key, value) -> { loaded.forEach((key, value) -> {
try { try {
history.put(UUID.fromString(key), new ArrayList<>(value)); history.put(UUID.fromString(key), new ArrayList<>(value));
} catch (IllegalArgumentException ignored) {} } catch (IllegalArgumentException ignored) {
}
}); });
} }
} catch (IOException e) { } catch (IOException e) {
plugin.getLogger().warning("Ошибка загрузки истории мутов: " + e.getMessage()); plugin.getLogger().warning("Ошибка загрузки истории мутов: " + e.getMessage());
} }
} }
private void saveHistory() { private void saveHistory() {
try { try {
if (!historyFile.getParentFile().exists()) { if (!historyFile.getParentFile().exists()) {
historyFile.getParentFile().mkdirs(); historyFile.getParentFile().mkdirs();
} }
Map<String, List<MuteData.MuteHistoryEntry>> toSave = new ConcurrentHashMap<>(); Map<String, List<MuteData.MuteHistoryEntry>> toSave = new ConcurrentHashMap<>();
history.forEach((uuid, data) -> toSave.put(uuid.toString(), data)); history.forEach((uuid, data) -> toSave.put(uuid.toString(), data));
try (Writer writer = new FileWriter(historyFile)) { try (Writer writer = new FileWriter(historyFile)) {
gson.toJson(toSave, writer); gson.toJson(toSave, writer);
} }
@ -279,7 +283,7 @@ public class MuteServiceImpl implements MuteService {
plugin.getLogger().warning("Ошибка сохранения истории мутов: " + e.getMessage()); plugin.getLogger().warning("Ошибка сохранения истории мутов: " + e.getMessage());
} }
} }
private void addToHistory(UUID uuid, String playerName, long duration, String reason, String mutedBy) { private void addToHistory(UUID uuid, String playerName, long duration, String reason, String mutedBy) {
List<MuteData.MuteHistoryEntry> playerHistory = history.computeIfAbsent(uuid, k -> new ArrayList<>()); List<MuteData.MuteHistoryEntry> playerHistory = history.computeIfAbsent(uuid, k -> new ArrayList<>());
playerHistory.add(new MuteData.MuteHistoryEntry( playerHistory.add(new MuteData.MuteHistoryEntry(
@ -294,7 +298,7 @@ public class MuteServiceImpl implements MuteService {
)); ));
saveHistoryAsync(); saveHistoryAsync();
} }
private void updateHistoryUnmute(UUID uuid, String unmutedBy) { private void updateHistoryUnmute(UUID uuid, String unmutedBy) {
List<MuteData.MuteHistoryEntry> playerHistory = history.get(uuid); List<MuteData.MuteHistoryEntry> playerHistory = history.get(uuid);
if (playerHistory != null && !playerHistory.isEmpty()) { if (playerHistory != null && !playerHistory.isEmpty()) {
@ -310,11 +314,11 @@ public class MuteServiceImpl implements MuteService {
} }
saveHistoryAsync(); saveHistoryAsync();
} }
private void saveHistoryAsync() { private void saveHistoryAsync() {
FoliaUtil.runAsync(plugin, this::saveHistory); FoliaUtil.runAsync(plugin, this::saveHistory);
} }
private void saveAsync() { private void saveAsync() {
FoliaUtil.runAsync(plugin, () -> { FoliaUtil.runAsync(plugin, () -> {
save(); save();

View file

@ -12,28 +12,29 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* Реализация сервиса кастомных ников * Реализация сервиса кастомных ников
*/ */
public class NickServiceImpl implements NickService { public class NickServiceImpl implements NickService {
// Настройки
private static final int MIN_LENGTH = 3;
private static final int MAX_LENGTH = 16;
private final JavaPlugin plugin; private final JavaPlugin plugin;
private final Map<UUID, String> nicknames = new ConcurrentHashMap<>(); private final Map<UUID, String> nicknames = new ConcurrentHashMap<>();
private final File dataFile; private final File dataFile;
private FileConfiguration data; private FileConfiguration data;
// Настройки
private static final int MIN_LENGTH = 3;
private static final int MAX_LENGTH = 16;
public NickServiceImpl(JavaPlugin plugin) { public NickServiceImpl(JavaPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.dataFile = new File(plugin.getDataFolder(), "nicknames.yml"); this.dataFile = new File(plugin.getDataFolder(), "nicknames.yml");
load(); load();
} }
private void load() { private void load() {
if (!dataFile.exists()) { if (!dataFile.exists()) {
try { try {
@ -43,9 +44,9 @@ public class NickServiceImpl implements NickService {
plugin.getLogger().warning("Не удалось создать nicknames.yml: " + e.getMessage()); plugin.getLogger().warning("Не удалось создать nicknames.yml: " + e.getMessage());
} }
} }
data = YamlConfiguration.loadConfiguration(dataFile); data = YamlConfiguration.loadConfiguration(dataFile);
// Загружаем ники // Загружаем ники
if (data.contains("nicknames")) { if (data.contains("nicknames")) {
for (String key : data.getConfigurationSection("nicknames").getKeys(false)) { for (String key : data.getConfigurationSection("nicknames").getKeys(false)) {
@ -54,10 +55,10 @@ public class NickServiceImpl implements NickService {
nicknames.put(uuid, nickname); nicknames.put(uuid, nickname);
} }
} }
plugin.getLogger().info("Загружено " + nicknames.size() + " кастомных ников"); plugin.getLogger().info("Загружено " + nicknames.size() + " кастомных ников");
} }
@Override @Override
public void save() { public void save() {
// Сохраняем ники // Сохраняем ники
@ -65,21 +66,21 @@ public class NickServiceImpl implements NickService {
for (Map.Entry<UUID, String> entry : nicknames.entrySet()) { for (Map.Entry<UUID, String> entry : nicknames.entrySet()) {
data.set("nicknames." + entry.getKey().toString(), entry.getValue()); data.set("nicknames." + entry.getKey().toString(), entry.getValue());
} }
try { try {
data.save(dataFile); data.save(dataFile);
} catch (IOException e) { } catch (IOException e) {
plugin.getLogger().warning("Не удалось сохранить nicknames.yml: " + e.getMessage()); plugin.getLogger().warning("Не удалось сохранить nicknames.yml: " + e.getMessage());
} }
} }
@Override @Override
public boolean setNickname(UUID player, String nickname) { public boolean setNickname(UUID player, String nickname) {
// Валидация // Валидация
if (!isValidNickname(nickname)) { if (!isValidNickname(nickname)) {
return false; return false;
} }
// Проверка уникальности // Проверка уникальности
if (isNicknameTaken(nickname)) { if (isNicknameTaken(nickname)) {
// Проверяем не свой ли это ник // Проверяем не свой ли это ник
@ -88,23 +89,23 @@ public class NickServiceImpl implements NickService {
return false; return false;
} }
} }
// Устанавливаем ник // Устанавливаем ник
nicknames.put(player, nickname); nicknames.put(player, nickname);
// Обновляем display // Обновляем display
Player onlinePlayer = Bukkit.getPlayer(player); Player onlinePlayer = Bukkit.getPlayer(player);
if (onlinePlayer != null) { if (onlinePlayer != null) {
updatePlayerDisplay(onlinePlayer); updatePlayerDisplay(onlinePlayer);
} }
return true; return true;
} }
@Override @Override
public void resetNickname(UUID player) { public void resetNickname(UUID player) {
nicknames.remove(player); nicknames.remove(player);
// Сбрасываем display // Сбрасываем display
Player onlinePlayer = Bukkit.getPlayer(player); Player onlinePlayer = Bukkit.getPlayer(player);
if (onlinePlayer != null) { if (onlinePlayer != null) {
@ -112,59 +113,55 @@ public class NickServiceImpl implements NickService {
onlinePlayer.playerListName(Component.text(onlinePlayer.getName())); onlinePlayer.playerListName(Component.text(onlinePlayer.getName()));
} }
} }
@Override @Override
public Optional<String> getNickname(UUID player) { public Optional<String> getNickname(UUID player) {
return Optional.ofNullable(nicknames.get(player)); return Optional.ofNullable(nicknames.get(player));
} }
@Override @Override
public boolean isNicknameTaken(String nickname) { public boolean isNicknameTaken(String nickname) {
String cleanNick = stripColors(nickname).toLowerCase(); String cleanNick = stripColors(nickname).toLowerCase();
// Проверяем существующие ники // Проверяем существующие ники
for (String existingNick : nicknames.values()) { for (String existingNick : nicknames.values()) {
if (stripColors(existingNick).equalsIgnoreCase(cleanNick)) { if (stripColors(existingNick).equalsIgnoreCase(cleanNick)) {
return true; return true;
} }
} }
// Проверяем реальные ники онлайн игроков // Проверяем реальные ники онлайн игроков
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
if (player.getName().equalsIgnoreCase(cleanNick)) { if (player.getName().equalsIgnoreCase(cleanNick)) {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public boolean isValidNickname(String nickname) { public boolean isValidNickname(String nickname) {
if (nickname == null || nickname.isEmpty()) { if (nickname == null || nickname.isEmpty()) {
return false; return false;
} }
// Убираем цвета для проверки длины // Убираем цвета для проверки длины
String cleanNick = stripColors(nickname); String cleanNick = stripColors(nickname);
// Проверка длины // Проверка длины
if (cleanNick.length() < MIN_LENGTH || cleanNick.length() > MAX_LENGTH) { if (cleanNick.length() < MIN_LENGTH || cleanNick.length() > MAX_LENGTH) {
return false; return false;
} }
// Проверка символов (разрешены буквы, цифры, _, русские буквы) // Проверка символов (разрешены буквы, цифры, _, русские буквы)
if (!cleanNick.matches("[a-zA-Zа-яА-Я0-9_]+")) { return cleanNick.matches("[a-zA-Zа-яА-Я0-9_]+");
return false;
}
return true;
} }
@Override @Override
public void updatePlayerDisplay(Player player) { public void updatePlayerDisplay(Player player) {
Optional<String> nickname = getNickname(player.getUniqueId()); Optional<String> nickname = getNickname(player.getUniqueId());
if (nickname.isPresent()) { if (nickname.isPresent()) {
// Парсим ник с цветами // Парсим ник с цветами
Component nickComponent = ChatFormatter.parse(nickname.get()); Component nickComponent = ChatFormatter.parse(nickname.get());
@ -176,7 +173,7 @@ public class NickServiceImpl implements NickService {
player.playerListName(Component.text(player.getName())); player.playerListName(Component.text(player.getName()));
} }
} }
/** /**
* Убирает цвета из строки * Убирает цвета из строки
*/ */

View file

@ -11,16 +11,16 @@ import java.util.UUID;
*/ */
public class PlayerDataServiceImpl implements PlayerDataService { public class PlayerDataServiceImpl implements PlayerDataService {
private final CooldownService cooldownService; private final CooldownService cooldownService;
public PlayerDataServiceImpl(JavaPlugin plugin) { public PlayerDataServiceImpl(JavaPlugin plugin) {
this.cooldownService = new CooldownServiceImpl(); this.cooldownService = new CooldownServiceImpl();
} }
@Override @Override
public void clearPlayerData(UUID player) { public void clearPlayerData(UUID player) {
cooldownService.removeCooldown(player); cooldownService.removeCooldown(player);
} }
@Override @Override
public void saveAll() { public void saveAll() {
// Сохранение всех данных при выключении // Сохранение всех данных при выключении

View file

@ -60,10 +60,10 @@ public class SpyServiceImpl implements SpyService {
@Override @Override
public void sendToSpies(Player sender, Component message, boolean isGlobal) { public void sendToSpies(Player sender, Component message, boolean isGlobal) {
if (spyEnabled.isEmpty()) return; if (spyEnabled.isEmpty()) return;
String chatType = isGlobal ? "Global" : "Local"; String chatType = isGlobal ? "Global" : "Local";
String plainMessage = PlainTextComponentSerializer.plainText().serialize(message); String plainMessage = PlainTextComponentSerializer.plainText().serialize(message);
String format = messageConfig.get("spy.chat-format", String format = messageConfig.get("spy.chat-format",
"§7[SPY] §e{type} §7{sender}: §f{message}"); "§7[SPY] §e{type} §7{sender}: §f{message}");
for (UUID spyUuid : spyEnabled) { for (UUID spyUuid : spyEnabled) {

View file

@ -7,33 +7,50 @@ import org.bukkit.entity.Player;
*/ */
public class ChatMessage { public class ChatMessage {
private final Player sender; private final Player sender;
private String content;
private final boolean isGlobal; private final boolean isGlobal;
private final long timestamp; private final long timestamp;
private String content;
private ChatMessage(Player sender, String content, boolean isGlobal) { private ChatMessage(Player sender, String content, boolean isGlobal) {
this.sender = sender; this.sender = sender;
this.content = content; this.content = content;
this.isGlobal = isGlobal; this.isGlobal = isGlobal;
this.timestamp = System.currentTimeMillis(); this.timestamp = System.currentTimeMillis();
} }
public static ChatMessage create(Player sender, String rawMessage) { public static ChatMessage create(Player sender, String rawMessage) {
// Определяем тип чата // Определяем тип чата
boolean isGlobal = rawMessage.startsWith("!") && boolean isGlobal = rawMessage.startsWith("!") &&
sender.hasPermission("chat.global.use"); sender.hasPermission("chat.global.use");
String content = isGlobal ? String content = isGlobal ?
rawMessage.substring(1).trim() : rawMessage.substring(1).trim() :
rawMessage.trim(); rawMessage.trim();
return new ChatMessage(sender, content, isGlobal); return new ChatMessage(sender, content, isGlobal);
} }
public Player getSender() { return sender; } public Player getSender() {
public String getContent() { return content; } return sender;
public void setContent(String content) { this.content = content; } }
public boolean isGlobal() { return isGlobal; }
public long getTimestamp() { return timestamp; } public String getContent() {
public String getChatType() { return isGlobal ? "global" : "local"; } return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isGlobal() {
return isGlobal;
}
public long getTimestamp() {
return timestamp;
}
public String getChatType() {
return isGlobal ? "global" : "local";
}
} }

View file

@ -6,15 +6,16 @@ import java.util.UUID;
* Модель данных мута (Value Object) * Модель данных мута (Value Object)
*/ */
public class MuteData { public class MuteData {
private UUID uuid;
private String playerName;
public long endTime; // 0 = перманентный (public for JSON serialization) public long endTime; // 0 = перманентный (public for JSON serialization)
public String reason; public String reason;
public String mutedBy; public String mutedBy;
public long mutedAt; public long mutedAt;
private UUID uuid;
public MuteData() {} // For JSON deserialization private String playerName;
public MuteData() {
} // For JSON deserialization
public MuteData(UUID uuid, String playerName, long endTime, String reason, String mutedBy) { public MuteData(UUID uuid, String playerName, long endTime, String reason, String mutedBy) {
this.uuid = uuid; this.uuid = uuid;
this.playerName = playerName; this.playerName = playerName;
@ -23,7 +24,7 @@ public class MuteData {
this.mutedBy = mutedBy; this.mutedBy = mutedBy;
this.mutedAt = System.currentTimeMillis(); this.mutedAt = System.currentTimeMillis();
} }
public MuteData(long endTime, String reason, String mutedBy, long mutedAt, String playerName) { public MuteData(long endTime, String reason, String mutedBy, long mutedAt, String playerName) {
this.endTime = endTime; this.endTime = endTime;
this.reason = reason; this.reason = reason;
@ -31,15 +32,35 @@ public class MuteData {
this.mutedAt = mutedAt; this.mutedAt = mutedAt;
this.playerName = playerName; this.playerName = playerName;
} }
public UUID getUuid() { return uuid; } public UUID getUuid() {
public String getPlayerName() { return playerName; } return uuid;
public long getEndTime() { return endTime; } }
public String getReason() { return reason; }
public String getMutedBy() { return mutedBy; } public String getPlayerName() {
public long getMutedAt() { return mutedAt; } return playerName;
public boolean isPermanent() { return endTime == 0; } }
public long getEndTime() {
return endTime;
}
public String getReason() {
return reason;
}
public String getMutedBy() {
return mutedBy;
}
public long getMutedAt() {
return mutedAt;
}
public boolean isPermanent() {
return endTime == 0;
}
/** /**
* Запись истории мута * Запись истории мута
*/ */
@ -52,12 +73,13 @@ public class MuteData {
public boolean unmuted; public boolean unmuted;
public String unmutedBy; public String unmutedBy;
public long unmutedAt; public long unmutedAt;
public MuteHistoryEntry() {} // For JSON deserialization public MuteHistoryEntry() {
} // For JSON deserialization
public MuteHistoryEntry(String playerName, long duration, String reason,
String mutedBy, long mutedAt, boolean unmuted, public MuteHistoryEntry(String playerName, long duration, String reason,
String unmutedBy, long unmutedAt) { String mutedBy, long mutedAt, boolean unmuted,
String unmutedBy, long unmutedAt) {
this.playerName = playerName; this.playerName = playerName;
this.duration = duration; this.duration = duration;
this.reason = reason; this.reason = reason;

View file

@ -37,18 +37,19 @@ public class GradientModule {
/** /**
* Инициализация модуля * Инициализация модуля
*
* @return true если модуль успешно инициализирован * @return true если модуль успешно инициализирован
*/ */
public boolean init() { public boolean init() {
// Загружаем конфиги // Загружаем конфиги
config = new GradientConfig(plugin); config = new GradientConfig(plugin);
messages = new GradientMessages(plugin); messages = new GradientMessages(plugin);
if (!config.isEnabled()) { if (!config.isEnabled()) {
plugin.getLogger().info("Gradient модуль отключен в конфиге."); plugin.getLogger().info("Gradient модуль отключен в конфиге.");
return false; return false;
} }
// Проверяем PlayerPoints (опционально теперь) // Проверяем PlayerPoints (опционально теперь)
if (Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) { if (Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) {
playerPointsAPI = PlayerPoints.getInstance().getAPI(); playerPointsAPI = PlayerPoints.getInstance().getAPI();
@ -56,10 +57,10 @@ public class GradientModule {
} else { } else {
plugin.getLogger().warning("Gradient: PlayerPoints не найден. Покупки будут бесплатными."); plugin.getLogger().warning("Gradient: PlayerPoints не найден. Покупки будут бесплатными.");
} }
// Инициализация хранилища // Инициализация хранилища
dataManager = new GradientDataManager(plugin, config); dataManager = new GradientDataManager(plugin, config);
// Подключение LuckPerms (опционально) // Подключение LuckPerms (опционально)
try { try {
if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) { if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) {
@ -71,15 +72,15 @@ public class GradientModule {
} catch (NoClassDefFoundError e) { } catch (NoClassDefFoundError e) {
plugin.getLogger().info("Gradient: LuckPerms не найден. Префиксы LuckPerms будут недоступны."); plugin.getLogger().info("Gradient: LuckPerms не найден. Префиксы LuckPerms будут недоступны.");
} }
// Регистрация команд // Регистрация команд
registerCommands(); registerCommands();
// Регистрация слушателей // Регистрация слушателей
Bukkit.getPluginManager().registerEvents(new GradientPlayerListener(this), plugin); Bukkit.getPluginManager().registerEvents(new GradientPlayerListener(this), plugin);
Bukkit.getPluginManager().registerEvents(new GradientGUIListener(this), plugin); Bukkit.getPluginManager().registerEvents(new GradientGUIListener(this), plugin);
enabled = true; enabled = true;
plugin.getLogger().info("Gradient модуль успешно загружен!"); plugin.getLogger().info("Gradient модуль успешно загружен!");
return true; return true;
@ -91,13 +92,13 @@ public class GradientModule {
plugin.getCommand("color").setExecutor(colorCommand); plugin.getCommand("color").setExecutor(colorCommand);
plugin.getCommand("color").setTabCompleter(colorCommand); plugin.getCommand("color").setTabCompleter(colorCommand);
} }
GradientPrefixCommand prefixCommand = new GradientPrefixCommand(this); GradientPrefixCommand prefixCommand = new GradientPrefixCommand(this);
if (plugin.getCommand("prefix") != null) { if (plugin.getCommand("prefix") != null) {
plugin.getCommand("prefix").setExecutor(prefixCommand); plugin.getCommand("prefix").setExecutor(prefixCommand);
plugin.getCommand("prefix").setTabCompleter(prefixCommand); plugin.getCommand("prefix").setTabCompleter(prefixCommand);
} }
GradientAdminCommand adminCommand = new GradientAdminCommand(this); GradientAdminCommand adminCommand = new GradientAdminCommand(this);
if (plugin.getCommand("aprefix") != null) { if (plugin.getCommand("aprefix") != null) {
plugin.getCommand("aprefix").setExecutor(adminCommand); plugin.getCommand("aprefix").setExecutor(adminCommand);
@ -141,22 +142,23 @@ public class GradientModule {
/** /**
* Получает отформатированное имя игрока с градиентом и LuckPerms префиксом * Получает отформатированное имя игрока с градиентом и LuckPerms префиксом
*
* @param useTabFormat true для §x§... формата (TAB), false для &#RRGGBB * @param useTabFormat true для §x§... формата (TAB), false для &#RRGGBB
*/ */
private String getFormattedName(Player player, boolean useTabFormat) { private String getFormattedName(Player player, boolean useTabFormat) {
if (!enabled) return player.getName(); if (!enabled) return player.getName();
GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId()); GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId());
// Собираем полную строку: префикс + ник // Собираем полную строку: префикс + ник
StringBuilder fullText = new StringBuilder(); StringBuilder fullText = new StringBuilder();
// LuckPerms префикс // LuckPerms префикс
String lpPrefix = null; String lpPrefix = null;
if (luckPermsHook.isEnabled()) { if (luckPermsHook.isEnabled()) {
lpPrefix = luckPermsHook.getActivePrefix(player); lpPrefix = luckPermsHook.getActivePrefix(player);
} }
// Определяем какой префикс использовать // Определяем какой префикс использовать
if (data.hasPrefix() && data.isPrefixEnabled()) { if (data.hasPrefix() && data.isPrefixEnabled()) {
// Кастомный префикс // Кастомный префикс
@ -167,21 +169,21 @@ public class GradientModule {
fullText.append(stripColors(lpPrefix)); fullText.append(stripColors(lpPrefix));
} else { } else {
// LP префикс со своими цветами, ник отдельно // LP префикс со своими цветами, ник отдельно
String nick = data.hasColors() && data.isColorEnabled() String nick = data.hasColors() && data.isColorEnabled()
? applyGradientWithFormat(player.getName(), data.getColors(), useTabFormat) ? applyGradientWithFormat(player.getName(), data.getColors(), useTabFormat)
: player.getName(); : player.getName();
return lpPrefix + nick; return lpPrefix + nick;
} }
} }
// Добавляем ник // Добавляем ник
fullText.append(player.getName()); fullText.append(player.getName());
// Применяем единый градиент на всю строку // Применяем единый градиент на всю строку
if (data.hasColors() && data.isColorEnabled()) { if (data.hasColors() && data.isColorEnabled()) {
return applyGradientWithFormat(fullText.toString(), data.getColors(), useTabFormat); return applyGradientWithFormat(fullText.toString(), data.getColors(), useTabFormat);
} }
return fullText.toString(); return fullText.toString();
} }
@ -211,12 +213,12 @@ public class GradientModule {
*/ */
public String getGradientNick(Player player) { public String getGradientNick(Player player) {
if (!enabled) return player.getName(); if (!enabled) return player.getName();
GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId()); GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId());
if (!data.hasColors() || !data.isColorEnabled()) { if (!data.hasColors() || !data.isColorEnabled()) {
return player.getName(); return player.getName();
} }
return GradientUtil.applyGradient(player.getName(), data.getColors(), config.isUseLegacyRgbFormat()); return GradientUtil.applyGradient(player.getName(), data.getColors(), config.isUseLegacyRgbFormat());
} }
@ -226,9 +228,9 @@ public class GradientModule {
*/ */
public String getPrefix(Player player) { public String getPrefix(Player player) {
if (!enabled) return ""; if (!enabled) return "";
GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId()); GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId());
// Кастомный префикс // Кастомный префикс
if (data.hasPrefix() && data.isPrefixEnabled()) { if (data.hasPrefix() && data.isPrefixEnabled()) {
String prefix = config.getPrefixFormat().replace("{prefix}", data.getPrefix()); String prefix = config.getPrefixFormat().replace("{prefix}", data.getPrefix());
@ -237,7 +239,7 @@ public class GradientModule {
} }
return prefix; return prefix;
} }
// LuckPerms префикс // LuckPerms префикс
if (luckPermsHook.isEnabled()) { if (luckPermsHook.isEnabled()) {
String lpPrefix = luckPermsHook.getActivePrefix(player); String lpPrefix = luckPermsHook.getActivePrefix(player);
@ -249,7 +251,7 @@ public class GradientModule {
return lpPrefix; return lpPrefix;
} }
} }
return ""; return "";
} }
@ -263,12 +265,35 @@ public class GradientModule {
} }
// Геттеры // Геттеры
public JavaPlugin getPlugin() { return plugin; } public JavaPlugin getPlugin() {
public GradientConfig getConfig() { return config; } return plugin;
public GradientMessages getMessages() { return messages; } }
public GradientDataManager getDataManager() { return dataManager; }
public GradientLuckPermsHook getLuckPermsHook() { return luckPermsHook; } public GradientConfig getConfig() {
public PlayerPointsAPI getPlayerPointsAPI() { return playerPointsAPI; } return config;
public boolean hasPlayerPoints() { return playerPointsAPI != null; } }
public boolean isEnabled() { return enabled; }
public GradientMessages getMessages() {
return messages;
}
public GradientDataManager getDataManager() {
return dataManager;
}
public GradientLuckPermsHook getLuckPermsHook() {
return luckPermsHook;
}
public PlayerPointsAPI getPlayerPointsAPI() {
return playerPointsAPI;
}
public boolean hasPlayerPoints() {
return playerPointsAPI != null;
}
public boolean isEnabled() {
return enabled;
}
} }

View file

@ -26,10 +26,10 @@ import java.util.List;
*/ */
public class GradientAdminCommand implements CommandExecutor, TabCompleter { public class GradientAdminCommand implements CommandExecutor, TabCompleter {
private final GradientModule module;
private static final List<String> PRESET_COLORS = Arrays.asList( private static final List<String> PRESET_COLORS = Arrays.asList(
"#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3" "#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3"
); );
private final GradientModule module;
public GradientAdminCommand(GradientModule module) { public GradientAdminCommand(GradientModule module) {
this.module = module; this.module = module;
@ -153,11 +153,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
Player onlineTarget = target.getPlayer(); Player onlineTarget = target.getPlayer();
if (onlineTarget != null) { if (onlineTarget != null) {
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget, FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data)); () -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
} }
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(target.getUniqueId())); () -> module.getDataManager().savePlayerData(target.getUniqueId()));
sender.sendMessage("§aЦвет для игрока §f" + args[1] + " §aустановлен: §f" + String.join(" ", colors)); sender.sendMessage("§aЦвет для игрока §f" + args[1] + " §aустановлен: §f" + String.join(" ", colors));
@ -194,11 +194,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
Player onlineTarget = target.getPlayer(); Player onlineTarget = target.getPlayer();
if (onlineTarget != null) { if (onlineTarget != null) {
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget, FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data)); () -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
} }
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(target.getUniqueId())); () -> module.getDataManager().savePlayerData(target.getUniqueId()));
sender.sendMessage("§aПрефикс для игрока §f" + args[1] + " §aустановлен: §f" + prefix); sender.sendMessage("§aПрефикс для игрока §f" + args[1] + " §aустановлен: §f" + prefix);
@ -209,7 +209,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
sender.sendMessage("§cИспользование: /aprefix " + (enable ? "coloron" : "coloroff") + " <игрок>"); sender.sendMessage("§cИспользование: /aprefix " + (enable ? "coloron" : "coloroff") + " <игрок>");
return; return;
} }
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]); OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
if (!target.hasPlayedBefore() && !target.isOnline()) { if (!target.hasPlayedBefore() && !target.isOnline()) {
msg.send(sender, "player-not-found"); msg.send(sender, "player-not-found");
@ -221,11 +221,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
Player onlineTarget = target.getPlayer(); Player onlineTarget = target.getPlayer();
if (onlineTarget != null) { if (onlineTarget != null) {
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget, FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data)); () -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
} }
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(target.getUniqueId())); () -> module.getDataManager().savePlayerData(target.getUniqueId()));
sender.sendMessage("§aЦвет для игрока §f" + args[1] + (enable ? " §aвключён" : " §cвыключен")); sender.sendMessage("§aЦвет для игрока §f" + args[1] + (enable ? " §aвключён" : " §cвыключен"));
@ -236,7 +236,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
sender.sendMessage("§cИспользование: /aprefix " + (enable ? "prefixon" : "prefixoff") + " <игрок>"); sender.sendMessage("§cИспользование: /aprefix " + (enable ? "prefixon" : "prefixoff") + " <игрок>");
return; return;
} }
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]); OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
if (!target.hasPlayedBefore() && !target.isOnline()) { if (!target.hasPlayedBefore() && !target.isOnline()) {
msg.send(sender, "player-not-found"); msg.send(sender, "player-not-found");
@ -256,11 +256,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
Player onlineTarget = target.getPlayer(); Player onlineTarget = target.getPlayer();
if (onlineTarget != null) { if (onlineTarget != null) {
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget, FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data)); () -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
} }
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(target.getUniqueId())); () -> module.getDataManager().savePlayerData(target.getUniqueId()));
sender.sendMessage("§aПрефикс для игрока §f" + args[1] + (enable ? " §aвключён" : " §cвыключен")); sender.sendMessage("§aПрефикс для игрока §f" + args[1] + (enable ? " §aвключён" : " §cвыключен"));
@ -271,7 +271,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
sender.sendMessage("§cИспользование: /aprefix resetcolor <игрок>"); sender.sendMessage("§cИспользование: /aprefix resetcolor <игрок>");
return; return;
} }
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]); OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
if (!target.hasPlayedBefore() && !target.isOnline()) { if (!target.hasPlayedBefore() && !target.isOnline()) {
msg.send(sender, "player-not-found"); msg.send(sender, "player-not-found");
@ -284,11 +284,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
Player onlineTarget = target.getPlayer(); Player onlineTarget = target.getPlayer();
if (onlineTarget != null) { if (onlineTarget != null) {
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget, FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data)); () -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
} }
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(target.getUniqueId())); () -> module.getDataManager().savePlayerData(target.getUniqueId()));
sender.sendMessage("§aЦвет для игрока §f" + args[1] + " §aсброшен"); sender.sendMessage("§aЦвет для игрока §f" + args[1] + " §aсброшен");
@ -299,7 +299,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
sender.sendMessage("§cИспользование: /aprefix resetprefix <игрок>"); sender.sendMessage("§cИспользование: /aprefix resetprefix <игрок>");
return; return;
} }
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]); OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
if (!target.hasPlayedBefore() && !target.isOnline()) { if (!target.hasPlayedBefore() && !target.isOnline()) {
msg.send(sender, "player-not-found"); msg.send(sender, "player-not-found");
@ -316,11 +316,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
Player onlineTarget = target.getPlayer(); Player onlineTarget = target.getPlayer();
if (onlineTarget != null) { if (onlineTarget != null) {
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget, FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data)); () -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
} }
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(target.getUniqueId())); () -> module.getDataManager().savePlayerData(target.getUniqueId()));
sender.sendMessage("§aПрефикс для игрока §f" + args[1] + " §aсброшен"); sender.sendMessage("§aПрефикс для игрока §f" + args[1] + " §aсброшен");
@ -330,7 +330,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
int count = 0; int count = 0;
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
FoliaUtil.runEntityTask(module.getPlugin(), player, FoliaUtil.runEntityTask(module.getPlugin(), player,
() -> DisplayNameUtil.updateDisplayName(module, player, data)); () -> DisplayNameUtil.updateDisplayName(module, player, data));
count++; count++;
} }
@ -340,19 +340,19 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) { @NotNull String alias, @NotNull String[] args) {
if (!sender.hasPermission("gradient.admin")) return new ArrayList<>(); if (!sender.hasPermission("gradient.admin")) return new ArrayList<>();
if (args.length == 1) { if (args.length == 1) {
return Arrays.asList("reload", "info", "setcolor", "setprefix", "coloron", "coloroff", return Arrays.asList("reload", "info", "setcolor", "setprefix", "coloron", "coloroff",
"prefixon", "prefixoff", "resetcolor", "resetprefix", "updateall").stream() "prefixon", "prefixoff", "resetcolor", "resetprefix", "updateall").stream()
.filter(s -> s.startsWith(args[0].toLowerCase())) .filter(s -> s.startsWith(args[0].toLowerCase()))
.toList(); .toList();
} }
if (args.length == 2) { if (args.length == 2) {
String sub = args[0].toLowerCase(); String sub = args[0].toLowerCase();
if (Arrays.asList("info", "setcolor", "setprefix", "coloron", "coloroff", if (Arrays.asList("info", "setcolor", "setprefix", "coloron", "coloroff",
"prefixon", "prefixoff", "resetcolor", "resetprefix").contains(sub)) { "prefixon", "prefixoff", "resetcolor", "resetprefix").contains(sub)) {
return Bukkit.getOnlinePlayers().stream() return Bukkit.getOnlinePlayers().stream()
.map(Player::getName) .map(Player::getName)

View file

@ -26,14 +26,13 @@ import java.util.function.BiFunction;
*/ */
public class GradientColorCommand implements CommandExecutor, TabCompleter { public class GradientColorCommand implements CommandExecutor, TabCompleter {
private final GradientModule module;
private final Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>();
private static final List<String> PRESET_COLORS = List.of( private static final List<String> PRESET_COLORS = List.of(
"#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3", "#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3",
"#FF69B4", "#00FFFF", "#FFD700", "#FFFFFF", "#000000" "#FF69B4", "#00FFFF", "#FFD700", "#FFFFFF", "#000000"
); );
private static final Set<String> SUB_COMMANDS = Set.of("on", "off", "reset", "copy"); private static final Set<String> SUB_COMMANDS = Set.of("on", "off", "reset", "copy");
private final GradientModule module;
private final Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>();
public GradientColorCommand(GradientModule module) { public GradientColorCommand(GradientModule module) {
this.module = module; this.module = module;
@ -77,12 +76,12 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
private boolean handleOn(Player player, String[] args) { private boolean handleOn(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
GradientMessages msg = module.getMessages(); GradientMessages msg = module.getMessages();
if (!data.hasColors()) { if (!data.hasColors()) {
msg.send(player, "color-no-colors"); msg.send(player, "color-no-colors");
return true; return true;
} }
data.setColorEnabled(true); data.setColorEnabled(true);
saveAndUpdate(player, data); saveAndUpdate(player, data);
msg.send(player, "color-enabled"); msg.send(player, "color-enabled");
@ -100,12 +99,12 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
private boolean handleReset(Player player, String[] args) { private boolean handleReset(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
GradientMessages msg = module.getMessages(); GradientMessages msg = module.getMessages();
if (!data.hasColors()) { if (!data.hasColors()) {
msg.send(player, "color-no-colors"); msg.send(player, "color-no-colors");
return true; return true;
} }
data.setColors(new ArrayList<>()); data.setColors(new ArrayList<>());
data.setColorEnabled(false); data.setColorEnabled(false);
saveAndUpdate(player, data); saveAndUpdate(player, data);
@ -116,18 +115,18 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
private boolean handleCopy(Player player, String[] args) { private boolean handleCopy(Player player, String[] args) {
GradientMessages msg = module.getMessages(); GradientMessages msg = module.getMessages();
GradientConfig cfg = module.getConfig(); GradientConfig cfg = module.getConfig();
if (args.length < 2) { if (args.length < 2) {
msg.send(player, "color-copy-usage"); msg.send(player, "color-copy-usage");
return true; return true;
} }
Player target = Bukkit.getPlayer(args[1]); Player target = Bukkit.getPlayer(args[1]);
if (target == null) { if (target == null) {
msg.send(player, "player-not-found"); msg.send(player, "player-not-found");
return true; return true;
} }
GradientPlayerData targetData = module.getDataManager().getPlayerData(target.getUniqueId()); GradientPlayerData targetData = module.getDataManager().getPlayerData(target.getUniqueId());
if (!targetData.hasColors()) { if (!targetData.hasColors()) {
msg.send(player, "color-copy-no-colors", "player", target.getName()); msg.send(player, "color-copy-no-colors", "player", target.getName());
@ -135,8 +134,8 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
} }
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
if (!player.hasPermission("gradient.bypass.cooldown") && if (!player.hasPermission("gradient.bypass.cooldown") &&
!checkCooldown(player, cfg.getColorCooldown(), data.getLastColorChange())) { !checkCooldown(player, cfg.getColorCooldown(), data.getLastColorChange())) {
return true; return true;
} }
@ -148,7 +147,7 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
return true; return true;
} }
GradientConfirmGUI gui = new GradientConfirmGUI(module, player, GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
GradientConfirmGUI.ConfirmType.COLOR, colors, data.getPrefix(), price); GradientConfirmGUI.ConfirmType.COLOR, colors, data.getPrefix(), price);
FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open); FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open);
return true; return true;
@ -170,7 +169,7 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
if (!player.hasPermission("gradient.bypass.cooldown") && if (!player.hasPermission("gradient.bypass.cooldown") &&
!checkCooldown(player, cfg.getColorCooldown(), data.getLastColorChange())) { !checkCooldown(player, cfg.getColorCooldown(), data.getLastColorChange())) {
return true; return true;
} }
@ -191,7 +190,7 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
return true; return true;
} }
GradientConfirmGUI gui = new GradientConfirmGUI(module, player, GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
GradientConfirmGUI.ConfirmType.COLOR, colors, data.getPrefix(), price); GradientConfirmGUI.ConfirmType.COLOR, colors, data.getPrefix(), price);
FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open); FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open);
return true; return true;
@ -222,35 +221,35 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
} }
private void saveAndUpdate(Player player, GradientPlayerData data) { private void saveAndUpdate(Player player, GradientPlayerData data) {
FoliaUtil.runEntityTask(module.getPlugin(), player, FoliaUtil.runEntityTask(module.getPlugin(), player,
() -> DisplayNameUtil.updateDisplayName(module, player, data)); () -> DisplayNameUtil.updateDisplayName(module, player, data));
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(player.getUniqueId())); () -> module.getDataManager().savePlayerData(player.getUniqueId()));
} }
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) { @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) { if (args.length == 1) {
String input = args[0].toLowerCase(); String input = args[0].toLowerCase();
List<String> completions = new ArrayList<>(SUB_COMMANDS); List<String> completions = new ArrayList<>(SUB_COMMANDS);
completions.addAll(PRESET_COLORS); completions.addAll(PRESET_COLORS);
return completions.stream().filter(s -> s.toLowerCase().startsWith(input)).toList(); return completions.stream().filter(s -> s.toLowerCase().startsWith(input)).toList();
} }
String firstArg = args[0].toLowerCase(); String firstArg = args[0].toLowerCase();
if (args.length == 2 && firstArg.equals("copy")) { if (args.length == 2 && firstArg.equals("copy")) {
return Bukkit.getOnlinePlayers().stream().map(Player::getName) return Bukkit.getOnlinePlayers().stream().map(Player::getName)
.filter(s -> s.toLowerCase().startsWith(args[1].toLowerCase())).toList(); .filter(s -> s.toLowerCase().startsWith(args[1].toLowerCase())).toList();
} }
if (!SUB_COMMANDS.contains(firstArg) && args.length <= module.getConfig().getMaxColors()) { if (!SUB_COMMANDS.contains(firstArg) && args.length <= module.getConfig().getMaxColors()) {
return PRESET_COLORS.stream() return PRESET_COLORS.stream()
.filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) .filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase()))
.toList(); .toList();
} }
return List.of(); return List.of();
} }
} }

View file

@ -28,13 +28,12 @@ import java.util.regex.Pattern;
*/ */
public class GradientPrefixCommand implements CommandExecutor, TabCompleter { public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
private final GradientModule module;
private final Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>();
private static final Pattern COLOR_CODE_PATTERN = Pattern.compile( 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}>)"); "(?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 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 Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>();
public GradientPrefixCommand(GradientModule module) { public GradientPrefixCommand(GradientModule module) {
this.module = module; this.module = module;
@ -77,12 +76,12 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
private boolean handleOn(Player player, String[] args) { private boolean handleOn(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
GradientMessages msg = module.getMessages(); GradientMessages msg = module.getMessages();
if (!data.hasPrefix()) { if (!data.hasPrefix()) {
msg.send(player, "prefix-no-prefix"); msg.send(player, "prefix-no-prefix");
return true; return true;
} }
data.setPrefixEnabled(true); data.setPrefixEnabled(true);
if (module.getLuckPermsHook() != null) { if (module.getLuckPermsHook() != null) {
module.getLuckPermsHook().setPrefix(player, DisplayNameUtil.buildColoredPrefix(module, data)); module.getLuckPermsHook().setPrefix(player, DisplayNameUtil.buildColoredPrefix(module, data));
@ -106,12 +105,12 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
private boolean handleReset(Player player, String[] args) { private boolean handleReset(Player player, String[] args) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
GradientMessages msg = module.getMessages(); GradientMessages msg = module.getMessages();
if (!data.hasPrefix()) { if (!data.hasPrefix()) {
msg.send(player, "prefix-no-prefix"); msg.send(player, "prefix-no-prefix");
return true; return true;
} }
data.setPrefix(null); data.setPrefix(null);
data.setPrefixEnabled(false); data.setPrefixEnabled(false);
if (module.getLuckPermsHook() != null) { if (module.getLuckPermsHook() != null) {
@ -154,7 +153,7 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
if (!player.hasPermission("gradient.bypass.cooldown") && if (!player.hasPermission("gradient.bypass.cooldown") &&
!checkCooldown(player, cfg.getPrefixCooldown(), data.getLastPrefixChange())) { !checkCooldown(player, cfg.getPrefixCooldown(), data.getLastPrefixChange())) {
return true; return true;
} }
@ -165,9 +164,9 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
return true; return true;
} }
GradientConfirmGUI gui = new GradientConfirmGUI(module, player, GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
GradientConfirmGUI.ConfirmType.PREFIX, GradientConfirmGUI.ConfirmType.PREFIX,
data.hasColors() && data.isColorEnabled() ? data.getColors() : null, data.hasColors() && data.isColorEnabled() ? data.getColors() : null,
prefix, price); prefix, price);
FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open); FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open);
return true; return true;
@ -203,15 +202,15 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
} }
private void saveAndUpdate(Player player, GradientPlayerData data) { private void saveAndUpdate(Player player, GradientPlayerData data) {
FoliaUtil.runEntityTask(module.getPlugin(), player, FoliaUtil.runEntityTask(module.getPlugin(), player,
() -> DisplayNameUtil.updateDisplayName(module, player, data)); () -> DisplayNameUtil.updateDisplayName(module, player, data));
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(player.getUniqueId())); () -> module.getDataManager().savePlayerData(player.getUniqueId()));
} }
@Override @Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) { @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) { if (args.length == 1) {
return SUB_COMMANDS.stream() return SUB_COMMANDS.stream()
.filter(s -> s.startsWith(args[0].toLowerCase())) .filter(s -> s.startsWith(args[0].toLowerCase()))

View file

@ -33,7 +33,7 @@ public class GradientConfig {
plugin.saveResource("gradient-config.yml", false); plugin.saveResource("gradient-config.yml", false);
} }
config = YamlConfiguration.loadConfiguration(configFile); config = YamlConfiguration.loadConfiguration(configFile);
// Загружаем дефолты // Загружаем дефолты
InputStream defStream = plugin.getResource("gradient-config.yml"); InputStream defStream = plugin.getResource("gradient-config.yml");
if (defStream != null) { if (defStream != null) {
@ -56,23 +56,70 @@ public class GradientConfig {
} }
} }
public boolean isEnabled() { return config.getBoolean("enabled", true); } public boolean isEnabled() {
public int getMaxColors() { return config.getInt("max-colors", 7); } return config.getBoolean("enabled", true);
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 int getMaxColors() {
public boolean isPrefixOneTimePurchase() { return config.getBoolean("prefix-one-time-purchase", true); } return config.getInt("max-colors", 7);
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 int getMinColors() {
public String getPrefixFormat() { return config.getString("prefix-format", "[{prefix}] "); } return config.getInt("min-colors", 1);
public boolean isGradientOnPrefix() { return config.getBoolean("gradient-on-prefix", true); } }
public boolean isGradientOnLuckPermsPrefix() { return config.getBoolean("gradient-on-luckperms-prefix", true); }
public boolean isContinuousGradient() { return config.getBoolean("continuous-gradient", true); } public int getPricePerColor() {
public boolean isUseLegacyRgbFormat() { return config.getBoolean("use-legacy-rgb-format", true); } return config.getInt("price-per-color", 50);
public String getStorageType() { return config.getString("storage-type", "YAML"); } }
public String getSqliteFile() { return config.getString("sqlite-file", "gradient-data.db"); }
public int getPrefixPrice() {
return config.getInt("prefix-price", 500);
}
public boolean isPrefixOneTimePurchase() {
return config.getBoolean("prefix-one-time-purchase", true);
}
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 isGradientOnLuckPermsPrefix() {
return config.getBoolean("gradient-on-luckperms-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", "gradient-data.db");
}
public List<String> getPrefixBlacklist() { public List<String> getPrefixBlacklist() {
return config.getStringList("prefix-blacklist"); return config.getStringList("prefix-blacklist");
} }
@ -83,17 +130,17 @@ public class GradientConfig {
.anyMatch(blacklisted -> lowerPrefix.contains(blacklisted.toLowerCase())); .anyMatch(blacklisted -> lowerPrefix.contains(blacklisted.toLowerCase()));
} }
public boolean isUpdateDisplayName() { public boolean isUpdateDisplayName() {
if (mainConfig.contains("display.update-display-name")) { if (mainConfig.contains("display.update-display-name")) {
return mainConfig.getBoolean("display.update-display-name", true); return mainConfig.getBoolean("display.update-display-name", true);
} }
return config.getBoolean("display.update-display-name", true); return config.getBoolean("display.update-display-name", true);
} }
public boolean isUpdateTabList() { public boolean isUpdateTabList() {
if (mainConfig.contains("display.update-tab-list")) { if (mainConfig.contains("display.update-tab-list")) {
return mainConfig.getBoolean("display.update-tab-list", true); return mainConfig.getBoolean("display.update-tab-list", true);
} }
return config.getBoolean("display.update-tab-list", true); return config.getBoolean("display.update-tab-list", true);
} }
} }

View file

@ -32,7 +32,7 @@ public class GradientMessages {
plugin.saveResource("gradient-messages.yml", false); plugin.saveResource("gradient-messages.yml", false);
} }
messages = YamlConfiguration.loadConfiguration(messagesFile); messages = YamlConfiguration.loadConfiguration(messagesFile);
InputStream defStream = plugin.getResource("gradient-messages.yml"); InputStream defStream = plugin.getResource("gradient-messages.yml");
if (defStream != null) { if (defStream != null) {
YamlConfiguration defConfig = YamlConfiguration.loadConfiguration( YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(

View file

@ -28,7 +28,7 @@ public class GradientDataManager {
this.plugin = plugin; this.plugin = plugin;
this.config = config; this.config = config;
this.useSqlite = config.getStorageType().equalsIgnoreCase("SQLITE"); this.useSqlite = config.getStorageType().equalsIgnoreCase("SQLITE");
if (useSqlite) { if (useSqlite) {
initSqlite(); initSqlite();
} else { } else {
@ -40,20 +40,20 @@ public class GradientDataManager {
try { try {
File dbFile = new File(plugin.getDataFolder(), config.getSqliteFile()); File dbFile = new File(plugin.getDataFolder(), config.getSqliteFile());
sqliteConnection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath()); sqliteConnection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
try (Statement stmt = sqliteConnection.createStatement()) { try (Statement stmt = sqliteConnection.createStatement()) {
stmt.executeUpdate(""" stmt.executeUpdate("""
CREATE TABLE IF NOT EXISTS gradient_data ( CREATE TABLE IF NOT EXISTS gradient_data (
uuid TEXT PRIMARY KEY, uuid TEXT PRIMARY KEY,
prefix TEXT, prefix TEXT,
colors TEXT, colors TEXT,
color_enabled INTEGER DEFAULT 1, color_enabled INTEGER DEFAULT 1,
prefix_enabled INTEGER DEFAULT 1, prefix_enabled INTEGER DEFAULT 1,
prefix_purchased INTEGER DEFAULT 0, prefix_purchased INTEGER DEFAULT 0,
last_color_change INTEGER DEFAULT 0, last_color_change INTEGER DEFAULT 0,
last_prefix_change INTEGER DEFAULT 0 last_prefix_change INTEGER DEFAULT 0
) )
"""); """);
} }
plugin.getLogger().info("Gradient SQLite база данных инициализирована."); plugin.getLogger().info("Gradient SQLite база данных инициализирована.");
} catch (SQLException e) { } catch (SQLException e) {
@ -65,7 +65,7 @@ public class GradientDataManager {
private void loadYamlData() { private void loadYamlData() {
File dataFile = new File(plugin.getDataFolder(), "gradient-data.yml"); File dataFile = new File(plugin.getDataFolder(), "gradient-data.yml");
if (!dataFile.exists()) return; if (!dataFile.exists()) return;
FileConfiguration data = YamlConfiguration.loadConfiguration(dataFile); FileConfiguration data = YamlConfiguration.loadConfiguration(dataFile);
for (String uuidStr : data.getKeys(false)) { for (String uuidStr : data.getKeys(false)) {
try { try {
@ -79,7 +79,8 @@ public class GradientDataManager {
playerData.setLastColorChange(data.getLong(uuidStr + ".last-color-change", 0)); playerData.setLastColorChange(data.getLong(uuidStr + ".last-color-change", 0));
playerData.setLastPrefixChange(data.getLong(uuidStr + ".last-prefix-change", 0)); playerData.setLastPrefixChange(data.getLong(uuidStr + ".last-prefix-change", 0));
cache.put(uuid, playerData); cache.put(uuid, playerData);
} catch (IllegalArgumentException ignored) {} } catch (IllegalArgumentException ignored) {
}
} }
} }
@ -89,7 +90,7 @@ public class GradientDataManager {
private GradientPlayerData loadPlayerData(UUID uuid) { private GradientPlayerData loadPlayerData(UUID uuid) {
GradientPlayerData data = new GradientPlayerData(uuid); GradientPlayerData data = new GradientPlayerData(uuid);
if (useSqlite && sqliteConnection != null) { if (useSqlite && sqliteConnection != null) {
try (PreparedStatement stmt = sqliteConnection.prepareStatement( try (PreparedStatement stmt = sqliteConnection.prepareStatement(
"SELECT prefix, colors, color_enabled, prefix_enabled, prefix_purchased, last_color_change, last_prefix_change FROM gradient_data WHERE uuid = ?")) { "SELECT prefix, colors, color_enabled, prefix_enabled, prefix_purchased, last_color_change, last_prefix_change FROM gradient_data WHERE uuid = ?")) {
@ -111,14 +112,14 @@ public class GradientDataManager {
plugin.getLogger().warning("Ошибка загрузки gradient данных: " + e.getMessage()); plugin.getLogger().warning("Ошибка загрузки gradient данных: " + e.getMessage());
} }
} }
return data; return data;
} }
public void savePlayerData(UUID uuid) { public void savePlayerData(UUID uuid) {
GradientPlayerData data = cache.get(uuid); GradientPlayerData data = cache.get(uuid);
if (data == null) return; if (data == null) return;
if (useSqlite && sqliteConnection != null) { if (useSqlite && sqliteConnection != null) {
try (PreparedStatement stmt = sqliteConnection.prepareStatement( try (PreparedStatement stmt = sqliteConnection.prepareStatement(
"INSERT OR REPLACE INTO gradient_data (uuid, prefix, colors, color_enabled, prefix_enabled, prefix_purchased, last_color_change, last_prefix_change) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")) { "INSERT OR REPLACE INTO gradient_data (uuid, prefix, colors, color_enabled, prefix_enabled, prefix_purchased, last_color_change, last_prefix_change) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")) {
@ -150,7 +151,7 @@ public class GradientDataManager {
private void saveYamlData() { private void saveYamlData() {
File dataFile = new File(plugin.getDataFolder(), "gradient-data.yml"); File dataFile = new File(plugin.getDataFolder(), "gradient-data.yml");
FileConfiguration data = new YamlConfiguration(); FileConfiguration data = new YamlConfiguration();
for (Map.Entry<UUID, GradientPlayerData> entry : cache.entrySet()) { for (Map.Entry<UUID, GradientPlayerData> entry : cache.entrySet()) {
String path = entry.getKey().toString(); String path = entry.getKey().toString();
GradientPlayerData pd = entry.getValue(); GradientPlayerData pd = entry.getValue();
@ -162,7 +163,7 @@ public class GradientDataManager {
data.set(path + ".last-color-change", pd.getLastColorChange()); data.set(path + ".last-color-change", pd.getLastColorChange());
data.set(path + ".last-prefix-change", pd.getLastPrefixChange()); data.set(path + ".last-prefix-change", pd.getLastPrefixChange());
} }
try { try {
data.save(dataFile); data.save(dataFile);
} catch (IOException e) { } catch (IOException e) {

View file

@ -29,25 +29,71 @@ public class GradientPlayerData {
this.lastPrefixChange = 0; this.lastPrefixChange = 0;
} }
public UUID getUuid() { return uuid; } public UUID getUuid() {
public String getPrefix() { return prefix; } return uuid;
public void setPrefix(String prefix) { this.prefix = prefix; } }
public List<String> getColors() { return colors; }
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) { public void setColors(List<String> colors) {
this.colors = colors != null ? new ArrayList<>(colors) : new ArrayList<>(); this.colors = colors != null ? new ArrayList<>(colors) : new ArrayList<>();
} }
public boolean hasPrefix() { return prefix != null && !prefix.isEmpty(); } public boolean hasPrefix() {
public boolean hasColors() { return colors != null && !colors.isEmpty(); } return prefix != null && !prefix.isEmpty();
public boolean isColorEnabled() { return colorEnabled; } }
public void setColorEnabled(boolean colorEnabled) { this.colorEnabled = colorEnabled; }
public boolean isPrefixEnabled() { return prefixEnabled; } public boolean hasColors() {
public void setPrefixEnabled(boolean prefixEnabled) { this.prefixEnabled = prefixEnabled; } return colors != null && !colors.isEmpty();
public boolean isPrefixPurchased() { return prefixPurchased; } }
public void setPrefixPurchased(boolean prefixPurchased) { this.prefixPurchased = prefixPurchased; }
public long getLastColorChange() { return lastColorChange; } public boolean isColorEnabled() {
public void setLastColorChange(long lastColorChange) { this.lastColorChange = lastColorChange; } return colorEnabled;
public long getLastPrefixChange() { return lastPrefixChange; } }
public void setLastPrefixChange(long lastPrefixChange) { this.lastPrefixChange = lastPrefixChange; }
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;
}
} }

View file

@ -23,27 +23,22 @@ import java.util.List;
/** /**
* GUI подтверждения для градиентного модуля * GUI подтверждения для градиентного модуля
*/ */
public class GradientConfirmGUI implements InventoryHolder { public final class GradientConfirmGUI implements InventoryHolder {
public enum ConfirmType {
COLOR, PREFIX
}
private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder() private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder()
.character('&') .character('&')
.hexCharacter('#') .hexCharacter('#')
.hexColors() .hexColors()
.build(); .build();
private final GradientModule module; private final GradientModule module;
private final Player player; private final Player player;
private final Inventory inventory; private Inventory inventory;
private final ConfirmType type; private final ConfirmType type;
private final List<String> colors; private final List<String> colors;
private final String prefix; private final String prefix;
private final int price; private final int price;
public GradientConfirmGUI(GradientModule module, Player player, ConfirmType type, public GradientConfirmGUI(GradientModule module, Player player, ConfirmType type,
List<String> colors, String prefix, int price) { List<String> colors, String prefix, int price) {
this.module = module; this.module = module;
this.player = player; this.player = player;
@ -51,7 +46,11 @@ public class GradientConfirmGUI implements InventoryHolder {
this.colors = colors; this.colors = colors;
this.prefix = prefix; this.prefix = prefix;
this.price = price; this.price = price;
this.inventory = Bukkit.createInventory(this, 27, }
private void initInventory() {
if (inventory != null) return;
this.inventory = Bukkit.createInventory(this, 27,
Component.text("Подтверждение", NamedTextColor.DARK_GRAY)); Component.text("Подтверждение", NamedTextColor.DARK_GRAY));
setupItems(); setupItems();
} }
@ -65,12 +64,12 @@ public class GradientConfirmGUI implements InventoryHolder {
ItemStack head = new ItemStack(Material.PLAYER_HEAD); ItemStack head = new ItemStack(Material.PLAYER_HEAD);
SkullMeta skullMeta = (SkullMeta) head.getItemMeta(); SkullMeta skullMeta = (SkullMeta) head.getItemMeta();
skullMeta.setOwningPlayer(player); skullMeta.setOwningPlayer(player);
String preview = buildPreview(); String preview = buildPreview();
// Для GUI используем LegacyComponentSerializer с поддержкой HEX // Для GUI используем LegacyComponentSerializer с поддержкой HEX
Component previewComponent = SERIALIZER.deserialize(preview); Component previewComponent = SERIALIZER.deserialize(preview);
skullMeta.displayName(previewComponent.decoration(TextDecoration.ITALIC, false)); skullMeta.displayName(previewComponent.decoration(TextDecoration.ITALIC, false));
List<Component> lore = new ArrayList<>(); List<Component> lore = new ArrayList<>();
lore.add(Component.empty()); lore.add(Component.empty());
lore.add(Component.text("Так будет выглядеть ваш ник", NamedTextColor.GRAY) lore.add(Component.text("Так будет выглядеть ваш ник", NamedTextColor.GRAY)
@ -134,7 +133,7 @@ public class GradientConfirmGUI implements InventoryHolder {
if (lpPrefix != null && !lpPrefix.isEmpty()) { if (lpPrefix != null && !lpPrefix.isEmpty()) {
// Конвертируем LP префикс в legacy формат // Конвертируем LP префикс в legacy формат
lpPrefix = convertToLegacy(lpPrefix); lpPrefix = convertToLegacy(lpPrefix);
// Если градиент на LP префикс включен - применяем градиент на всю строку // Если градиент на LP префикс включен - применяем градиент на всю строку
if (colorsToUse != null && !colorsToUse.isEmpty() && module.getConfig().isGradientOnLuckPermsPrefix()) { if (colorsToUse != null && !colorsToUse.isEmpty() && module.getConfig().isGradientOnLuckPermsPrefix()) {
String cleanLpPrefix = stripColors(lpPrefix); String cleanLpPrefix = stripColors(lpPrefix);
@ -187,14 +186,37 @@ public class GradientConfirmGUI implements InventoryHolder {
} }
public void open() { public void open() {
initInventory();
player.openInventory(inventory); player.openInventory(inventory);
} }
@Override @Override
public @NotNull Inventory getInventory() { return inventory; } public @NotNull Inventory getInventory() {
public Player getPlayer() { return player; } initInventory();
public ConfirmType getType() { return type; } return inventory;
public List<String> getColors() { return colors; } }
public String getPrefix() { return prefix; }
public int getPrice() { return price; } 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;
}
public enum ConfirmType {
COLOR, PREFIX
}
} }

View file

@ -22,7 +22,7 @@ public class GradientLuckPermsHook {
public GradientLuckPermsHook(JavaPlugin plugin) { public GradientLuckPermsHook(JavaPlugin plugin) {
this.enabled = false; this.enabled = false;
if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) { if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) {
try { try {
this.luckPerms = LuckPermsProvider.get(); this.luckPerms = LuckPermsProvider.get();
@ -40,12 +40,12 @@ public class GradientLuckPermsHook {
public void setPrefix(Player player, String prefix) { public void setPrefix(Player player, String prefix) {
if (!isEnabled()) return; if (!isEnabled()) return;
User user = luckPerms.getUserManager().getUser(player.getUniqueId()); User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) return; if (user == null) return;
user.data().clear(node -> user.data().clear(node ->
node instanceof PrefixNode && ((PrefixNode) node).getPriority() == GradientConstants.LUCKPERMS_PREFIX_PRIORITY node instanceof PrefixNode && ((PrefixNode) node).getPriority() == GradientConstants.LUCKPERMS_PREFIX_PRIORITY
); );
if (prefix != null && !prefix.isEmpty()) { if (prefix != null && !prefix.isEmpty()) {
@ -58,12 +58,12 @@ public class GradientLuckPermsHook {
public void setPrefix(UUID uuid, String prefix) { public void setPrefix(UUID uuid, String prefix) {
if (!isEnabled()) return; if (!isEnabled()) return;
luckPerms.getUserManager().loadUser(uuid).thenAccept(user -> { luckPerms.getUserManager().loadUser(uuid).thenAccept(user -> {
if (user == null) return; if (user == null) return;
user.data().clear(node -> user.data().clear(node ->
node instanceof PrefixNode && ((PrefixNode) node).getPriority() == GradientConstants.LUCKPERMS_PREFIX_PRIORITY node instanceof PrefixNode && ((PrefixNode) node).getPriority() == GradientConstants.LUCKPERMS_PREFIX_PRIORITY
); );
if (prefix != null && !prefix.isEmpty()) { if (prefix != null && !prefix.isEmpty()) {
@ -85,10 +85,10 @@ public class GradientLuckPermsHook {
public String getActivePrefix(Player player) { public String getActivePrefix(Player player) {
if (!isEnabled()) return null; if (!isEnabled()) return null;
User user = luckPerms.getUserManager().getUser(player.getUniqueId()); User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) return null; if (user == null) return null;
CachedMetaData metaData = user.getCachedData().getMetaData(); CachedMetaData metaData = user.getCachedData().getMetaData();
return metaData.getPrefix(); return metaData.getPrefix();
} }

View file

@ -19,12 +19,11 @@ import java.util.Map;
*/ */
public class GradientGUIListener implements Listener { public class GradientGUIListener implements Listener {
private final GradientModule module;
private static final Map<GradientConfirmGUI.ConfirmType, String> PRICE_MSG_KEYS = Map.of( private static final Map<GradientConfirmGUI.ConfirmType, String> PRICE_MSG_KEYS = Map.of(
GradientConfirmGUI.ConfirmType.COLOR, "not-enough-points-color", GradientConfirmGUI.ConfirmType.COLOR, "not-enough-points-color",
GradientConfirmGUI.ConfirmType.PREFIX, "not-enough-points-prefix" GradientConfirmGUI.ConfirmType.PREFIX, "not-enough-points-prefix"
); );
private final GradientModule module;
public GradientGUIListener(GradientModule module) { public GradientGUIListener(GradientModule module) {
this.module = module; this.module = module;
@ -33,9 +32,9 @@ public class GradientGUIListener implements Listener {
@EventHandler @EventHandler
public void onInventoryClick(InventoryClickEvent event) { public void onInventoryClick(InventoryClickEvent event) {
if (!(event.getInventory().getHolder() instanceof GradientConfirmGUI gui)) return; if (!(event.getInventory().getHolder() instanceof GradientConfirmGUI gui)) return;
event.setCancelled(true); event.setCancelled(true);
if (!(event.getWhoClicked() instanceof Player player) || !player.equals(gui.getPlayer())) return; if (!(event.getWhoClicked() instanceof Player player) || !player.equals(gui.getPlayer())) return;
switch (event.getRawSlot()) { switch (event.getRawSlot()) {
@ -46,10 +45,10 @@ public class GradientGUIListener implements Listener {
private void handleConfirm(Player player, GradientConfirmGUI gui) { private void handleConfirm(Player player, GradientConfirmGUI gui) {
player.closeInventory(); player.closeInventory();
GradientMessages msg = module.getMessages(); GradientMessages msg = module.getMessages();
int price = gui.getPrice(); int price = gui.getPrice();
if (price > 0 && !player.hasPermission("gradient.bypass.cost")) { if (price > 0 && !player.hasPermission("gradient.bypass.cost")) {
if (!module.hasPlayerPoints()) { if (!module.hasPlayerPoints()) {
player.sendMessage("§cPlayerPoints не установлен!"); player.sendMessage("§cPlayerPoints не установлен!");
@ -85,14 +84,14 @@ public class GradientGUIListener implements Listener {
if (module.getLuckPermsHook() != null) { if (module.getLuckPermsHook() != null) {
module.getLuckPermsHook().setPrefix(player, DisplayNameUtil.buildColoredPrefix(module, data)); module.getLuckPermsHook().setPrefix(player, DisplayNameUtil.buildColoredPrefix(module, data));
} }
msg.send(player, price > 0 ? "prefix-success" : "prefix-success-free", msg.send(player, price > 0 ? "prefix-success" : "prefix-success-free",
"price", String.valueOf(price)); "price", String.valueOf(price));
} }
} }
FoliaUtil.runEntityTask(module.getPlugin(), player, FoliaUtil.runEntityTask(module.getPlugin(), player,
() -> DisplayNameUtil.updateDisplayName(module, player, data)); () -> DisplayNameUtil.updateDisplayName(module, player, data));
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(player.getUniqueId())); () -> module.getDataManager().savePlayerData(player.getUniqueId()));
} }

View file

@ -31,7 +31,7 @@ public class GradientPlayerListener implements Listener {
@EventHandler @EventHandler
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
FoliaUtil.runAsync(module.getPlugin(), FoliaUtil.runAsync(module.getPlugin(),
() -> module.getDataManager().savePlayerData(player.getUniqueId())); () -> module.getDataManager().savePlayerData(player.getUniqueId()));
} }
} }

View file

@ -21,13 +21,14 @@ public final class DisplayNameUtil {
.hexColors() .hexColors()
.build(); .build();
private DisplayNameUtil() {} private DisplayNameUtil() {
}
public static void updateDisplayName(GradientModule module, Player player, GradientPlayerData data) { public static void updateDisplayName(GradientModule module, Player player, GradientPlayerData data) {
GradientConfig cfg = module.getConfig(); GradientConfig cfg = module.getConfig();
String prefix = null; String prefix = null;
String prefixFormat = cfg.getPrefixFormat(); String prefixFormat = cfg.getPrefixFormat();
// Определяем префикс: сначала кастомный, потом LuckPerms // Определяем префикс: сначала кастомный, потом LuckPerms
if (data.isPrefixEnabled() && data.hasPrefix()) { if (data.isPrefixEnabled() && data.hasPrefix()) {
// Есть кастомный префикс // Есть кастомный префикс
@ -37,9 +38,9 @@ public final class DisplayNameUtil {
String lpPrefix = module.getLuckPermsHook().getActivePrefix(player); String lpPrefix = module.getLuckPermsHook().getActivePrefix(player);
if (lpPrefix != null && !lpPrefix.isEmpty()) { if (lpPrefix != null && !lpPrefix.isEmpty()) {
String displayName = buildWithLuckPermsPrefix( String displayName = buildWithLuckPermsPrefix(
lpPrefix, lpPrefix,
player.getName(), player.getName(),
data.isColorEnabled() ? data.getColors() : null, data.isColorEnabled() ? data.getColors() : null,
cfg.isUseLegacyRgbFormat(), cfg.isUseLegacyRgbFormat(),
cfg.isContinuousGradient() cfg.isContinuousGradient()
); );
@ -51,7 +52,7 @@ public final class DisplayNameUtil {
return; return;
} }
} }
// Строим display name с кастомным префиксом или без префикса // Строим display name с кастомным префиксом или без префикса
String displayName = GradientUtil.buildDisplayName( String displayName = GradientUtil.buildDisplayName(
prefix, prefix,
@ -62,7 +63,7 @@ public final class DisplayNameUtil {
prefixFormat, prefixFormat,
cfg.isUseLegacyRgbFormat() cfg.isUseLegacyRgbFormat()
); );
// Для display name нужен §x формат, конвертируем MiniMessage в legacy // Для display name нужен §x формат, конвертируем MiniMessage в legacy
displayName = convertMiniMessageToLegacy(displayName); displayName = convertMiniMessageToLegacy(displayName);
var component = SERIALIZER.deserialize(displayName); var component = SERIALIZER.deserialize(displayName);
@ -75,12 +76,12 @@ public final class DisplayNameUtil {
*/ */
private static String convertMiniMessageToLegacy(String text) { private static String convertMiniMessageToLegacy(String text) {
if (text == null) return ""; if (text == null) return "";
// Конвертируем <#RRGGBB> в §x§R§R§G§G§B§B // Конвертируем <#RRGGBB> в §x§R§R§G§G§B§B
Pattern pattern = Pattern.compile("<#([0-9a-fA-F]{6})>"); Pattern pattern = Pattern.compile("<#([0-9a-fA-F]{6})>");
Matcher matcher = pattern.matcher(text); Matcher matcher = pattern.matcher(text);
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
while (matcher.find()) { while (matcher.find()) {
String hex = matcher.group(1).toLowerCase(); String hex = matcher.group(1).toLowerCase();
StringBuilder replacement = new StringBuilder("§x"); StringBuilder replacement = new StringBuilder("§x");
@ -90,18 +91,18 @@ public final class DisplayNameUtil {
matcher.appendReplacement(sb, replacement.toString()); matcher.appendReplacement(sb, replacement.toString());
} }
matcher.appendTail(sb); matcher.appendTail(sb);
return sb.toString(); return sb.toString();
} }
private static String buildWithLuckPermsPrefix(String lpPrefix, String nick, private static String buildWithLuckPermsPrefix(String lpPrefix, String nick,
List<String> colors, List<String> colors,
boolean useLegacyFormat, boolean useLegacyFormat,
boolean continuousGradient) { boolean continuousGradient) {
if (colors == null || colors.isEmpty()) { if (colors == null || colors.isEmpty()) {
return lpPrefix + nick; return lpPrefix + nick;
} }
if (continuousGradient) { if (continuousGradient) {
String cleanPrefix = stripColors(lpPrefix); String cleanPrefix = stripColors(lpPrefix);
String fullText = cleanPrefix + nick; String fullText = cleanPrefix + nick;
@ -118,15 +119,15 @@ public final class DisplayNameUtil {
public static String buildColoredPrefix(GradientModule module, GradientPlayerData data) { public static String buildColoredPrefix(GradientModule module, GradientPlayerData data) {
if (!data.hasPrefix() || !data.isPrefixEnabled()) return null; if (!data.hasPrefix() || !data.isPrefixEnabled()) return null;
GradientConfig cfg = module.getConfig(); GradientConfig cfg = module.getConfig();
String prefix = cfg.getPrefixFormat().replace("{prefix}", data.getPrefix()).stripTrailing(); String prefix = cfg.getPrefixFormat().replace("{prefix}", data.getPrefix()).stripTrailing();
// Применяем градиент только если цвета включены И есть цвета // Применяем градиент только если цвета включены И есть цвета
if (data.hasColors() && data.isColorEnabled() && cfg.isGradientOnPrefix()) { if (data.hasColors() && data.isColorEnabled() && cfg.isGradientOnPrefix()) {
return GradientUtil.applyGradient(prefix, data.getColors(), cfg.isUseLegacyRgbFormat()); return GradientUtil.applyGradient(prefix, data.getColors(), cfg.isUseLegacyRgbFormat());
} }
// Возвращаем префикс без цветов // Возвращаем префикс без цветов
return prefix; return prefix;
} }
@ -137,12 +138,12 @@ public final class DisplayNameUtil {
public static String getFullDisplayName(GradientModule module, Player player) { public static String getFullDisplayName(GradientModule module, Player player) {
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId()); GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
GradientConfig cfg = module.getConfig(); GradientConfig cfg = module.getConfig();
String prefix = null; String prefix = null;
if (data.isPrefixEnabled() && data.hasPrefix()) { if (data.isPrefixEnabled() && data.hasPrefix()) {
prefix = data.getPrefix(); prefix = data.getPrefix();
} }
return GradientUtil.buildDisplayName( return GradientUtil.buildDisplayName(
prefix, prefix,
player.getName(), player.getName(),

View file

@ -17,7 +17,8 @@ public final class FoliaUtil {
IS_FOLIA = checkFolia(); IS_FOLIA = checkFolia();
} }
private FoliaUtil() {} private FoliaUtil() {
}
private static boolean checkFolia() { private static boolean checkFolia() {
try { try {

View file

@ -5,15 +5,14 @@ package com.loki.lochat.gradient.util;
*/ */
public final class GradientConstants { public final class GradientConstants {
private GradientConstants() {}
public static final long MILLIS_PER_SECOND = 1000L; public static final long MILLIS_PER_SECOND = 1000L;
// GUI слоты // GUI слоты
public static final int GUI_CONFIRM_SLOT = 11; public static final int GUI_CONFIRM_SLOT = 11;
public static final int GUI_CANCEL_SLOT = 15; public static final int GUI_CANCEL_SLOT = 15;
public static final int GUI_PREVIEW_SLOT = 13; public static final int GUI_PREVIEW_SLOT = 13;
// LuckPerms // LuckPerms
public static final int LUCKPERMS_PREFIX_PRIORITY = 100; public static final int LUCKPERMS_PREFIX_PRIORITY = 100;
private GradientConstants() {
}
} }

View file

@ -11,7 +11,8 @@ public final class GradientUtil {
private static final Pattern HEX_PATTERN = Pattern.compile("^#[0-9A-Fa-f]{6}$"); private static final Pattern HEX_PATTERN = Pattern.compile("^#[0-9A-Fa-f]{6}$");
private GradientUtil() {} private GradientUtil() {
}
public static boolean isValidHex(String color) { public static boolean isValidHex(String color) {
return HEX_PATTERN.matcher(color).matches(); return HEX_PATTERN.matcher(color).matches();
@ -50,7 +51,7 @@ public final class GradientUtil {
// Вычисляем позицию символа от 0.0 до 1.0 // Вычисляем позицию символа от 0.0 до 1.0
double ratio = length > 1 ? (double) i / (length - 1) : 0.0; double ratio = length > 1 ? (double) i / (length - 1) : 0.0;
Color interpolated = interpolateMultiColor(colors, ratio); Color interpolated = interpolateMultiColor(colors, ratio);
String hex = String.format("#%02x%02x%02x", String hex = String.format("#%02x%02x%02x",
interpolated.getRed(), interpolated.getGreen(), interpolated.getBlue()); interpolated.getRed(), interpolated.getGreen(), interpolated.getBlue());
result.append(formatHex(hex, useLegacyFormat)).append(chars[i]); result.append(formatHex(hex, useLegacyFormat)).append(chars[i]);
} }
@ -142,7 +143,7 @@ public final class GradientUtil {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
double ratio = length > 1 ? (double) i / (length - 1) : 0.0; double ratio = length > 1 ? (double) i / (length - 1) : 0.0;
Color interpolated = interpolateMultiColor(colors, ratio); Color interpolated = interpolateMultiColor(colors, ratio);
String hex = String.format("#%02x%02x%02x", String hex = String.format("#%02x%02x%02x",
interpolated.getRed(), interpolated.getGreen(), interpolated.getBlue()); interpolated.getRed(), interpolated.getGreen(), interpolated.getBlue());
result.append(formatHexForTab(hex)).append(chars[i]); result.append(formatHexForTab(hex)).append(chars[i]);
} }
@ -151,8 +152,8 @@ public final class GradientUtil {
return result.toString(); return result.toString();
} }
public static String buildDisplayName(String prefix, String nick, List<String> colors, public static String buildDisplayName(String prefix, String nick, List<String> colors,
boolean gradientOnPrefix, boolean continuousGradient, boolean gradientOnPrefix, boolean continuousGradient,
String prefixFormat, boolean useLegacyFormat) { String prefixFormat, boolean useLegacyFormat) {
if (colors == null || colors.isEmpty()) { if (colors == null || colors.isEmpty()) {
if (prefix != null && !prefix.isEmpty()) { if (prefix != null && !prefix.isEmpty()) {

View file

@ -16,7 +16,7 @@ public class LibertyBansHook {
public LibertyBansHook(LoChat plugin) { public LibertyBansHook(LoChat plugin) {
this.plugin = plugin; this.plugin = plugin;
this.muteService = plugin.getServiceRegistry().get(MuteService.class); this.muteService = plugin.getServiceRegistry().get(MuteService.class);
// Проверяем наличие LibertyBans // Проверяем наличие LibertyBans
if (plugin.getServer().getPluginManager().getPlugin("LibertyBans") != null) { if (plugin.getServer().getPluginManager().getPlugin("LibertyBans") != null) {
plugin.getLogger().info("LibertyBans обнаружен. Используйте встроенную систему мутов LoChat (/lmute, /lunmute)"); plugin.getLogger().info("LibertyBans обнаружен. Используйте встроенную систему мутов LoChat (/lmute, /lunmute)");

Some files were not shown because too many files have changed in this diff Show more