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

@ -29,10 +29,14 @@ public class HubProtectionListener implements Listener {
@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);
@ -41,10 +45,14 @@ public class HubProtectionListener implements Listener {
@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);
@ -53,12 +61,20 @@ public class HubProtectionListener implements Listener {
@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);
@ -67,10 +83,14 @@ public class HubProtectionListener implements Listener {
@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);
@ -79,10 +99,14 @@ public class HubProtectionListener implements Listener {
@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);
@ -91,11 +115,17 @@ public class HubProtectionListener implements Listener {
@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,9 +20,33 @@ 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) {
@ -140,7 +164,7 @@ public class PlayerJoinListener implements Listener {
} }
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");
@ -176,26 +200,7 @@ public class PlayerJoinListener implements Listener {
} }
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) {

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;
@ -13,8 +22,8 @@ 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;

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;
@ -12,8 +14,8 @@ 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;
@ -67,23 +69,7 @@ public class RegionManager {
); );
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);
@ -96,6 +82,17 @@ public class RegionManager {
} }
} }
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;

View file

@ -53,6 +53,10 @@ public class SpawnManager {
} }
} }
public Location getSpawn() {
return spawnLocation;
}
public void setSpawn(Location location) { public void setSpawn(Location location) {
this.spawnLocation = location; this.spawnLocation = location;
@ -72,10 +76,6 @@ public class SpawnManager {
} }
} }
public Location getSpawn() {
return spawnLocation;
}
public void teleportToSpawn(Player player) { public void teleportToSpawn(Player player) {
if (spawnLocation == null) { if (spawnLocation == null) {
return; return;

View file

@ -9,7 +9,6 @@ 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;
@ -69,7 +68,8 @@ public class ItemBuilder {
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) {
}
}); });
} }
@ -123,7 +123,7 @@ public class ItemBuilder {
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);
} }

View file

@ -9,6 +9,10 @@ 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");
} }

View file

@ -11,6 +11,10 @@ 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;

View file

@ -1,5 +1,6 @@
plugins { plugins {
java java
checkstyle
} }
repositories { repositories {
@ -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

@ -31,6 +31,11 @@ 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;
@ -41,11 +46,11 @@ public final class LoChat extends JavaPlugin {
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);
// Интеграции // Интеграции
@ -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

@ -14,12 +14,14 @@ public interface IgnoreService {
/** /**
* Добавляет игрока в список игнорируемых * Добавляет игрока в список игнорируемых
*
* @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);

View file

@ -10,6 +10,7 @@ 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);

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,22 +13,30 @@ 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);
// Список активных мутов // Список активных мутов

View file

@ -12,6 +12,7 @@ public interface NickService {
/** /**
* Устанавливает кастомный ник игроку * Устанавливает кастомный ник игроку
*
* @param player UUID игрока * @param player UUID игрока
* @param nickname Новый ник (с поддержкой цветов и русских символов) * @param nickname Новый ник (с поддержкой цветов и русских символов)
* @return true если успешно, false если ник занят или невалиден * @return true если успешно, false если ник занят или невалиден
@ -20,12 +21,14 @@ public interface NickService {
/** /**
* Сбрасывает кастомный ник игрока * Сбрасывает кастомный ник игрока
*
* @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 если нет кастомного ника
*/ */
@ -33,6 +36,7 @@ public interface NickService {
/** /**
* Проверяет занят ли ник * Проверяет занят ли ник
*
* @param nickname Ник для проверки * @param nickname Ник для проверки
* @return true если ник уже используется * @return true если ник уже используется
*/ */
@ -40,6 +44,7 @@ public interface NickService {
/** /**
* Валидирует ник (длина, символы) * Валидирует ник (длина, символы)
*
* @param nickname Ник для проверки * @param nickname Ник для проверки
* @return true если ник валиден * @return true если ник валиден
*/ */
@ -47,6 +52,7 @@ public interface NickService {
/** /**
* Обновляет displayName и tabName игрока * Обновляет displayName и tabName игрока
*
* @param player Игрок * @param player Игрок
*/ */
void updatePlayerDisplay(Player player); void updatePlayerDisplay(Player 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,6 +9,7 @@ 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);

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;

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;

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;

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

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

@ -35,18 +35,18 @@ public class AdvancedMessageFilter {
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)) {
@ -138,27 +138,6 @@ 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,22 +13,20 @@ 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() {

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<>();
@ -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);
@ -123,10 +118,10 @@ public class MentionServiceImpl implements MentionService {
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;

View file

@ -231,13 +231,15 @@ public class MuteServiceImpl implements MuteService {
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) {
@ -249,13 +251,15 @@ public class MuteServiceImpl implements MuteService {
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) {

View file

@ -12,22 +12,23 @@ 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");
@ -154,11 +155,7 @@ public class NickServiceImpl implements NickService {
} }
// Проверка символов (разрешены буквы, цифры, _, русские буквы) // Проверка символов (разрешены буквы, цифры, _, русские буквы)
if (!cleanNick.matches("[a-zA-Zа-яА-Я0-9_]+")) { return cleanNick.matches("[a-zA-Zа-яА-Я0-9_]+");
return false;
}
return true;
} }
@Override @Override

View file

@ -7,9 +7,9 @@ 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;
@ -30,10 +30,27 @@ public class ChatMessage {
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,14 +6,15 @@ 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;
private String playerName;
public MuteData() {} // For JSON deserialization 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;
@ -32,13 +33,33 @@ public class MuteData {
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;
}
/** /**
* Запись истории мута * Запись истории мута
@ -53,7 +74,8 @@ public class MuteData {
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, public MuteHistoryEntry(String playerName, long duration, String reason,
String mutedBy, long mutedAt, boolean unmuted, String mutedBy, long mutedAt, boolean unmuted,

View file

@ -37,6 +37,7 @@ public class GradientModule {
/** /**
* Инициализация модуля * Инициализация модуля
*
* @return true если модуль успешно инициализирован * @return true если модуль успешно инициализирован
*/ */
public boolean init() { public boolean init() {
@ -141,6 +142,7 @@ 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) {
@ -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;

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;

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;

View file

@ -56,22 +56,69 @@ 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");

View file

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

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,21 +23,16 @@ 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;
@ -51,6 +46,10 @@ public class GradientConfirmGUI implements InventoryHolder {
this.colors = colors; this.colors = colors;
this.prefix = prefix; this.prefix = prefix;
this.price = price; this.price = price;
}
private void initInventory() {
if (inventory != null) return;
this.inventory = Bukkit.createInventory(this, 27, this.inventory = Bukkit.createInventory(this, 27,
Component.text("Подтверждение", NamedTextColor.DARK_GRAY)); Component.text("Подтверждение", NamedTextColor.DARK_GRAY));
setupItems(); setupItems();
@ -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

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

View file

@ -21,7 +21,8 @@ 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();

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

View file

@ -1,7 +1,10 @@
package com.loki.lochat.integrations; package com.loki.lochat.integrations;
import com.loki.lochat.LoChat; import com.loki.lochat.LoChat;
import com.loki.lochat.api.service.*; import com.loki.lochat.api.service.ChatService;
import com.loki.lochat.api.service.IgnoreService;
import com.loki.lochat.api.service.PMService;
import com.loki.lochat.api.service.SpyService;
import com.loki.lochat.gradient.GradientModule; import com.loki.lochat.gradient.GradientModule;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;

View file

@ -52,6 +52,7 @@ public class SkinsRestorerHook {
/** /**
* Получает текстуру скина игрока * Получает текстуру скина игрока
*
* @param player игрок * @param player игрок
* @return URL текстуры или null * @return URL текстуры или null
*/ */
@ -72,6 +73,7 @@ public class SkinsRestorerHook {
/** /**
* Получает URL головы игрока для отображения * Получает URL головы игрока для отображения
*
* @param playerName имя игрока * @param playerName имя игрока
* @return URL головы * @return URL головы
*/ */

View file

@ -5,8 +5,8 @@ import com.loki.lochat.core.filter.AdvancedMessageFilter;
import com.loki.lochat.core.registry.ServiceRegistry; import com.loki.lochat.core.registry.ServiceRegistry;
import com.loki.lochat.utils.MentionHandler; import com.loki.lochat.utils.MentionHandler;
import com.loki.lochat.utils.TextFormatter; import com.loki.lochat.utils.TextFormatter;
import io.papermc.paper.event.player.AsyncChatEvent;
import io.papermc.paper.chat.ChatRenderer; import io.papermc.paper.chat.ChatRenderer;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.audience.Audience; import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.ClickEvent;
@ -47,13 +47,13 @@ public class ChatEventListener implements Listener {
AdvancedMessageFilter.FilterResult filterResult = advancedFilter.filterMessage(sender, message); AdvancedMessageFilter.FilterResult filterResult = advancedFilter.filterMessage(sender, message);
if (!filterResult.isAllowed()) { if (!filterResult.allowed()) {
event.setCancelled(true); event.setCancelled(true);
sender.sendMessage(com.loki.lochat.utils.ChatFormatter.parse(filterResult.getBlockReason())); sender.sendMessage(com.loki.lochat.utils.ChatFormatter.parse(filterResult.blockReason()));
return; return;
} }
String filteredMessage = filterResult.getFilteredMessage(); String filteredMessage = filterResult.filteredMessage();
event.message(Component.text(filteredMessage)); event.message(Component.text(filteredMessage));
event.renderer(new EnhancedChatRenderer(sender, event.message())); event.renderer(new EnhancedChatRenderer(sender, event.message()));

View file

@ -24,14 +24,15 @@ public class CustomCommandManager {
private final LoChat plugin; private final LoChat plugin;
private final Map<String, CustomCommandData> commands; private final Map<String, CustomCommandData> commands;
public CustomCommandManager(LoChat plugin) { private CustomCommandManager(LoChat plugin) {
this.plugin = plugin; this.plugin = plugin;
this.commands = new HashMap<>(); this.commands = new HashMap<>();
init();
} }
private void init() { public static CustomCommandManager create(LoChat plugin) {
loadCommands(); CustomCommandManager manager = new CustomCommandManager(plugin);
manager.loadCommands();
return manager;
} }
private void loadCommands() { private void loadCommands() {
@ -263,22 +264,7 @@ public class CustomCommandManager {
return commands; return commands;
} }
public static class CustomCommandData { public record CustomCommandData(String name, String permission, String message, List<String> aliases, String type,
public final String name; String target) {
public final String permission;
public final String message;
public final List<String> aliases;
public final String type;
public final String target;
public CustomCommandData(String name, String permission, String message,
List<String> aliases, String type, String target) {
this.name = name;
this.permission = permission;
this.message = message;
this.aliases = aliases;
this.type = type;
this.target = target;
}
} }
} }

View file

@ -17,9 +17,14 @@ public class EmojiManager {
private boolean enabled; private boolean enabled;
private boolean requirePermission; private boolean requirePermission;
public EmojiManager(LoChat plugin) { private EmojiManager(LoChat plugin) {
this.plugin = plugin; this.plugin = plugin;
load(); }
public static EmojiManager create(LoChat plugin) {
EmojiManager manager = new EmojiManager(plugin);
manager.load();
return manager;
} }
public void load() { public void load() {

View file

@ -41,6 +41,7 @@ public class FoliaUtil {
/** /**
* Запускает глобальную повторяющуюся задачу * Запускает глобальную повторяющуюся задачу
*
* @param plugin плагин * @param plugin плагин
* @param task задача * @param task задача
* @param delayTicks задержка перед первым запуском (в тиках) * @param delayTicks задержка перед первым запуском (в тиках)

View file

@ -7,6 +7,7 @@ public class TimeParser {
/** /**
* Парсит строку времени в миллисекунды * Парсит строку времени в миллисекунды
*
* @param timeStr строка вида "1d", "2h", "30m", "60s" * @param timeStr строка вида "1d", "2h", "30m", "60s"
* @return миллисекунды или -1 при ошибке * @return миллисекунды или -1 при ошибке
*/ */

View file

@ -11,7 +11,8 @@ public final class ChatFormatter {
private static final PlainTextComponentSerializer PLAIN = private static final PlainTextComponentSerializer PLAIN =
PlainTextComponentSerializer.plainText(); PlainTextComponentSerializer.plainText();
private ChatFormatter() {} private ChatFormatter() {
}
/* ===================== BASIC ===================== */ /* ===================== BASIC ===================== */

View file

@ -5,27 +5,24 @@ package com.loki.lochat.utils;
*/ */
public final class Constants { public final class Constants {
private Constants() {}
// Чат // Чат
public static final int DEFAULT_LOCAL_RADIUS = 100; public static final int DEFAULT_LOCAL_RADIUS = 100;
public static final int CLEAR_CHAT_LINES = 100; public static final int CLEAR_CHAT_LINES = 100;
// Время // Время
public static final long MILLIS_IN_SECOND = 1000L; public static final long MILLIS_IN_SECOND = 1000L;
public static final int SECONDS_IN_MINUTE = 60; public static final int SECONDS_IN_MINUTE = 60;
public static final int MINUTES_IN_HOUR = 60; public static final int MINUTES_IN_HOUR = 60;
public static final int HOURS_IN_DAY = 24; public static final int HOURS_IN_DAY = 24;
// Градиенты // Градиенты
public static final int DEFAULT_PRICE_PER_COLOR = 50; public static final int DEFAULT_PRICE_PER_COLOR = 50;
public static final int DEFAULT_PREFIX_PRICE = 500; public static final int DEFAULT_PREFIX_PRICE = 500;
public static final int LUCKPERMS_PREFIX_PRIORITY = 100; public static final int LUCKPERMS_PREFIX_PRIORITY = 100;
// Folia/Paper совместимость // Folia/Paper совместимость
public static final int TICKS_PER_SECOND = 20; public static final int TICKS_PER_SECOND = 20;
public static final int MILLIS_PER_TICK = 50; public static final int MILLIS_PER_TICK = 50;
// Анти-спам // Анти-спам
public static final int PERCENTAGE_MULTIPLIER = 100; public static final int PERCENTAGE_MULTIPLIER = 100;
private Constants() {
}
} }

View file

@ -5,7 +5,8 @@ import org.bukkit.entity.Player;
public class DistanceUtil { public class DistanceUtil {
private DistanceUtil() {} private DistanceUtil() {
}
public static boolean isInRange(Player player1, Player player2, int radius) { public static boolean isInRange(Player player1, Player player2, int radius) {
// Проверка на один мир // Проверка на один мир

View file

@ -2,6 +2,7 @@ package com.loki.lochat.utils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.Sound;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.UUID; import java.util.UUID;
@ -11,10 +12,32 @@ import java.util.UUID;
*/ */
public final class PlayerUtil { public final class PlayerUtil {
private PlayerUtil() {} private PlayerUtil() {
}
/**
* Safely parses a sound name from config.
* Uses deprecated Sound.valueOf() for backward compatibility with string-based config values.
*
* @param soundName the sound name to parse
* @param defaultSound the default sound to return if parsing fails
* @return the parsed Sound or the default if invalid
*/
@SuppressWarnings("deprecation")
public static Sound parseSound(String soundName, Sound defaultSound) {
if (soundName == null || soundName.isEmpty()) {
return defaultSound;
}
try {
return Sound.valueOf(soundName.toUpperCase());
} catch (IllegalArgumentException e) {
return defaultSound;
}
}
/** /**
* Находит игрока по имени (онлайн или оффлайн) * Находит игрока по имени (онлайн или оффлайн)
*
* @param name имя игрока * @param name имя игрока
* @return UUID игрока или null если не найден * @return UUID игрока или null если не найден
*/ */
@ -36,6 +59,7 @@ public final class PlayerUtil {
/** /**
* Проверяет, существует ли игрок (играл на сервере) * Проверяет, существует ли игрок (играл на сервере)
*
* @param name имя игрока * @param name имя игрока
* @return true если игрок существует * @return true если игрок существует
*/ */
@ -45,6 +69,7 @@ public final class PlayerUtil {
/** /**
* Получает имя игрока по UUID * Получает имя игрока по UUID
*
* @param uuid UUID игрока * @param uuid UUID игрока
* @return имя игрока или null * @return имя игрока или null
*/ */
@ -60,6 +85,7 @@ public final class PlayerUtil {
/** /**
* Проверяет, онлайн ли игрок * Проверяет, онлайн ли игрок
*
* @param uuid UUID игрока * @param uuid UUID игрока
* @return true если игрок онлайн * @return true если игрок онлайн
*/ */