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:
parent
6a4c8a7886
commit
e78d8a2de4
121 changed files with 1792 additions and 1301 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -20,3 +20,6 @@ Thumbs.db
|
|||
|
||||
# Local config
|
||||
local.properties
|
||||
|
||||
# Temp folders
|
||||
temp_*/
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
plugins {
|
||||
java
|
||||
checkstyle
|
||||
}
|
||||
|
||||
group = "com.loki"
|
||||
version = "1.5.5-1.20.1"
|
||||
version = "1.5.5-1.21.8"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
|
@ -15,7 +16,7 @@ repositories {
|
|||
}
|
||||
|
||||
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("org.black_ixx:playerpoints:3.2.7")
|
||||
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-engine:5.10.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")
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +49,21 @@ tasks.test {
|
|||
}
|
||||
|
||||
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) })
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
83
config/checkstyle/README.md
Normal file
83
config/checkstyle/README.md
Normal 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
|
||||
73
config/checkstyle/checkstyle.xml
Normal file
73
config/checkstyle/checkstyle.xml
Normal 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>
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
java
|
||||
checkstyle
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
@ -10,7 +11,7 @@ repositories {
|
|||
}
|
||||
|
||||
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("com.sk89q.worldguard:worldguard-bukkit:7.0.9")
|
||||
implementation("com.google.code.gson:gson:2.10.1")
|
||||
|
|
@ -21,8 +22,28 @@ dependencies {
|
|||
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0")
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(21))
|
||||
}
|
||||
}
|
||||
|
||||
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) })
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,67 +11,67 @@ import com.loki.lohub.utils.PlaceholderUtil;
|
|||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class LoHub extends JavaPlugin {
|
||||
|
||||
|
||||
private ConfigManager configManager;
|
||||
private SpawnManager spawnManager;
|
||||
private RegionManager regionManager;
|
||||
private ActionManager actionManager;
|
||||
private CooldownManager cooldownManager;
|
||||
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
getLogger().info("Loading LoHub v" + getDescription().getVersion());
|
||||
|
||||
|
||||
saveDefaultConfig();
|
||||
|
||||
|
||||
PlaceholderUtil.init();
|
||||
|
||||
|
||||
this.configManager = new ConfigManager(this);
|
||||
this.spawnManager = new SpawnManager(this);
|
||||
this.regionManager = new RegionManager(this);
|
||||
this.actionManager = new ActionManager(this);
|
||||
this.cooldownManager = new CooldownManager();
|
||||
|
||||
|
||||
registerListeners();
|
||||
registerCommands();
|
||||
|
||||
|
||||
regionManager.createHubRegion();
|
||||
|
||||
|
||||
getLogger().info("LoHub successfully loaded!");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getLogger().info("LoHub disabled!");
|
||||
}
|
||||
|
||||
|
||||
private void registerListeners() {
|
||||
getServer().getPluginManager().registerEvents(new HubProtectionListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
|
||||
}
|
||||
|
||||
|
||||
private void registerCommands() {
|
||||
getCommand("hub").setExecutor(new com.loki.lohub.commands.HubCommand(this));
|
||||
getCommand("sethub").setExecutor(new com.loki.lohub.commands.SetHubCommand(this));
|
||||
getCommand("lohub").setExecutor(new com.loki.lohub.commands.LoHubCommand(this));
|
||||
}
|
||||
|
||||
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
|
||||
public SpawnManager getSpawnManager() {
|
||||
return spawnManager;
|
||||
}
|
||||
|
||||
|
||||
public RegionManager getRegionManager() {
|
||||
return regionManager;
|
||||
}
|
||||
|
||||
|
||||
public ActionManager getActionManager() {
|
||||
return actionManager;
|
||||
}
|
||||
|
||||
|
||||
public CooldownManager getCooldownManager() {
|
||||
return cooldownManager;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package com.loki.lohub.actions;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface Action {
|
||||
|
||||
|
||||
void execute(Player player);
|
||||
|
||||
|
||||
ActionType getType();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public enum ActionType {
|
|||
EFFECT,
|
||||
CLOSE,
|
||||
UNKNOWN;
|
||||
|
||||
|
||||
public static ActionType fromString(String type) {
|
||||
try {
|
||||
return valueOf(type.toUpperCase());
|
||||
|
|
|
|||
|
|
@ -8,19 +8,19 @@ import net.kyori.adventure.text.Component;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class ActionbarAction implements Action {
|
||||
|
||||
|
||||
private final String message;
|
||||
|
||||
|
||||
public ActionbarAction(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
String parsed = PlaceholderUtil.parse(message, player);
|
||||
player.sendActionBar(Component.text(TextUtil.colorize(parsed)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.ACTIONBAR;
|
||||
|
|
|
|||
|
|
@ -8,19 +8,19 @@ import org.bukkit.Bukkit;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BroadcastAction implements Action {
|
||||
|
||||
|
||||
private final String message;
|
||||
|
||||
|
||||
public BroadcastAction(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
String parsed = PlaceholderUtil.parse(message, player);
|
||||
Bukkit.broadcastMessage(TextUtil.colorize(parsed));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.BROADCAST;
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ import com.loki.lohub.actions.ActionType;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class CloseAction implements Action {
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
player.closeInventory();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.CLOSE;
|
||||
|
|
|
|||
|
|
@ -6,19 +6,19 @@ import com.loki.lohub.utils.PlaceholderUtil;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class CommandAction implements Action {
|
||||
|
||||
|
||||
private final String command;
|
||||
|
||||
|
||||
public CommandAction(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
String parsed = PlaceholderUtil.parse(command, player);
|
||||
player.performCommand(parsed);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.COMMAND;
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ import org.bukkit.Bukkit;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class ConsoleAction implements Action {
|
||||
|
||||
|
||||
private final String command;
|
||||
|
||||
|
||||
public ConsoleAction(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
String parsed = PlaceholderUtil.parse(command, player);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsed);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.CONSOLE;
|
||||
|
|
|
|||
|
|
@ -7,36 +7,36 @@ import org.bukkit.potion.PotionEffect;
|
|||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
public class EffectAction implements Action {
|
||||
|
||||
|
||||
private final PotionEffectType effectType;
|
||||
private final int amplifier;
|
||||
private final int duration;
|
||||
|
||||
|
||||
public EffectAction(String effectData) {
|
||||
String[] parts = effectData.split(";");
|
||||
|
||||
|
||||
PotionEffectType parsed;
|
||||
try {
|
||||
parsed = PotionEffectType.getByName(parts[0].toUpperCase());
|
||||
} catch (Exception e) {
|
||||
parsed = PotionEffectType.SPEED;
|
||||
}
|
||||
|
||||
|
||||
this.effectType = parsed != null ? parsed : PotionEffectType.SPEED;
|
||||
this.amplifier = parts.length > 1 ? parseInt(parts[1], 0) : 0;
|
||||
this.duration = parts.length > 2 ? parseInt(parts[2], 999999) : 999999;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
player.addPotionEffect(new PotionEffect(effectType, duration * 20, amplifier, false, false));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.EFFECT;
|
||||
}
|
||||
|
||||
|
||||
private int parseInt(String value, int defaultValue) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import org.bukkit.GameMode;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class GamemodeAction implements Action {
|
||||
|
||||
|
||||
private final GameMode gameMode;
|
||||
|
||||
|
||||
public GamemodeAction(String mode) {
|
||||
GameMode parsed;
|
||||
try {
|
||||
|
|
@ -24,12 +24,12 @@ public class GamemodeAction implements Action {
|
|||
}
|
||||
this.gameMode = parsed;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
player.setGameMode(gameMode);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.GAMEMODE;
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ import com.loki.lohub.utils.TextUtil;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class MessageAction implements Action {
|
||||
|
||||
|
||||
private final String message;
|
||||
|
||||
|
||||
public MessageAction(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
String parsed = PlaceholderUtil.parse(message, player);
|
||||
player.sendMessage(TextUtil.colorize(parsed));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.MESSAGE;
|
||||
|
|
|
|||
|
|
@ -6,36 +6,36 @@ import org.bukkit.Sound;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SoundAction implements Action {
|
||||
|
||||
|
||||
private final Sound sound;
|
||||
private final float volume;
|
||||
private final float pitch;
|
||||
|
||||
|
||||
public SoundAction(String soundData) {
|
||||
String[] parts = soundData.split(";");
|
||||
|
||||
|
||||
Sound parsedSound;
|
||||
try {
|
||||
parsedSound = Sound.valueOf(parts[0].toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
parsedSound = Sound.ENTITY_EXPERIENCE_ORB_PICKUP;
|
||||
}
|
||||
|
||||
|
||||
this.sound = parsedSound;
|
||||
this.volume = parts.length > 1 ? parseFloat(parts[1], 1.0f) : 1.0f;
|
||||
this.pitch = parts.length > 2 ? parseFloat(parts[2], 1.0f) : 1.0f;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
player.playSound(player.getLocation(), sound, volume, pitch);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.SOUND;
|
||||
}
|
||||
|
||||
|
||||
private float parseFloat(String value, float defaultValue) {
|
||||
try {
|
||||
return Float.parseFloat(value);
|
||||
|
|
|
|||
|
|
@ -11,46 +11,46 @@ import org.bukkit.entity.Player;
|
|||
import java.time.Duration;
|
||||
|
||||
public class TitleAction implements Action {
|
||||
|
||||
|
||||
private final String title;
|
||||
private final String subtitle;
|
||||
private final int fadeIn;
|
||||
private final int stay;
|
||||
private final int fadeOut;
|
||||
|
||||
|
||||
public TitleAction(String titleData) {
|
||||
String[] parts = titleData.split(";");
|
||||
|
||||
|
||||
this.title = parts.length > 0 ? parts[0] : "";
|
||||
this.subtitle = parts.length > 1 ? parts[1] : "";
|
||||
this.fadeIn = parts.length > 2 ? parseInt(parts[2], 10) : 10;
|
||||
this.stay = parts.length > 3 ? parseInt(parts[3], 40) : 40;
|
||||
this.fadeOut = parts.length > 4 ? parseInt(parts[4], 10) : 10;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Player player) {
|
||||
String parsedTitle = PlaceholderUtil.parse(title, player);
|
||||
String parsedSubtitle = PlaceholderUtil.parse(subtitle, player);
|
||||
|
||||
|
||||
Component titleComponent = Component.text(TextUtil.colorize(parsedTitle));
|
||||
Component subtitleComponent = Component.text(TextUtil.colorize(parsedSubtitle));
|
||||
|
||||
|
||||
Title.Times times = Title.Times.times(
|
||||
Duration.ofMillis(fadeIn * 50L),
|
||||
Duration.ofMillis(stay * 50L),
|
||||
Duration.ofMillis(fadeOut * 50L)
|
||||
Duration.ofMillis(fadeIn * 50L),
|
||||
Duration.ofMillis(stay * 50L),
|
||||
Duration.ofMillis(fadeOut * 50L)
|
||||
);
|
||||
|
||||
|
||||
Title title = Title.title(titleComponent, subtitleComponent, times);
|
||||
player.showTitle(title);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionType getType() {
|
||||
return ActionType.TITLE;
|
||||
}
|
||||
|
||||
|
||||
private int parseInt(String value, int defaultValue) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
|
|
|
|||
|
|
@ -8,28 +8,28 @@ import org.bukkit.command.CommandSender;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class HubCommand implements CommandExecutor {
|
||||
|
||||
|
||||
private final LoHub plugin;
|
||||
|
||||
|
||||
public HubCommand(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(TextUtil.colorize("&cThis command is only for players!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (plugin.getSpawnManager().getSpawn() == null) {
|
||||
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-spawn")));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
plugin.getSpawnManager().teleportToSpawn(player);
|
||||
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.spawn-teleport")));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,32 +7,32 @@ import org.bukkit.command.CommandExecutor;
|
|||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class LoHubCommand implements CommandExecutor {
|
||||
|
||||
|
||||
private final LoHub plugin;
|
||||
|
||||
|
||||
public LoHubCommand(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!sender.hasPermission("lohub.admin")) {
|
||||
sender.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-permission")));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (args.length == 0) {
|
||||
sender.sendMessage(TextUtil.colorize("&7LoHub v" + plugin.getDescription().getVersion()));
|
||||
sender.sendMessage(TextUtil.colorize("&7Use: &e/lohub reload"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (args[0].equalsIgnoreCase("reload")) {
|
||||
plugin.getConfigManager().reload();
|
||||
sender.sendMessage(TextUtil.colorize("&aConfiguration reloaded!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,35 +8,35 @@ import org.bukkit.command.CommandSender;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SetHubCommand implements CommandExecutor {
|
||||
|
||||
|
||||
private final LoHub plugin;
|
||||
|
||||
|
||||
public SetHubCommand(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(TextUtil.colorize("&cThis command is only for players!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (!player.hasPermission("lohub.admin")) {
|
||||
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-permission")));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
plugin.getSpawnManager().setSpawn(player.getLocation());
|
||||
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.spawn-set")));
|
||||
|
||||
|
||||
plugin.getRegionManager().deleteHubRegion();
|
||||
plugin.getRegionManager().createHubRegion();
|
||||
|
||||
|
||||
if (plugin.getConfig().getBoolean("worldguard.auto-create-region")) {
|
||||
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.region-created")));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,52 +4,52 @@ import com.loki.lohub.LoHub;
|
|||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
|
||||
private final LoHub plugin;
|
||||
private FileConfiguration config;
|
||||
|
||||
|
||||
public ConfigManager(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
this.config = plugin.getConfig();
|
||||
}
|
||||
|
||||
|
||||
public void reload() {
|
||||
plugin.reloadConfig();
|
||||
this.config = plugin.getConfig();
|
||||
}
|
||||
|
||||
|
||||
public FileConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
public boolean isProtectionEnabled() {
|
||||
return config.getBoolean("protection.enabled", true);
|
||||
}
|
||||
|
||||
|
||||
public boolean isBlockBreakProtected() {
|
||||
return config.getBoolean("protection.block-break", true);
|
||||
}
|
||||
|
||||
|
||||
public boolean isBlockPlaceProtected() {
|
||||
return config.getBoolean("protection.block-place", true);
|
||||
}
|
||||
|
||||
|
||||
public boolean isPvPProtected() {
|
||||
return config.getBoolean("protection.pvp", true);
|
||||
}
|
||||
|
||||
|
||||
public boolean isItemDropProtected() {
|
||||
return config.getBoolean("protection.item-drop", true);
|
||||
}
|
||||
|
||||
|
||||
public boolean isItemPickupProtected() {
|
||||
return config.getBoolean("protection.item-pickup", true);
|
||||
}
|
||||
|
||||
|
||||
public boolean isFoodLevelProtected() {
|
||||
return config.getBoolean("protection.food-level", true);
|
||||
}
|
||||
|
||||
|
||||
public boolean isMobSpawningProtected() {
|
||||
return config.getBoolean("protection.mob-spawning", true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,90 +13,120 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
|||
import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||
|
||||
public class HubProtectionListener implements Listener {
|
||||
|
||||
|
||||
private final LoHub plugin;
|
||||
|
||||
|
||||
public HubProtectionListener(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if (plugin.getConfig().getBoolean("spawn.teleport-on-join", true)) {
|
||||
plugin.getSpawnManager().teleportToSpawn(event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) return;
|
||||
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasPermission("lohub.bypass.protection")) return;
|
||||
|
||||
if (player.hasPermission("lohub.bypass.protection")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.getConfigManager().isBlockBreakProtected()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) return;
|
||||
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasPermission("lohub.bypass.protection")) return;
|
||||
|
||||
if (player.hasPermission("lohub.bypass.protection")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.getConfigManager().isBlockPlaceProtected()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onPvP(EntityDamageByEntityEvent event) {
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) return;
|
||||
if (!(event.getDamager() instanceof Player)) return;
|
||||
if (!(event.getEntity() instanceof Player)) return;
|
||||
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getDamager() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getEntity() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player damager = (Player) event.getDamager();
|
||||
if (damager.hasPermission("lohub.bypass.protection")) return;
|
||||
|
||||
if (damager.hasPermission("lohub.bypass.protection")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.getConfigManager().isPvPProtected()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onItemDrop(PlayerDropItemEvent event) {
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) return;
|
||||
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasPermission("lohub.bypass.protection")) return;
|
||||
|
||||
if (player.hasPermission("lohub.bypass.protection")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.getConfigManager().isItemDropProtected()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onItemPickup(PlayerPickupItemEvent event) {
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) return;
|
||||
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasPermission("lohub.bypass.protection")) return;
|
||||
|
||||
if (player.hasPermission("lohub.bypass.protection")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.getConfigManager().isItemPickupProtected()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onFoodLevelChange(FoodLevelChangeEvent event) {
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) return;
|
||||
if (!(event.getEntity() instanceof Player)) return;
|
||||
|
||||
if (!plugin.getConfigManager().isProtectionEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getEntity() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = (Player) event.getEntity();
|
||||
if (player.hasPermission("lohub.bypass.protection")) return;
|
||||
|
||||
if (player.hasPermission("lohub.bypass.protection")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.getConfigManager().isFoodLevelProtected()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,37 +20,61 @@ import org.bukkit.inventory.meta.FireworkMeta;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
public PlayerJoinListener(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
|
||||
if (isWorldDisabled(player.getWorld().getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
handleJoinMessage(event, player);
|
||||
handleJoinSettings(player);
|
||||
handleJoinEvents(player);
|
||||
handleFirework(player);
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
|
||||
if (isWorldDisabled(player.getWorld().getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) {
|
||||
String quitMessage = plugin.getConfig().getString("join_leave_messages.quit_message", "");
|
||||
if (quitMessage.isEmpty()) {
|
||||
|
|
@ -60,15 +84,15 @@ public class PlayerJoinListener implements Listener {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerRespawn(PlayerRespawnEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
|
||||
if (isWorldDisabled(player.getWorld().getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (plugin.getConfig().getBoolean("spawn.teleport-on-respawn", true)) {
|
||||
Location spawn = plugin.getSpawnManager().getSpawn();
|
||||
if (spawn != null) {
|
||||
|
|
@ -76,18 +100,18 @@ public class PlayerJoinListener implements Listener {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||
if (isWorldDisabled(event.getPlayer().getWorld().getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (plugin.getConfig().getBoolean("world_settings.disable_death_message", true)) {
|
||||
event.deathMessage(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleJoinMessage(PlayerJoinEvent event, Player player) {
|
||||
if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) {
|
||||
String joinMessage = plugin.getConfig().getString("join_leave_messages.join_message", "");
|
||||
|
|
@ -98,7 +122,7 @@ public class PlayerJoinListener implements Listener {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleJoinSettings(Player player) {
|
||||
if (plugin.getConfig().getBoolean("join_settings.spawn_join", true)) {
|
||||
Location spawn = plugin.getSpawnManager().getSpawn();
|
||||
|
|
@ -106,43 +130,43 @@ public class PlayerJoinListener implements Listener {
|
|||
player.teleport(spawn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (plugin.getConfig().getBoolean("join_settings.heal", true)) {
|
||||
player.setHealth(player.getMaxHealth());
|
||||
player.setFoodLevel(20);
|
||||
player.setSaturation(20);
|
||||
}
|
||||
|
||||
|
||||
if (plugin.getConfig().getBoolean("join_settings.extinguish", true)) {
|
||||
player.setFireTicks(0);
|
||||
}
|
||||
|
||||
|
||||
if (plugin.getConfig().getBoolean("join_settings.clear_inventory", false)) {
|
||||
player.getInventory().clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleJoinEvents(Player player) {
|
||||
List<String> actions = plugin.getConfig().getStringList("join_events");
|
||||
if (!actions.isEmpty()) {
|
||||
plugin.getActionManager().executeActions(player, actions, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleFirework(Player player) {
|
||||
if (!plugin.getConfig().getBoolean("join_settings.firework.enabled", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
boolean firstJoinOnly = plugin.getConfig().getBoolean("join_settings.firework.first_join_only", true);
|
||||
if (firstJoinOnly && player.hasPlayedBefore()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
|
||||
|
||||
String typeStr = plugin.getConfig().getString("join_settings.firework.type", "BALL_LARGE");
|
||||
FireworkEffect.Type type;
|
||||
try {
|
||||
|
|
@ -150,7 +174,7 @@ public class PlayerJoinListener implements Listener {
|
|||
} catch (IllegalArgumentException e) {
|
||||
type = FireworkEffect.Type.BALL_LARGE;
|
||||
}
|
||||
|
||||
|
||||
List<Color> colors = new ArrayList<>();
|
||||
for (String colorStr : plugin.getConfig().getStringList("join_settings.firework.colors")) {
|
||||
Color color = parseColor(colorStr);
|
||||
|
|
@ -158,51 +182,32 @@ public class PlayerJoinListener implements Listener {
|
|||
colors.add(color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (colors.isEmpty()) {
|
||||
colors.add(Color.AQUA);
|
||||
}
|
||||
|
||||
|
||||
FireworkEffect effect = FireworkEffect.builder()
|
||||
.with(type)
|
||||
.withColor(colors)
|
||||
.flicker(plugin.getConfig().getBoolean("join_settings.firework.flicker", true))
|
||||
.trail(plugin.getConfig().getBoolean("join_settings.firework.trail", true))
|
||||
.build();
|
||||
|
||||
.with(type)
|
||||
.withColor(colors)
|
||||
.flicker(plugin.getConfig().getBoolean("join_settings.firework.flicker", true))
|
||||
.trail(plugin.getConfig().getBoolean("join_settings.firework.trail", true))
|
||||
.build();
|
||||
|
||||
meta.addEffect(effect);
|
||||
meta.setPower(plugin.getConfig().getInt("join_settings.firework.power", 1));
|
||||
firework.setFireworkMeta(meta);
|
||||
}
|
||||
|
||||
|
||||
private Color parseColor(String colorStr) {
|
||||
return switch (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;
|
||||
};
|
||||
return COLOR_MAP.get(colorStr.toUpperCase());
|
||||
}
|
||||
|
||||
|
||||
private boolean isWorldDisabled(String worldName) {
|
||||
List<String> disabledWorlds = plugin.getConfig().getStringList("disabled-worlds.worlds");
|
||||
boolean invert = plugin.getConfig().getBoolean("disabled-worlds.invert", false);
|
||||
boolean isInList = disabledWorlds.contains(worldName);
|
||||
|
||||
|
||||
return invert ? !isInList : isInList;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,16 @@ package com.loki.lohub.managers;
|
|||
import com.loki.lohub.LoHub;
|
||||
import com.loki.lohub.actions.Action;
|
||||
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 java.util.ArrayList;
|
||||
|
|
@ -12,43 +21,43 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
public class ActionManager {
|
||||
|
||||
private final LoHub plugin;
|
||||
|
||||
private static final Pattern ACTION_PATTERN = Pattern.compile("\\[([A-Z]+)]\\s*(.*)");
|
||||
|
||||
private final LoHub plugin;
|
||||
|
||||
public ActionManager(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
public List<Action> parseActions(List<String> actionStrings) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
|
||||
for (String actionString : actionStrings) {
|
||||
Action action = parseAction(actionString);
|
||||
if (action != null) {
|
||||
actions.add(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
||||
public Action parseAction(String actionString) {
|
||||
if (actionString == null || actionString.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Matcher matcher = ACTION_PATTERN.matcher(actionString);
|
||||
if (!matcher.matches()) {
|
||||
plugin.getLogger().warning("Invalid action format: " + actionString);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
String typeStr = matcher.group(1);
|
||||
String data = matcher.group(2);
|
||||
|
||||
|
||||
ActionType type = ActionType.fromString(typeStr);
|
||||
|
||||
|
||||
return switch (type) {
|
||||
case MESSAGE -> new MessageAction(data);
|
||||
case BROADCAST -> new BroadcastAction(data);
|
||||
|
|
@ -66,7 +75,7 @@ public class ActionManager {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void executeActions(Player player, List<Action> actions) {
|
||||
for (Action action : actions) {
|
||||
try {
|
||||
|
|
@ -77,7 +86,7 @@ public class ActionManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void executeActions(Player player, List<String> actionStrings, boolean parse) {
|
||||
if (parse) {
|
||||
List<Action> actions = parseActions(actionStrings);
|
||||
|
|
|
|||
|
|
@ -5,55 +5,55 @@ import java.util.Map;
|
|||
import java.util.UUID;
|
||||
|
||||
public class CooldownManager {
|
||||
|
||||
|
||||
private final Map<String, Map<UUID, Long>> cooldowns = new HashMap<>();
|
||||
|
||||
|
||||
public void setCooldown(String key, UUID playerId, int seconds) {
|
||||
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) {
|
||||
Map<UUID, Long> keyCooldowns = cooldowns.get(key);
|
||||
if (keyCooldowns == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Long expireTime = keyCooldowns.get(playerId);
|
||||
if (expireTime == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (System.currentTimeMillis() >= expireTime) {
|
||||
keyCooldowns.remove(playerId);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public int getRemainingSeconds(String key, UUID playerId) {
|
||||
Map<UUID, Long> keyCooldowns = cooldowns.get(key);
|
||||
if (keyCooldowns == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Long expireTime = keyCooldowns.get(playerId);
|
||||
if (expireTime == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long remaining = expireTime - System.currentTimeMillis();
|
||||
return remaining > 0 ? (int) (remaining / 1000) : 0;
|
||||
}
|
||||
|
||||
|
||||
public void removeCooldown(String key, UUID playerId) {
|
||||
Map<UUID, Long> keyCooldowns = cooldowns.get(key);
|
||||
if (keyCooldowns != null) {
|
||||
keyCooldowns.remove(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void clearAll() {
|
||||
cooldowns.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import com.loki.lohub.LoHub;
|
|||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
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.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.RegionContainer;
|
||||
|
|
@ -11,105 +13,100 @@ import org.bukkit.Location;
|
|||
import org.bukkit.World;
|
||||
|
||||
public class RegionManager {
|
||||
|
||||
private final LoHub plugin;
|
||||
|
||||
private static final String HUB_REGION_NAME = "lohub_spawn";
|
||||
|
||||
private final LoHub plugin;
|
||||
|
||||
public RegionManager(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
public void createHubRegion() {
|
||||
if (!plugin.getConfig().getBoolean("worldguard.auto-create-region", true)) {
|
||||
plugin.getLogger().info("WorldGuard region auto-creation is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!isWorldGuardAvailable()) {
|
||||
plugin.getLogger().warning("WorldGuard not found! Region will not be created.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Location spawn = plugin.getSpawnManager().getSpawn();
|
||||
if (spawn == null || spawn.getWorld() == null) {
|
||||
plugin.getLogger().warning("Spawn not set! Use /sethub");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
World world = spawn.getWorld();
|
||||
int radius = plugin.getConfig().getInt("worldguard.region-radius", 100);
|
||||
|
||||
|
||||
try {
|
||||
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||
com.sk89q.worldguard.protection.managers.RegionManager wgRegionManager = container.get(BukkitAdapter.adapt(world));
|
||||
|
||||
|
||||
if (wgRegionManager == null) {
|
||||
plugin.getLogger().warning("Failed to get RegionManager for world " + world.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ProtectedRegion existingRegion = wgRegionManager.getRegion(HUB_REGION_NAME);
|
||||
if (existingRegion != null) {
|
||||
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BlockVector3 min = BlockVector3.at(
|
||||
spawn.getBlockX() - radius,
|
||||
world.getMinHeight(),
|
||||
spawn.getBlockZ() - radius
|
||||
spawn.getBlockX() - radius,
|
||||
world.getMinHeight(),
|
||||
spawn.getBlockZ() - radius
|
||||
);
|
||||
|
||||
|
||||
BlockVector3 max = BlockVector3.at(
|
||||
spawn.getBlockX() + radius,
|
||||
world.getMaxHeight(),
|
||||
spawn.getBlockZ() + radius
|
||||
spawn.getBlockX() + radius,
|
||||
world.getMaxHeight(),
|
||||
spawn.getBlockZ() + radius
|
||||
);
|
||||
|
||||
|
||||
ProtectedCuboidRegion region = new ProtectedCuboidRegion(HUB_REGION_NAME, min, max);
|
||||
|
||||
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);
|
||||
|
||||
setRegionFlags(region);
|
||||
|
||||
wgRegionManager.addRegion(region);
|
||||
|
||||
|
||||
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' created around spawn (radius: " + radius + " blocks)");
|
||||
plugin.getLogger().info("Coordinates: " + min + " -> " + max);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe("Error creating WorldGuard region: " + e.getMessage());
|
||||
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() {
|
||||
if (!isWorldGuardAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Location spawn = plugin.getSpawnManager().getSpawn();
|
||||
if (spawn == null || spawn.getWorld() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||
com.sk89q.worldguard.protection.managers.RegionManager wgRegionManager = container.get(BukkitAdapter.adapt(spawn.getWorld()));
|
||||
|
||||
|
||||
if (wgRegionManager != null) {
|
||||
wgRegionManager.removeRegion(HUB_REGION_NAME);
|
||||
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' deleted");
|
||||
|
|
@ -118,7 +115,7 @@ public class RegionManager {
|
|||
plugin.getLogger().severe("Error deleting region: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean isWorldGuardAvailable() {
|
||||
try {
|
||||
Class.forName("com.sk89q.worldguard.WorldGuard");
|
||||
|
|
|
|||
|
|
@ -12,18 +12,18 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
|
||||
public class SpawnManager {
|
||||
|
||||
|
||||
private final LoHub plugin;
|
||||
private final File spawnFile;
|
||||
private FileConfiguration spawnConfig;
|
||||
private Location spawnLocation;
|
||||
|
||||
|
||||
public SpawnManager(LoHub plugin) {
|
||||
this.plugin = plugin;
|
||||
this.spawnFile = new File(plugin.getDataFolder(), "spawn.yml");
|
||||
loadSpawn();
|
||||
}
|
||||
|
||||
|
||||
private void loadSpawn() {
|
||||
if (!spawnFile.exists()) {
|
||||
try {
|
||||
|
|
@ -32,9 +32,9 @@ public class SpawnManager {
|
|||
plugin.getLogger().severe("Failed to create spawn.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
spawnConfig = YamlConfiguration.loadConfiguration(spawnFile);
|
||||
|
||||
|
||||
if (spawnConfig.contains("spawn")) {
|
||||
String worldName = spawnConfig.getString("spawn.world");
|
||||
double x = spawnConfig.getDouble("spawn.x");
|
||||
|
|
@ -42,7 +42,7 @@ public class SpawnManager {
|
|||
double z = spawnConfig.getDouble("spawn.z");
|
||||
float yaw = (float) spawnConfig.getDouble("spawn.yaw");
|
||||
float pitch = (float) spawnConfig.getDouble("spawn.pitch");
|
||||
|
||||
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world != null) {
|
||||
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) {
|
||||
this.spawnLocation = location;
|
||||
|
||||
|
||||
spawnConfig.set("spawn.world", location.getWorld().getName());
|
||||
spawnConfig.set("spawn.x", location.getX());
|
||||
spawnConfig.set("spawn.y", location.getY());
|
||||
spawnConfig.set("spawn.z", location.getZ());
|
||||
spawnConfig.set("spawn.yaw", location.getYaw());
|
||||
spawnConfig.set("spawn.pitch", location.getPitch());
|
||||
|
||||
|
||||
try {
|
||||
spawnConfig.save(spawnFile);
|
||||
plugin.getLogger().info("Spawn set: " + location.getWorld().getName() +
|
||||
" (" + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ() + ")");
|
||||
plugin.getLogger().info("Spawn set: " + location.getWorld().getName() +
|
||||
" (" + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ() + ")");
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().severe("Failed to save spawn.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public Location getSpawn() {
|
||||
return spawnLocation;
|
||||
}
|
||||
|
||||
|
||||
public void teleportToSpawn(Player player) {
|
||||
if (spawnLocation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
player.teleport(spawnLocation);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,83 +9,83 @@ import org.bukkit.inventory.ItemStack;
|
|||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ItemBuilder {
|
||||
|
||||
|
||||
private final ItemStack itemStack;
|
||||
|
||||
|
||||
public ItemBuilder(Material material) {
|
||||
this.itemStack = new ItemStack(material);
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder(ItemStack itemStack) {
|
||||
this.itemStack = itemStack.clone();
|
||||
}
|
||||
|
||||
|
||||
public static ItemBuilder fromConfig(ConfigurationSection section) {
|
||||
return fromConfig(section, null);
|
||||
}
|
||||
|
||||
|
||||
public static ItemBuilder fromConfig(ConfigurationSection section, Player player) {
|
||||
String materialName = section.getString("material", "STONE").toUpperCase();
|
||||
Material material;
|
||||
|
||||
|
||||
try {
|
||||
material = Material.valueOf(materialName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
material = Material.STONE;
|
||||
}
|
||||
|
||||
|
||||
ItemBuilder builder = new ItemBuilder(material);
|
||||
|
||||
|
||||
if (section.contains("amount")) {
|
||||
builder.amount(section.getInt("amount", 1));
|
||||
}
|
||||
|
||||
|
||||
if (section.contains("display_name")) {
|
||||
String name = section.getString("display_name");
|
||||
builder.name(player != null ? PlaceholderUtil.parse(name, player) : name);
|
||||
}
|
||||
|
||||
|
||||
if (section.contains("lore")) {
|
||||
List<String> lore = section.getStringList("lore");
|
||||
builder.lore(player != null ?
|
||||
lore.stream().map(line -> PlaceholderUtil.parse(line, player)).collect(Collectors.toList()) :
|
||||
lore);
|
||||
builder.lore(player != null ?
|
||||
lore.stream().map(line -> PlaceholderUtil.parse(line, player)).collect(Collectors.toList()) :
|
||||
lore);
|
||||
}
|
||||
|
||||
|
||||
if (section.contains("glow") && section.getBoolean("glow")) {
|
||||
builder.glow();
|
||||
}
|
||||
|
||||
|
||||
if (section.contains("custom_model_data")) {
|
||||
builder.customModelData(section.getInt("custom_model_data"));
|
||||
}
|
||||
|
||||
|
||||
if (section.contains("item_flags")) {
|
||||
section.getStringList("item_flags").forEach(flagName -> {
|
||||
try {
|
||||
builder.flag(ItemFlag.valueOf(flagName.toUpperCase()));
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (material == Material.PLAYER_HEAD && section.contains("skull_owner")) {
|
||||
String owner = section.getString("skull_owner");
|
||||
builder.skullOwner(player != null ? owner.replace("%player%", player.getName()) : owner);
|
||||
}
|
||||
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder amount(int amount) {
|
||||
itemStack.setAmount(Math.max(1, amount));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder name(String name) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta != null) {
|
||||
|
|
@ -94,23 +94,23 @@ public class ItemBuilder {
|
|||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder lore(List<String> lore) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta != null) {
|
||||
List<String> coloredLore = lore.stream()
|
||||
.map(TextUtil::colorize)
|
||||
.collect(Collectors.toList());
|
||||
.map(TextUtil::colorize)
|
||||
.collect(Collectors.toList());
|
||||
meta.setLore(coloredLore);
|
||||
itemStack.setItemMeta(meta);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder lore(String... lines) {
|
||||
return lore(List.of(lines));
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder flag(ItemFlag... flags) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta != null) {
|
||||
|
|
@ -119,17 +119,17 @@ public class ItemBuilder {
|
|||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder glow() {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.addEnchant(Enchantment.LUCK, 1, true);
|
||||
meta.addEnchant(Enchantment.UNBREAKING, 1, true);
|
||||
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||
itemStack.setItemMeta(meta);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder customModelData(int data) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta != null) {
|
||||
|
|
@ -138,7 +138,7 @@ public class ItemBuilder {
|
|||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ItemBuilder skullOwner(String owner) {
|
||||
if (itemStack.getType() == Material.PLAYER_HEAD) {
|
||||
SkullMeta meta = (SkullMeta) itemStack.getItemMeta();
|
||||
|
|
@ -149,7 +149,7 @@ public class ItemBuilder {
|
|||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ItemStack build() {
|
||||
return itemStack;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,49 +6,53 @@ import org.bukkit.Location;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PlaceholderUtil {
|
||||
|
||||
|
||||
private static boolean placeholderAPIEnabled = false;
|
||||
|
||||
|
||||
private PlaceholderUtil() {
|
||||
// Utility class - prevent instantiation
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
placeholderAPIEnabled = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
|
||||
}
|
||||
|
||||
|
||||
public static String parse(String text, Player player) {
|
||||
if (text == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
text = parseInternalPlaceholders(text, player);
|
||||
|
||||
|
||||
if (placeholderAPIEnabled && player != null) {
|
||||
text = PlaceholderAPI.setPlaceholders(player, text);
|
||||
}
|
||||
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
private static String parseInternalPlaceholders(String text, Player player) {
|
||||
if (player != null) {
|
||||
text = text.replace("%player%", player.getName());
|
||||
text = text.replace("%player_displayname%", player.getDisplayName());
|
||||
|
||||
|
||||
if (text.contains("%location%")) {
|
||||
Location loc = player.getLocation();
|
||||
text = text.replace("%location%",
|
||||
loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ());
|
||||
text = text.replace("%location%",
|
||||
loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ());
|
||||
}
|
||||
|
||||
|
||||
if (text.contains("%world%")) {
|
||||
text = text.replace("%world%", player.getWorld().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
text = text.replace("%online%", String.valueOf(Bukkit.getOnlinePlayers().size()));
|
||||
text = text.replace("%online_max%", String.valueOf(Bukkit.getMaxPlayers()));
|
||||
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isPlaceholderAPIEnabled() {
|
||||
return placeholderAPIEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,49 +8,53 @@ import java.util.regex.Pattern;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
public class TextUtil {
|
||||
|
||||
|
||||
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) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
text = translateHexCodes(text);
|
||||
text = ChatColor.translateAlternateColorCodes('&', text);
|
||||
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
public static List<String> colorize(List<String> lines) {
|
||||
return lines.stream()
|
||||
.map(TextUtil::colorize)
|
||||
.collect(Collectors.toList());
|
||||
.map(TextUtil::colorize)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private static String translateHexCodes(String text) {
|
||||
Matcher matcher = HEX_PATTERN.matcher(text);
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
|
||||
while (matcher.find()) {
|
||||
String hexCode = matcher.group(1);
|
||||
String replacement = ChatColor.of("#" + hexCode).toString();
|
||||
matcher.appendReplacement(buffer, replacement);
|
||||
}
|
||||
|
||||
|
||||
matcher.appendTail(buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String strip(String text) {
|
||||
return ChatColor.stripColor(text);
|
||||
}
|
||||
|
||||
|
||||
public static String joinFrom(int startIndex, String[] args) {
|
||||
if (args == null || startIndex >= args.length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = startIndex; i < args.length; i++) {
|
||||
builder.append(args[i]);
|
||||
|
|
@ -58,15 +62,15 @@ public class TextUtil {
|
|||
builder.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String listToString(List<String> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
return String.join("\n", list);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ commands:
|
|||
description: Teleport to spawn
|
||||
usage: /hub
|
||||
permission: lohub.hub
|
||||
aliases: [spawn, хаб, спавн]
|
||||
aliases: [ spawn, хаб, спавн ]
|
||||
|
||||
sethub:
|
||||
description: Set hub spawn location
|
||||
usage: /sethub
|
||||
permission: lohub.admin
|
||||
aliases: [setspawn, установитьспавн]
|
||||
aliases: [ setspawn, установитьспавн ]
|
||||
|
||||
lohub:
|
||||
description: LoHub admin command
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
java
|
||||
checkstyle
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
@ -12,7 +13,7 @@ dependencies {
|
|||
compileOnly("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")
|
||||
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.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) })
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,52 +13,52 @@ import org.slf4j.Logger;
|
|||
import java.nio.file.Path;
|
||||
|
||||
@Plugin(
|
||||
id = "lovelocity",
|
||||
name = "LoVelocity",
|
||||
version = "1.5.5",
|
||||
description = "Velocity integration for LoNetwork",
|
||||
authors = {"loki"}
|
||||
id = "lovelocity",
|
||||
name = "LoVelocity",
|
||||
version = "1.5.5",
|
||||
description = "Velocity integration for LoNetwork",
|
||||
authors = {"loki"}
|
||||
)
|
||||
public class LoVelocity {
|
||||
|
||||
|
||||
private final ProxyServer server;
|
||||
private final Logger logger;
|
||||
private final Path dataDirectory;
|
||||
|
||||
|
||||
@Inject
|
||||
public LoVelocity(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
|
||||
this.server = server;
|
||||
this.logger = logger;
|
||||
this.dataDirectory = dataDirectory;
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onProxyInitialization(ProxyInitializeEvent event) {
|
||||
logger.info("LoVelocity loaded!");
|
||||
logger.info("Version: 1.5.5");
|
||||
|
||||
|
||||
registerCommands();
|
||||
}
|
||||
|
||||
|
||||
private void registerCommands() {
|
||||
CommandMeta hubMeta = server.getCommandManager().metaBuilder("hub")
|
||||
.aliases("lobby")
|
||||
.plugin(this)
|
||||
.build();
|
||||
|
||||
.aliases("lobby")
|
||||
.plugin(this)
|
||||
.build();
|
||||
|
||||
server.getCommandManager().register(hubMeta, new HubCommand(this));
|
||||
|
||||
|
||||
logger.info("Commands registered: /hub, /lobby");
|
||||
}
|
||||
|
||||
|
||||
public ProxyServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
|
||||
public Path getDataDirectory() {
|
||||
return dataDirectory;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,66 +12,66 @@ import java.util.Optional;
|
|||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class HubCommand implements SimpleCommand {
|
||||
|
||||
|
||||
private final LoVelocity plugin;
|
||||
private final List<String> hubServers = List.of("hub", "lobby");
|
||||
|
||||
|
||||
public HubCommand(LoVelocity plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Invocation invocation) {
|
||||
if (!(invocation.source() instanceof Player player)) {
|
||||
invocation.source().sendMessage(Component.text("This command is only for players!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Optional<RegisteredServer> currentServer = player.getCurrentServer().map(s -> s.getServer());
|
||||
|
||||
|
||||
if (currentServer.isEmpty()) {
|
||||
player.sendMessage(Component.text("Failed to determine current server!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String currentServerName = currentServer.get().getServerInfo().getName().toLowerCase();
|
||||
|
||||
|
||||
if (isHubServer(currentServerName)) {
|
||||
player.sendMessage(Component.text("You are already on the hub!", NamedTextColor.YELLOW));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Optional<RegisteredServer> hubServer = findHubServer();
|
||||
|
||||
|
||||
if (hubServer.isEmpty()) {
|
||||
player.sendMessage(Component.text("Hub server not found!", NamedTextColor.RED));
|
||||
plugin.getLogger().warn("Hub server not found! Available servers: " +
|
||||
plugin.getServer().getAllServers().stream()
|
||||
.map(s -> s.getServerInfo().getName())
|
||||
.toList());
|
||||
plugin.getLogger().warn("Hub server not found! Available servers: " +
|
||||
plugin.getServer().getAllServers().stream()
|
||||
.map(s -> s.getServerInfo().getName())
|
||||
.toList());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
player.sendMessage(Component.text("Teleporting to hub...", NamedTextColor.GREEN));
|
||||
|
||||
|
||||
player.createConnectionRequest(hubServer.get()).fireAndForget();
|
||||
}
|
||||
|
||||
|
||||
private boolean isHubServer(String serverName) {
|
||||
return hubServers.stream().anyMatch(hub -> serverName.contains(hub));
|
||||
}
|
||||
|
||||
|
||||
private Optional<RegisteredServer> findHubServer() {
|
||||
return plugin.getServer().getAllServers().stream()
|
||||
.filter(server -> isHubServer(server.getServerInfo().getName().toLowerCase()))
|
||||
.findFirst();
|
||||
.filter(server -> isHubServer(server.getServerInfo().getName().toLowerCase()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<String>> suggestAsync(Invocation invocation) {
|
||||
return CompletableFuture.completedFuture(List.of());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Invocation invocation) {
|
||||
return invocation.source().hasPermission("lovelocity.hub");
|
||||
|
|
|
|||
|
|
@ -31,71 +31,76 @@ public final class LoChat extends JavaPlugin {
|
|||
private AutoMessageManager autoMessageManager;
|
||||
private CustomCommandManager customCommandManager;
|
||||
|
||||
// Геттеры
|
||||
public static LoChat getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
getLogger().info("Загрузка LoChat v" + getPluginMeta().getVersion() + " для Paper/Folia " + Bukkit.getMinecraftVersion() + "...");
|
||||
|
||||
|
||||
// Конфиги
|
||||
configManager = new ConfigManager(this);
|
||||
messageConfig = new MessageConfig(this);
|
||||
|
||||
|
||||
// Service Registry (SOLID DI) - с зависимостями
|
||||
serviceRegistry = new ServiceRegistry(this, configManager, messageConfig);
|
||||
serviceRegistry = ServiceRegistry.createWithDeps(this, configManager, messageConfig);
|
||||
getLogger().info("ServiceRegistry инициализирован (SOLID DI)");
|
||||
|
||||
|
||||
// Менеджеры
|
||||
customCommandManager = new CustomCommandManager(this);
|
||||
customCommandManager = CustomCommandManager.create(this);
|
||||
autoMessageManager = new AutoMessageManager(this);
|
||||
|
||||
|
||||
// Интеграции
|
||||
initIntegrations();
|
||||
|
||||
|
||||
// Команды и слушатели
|
||||
registerCommands();
|
||||
registerListeners();
|
||||
|
||||
|
||||
// Автосообщения
|
||||
autoMessageManager.start();
|
||||
|
||||
|
||||
getLogger().info("LoChat успешно запущен!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (autoMessageManager != null) autoMessageManager.stop();
|
||||
|
||||
|
||||
// Сохранение данных через сервисы
|
||||
IgnoreService ignoreService = serviceRegistry.get(IgnoreService.class);
|
||||
if (ignoreService != null) ignoreService.save();
|
||||
|
||||
|
||||
MuteService muteService = serviceRegistry.get(MuteService.class);
|
||||
if (muteService != null) muteService.save();
|
||||
|
||||
|
||||
NickService nickService = serviceRegistry.get(NickService.class);
|
||||
if (nickService != null) nickService.save();
|
||||
|
||||
|
||||
if (gradientModule != null) gradientModule.shutdown();
|
||||
getLogger().info("LoChat отключен!");
|
||||
}
|
||||
|
||||
|
||||
private void initIntegrations() {
|
||||
// Gradient модуль
|
||||
gradientModule = new GradientModule(this);
|
||||
if (gradientModule.init()) {
|
||||
getLogger().info("Gradient модуль (LoPreff) загружен!");
|
||||
}
|
||||
|
||||
|
||||
// LibertyBans
|
||||
new LibertyBansHook(this);
|
||||
|
||||
|
||||
// PlaceholderAPI
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
new PlaceholderAPIHook(this).register();
|
||||
getLogger().info("PlaceholderAPI подключен!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void registerCommands() {
|
||||
getCommand("g").setExecutor(new GlobalChatCommand(this));
|
||||
getCommand("l").setExecutor(new LocalChatCommand(this));
|
||||
|
|
@ -106,44 +111,44 @@ public final class LoChat extends JavaPlugin {
|
|||
getCommand("announce").setExecutor(new AnnounceCommand(this));
|
||||
getCommand("chatspy").setExecutor(new ChatSpyCommand(this));
|
||||
getCommand("clearchat").setExecutor(new ClearChatCommand(this));
|
||||
|
||||
|
||||
NickCommand nickCmd = new NickCommand(this);
|
||||
getCommand("nick").setExecutor(nickCmd);
|
||||
getCommand("nick").setTabCompleter(nickCmd);
|
||||
|
||||
|
||||
LoChatCommand loChatCmd = new LoChatCommand(this);
|
||||
getCommand("lochat").setExecutor(loChatCmd);
|
||||
getCommand("lochat").setTabCompleter(loChatCmd);
|
||||
|
||||
|
||||
MuteCommand muteCmd = new MuteCommand(this);
|
||||
getCommand("lmute").setExecutor(muteCmd);
|
||||
getCommand("lmute").setTabCompleter(muteCmd);
|
||||
|
||||
|
||||
UnmuteCommand unmuteCmd = new UnmuteCommand(this);
|
||||
getCommand("lunmute").setExecutor(unmuteCmd);
|
||||
getCommand("lunmute").setTabCompleter(unmuteCmd);
|
||||
|
||||
|
||||
getCommand("lmutelist").setExecutor(new MuteListCommand(this));
|
||||
|
||||
|
||||
MuteHistoryCommand historyCmd = new MuteHistoryCommand(this);
|
||||
getCommand("lmutehistory").setExecutor(historyCmd);
|
||||
getCommand("lmutehistory").setTabCompleter(historyCmd);
|
||||
|
||||
|
||||
MuteBlameCommand blameCmd = new MuteBlameCommand(this);
|
||||
getCommand("lmuteblame").setExecutor(blameCmd);
|
||||
getCommand("lmuteblame").setTabCompleter(blameCmd);
|
||||
|
||||
|
||||
ClearChatConfigCommand clearCfgCmd = new ClearChatConfigCommand(this);
|
||||
getCommand("clearchatconfig").setExecutor(clearCfgCmd);
|
||||
getCommand("clearchatconfig").setTabCompleter(clearCfgCmd);
|
||||
}
|
||||
|
||||
|
||||
private void registerListeners() {
|
||||
getServer().getPluginManager().registerEvents(new ChatEventListener(this, serviceRegistry), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerEventListener(serviceRegistry), this);
|
||||
getLogger().info("Слушатели зарегистрированы (новая архитектура)");
|
||||
}
|
||||
|
||||
|
||||
public void reload() {
|
||||
configManager.reload();
|
||||
messageConfig.reload();
|
||||
|
|
@ -152,11 +157,23 @@ public final class LoChat extends JavaPlugin {
|
|||
if (customCommandManager != null) customCommandManager.reload();
|
||||
}
|
||||
|
||||
// Геттеры
|
||||
public static LoChat getInstance() { return instance; }
|
||||
public ServiceRegistry getServiceRegistry() { return serviceRegistry; }
|
||||
public ConfigManager getConfigManager() { return configManager; }
|
||||
public MessageConfig getMessageConfig() { return messageConfig; }
|
||||
public GradientModule getGradientModule() { return gradientModule; }
|
||||
public CustomCommandManager getCustomCommandManager() { return customCommandManager; }
|
||||
public ServiceRegistry getServiceRegistry() {
|
||||
return serviceRegistry;
|
||||
}
|
||||
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
public MessageConfig getMessageConfig() {
|
||||
return messageConfig;
|
||||
}
|
||||
|
||||
public GradientModule getGradientModule() {
|
||||
return gradientModule;
|
||||
}
|
||||
|
||||
public CustomCommandManager getCustomCommandManager() {
|
||||
return customCommandManager;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ import org.bukkit.entity.Player;
|
|||
*/
|
||||
public interface ChatService {
|
||||
void sendGlobalMessage(Player sender, Object message);
|
||||
|
||||
void sendLocalMessage(Player sender, Object message);
|
||||
|
||||
boolean toggleGlobalChat(java.util.UUID player);
|
||||
|
||||
boolean isGlobalChatDisabled(java.util.UUID player);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ import java.util.UUID;
|
|||
*/
|
||||
public interface CooldownService {
|
||||
boolean isOnCooldown(UUID player, String type, int cooldownSeconds);
|
||||
|
||||
int getRemainingCooldown(UUID player, String type, int cooldownSeconds);
|
||||
|
||||
void setCooldown(UUID player, String type);
|
||||
|
||||
void removeCooldown(UUID player);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import org.bukkit.entity.Player;
|
|||
public interface MessageFilter {
|
||||
/**
|
||||
* Применить фильтр к сообщению
|
||||
*
|
||||
* @return отфильтрованное сообщение или null если заблокировано
|
||||
*/
|
||||
Object apply(Player player, Object message, String plainMessage);
|
||||
|
|
|
|||
|
|
@ -7,9 +7,14 @@ import java.util.UUID;
|
|||
*/
|
||||
public interface MuteService {
|
||||
void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy);
|
||||
|
||||
boolean unmute(UUID uuid, String unmutedBy);
|
||||
|
||||
boolean isMuted(UUID uuid);
|
||||
|
||||
long getRemainingTime(UUID uuid);
|
||||
|
||||
String formatTime(long millis);
|
||||
|
||||
long parseTime(String timeStr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import org.bukkit.entity.Player;
|
|||
public interface MessageFilter {
|
||||
/**
|
||||
* Применить фильтр к сообщению
|
||||
*
|
||||
* @return true если сообщение прошло фильтр, false если заблокировано
|
||||
*/
|
||||
boolean apply(Player player, ChatMessage message);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ import java.util.UUID;
|
|||
*/
|
||||
public interface ChatService {
|
||||
void sendGlobalMessage(Player sender, Object message);
|
||||
|
||||
void sendLocalMessage(Player sender, Object message);
|
||||
|
||||
boolean toggleGlobalChat(UUID player);
|
||||
|
||||
boolean isGlobalChatDisabled(UUID player);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ import java.util.UUID;
|
|||
*/
|
||||
public interface CooldownService {
|
||||
boolean isOnCooldown(UUID player, String type, int cooldownSeconds);
|
||||
|
||||
int getRemainingCooldown(UUID player, String type, int cooldownSeconds);
|
||||
|
||||
void setCooldown(UUID player, String type);
|
||||
|
||||
void removeCooldown(UUID player);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,39 +11,41 @@ public interface IgnoreService {
|
|||
* Проверяет, игнорирует ли игрок другого
|
||||
*/
|
||||
boolean isIgnoring(UUID player, UUID target);
|
||||
|
||||
|
||||
/**
|
||||
* Добавляет игрока в список игнорируемых
|
||||
*
|
||||
* @return true если успешно добавлен
|
||||
*/
|
||||
boolean addIgnore(UUID player, UUID target);
|
||||
|
||||
|
||||
/**
|
||||
* Удаляет игрока из списка игнорируемых
|
||||
*
|
||||
* @return true если успешно удалён
|
||||
*/
|
||||
boolean removeIgnore(UUID player, UUID target);
|
||||
|
||||
|
||||
/**
|
||||
* Получает список всех игнорируемых игроков
|
||||
*/
|
||||
Set<UUID> getIgnoredPlayers(UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Получает количество игнорируемых игроков
|
||||
*/
|
||||
int getIgnoredCount(UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Очищает список игнорируемых для игрока
|
||||
*/
|
||||
void clearIgnores(UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Сохраняет данные на диск
|
||||
*/
|
||||
void save();
|
||||
|
||||
|
||||
/**
|
||||
* Загружает данные с диска
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -10,26 +10,27 @@ import java.util.Set;
|
|||
public interface MentionService {
|
||||
/**
|
||||
* Обрабатывает упоминания в сообщении
|
||||
*
|
||||
* @return сообщение с подсвеченными никами
|
||||
*/
|
||||
String processMentions(String message, Set<Player> mentionedPlayers);
|
||||
|
||||
|
||||
/**
|
||||
* Создаёт персонализированное сообщение для игрока
|
||||
* Если его ник упомянут — выделяет его особым образом
|
||||
*/
|
||||
String getPersonalizedMessage(String message, Player viewer);
|
||||
|
||||
|
||||
/**
|
||||
* Проверяет, упомянут ли игрок в сообщении (по нику без @)
|
||||
*/
|
||||
boolean isPlayerMentioned(String message, Player player);
|
||||
|
||||
|
||||
/**
|
||||
* Уведомляет упомянутых игроков звуком
|
||||
*/
|
||||
void notifyMentioned(Set<Player> players);
|
||||
|
||||
|
||||
/**
|
||||
* Уведомляет игрока если его ник упомянут (без @)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import org.bukkit.entity.Player;
|
|||
public interface MessageService {
|
||||
/**
|
||||
* Обработать входящее сообщение чата
|
||||
*
|
||||
* @return true если сообщение обработано успешно
|
||||
*/
|
||||
boolean processMessage(Player player, String message);
|
||||
|
|
|
|||
|
|
@ -13,30 +13,38 @@ import java.util.UUID;
|
|||
public interface MuteService {
|
||||
// Основные операции
|
||||
void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy);
|
||||
|
||||
boolean unmute(UUID uuid, String unmutedBy);
|
||||
|
||||
boolean isMuted(UUID uuid);
|
||||
|
||||
MuteData getMuteData(UUID uuid);
|
||||
|
||||
long getRemainingTime(UUID uuid);
|
||||
|
||||
|
||||
// Утилиты времени
|
||||
String formatTime(long millis);
|
||||
|
||||
long parseTime(String timeStr);
|
||||
|
||||
|
||||
// Права доступа
|
||||
long getMaxDuration(Player player);
|
||||
|
||||
boolean canMuteForDuration(Player player, long duration);
|
||||
|
||||
|
||||
// История
|
||||
List<MuteData.MuteHistoryEntry> getPlayerHistory(UUID uuid);
|
||||
|
||||
List<MuteData.MuteHistoryEntry> getMutesByOperator(String operatorName);
|
||||
|
||||
UUID getUUIDByName(String name);
|
||||
|
||||
|
||||
// Список активных мутов
|
||||
Map<UUID, MuteData> getActiveMutes();
|
||||
|
||||
|
||||
// Форматирование сообщений
|
||||
String formatMessage(String message, String player, String operator, String duration, String reason);
|
||||
|
||||
|
||||
// Сохранение
|
||||
void save();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,48 +9,54 @@ import java.util.UUID;
|
|||
* Сервис для управления кастомными никами
|
||||
*/
|
||||
public interface NickService {
|
||||
|
||||
|
||||
/**
|
||||
* Устанавливает кастомный ник игроку
|
||||
* @param player UUID игрока
|
||||
*
|
||||
* @param player UUID игрока
|
||||
* @param nickname Новый ник (с поддержкой цветов и русских символов)
|
||||
* @return true если успешно, false если ник занят или невалиден
|
||||
*/
|
||||
boolean setNickname(UUID player, String nickname);
|
||||
|
||||
|
||||
/**
|
||||
* Сбрасывает кастомный ник игрока
|
||||
*
|
||||
* @param player UUID игрока
|
||||
*/
|
||||
void resetNickname(UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Получает кастомный ник игрока
|
||||
*
|
||||
* @param player UUID игрока
|
||||
* @return Optional с ником или empty если нет кастомного ника
|
||||
*/
|
||||
Optional<String> getNickname(UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Проверяет занят ли ник
|
||||
*
|
||||
* @param nickname Ник для проверки
|
||||
* @return true если ник уже используется
|
||||
*/
|
||||
boolean isNicknameTaken(String nickname);
|
||||
|
||||
|
||||
/**
|
||||
* Валидирует ник (длина, символы)
|
||||
*
|
||||
* @param nickname Ник для проверки
|
||||
* @return true если ник валиден
|
||||
*/
|
||||
boolean isValidNickname(String nickname);
|
||||
|
||||
|
||||
/**
|
||||
* Обновляет displayName и tabName игрока
|
||||
*
|
||||
* @param player Игрок
|
||||
*/
|
||||
void updatePlayerDisplay(Player player);
|
||||
|
||||
|
||||
/**
|
||||
* Сохраняет данные
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,17 +11,17 @@ public interface PMService {
|
|||
* Устанавливает последнего собеседника для игрока
|
||||
*/
|
||||
void setLastConversation(UUID player, UUID target);
|
||||
|
||||
|
||||
/**
|
||||
* Получает последнего собеседника игрока
|
||||
*/
|
||||
Optional<UUID> getLastConversation(UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Удаляет информацию о последнем разговоре
|
||||
*/
|
||||
void removeConversation(UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Проверяет, есть ли у игрока активный разговор
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ import java.util.UUID;
|
|||
*/
|
||||
public interface PlayerDataService {
|
||||
void clearPlayerData(UUID player);
|
||||
|
||||
void saveAll();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,25 +9,26 @@ import org.bukkit.entity.Player;
|
|||
public interface SpyService {
|
||||
/**
|
||||
* Переключает режим шпиона для игрока
|
||||
*
|
||||
* @return true если шпион включен, false если выключен
|
||||
*/
|
||||
boolean toggleSpy(java.util.UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Проверяет, находится ли игрок в режиме шпиона
|
||||
*/
|
||||
boolean isSpying(java.util.UUID player);
|
||||
|
||||
|
||||
/**
|
||||
* Отправляет сообщение всем шпионам (для обычного чата)
|
||||
*/
|
||||
void sendToSpies(Player sender, Component message, boolean isGlobal);
|
||||
|
||||
|
||||
/**
|
||||
* Отправляет информацию о личном сообщении шпионам
|
||||
*/
|
||||
void broadcastPM(Player sender, Player receiver, String message);
|
||||
|
||||
|
||||
/**
|
||||
* Удаляет игрока из списка шпионов
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -42,20 +42,20 @@ public class AnnounceCommand implements CommandExecutor {
|
|||
// Отправка в чат
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
player.sendMessage(formatted);
|
||||
|
||||
|
||||
// ActionBar (если включен)
|
||||
if (plugin.getConfigManager().isAnnouncementActionBarEnabled()) {
|
||||
player.sendActionBar(formatted);
|
||||
}
|
||||
|
||||
|
||||
// Title (если включен)
|
||||
if (plugin.getConfigManager().isAnnouncementTitleEnabled()) {
|
||||
Title title = Title.title(
|
||||
ChatFormatter.parse(plugin.getConfigManager().getAnnouncementTitleHeader()),
|
||||
ChatFormatter.parse(message),
|
||||
Title.Times.times(
|
||||
Duration.ofMillis(500),
|
||||
Duration.ofSeconds(plugin.getConfigManager().getAnnouncementTitleDuration()),
|
||||
Duration.ofMillis(500),
|
||||
Duration.ofSeconds(plugin.getConfigManager().getAnnouncementTitleDuration()),
|
||||
Duration.ofMillis(500)
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public class ClearChatCommand implements CommandExecutor {
|
|||
for (int i = 0; i < com.loki.lochat.utils.Constants.CLEAR_CHAT_LINES; i++) {
|
||||
player.sendMessage("");
|
||||
}
|
||||
|
||||
|
||||
// Уведомление (если включено)
|
||||
if (plugin.getConfigManager().isClearChatMessageEnabled()) {
|
||||
String message = plugin.getConfigManager().getClearChatMessage();
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public class ClearChatConfigCommand implements CommandExecutor, TabCompleter {
|
|||
sender.sendMessage(ChatFormatter.parse("&cУкажите текст сообщения!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
String message = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
plugin.getConfigManager().setClearChatMessage(message);
|
||||
sender.sendMessage(ChatFormatter.parse("&aСообщение установлено: &f" + message));
|
||||
|
|
@ -64,7 +64,7 @@ public class ClearChatConfigCommand implements CommandExecutor, TabCompleter {
|
|||
case "status" -> {
|
||||
boolean enabled = plugin.getConfigManager().isClearChatMessageEnabled();
|
||||
String message = plugin.getConfigManager().getClearChatMessage();
|
||||
|
||||
|
||||
sender.sendMessage(ChatFormatter.parse("&6Статус сообщения очистки чата:"));
|
||||
sender.sendMessage(ChatFormatter.parse("&eВключено: " + (enabled ? "&aДа" : "&cНет")));
|
||||
sender.sendMessage(ChatFormatter.parse("&eСообщение: &f" + message));
|
||||
|
|
|
|||
|
|
@ -9,17 +9,13 @@ import org.jetbrains.annotations.NotNull;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomCommand extends Command {
|
||||
public final class CustomCommand extends Command {
|
||||
|
||||
private final CustomCommandManager manager;
|
||||
|
||||
public CustomCommand(String name, CustomCommandManager manager) {
|
||||
super(name);
|
||||
this.manager = manager;
|
||||
init(name);
|
||||
}
|
||||
|
||||
private void init(String name) {
|
||||
this.setDescription("Кастомная команда LoChat");
|
||||
this.setUsage("/" + name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ import org.jetbrains.annotations.NotNull;
|
|||
*/
|
||||
public class GlobalChatCommand implements CommandExecutor {
|
||||
|
||||
private static final MiniMessage MM = MiniMessage.miniMessage();
|
||||
private final LoChat plugin;
|
||||
private final ChatService chatService;
|
||||
private static final MiniMessage MM = MiniMessage.miniMessage();
|
||||
|
||||
public GlobalChatCommand(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
|
|
@ -53,10 +53,10 @@ public class GlobalChatCommand implements CommandExecutor {
|
|||
}
|
||||
|
||||
String message = String.join(" ", args);
|
||||
|
||||
|
||||
// Конвертируем String в Component для новой сигнатуры ChatService
|
||||
Component messageComponent = MM.deserialize(message);
|
||||
|
||||
|
||||
chatService.sendGlobalMessage(player, messageComponent);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import java.util.List;
|
|||
|
||||
public class LoChatCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final LoChat plugin;
|
||||
private static final MiniMessage MM = MiniMessage.miniMessage();
|
||||
private final LoChat plugin;
|
||||
|
||||
public LoChatCommand(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
|
|
@ -51,14 +51,15 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
|
|||
var commands = plugin.getCustomCommandManager().getCommands();
|
||||
sender.sendMessage(MM.deserialize("&#FFD700Кастомные команды (" + commands.size() + "):"));
|
||||
for (var cmd : commands.values()) {
|
||||
sender.sendMessage(MM.deserialize("&e/" + cmd.name + " 󅒐(" + cmd.type + ")"));
|
||||
if (!cmd.aliases.isEmpty()) {
|
||||
sender.sendMessage(MM.deserialize("󅒐 Алиасы: " + String.join(", ", cmd.aliases)));
|
||||
sender.sendMessage(MM.deserialize("&e/" + cmd.name() + " 󅒐(" + cmd.type() + ")"));
|
||||
if (!cmd.aliases().isEmpty()) {
|
||||
sender.sendMessage(MM.deserialize("󅒐 Алиасы: " + String.join(", ", cmd.aliases())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default -> sender.sendMessage(MM.deserialize("&#FF0000Неизвестная команда. Используйте /lochat для помощи."));
|
||||
default ->
|
||||
sender.sendMessage(MM.deserialize("&#FF0000Неизвестная команда. Используйте /lochat для помощи."));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -66,7 +67,7 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
@Override
|
||||
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")) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
|
@ -74,7 +75,7 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
|
|||
if (args.length == 1) {
|
||||
List<String> completions = new ArrayList<>();
|
||||
String input = args[0].toLowerCase();
|
||||
|
||||
|
||||
for (String cmd : List.of("reload", "commands")) {
|
||||
if (cmd.startsWith(input)) {
|
||||
completions.add(cmd);
|
||||
|
|
@ -82,11 +83,11 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
|
|||
}
|
||||
return completions;
|
||||
}
|
||||
|
||||
|
||||
if (args.length == 2 && args[0].equalsIgnoreCase("commands")) {
|
||||
List<String> completions = new ArrayList<>();
|
||||
String input = args[1].toLowerCase();
|
||||
|
||||
|
||||
if ("reload".startsWith(input)) {
|
||||
completions.add("reload");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ import org.jetbrains.annotations.NotNull;
|
|||
*/
|
||||
public class LocalChatCommand implements CommandExecutor {
|
||||
|
||||
private static final MiniMessage MM = MiniMessage.miniMessage();
|
||||
private final LoChat plugin;
|
||||
private final ChatService chatService;
|
||||
private static final MiniMessage MM = MiniMessage.miniMessage();
|
||||
|
||||
public LocalChatCommand(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
|
|
@ -39,10 +39,10 @@ public class LocalChatCommand implements CommandExecutor {
|
|||
}
|
||||
|
||||
String message = String.join(" ", args);
|
||||
|
||||
|
||||
// Конвертируем String в Component для новой сигнатуры ChatService
|
||||
Component messageComponent = MM.deserialize(message);
|
||||
|
||||
|
||||
chatService.sendLocalMessage(player, messageComponent);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ 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.utils.ChatFormatter;
|
||||
import com.loki.lochat.utils.PlayerUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.Command;
|
||||
|
|
@ -89,10 +90,10 @@ public class MsgCommand implements CommandExecutor {
|
|||
|
||||
// Звук для получателя
|
||||
if (plugin.getConfigManager().isPmSoundEnabled()) {
|
||||
try {
|
||||
Sound sound = Sound.valueOf(plugin.getConfigManager().getPmSoundType());
|
||||
Sound sound = PlayerUtil.parseSound(plugin.getConfigManager().getPmSoundType(), null);
|
||||
if (sound != null) {
|
||||
target.playSound(target.getLocation(), sound, 1.0f, 1.0f);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
// Шпион
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ public class MuteBlameCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
@Override
|
||||
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<>();
|
||||
|
||||
if (args.length == 1) {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
|
|||
// Получаем настройки из конфига
|
||||
String defaultReason = plugin.getConfigManager().getString("mute.default-reason", "Нету.");
|
||||
String defaultDuration = plugin.getConfigManager().getString("mute.default-duration", "7d");
|
||||
|
||||
|
||||
String reason = reasonBuilder.length() > 0 ? reasonBuilder.toString() : defaultReason;
|
||||
|
||||
// Определяем длительность
|
||||
|
|
@ -136,7 +136,7 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
|
|||
// Уведомляем замученного (если онлайн)
|
||||
if (target != null) {
|
||||
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%");
|
||||
msg = muteService.formatMessage(msg, finalTargetName, operatorName, timeDisplay, reason);
|
||||
target.sendMessage(ChatFormatter.parse(msg));
|
||||
|
|
@ -147,7 +147,7 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
|
|||
String silentMsg = plugin.getConfigManager().getString("mute.messages.silent-muted",
|
||||
"§8[Тихо] §c%player% §7замучен на §c%duration% §7(%operator%). Причина: %reason%");
|
||||
silentMsg = muteService.formatMessage(silentMsg, finalTargetName, operatorName, timeDisplay, reason);
|
||||
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
if (p.hasPermission("lochat.mute.see-silent")) {
|
||||
p.sendMessage(ChatFormatter.parse(silentMsg));
|
||||
|
|
@ -170,7 +170,7 @@ public class MuteCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
@Override
|
||||
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<>();
|
||||
|
||||
if (args.length == 1) {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public class MuteHistoryCommand implements CommandExecutor, TabCompleter {
|
|||
// Выводим от новых к старым
|
||||
for (int i = history.size() - 1; i >= 0; i--) {
|
||||
MuteData.MuteHistoryEntry entry = history.get(i);
|
||||
|
||||
|
||||
// Статус
|
||||
String status;
|
||||
if (entry.unmuted) {
|
||||
|
|
@ -99,13 +99,13 @@ public class MuteHistoryCommand implements CommandExecutor, TabCompleter {
|
|||
sender.sendMessage(" §7Длительность: §f" + durationStr);
|
||||
sender.sendMessage(" §7Причина: §f" + (entry.reason != null ? entry.reason : "Не указана"));
|
||||
sender.sendMessage(" §7Выдал: §f" + entry.mutedBy);
|
||||
|
||||
|
||||
if (entry.unmuted && entry.unmutedBy != null) {
|
||||
sender.sendMessage(" §7Размутил: §f" + entry.unmutedBy + " §7(" + dateFormat.format(new Date(entry.unmutedAt)) + ")");
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
|
||||
// Ограничиваем вывод
|
||||
if (index > 10) {
|
||||
sender.sendMessage("§7... и ещё " + (history.size() - 10) + " записей");
|
||||
|
|
@ -118,7 +118,7 @@ public class MuteHistoryCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
@Override
|
||||
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<>();
|
||||
|
||||
if (args.length == 1) {
|
||||
|
|
|
|||
|
|
@ -45,19 +45,19 @@ public class MuteListCommand implements CommandExecutor {
|
|||
}
|
||||
|
||||
sender.sendMessage("§6§l=== Активные муты (" + activeMutes.size() + ") ===");
|
||||
|
||||
|
||||
int index = 1;
|
||||
for (Map.Entry<UUID, MuteData> entry : activeMutes.entrySet()) {
|
||||
UUID uuid = entry.getKey();
|
||||
MuteData data = entry.getValue();
|
||||
|
||||
|
||||
// Получаем имя игрока
|
||||
String playerName = data.getPlayerName();
|
||||
if (playerName == null) {
|
||||
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
|
||||
playerName = offlinePlayer.getName() != null ? offlinePlayer.getName() : uuid.toString().substring(0, 8);
|
||||
}
|
||||
|
||||
|
||||
// Форматируем время
|
||||
String timeStr;
|
||||
if (data.isPermanent()) {
|
||||
|
|
@ -66,11 +66,11 @@ public class MuteListCommand implements CommandExecutor {
|
|||
long remaining = data.getEndTime() - System.currentTimeMillis();
|
||||
timeStr = "§e" + muteService.formatTime(remaining);
|
||||
}
|
||||
|
||||
|
||||
sender.sendMessage("§7" + index + ". §f" + playerName + " §7- " + timeStr);
|
||||
sender.sendMessage(" §7Причина: §f" + (data.getReason() != null ? data.getReason() : "Не указана"));
|
||||
sender.sendMessage(" §7Выдал: §f" + data.getMutedBy() + " §7(" + dateFormat.format(new Date(data.getMutedAt())) + ")");
|
||||
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,39 +17,39 @@ import java.util.List;
|
|||
public class NickCommand implements CommandExecutor, TabCompleter {
|
||||
private final LoChat plugin;
|
||||
private final NickService nickService;
|
||||
|
||||
|
||||
public NickCommand(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
this.nickService = plugin.getServiceRegistry().get(NickService.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(Component.text("Эта команда только для игроков!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (!player.hasPermission("lochat.nick")) {
|
||||
player.sendMessage(Component.text("У вас нет прав на использование этой команды!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (args.length == 0) {
|
||||
return showCurrentNick(player);
|
||||
}
|
||||
|
||||
|
||||
if (args[0].equalsIgnoreCase("reset")) {
|
||||
return resetNick(player);
|
||||
}
|
||||
|
||||
|
||||
String nickname = String.join(" ", args);
|
||||
return setNick(player, nickname);
|
||||
}
|
||||
|
||||
|
||||
private boolean showCurrentNick(Player player) {
|
||||
var currentNick = nickService.getNickname(player.getUniqueId());
|
||||
|
||||
|
||||
if (currentNick.isPresent()) {
|
||||
Component nickComponent = ChatFormatter.parse(currentNick.get());
|
||||
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(" для установки", NamedTextColor.GRAY)));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean resetNick(Player player) {
|
||||
var currentNick = nickService.getNickname(player.getUniqueId());
|
||||
|
||||
|
||||
if (currentNick.isEmpty()) {
|
||||
player.sendMessage(Component.text("У вас нет кастомного ника!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
nickService.resetNickname(player.getUniqueId());
|
||||
player.sendMessage(Component.text("Ваш ник сброшен!", NamedTextColor.GREEN));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean setNick(Player player, String nickname) {
|
||||
if (!nickService.isValidNickname(nickname)) {
|
||||
player.sendMessage(Component.text("Невалидный ник!", NamedTextColor.RED));
|
||||
|
|
@ -89,7 +89,7 @@ public class NickCommand implements CommandExecutor, TabCompleter {
|
|||
player.sendMessage(Component.text("• Поддержка цветов: &#FF0000текст, <gradient:&#FF0000:�FF00>текст</gradient>", NamedTextColor.GRAY));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (nickService.isNicknameTaken(nickname)) {
|
||||
var currentNick = nickService.getNickname(player.getUniqueId());
|
||||
if (currentNick.isEmpty() || !currentNick.get().equals(nickname)) {
|
||||
|
|
@ -97,9 +97,9 @@ public class NickCommand implements CommandExecutor, TabCompleter {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean success = nickService.setNickname(player.getUniqueId(), nickname);
|
||||
|
||||
|
||||
if (success) {
|
||||
Component nickComponent = ChatFormatter.parse(nickname);
|
||||
player.sendMessage(Component.text("Ваш ник изменён на: ", NamedTextColor.GREEN)
|
||||
|
|
@ -107,33 +107,33 @@ public class NickCommand implements CommandExecutor, TabCompleter {
|
|||
} else {
|
||||
player.sendMessage(Component.text("Не удалось установить ник!", NamedTextColor.RED));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
List<String> completions = new ArrayList<>();
|
||||
|
||||
|
||||
if (args.length == 1) {
|
||||
String input = args[0].toLowerCase();
|
||||
|
||||
|
||||
if ("reset".startsWith(input)) {
|
||||
completions.add("reset");
|
||||
}
|
||||
|
||||
|
||||
if (sender instanceof Player player) {
|
||||
var currentNick = nickService.getNickname(player.getUniqueId());
|
||||
if (currentNick.isPresent()) {
|
||||
completions.add(currentNick.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
completions.add("&#FF0000Красный");
|
||||
completions.add("�FF00Зелёный");
|
||||
completions.add("Русский_Ник");
|
||||
}
|
||||
|
||||
|
||||
return completions;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class PlayerInfoCommand implements CommandExecutor {
|
|||
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" + target.getWorld().getName()));
|
||||
|
||||
|
||||
// Если есть градиентный модуль, показываем градиентное имя
|
||||
if (plugin.getGradientModule() != null) {
|
||||
String gradientName = plugin.getGradientModule().getFormattedName(target);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ 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.utils.ChatFormatter;
|
||||
import com.loki.lochat.utils.PlayerUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.Command;
|
||||
|
|
@ -88,10 +89,10 @@ public class ReplyCommand implements CommandExecutor {
|
|||
|
||||
// Звук для получателя
|
||||
if (plugin.getConfigManager().isPmSoundEnabled()) {
|
||||
try {
|
||||
Sound sound = Sound.valueOf(plugin.getConfigManager().getPmSoundType());
|
||||
Sound sound = PlayerUtil.parseSound(plugin.getConfigManager().getPmSoundType(), null);
|
||||
if (sound != null) {
|
||||
target.playSound(target.getLocation(), sound, 1.0f, 1.0f);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
// Шпион
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public class UnmuteCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
@Override
|
||||
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<>();
|
||||
|
||||
if (args.length == 1) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public class ConfigManager {
|
|||
this.plugin = plugin;
|
||||
plugin.saveDefaultConfig();
|
||||
this.config = plugin.getConfig();
|
||||
|
||||
|
||||
// Проверяем версию конфига и обновляем при необходимости
|
||||
updateConfig();
|
||||
}
|
||||
|
|
@ -23,17 +23,17 @@ public class ConfigManager {
|
|||
private void updateConfig() {
|
||||
int currentVersion = config.getInt("config-version", 1);
|
||||
int requiredVersion = 2; // Текущая версия конфига
|
||||
|
||||
|
||||
if (currentVersion < requiredVersion) {
|
||||
plugin.getLogger().info("Обновление конфига с версии " + currentVersion + " до " + requiredVersion);
|
||||
|
||||
|
||||
// Добавляем новые настройки если их нет
|
||||
addMissingConfigOptions();
|
||||
|
||||
|
||||
// Обновляем версию
|
||||
config.set("config-version", requiredVersion);
|
||||
plugin.saveConfig();
|
||||
|
||||
|
||||
plugin.getLogger().info("Конфиг успешно обновлен!");
|
||||
}
|
||||
}
|
||||
|
|
@ -46,12 +46,12 @@ public class ConfigManager {
|
|||
config.set("announcements.show-actionbar", true);
|
||||
config.set("announcements.title-duration", 3);
|
||||
}
|
||||
|
||||
|
||||
// Можно добавить другие недостающие настройки
|
||||
if (!config.contains("chat.pm.enabled")) {
|
||||
config.set("chat.pm.enabled", true);
|
||||
}
|
||||
|
||||
|
||||
if (!config.contains("mentions.enabled")) {
|
||||
config.set("mentions.enabled", true);
|
||||
config.set("mentions.sound", true);
|
||||
|
|
@ -59,18 +59,18 @@ public class ConfigManager {
|
|||
config.set("mentions.highlight", "&#FFFF00@{player}");
|
||||
config.set("mentions.self-highlight", "&#FFD700{player}");
|
||||
}
|
||||
|
||||
|
||||
if (!config.contains("automessages.enabled")) {
|
||||
config.set("automessages.enabled", true);
|
||||
config.set("automessages.interval", 300);
|
||||
config.set("automessages.random", false);
|
||||
}
|
||||
|
||||
|
||||
if (!config.contains("clearchat.message.enabled")) {
|
||||
config.set("clearchat.message.enabled", true);
|
||||
config.set("clearchat.message.text", "CADFЧат очищен администратором {player}");
|
||||
}
|
||||
|
||||
|
||||
if (!config.contains("lopreff.enabled")) {
|
||||
config.set("lopreff.enabled", true);
|
||||
config.set("lopreff.use-gradient-name", true);
|
||||
|
|
@ -197,21 +197,21 @@ public class ConfigManager {
|
|||
public String getSelfMentionHighlight() {
|
||||
return ChatFormatter.convertAllColors(config.getString("mentions.self-highlight", "&#FFD700{player}"));
|
||||
}
|
||||
|
||||
|
||||
// Clear chat
|
||||
public boolean isClearChatMessageEnabled() {
|
||||
return config.getBoolean("clearchat.message.enabled", true);
|
||||
}
|
||||
|
||||
|
||||
public void setClearChatMessageEnabled(boolean enabled) {
|
||||
config.set("clearchat.message.enabled", enabled);
|
||||
plugin.saveConfig();
|
||||
}
|
||||
|
||||
|
||||
public String getClearChatMessage() {
|
||||
return config.getString("clearchat.message.text", "CADFЧат очищен администратором {player}");
|
||||
}
|
||||
|
||||
|
||||
public void setClearChatMessage(String message) {
|
||||
config.set("clearchat.message.text", message);
|
||||
plugin.saveConfig();
|
||||
|
|
|
|||
|
|
@ -8,127 +8,127 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
public class AdvancedMessageFilter {
|
||||
|
||||
|
||||
private static final Pattern URL_PATTERN = Pattern.compile(
|
||||
"(https?://)?([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
"(https?://)?([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
);
|
||||
|
||||
|
||||
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(
|
||||
"(.)\\1{3,}"
|
||||
"(.)\\1{3,}"
|
||||
);
|
||||
|
||||
|
||||
private final FileConfiguration config;
|
||||
private final List<String> whitelistedDomains;
|
||||
private final List<String> blacklistedDomains;
|
||||
|
||||
|
||||
public AdvancedMessageFilter(FileConfiguration config) {
|
||||
this.config = config;
|
||||
this.whitelistedDomains = config.getStringList("filters.url.whitelist");
|
||||
this.blacklistedDomains = config.getStringList("filters.url.blacklist");
|
||||
}
|
||||
|
||||
|
||||
public FilterResult filterMessage(Player player, String message) {
|
||||
if (config.getBoolean("filters.url.enabled", true)) {
|
||||
FilterResult urlResult = filterUrls(player, message);
|
||||
if (!urlResult.isAllowed()) {
|
||||
if (!urlResult.allowed()) {
|
||||
return urlResult;
|
||||
}
|
||||
message = urlResult.getFilteredMessage();
|
||||
message = urlResult.filteredMessage();
|
||||
}
|
||||
|
||||
|
||||
if (config.getBoolean("filters.ip.enabled", true)) {
|
||||
FilterResult ipResult = filterIPs(player, message);
|
||||
if (!ipResult.isAllowed()) {
|
||||
if (!ipResult.allowed()) {
|
||||
return ipResult;
|
||||
}
|
||||
message = ipResult.getFilteredMessage();
|
||||
message = ipResult.filteredMessage();
|
||||
}
|
||||
|
||||
|
||||
if (config.getBoolean("filters.repeat.enabled", true)) {
|
||||
message = filterRepeatingChars(message);
|
||||
}
|
||||
|
||||
|
||||
return new FilterResult(true, message, null);
|
||||
}
|
||||
|
||||
|
||||
private FilterResult filterUrls(Player player, String message) {
|
||||
if (player.hasPermission("lochat.bypass.urlfilter")) {
|
||||
return new FilterResult(true, message, null);
|
||||
}
|
||||
|
||||
|
||||
Matcher matcher = URL_PATTERN.matcher(message);
|
||||
|
||||
|
||||
while (matcher.find()) {
|
||||
String url = matcher.group();
|
||||
String domain = extractDomain(url);
|
||||
|
||||
|
||||
if (!whitelistedDomains.isEmpty()) {
|
||||
boolean isWhitelisted = whitelistedDomains.stream()
|
||||
.anyMatch(d -> domain.toLowerCase().contains(d.toLowerCase()));
|
||||
|
||||
.anyMatch(d -> domain.toLowerCase().contains(d.toLowerCase()));
|
||||
|
||||
if (!isWhitelisted) {
|
||||
return new FilterResult(false, message,
|
||||
config.getString("filters.url.blocked-message", "&#FF6B6BСсылки запрещены!"));
|
||||
return new FilterResult(false, message,
|
||||
config.getString("filters.url.blocked-message", "&#FF6B6BСсылки запрещены!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!blacklistedDomains.isEmpty()) {
|
||||
boolean isBlacklisted = blacklistedDomains.stream()
|
||||
.anyMatch(d -> domain.toLowerCase().contains(d.toLowerCase()));
|
||||
|
||||
.anyMatch(d -> domain.toLowerCase().contains(d.toLowerCase()));
|
||||
|
||||
if (isBlacklisted) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
private FilterResult filterIPs(Player player, String message) {
|
||||
if (player.hasPermission("lochat.bypass.ipfilter")) {
|
||||
return new FilterResult(true, message, null);
|
||||
}
|
||||
|
||||
|
||||
Matcher matcher = IP_PATTERN.matcher(message);
|
||||
|
||||
|
||||
if (matcher.find()) {
|
||||
String replacement = config.getString("filters.ip.replacement", "[IP скрыт]");
|
||||
String filtered = matcher.replaceAll(replacement);
|
||||
|
||||
|
||||
if (config.getBoolean("filters.ip.block", false)) {
|
||||
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, message, null);
|
||||
}
|
||||
|
||||
|
||||
private String filterRepeatingChars(String message) {
|
||||
int maxRepeats = config.getInt("filters.repeat.max-repeats", 3);
|
||||
|
||||
|
||||
Matcher matcher = REPEAT_PATTERN.matcher(message);
|
||||
StringBuffer result = new StringBuffer();
|
||||
|
||||
|
||||
while (matcher.find()) {
|
||||
String repeated = matcher.group(1);
|
||||
String replacement = repeated.repeat(Math.min(maxRepeats, matcher.group().length()));
|
||||
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
|
||||
}
|
||||
matcher.appendTail(result);
|
||||
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
private String extractDomain(String url) {
|
||||
url = url.replaceFirst("^https?://", "");
|
||||
int slashIndex = url.indexOf('/');
|
||||
|
|
@ -137,28 +137,7 @@ public class AdvancedMessageFilter {
|
|||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
public static class FilterResult {
|
||||
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;
|
||||
}
|
||||
|
||||
public record FilterResult(boolean allowed, String filteredMessage, String blockReason) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,30 +13,30 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||
public class CooldownFilter implements MessageFilter {
|
||||
private final CooldownService cooldownService;
|
||||
private final FileConfiguration config;
|
||||
|
||||
|
||||
public CooldownFilter(CooldownService cooldownService, JavaPlugin plugin) {
|
||||
this.cooldownService = cooldownService;
|
||||
this.config = plugin.getConfig();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean apply(Player player, ChatMessage message) {
|
||||
if (player.hasPermission("chat.bypass.cooldown")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
String chatType = message.getChatType();
|
||||
int cooldown = config.getInt("chat." + chatType + ".cooldown", 0);
|
||||
|
||||
|
||||
if (cooldown > 0) {
|
||||
if (cooldownService.isOnCooldown(player.getUniqueId(), chatType, cooldown)) {
|
||||
int remaining = cooldownService.getRemainingCooldown(
|
||||
player.getUniqueId(), chatType, cooldown);
|
||||
player.getUniqueId(), chatType, cooldown);
|
||||
player.sendMessage("§cПодождите " + remaining + " сек.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cooldownService.setCooldown(player.getUniqueId(), chatType);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import org.bukkit.entity.Player;
|
|||
*/
|
||||
public class MuteFilter implements MessageFilter {
|
||||
private final MuteService muteService;
|
||||
|
||||
|
||||
public MuteFilter(MuteService muteService) {
|
||||
this.muteService = muteService;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean apply(Player player, ChatMessage message) {
|
||||
if (muteService.isMuted(player.getUniqueId())) {
|
||||
|
|
@ -23,7 +23,7 @@ public class MuteFilter implements MessageFilter {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void sendMuteNotification(Player player) {
|
||||
long remaining = muteService.getRemainingTime(player.getUniqueId());
|
||||
String timeStr = muteService.formatTime(remaining);
|
||||
|
|
|
|||
|
|
@ -12,25 +12,23 @@ import java.util.Map;
|
|||
public class ServiceRegistry {
|
||||
private final Map<Class<?>, Object> services = new HashMap<>();
|
||||
private final JavaPlugin plugin;
|
||||
|
||||
public ServiceRegistry(JavaPlugin plugin) {
|
||||
|
||||
private ServiceRegistry(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
init();
|
||||
}
|
||||
|
||||
public ServiceRegistry(JavaPlugin plugin, ConfigManager configManager, MessageConfig messageConfig) {
|
||||
this.plugin = plugin;
|
||||
initWithDeps(configManager, messageConfig);
|
||||
|
||||
public static ServiceRegistry create(JavaPlugin plugin) {
|
||||
ServiceRegistry registry = new ServiceRegistry(plugin);
|
||||
registry.registerServices();
|
||||
return registry;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
registerServices();
|
||||
|
||||
public static ServiceRegistry createWithDeps(JavaPlugin plugin, ConfigManager configManager, MessageConfig messageConfig) {
|
||||
ServiceRegistry registry = new ServiceRegistry(plugin);
|
||||
registry.registerServicesWithDeps(configManager, messageConfig);
|
||||
return registry;
|
||||
}
|
||||
|
||||
private void initWithDeps(ConfigManager configManager, MessageConfig messageConfig) {
|
||||
registerServicesWithDeps(configManager, messageConfig);
|
||||
}
|
||||
|
||||
|
||||
private void registerServices() {
|
||||
register(ChatService.class, new ChatServiceImpl(plugin, this));
|
||||
register(MuteService.class, new MuteServiceImpl(plugin));
|
||||
|
|
@ -38,25 +36,25 @@ public class ServiceRegistry {
|
|||
register(MessageService.class, new MessageServiceImpl(plugin, this));
|
||||
register(PlayerDataService.class, new PlayerDataServiceImpl(plugin));
|
||||
}
|
||||
|
||||
|
||||
private void registerServicesWithDeps(ConfigManager configManager, MessageConfig messageConfig) {
|
||||
register(ChatService.class, new ChatServiceImpl(plugin, this));
|
||||
register(MuteService.class, new MuteServiceImpl(plugin));
|
||||
register(CooldownService.class, new CooldownServiceImpl());
|
||||
register(MessageService.class, new MessageServiceImpl(plugin, this));
|
||||
register(PlayerDataService.class, new PlayerDataServiceImpl(plugin));
|
||||
|
||||
|
||||
register(PMService.class, new PMServiceImpl());
|
||||
register(IgnoreService.class, new IgnoreServiceImpl(plugin));
|
||||
register(SpyService.class, new SpyServiceImpl(plugin, messageConfig));
|
||||
register(MentionService.class, new MentionServiceImpl(configManager));
|
||||
register(NickService.class, new NickServiceImpl(plugin));
|
||||
}
|
||||
|
||||
|
||||
public <T> void register(Class<T> serviceClass, T implementation) {
|
||||
services.put(serviceClass, implementation);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(Class<T> serviceClass) {
|
||||
Object service = services.get(serviceClass);
|
||||
|
|
@ -65,7 +63,7 @@ public class ServiceRegistry {
|
|||
}
|
||||
return (T) service;
|
||||
}
|
||||
|
||||
|
||||
public void shutdown() {
|
||||
services.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,61 +19,61 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
public class ChatServiceImpl implements ChatService {
|
||||
private final JavaPlugin plugin;
|
||||
private final Set<UUID> globalChatDisabled = ConcurrentHashMap.newKeySet();
|
||||
|
||||
|
||||
public ChatServiceImpl(JavaPlugin plugin, ServiceRegistry registry) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void sendGlobalMessage(Player sender, Object message) {
|
||||
String format = plugin.getConfig().getString("chat.global.format",
|
||||
"{prefix} {player}: {message}");
|
||||
String format = plugin.getConfig().getString("chat.global.format",
|
||||
"{prefix} {player}: {message}");
|
||||
String prefix = plugin.getConfig().getString("chat.global.prefix", "[G]");
|
||||
|
||||
Component messageComponent = (message instanceof Component)
|
||||
? (Component) message
|
||||
: ChatFormatter.parse(message.toString());
|
||||
|
||||
|
||||
Component messageComponent = (message instanceof Component)
|
||||
? (Component) message
|
||||
: ChatFormatter.parse(message.toString());
|
||||
|
||||
// Используем displayName игрока (с градиентом если есть)
|
||||
Component playerName = sender.displayName();
|
||||
|
||||
|
||||
String formatted = format.replace("{prefix}", prefix);
|
||||
|
||||
|
||||
Component finalComponent = ChatFormatter.parse(formatted)
|
||||
.replaceText(builder -> builder.matchLiteral("{player}").replacement(playerName))
|
||||
.replaceText(builder -> builder.matchLiteral("{message}").replacement(messageComponent));
|
||||
|
||||
.replaceText(builder -> builder.matchLiteral("{player}").replacement(playerName))
|
||||
.replaceText(builder -> builder.matchLiteral("{message}").replacement(messageComponent));
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (!isGlobalChatDisabled(player.getUniqueId())) {
|
||||
player.sendMessage(finalComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void sendLocalMessage(Player sender, Object message) {
|
||||
int radius = plugin.getConfig().getInt("chat.local.radius", 100);
|
||||
String format = plugin.getConfig().getString("chat.local.format",
|
||||
"{player}: {message}");
|
||||
|
||||
Component messageComponent = (message instanceof Component)
|
||||
? (Component) message
|
||||
: ChatFormatter.parse(message.toString());
|
||||
|
||||
String format = plugin.getConfig().getString("chat.local.format",
|
||||
"{player}: {message}");
|
||||
|
||||
Component messageComponent = (message instanceof Component)
|
||||
? (Component) message
|
||||
: ChatFormatter.parse(message.toString());
|
||||
|
||||
// Используем displayName игрока (с градиентом если есть)
|
||||
Component playerName = sender.displayName();
|
||||
|
||||
|
||||
Component finalComponent = ChatFormatter.parse(format)
|
||||
.replaceText(builder -> builder.matchLiteral("{player}").replacement(playerName))
|
||||
.replaceText(builder -> builder.matchLiteral("{message}").replacement(messageComponent));
|
||||
|
||||
.replaceText(builder -> builder.matchLiteral("{player}").replacement(playerName))
|
||||
.replaceText(builder -> builder.matchLiteral("{message}").replacement(messageComponent));
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (DistanceUtil.isInRange(sender, player, radius)) {
|
||||
player.sendMessage(finalComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean toggleGlobalChat(UUID player) {
|
||||
if (globalChatDisabled.contains(player)) {
|
||||
|
|
@ -84,7 +84,7 @@ public class ChatServiceImpl implements ChatService {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isGlobalChatDisabled(UUID player) {
|
||||
return globalChatDisabled.contains(player);
|
||||
|
|
|
|||
|
|
@ -12,40 +12,40 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
public class CooldownServiceImpl implements CooldownService {
|
||||
private final Map<UUID, Long> globalCooldowns = new ConcurrentHashMap<>();
|
||||
private final Map<UUID, Long> localCooldowns = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isOnCooldown(UUID player, String type, int cooldownSeconds) {
|
||||
Map<UUID, Long> cooldowns = getCooldownMap(type);
|
||||
Long lastTime = cooldowns.get(player);
|
||||
|
||||
|
||||
if (lastTime == null) return false;
|
||||
|
||||
|
||||
long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
|
||||
return elapsed < cooldownSeconds;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getRemainingCooldown(UUID player, String type, int cooldownSeconds) {
|
||||
Map<UUID, Long> cooldowns = getCooldownMap(type);
|
||||
Long lastTime = cooldowns.get(player);
|
||||
|
||||
|
||||
if (lastTime == null) return 0;
|
||||
|
||||
|
||||
long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
|
||||
return Math.max(0, cooldownSeconds - (int) elapsed);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setCooldown(UUID player, String type) {
|
||||
getCooldownMap(type).put(player, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void removeCooldown(UUID player) {
|
||||
globalCooldowns.remove(player);
|
||||
localCooldowns.remove(player);
|
||||
}
|
||||
|
||||
|
||||
private Map<UUID, Long> getCooldownMap(String type) {
|
||||
return type.equals("global") ? globalCooldowns : localCooldowns;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.loki.lochat.core.service;
|
|||
|
||||
import com.loki.lochat.api.service.IgnoreService;
|
||||
import com.loki.lochat.gradient.util.FoliaUtil;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -9,8 +10,6 @@ import java.io.IOException;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
/**
|
||||
* Реализация сервиса игнорирования
|
||||
*/
|
||||
|
|
@ -39,13 +38,15 @@ public class IgnoreServiceImpl implements IgnoreService {
|
|||
for (String ignoredStr : ignoredList) {
|
||||
try {
|
||||
ignored.add(UUID.fromString(ignoredStr));
|
||||
} catch (Exception ignored2) {}
|
||||
} catch (Exception ignored2) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignored.isEmpty()) {
|
||||
ignoreMap.put(uuid, ignored);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.loki.lochat.core.service;
|
|||
|
||||
import com.loki.lochat.api.service.MentionService;
|
||||
import com.loki.lochat.config.ConfigManager;
|
||||
import com.loki.lochat.utils.PlayerUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
|
|
@ -17,9 +18,8 @@ import java.util.regex.Pattern;
|
|||
* Реализация сервиса упоминаний
|
||||
*/
|
||||
public class MentionServiceImpl implements MentionService {
|
||||
private final ConfigManager configManager;
|
||||
private static final Pattern MENTION_PATTERN = Pattern.compile("@(\\w+)");
|
||||
|
||||
private final ConfigManager configManager;
|
||||
// Хранит для какого игрока какие части сообщения выделить
|
||||
private final Map<Player, Set<String>> highlightedNicks = new HashMap<>();
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ public class MentionServiceImpl implements MentionService {
|
|||
mentionedPlayers.add(mentioned);
|
||||
String replacement = highlight.replace("{player}", mentioned.getName());
|
||||
matcher.appendReplacement(result, replacement);
|
||||
|
||||
|
||||
// Запоминаем что этот игрок упомянут
|
||||
highlightedNicks.computeIfAbsent(mentioned, k -> new HashSet<>()).add(mentioned.getName());
|
||||
}
|
||||
|
|
@ -64,23 +64,23 @@ public class MentionServiceImpl implements MentionService {
|
|||
|
||||
String viewerName = viewer.getName();
|
||||
String result = message;
|
||||
|
||||
|
||||
// Проверяем упоминание через @ник
|
||||
String highlight = configManager.getMentionHighlight();
|
||||
String highlightedName = highlight.replace("{player}", viewerName);
|
||||
|
||||
|
||||
// Если в сообщении есть выделенный ник этого игрока — добавляем дополнительное выделение
|
||||
if (result.contains(highlightedName)) {
|
||||
// Уже выделено через processMentions, добавляем эффект
|
||||
String extraHighlight = "<bold>" + highlightedName + "</bold>";
|
||||
result = result.replace(highlightedName, extraHighlight);
|
||||
}
|
||||
|
||||
|
||||
// Также проверяем просто ник в сообщении (без @)
|
||||
// Регистронезависимый поиск
|
||||
Pattern nickPattern = Pattern.compile("(?i)\\b" + Pattern.quote(viewerName) + "\\b");
|
||||
Matcher nickMatcher = nickPattern.matcher(result);
|
||||
|
||||
|
||||
if (nickMatcher.find()) {
|
||||
// Ник найден в сообщении — выделяем для этого игрока
|
||||
String selfHighlight = configManager.getSelfMentionHighlight();
|
||||
|
|
@ -104,12 +104,7 @@ public class MentionServiceImpl implements MentionService {
|
|||
}
|
||||
|
||||
String soundName = configManager.getMentionSoundType();
|
||||
Sound sound;
|
||||
try {
|
||||
sound = Sound.valueOf(soundName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sound = Sound.BLOCK_NOTE_BLOCK_PLING;
|
||||
}
|
||||
Sound sound = PlayerUtil.parseSound(soundName, Sound.BLOCK_NOTE_BLOCK_PLING);
|
||||
|
||||
for (Player player : players) {
|
||||
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) {
|
||||
if (viewer.equals(sender)) return;
|
||||
if (!configManager.isMentionSoundEnabled()) return;
|
||||
|
||||
|
||||
if (isPlayerMentioned(message, viewer)) {
|
||||
String soundName = configManager.getMentionSoundType();
|
||||
try {
|
||||
Sound sound = Sound.valueOf(soundName);
|
||||
Sound sound = PlayerUtil.parseSound(soundName, null);
|
||||
if (sound != null) {
|
||||
viewer.playSound(viewer.getLocation(), sound, 1.0f, 1.0f);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
package com.loki.lochat.core.service;
|
||||
|
||||
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.MuteFilter;
|
||||
import com.loki.lochat.core.registry.ServiceRegistry;
|
||||
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.plugin.java.JavaPlugin;
|
||||
|
||||
|
|
@ -21,29 +22,29 @@ public class MessageServiceImpl implements MessageService {
|
|||
private final JavaPlugin plugin;
|
||||
private final List<MessageFilter> filters;
|
||||
private final ChatService chatService;
|
||||
|
||||
|
||||
public MessageServiceImpl(JavaPlugin plugin, ServiceRegistry registry) {
|
||||
this.plugin = plugin;
|
||||
this.chatService = registry.get(ChatService.class);
|
||||
this.filters = new ArrayList<>();
|
||||
|
||||
|
||||
// Регистрируем фильтры в порядке применения
|
||||
filters.add(new MuteFilter(registry.get(MuteService.class)));
|
||||
filters.add(new CooldownFilter(registry.get(CooldownService.class), plugin));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean processMessage(Player player, String rawMessage) {
|
||||
// Создаем объект сообщения
|
||||
ChatMessage message = ChatMessage.create(player, rawMessage);
|
||||
|
||||
|
||||
// Применяем фильтры (мут, кулдаун)
|
||||
for (MessageFilter filter : filters) {
|
||||
if (!filter.apply(player, message)) {
|
||||
return false; // Сообщение заблокировано
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Возвращаем true - сообщение разрешено
|
||||
// Рендерер сам отправит его
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public class MuteServiceImpl implements MuteService {
|
|||
private final File dataFile;
|
||||
private final File historyFile;
|
||||
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
|
||||
public MuteServiceImpl(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.dataFile = new File(plugin.getDataFolder(), "mutes.json");
|
||||
|
|
@ -32,19 +32,19 @@ public class MuteServiceImpl implements MuteService {
|
|||
load();
|
||||
loadHistory();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void mute(UUID uuid, String playerName, long duration, String reason, String mutedBy) {
|
||||
long endTime = duration > 0 ? System.currentTimeMillis() + duration : 0;
|
||||
MuteData data = new MuteData(uuid, playerName, endTime, reason, mutedBy);
|
||||
mutes.put(uuid, data);
|
||||
|
||||
|
||||
// Добавляем в историю
|
||||
addToHistory(uuid, playerName, duration, reason, mutedBy);
|
||||
|
||||
|
||||
saveAsync();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean unmute(UUID uuid, String unmutedBy) {
|
||||
MuteData removed = mutes.remove(uuid);
|
||||
|
|
@ -55,12 +55,12 @@ public class MuteServiceImpl implements MuteService {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isMuted(UUID uuid) {
|
||||
MuteData data = mutes.get(uuid);
|
||||
if (data == null) return false;
|
||||
|
||||
|
||||
if (data.getEndTime() > 0 && System.currentTimeMillis() > data.getEndTime()) {
|
||||
mutes.remove(uuid);
|
||||
saveAsync();
|
||||
|
|
@ -68,13 +68,13 @@ public class MuteServiceImpl implements MuteService {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MuteData getMuteData(UUID uuid) {
|
||||
if (!isMuted(uuid)) return null;
|
||||
return mutes.get(uuid);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getRemainingTime(UUID uuid) {
|
||||
MuteData data = mutes.get(uuid);
|
||||
|
|
@ -82,16 +82,16 @@ public class MuteServiceImpl implements MuteService {
|
|||
if (data.getEndTime() == 0) return -1; // Перманентный
|
||||
return Math.max(0, data.getEndTime() - System.currentTimeMillis());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String formatTime(long millis) {
|
||||
if (millis <= 0) return "0с";
|
||||
|
||||
|
||||
long seconds = millis / 1000;
|
||||
long minutes = seconds / 60;
|
||||
long hours = minutes / 60;
|
||||
long days = hours / 24;
|
||||
|
||||
|
||||
if (days > 0) {
|
||||
return days + "д " + (hours % 24) + "ч";
|
||||
} else if (hours > 0) {
|
||||
|
|
@ -102,14 +102,14 @@ public class MuteServiceImpl implements MuteService {
|
|||
return seconds + "с";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long parseTime(String timeStr) {
|
||||
if (timeStr == null || timeStr.isEmpty()) return 0;
|
||||
|
||||
|
||||
timeStr = timeStr.toLowerCase();
|
||||
long multiplier = 1000; // базово в миллисекундах
|
||||
|
||||
|
||||
try {
|
||||
if (timeStr.endsWith("d")) {
|
||||
return Long.parseLong(timeStr.replace("d", "")) * 24 * 60 * 60 * multiplier;
|
||||
|
|
@ -126,45 +126,45 @@ public class MuteServiceImpl implements MuteService {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getMaxDuration(Player player) {
|
||||
if (player.hasPermission("lochat.mute.dur.perm")) {
|
||||
return 0; // Перманентный
|
||||
}
|
||||
|
||||
|
||||
String[] durations = {"30d", "14d", "7d", "3d", "1d", "12h", "6h", "1h", "30m", "10m"};
|
||||
for (String dur : durations) {
|
||||
if (player.hasPermission("lochat.mute.dur." + dur)) {
|
||||
return parseTime(dur);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return -1; // Нет прав
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canMuteForDuration(Player player, long duration) {
|
||||
if (player.hasPermission("lochat.mute.dur.perm")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (duration == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
long maxDuration = getMaxDuration(player);
|
||||
if (maxDuration == -1) return false;
|
||||
if (maxDuration == 0) return true;
|
||||
|
||||
|
||||
return duration <= maxDuration;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<MuteData.MuteHistoryEntry> getPlayerHistory(UUID uuid) {
|
||||
return history.getOrDefault(uuid, new ArrayList<>());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<MuteData.MuteHistoryEntry> getMutesByOperator(String operatorName) {
|
||||
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));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UUID getUUIDByName(String name) {
|
||||
for (Map.Entry<UUID, List<MuteData.MuteHistoryEntry>> entry : history.entrySet()) {
|
||||
|
|
@ -190,7 +190,7 @@ public class MuteServiceImpl implements MuteService {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<UUID, MuteData> getActiveMutes() {
|
||||
mutes.entrySet().removeIf(entry -> {
|
||||
|
|
@ -199,7 +199,7 @@ public class MuteServiceImpl implements MuteService {
|
|||
});
|
||||
return new HashMap<>(mutes);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String formatMessage(String message, String player, String operator, String duration, String reason) {
|
||||
return message
|
||||
|
|
@ -208,17 +208,17 @@ public class MuteServiceImpl implements MuteService {
|
|||
.replace("%duration%", duration != null ? duration : "")
|
||||
.replace("%reason%", reason != null ? reason : "");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
try {
|
||||
if (!dataFile.getParentFile().exists()) {
|
||||
dataFile.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
|
||||
Map<String, MuteData> toSave = new ConcurrentHashMap<>();
|
||||
mutes.forEach((uuid, data) -> toSave.put(uuid.toString(), data));
|
||||
|
||||
|
||||
try (Writer writer = new FileWriter(dataFile)) {
|
||||
gson.toJson(toSave, writer);
|
||||
}
|
||||
|
|
@ -226,52 +226,56 @@ public class MuteServiceImpl implements MuteService {
|
|||
plugin.getLogger().warning("Ошибка сохранения мутов: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void load() {
|
||||
if (!dataFile.exists()) return;
|
||||
|
||||
|
||||
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);
|
||||
if (loaded != null) {
|
||||
loaded.forEach((key, value) -> {
|
||||
try {
|
||||
mutes.put(UUID.fromString(key), value);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().warning("Ошибка загрузки мутов: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void loadHistory() {
|
||||
if (!historyFile.exists()) return;
|
||||
|
||||
|
||||
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);
|
||||
if (loaded != null) {
|
||||
loaded.forEach((key, value) -> {
|
||||
try {
|
||||
history.put(UUID.fromString(key), new ArrayList<>(value));
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().warning("Ошибка загрузки истории мутов: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void saveHistory() {
|
||||
try {
|
||||
if (!historyFile.getParentFile().exists()) {
|
||||
historyFile.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
|
||||
Map<String, List<MuteData.MuteHistoryEntry>> toSave = new ConcurrentHashMap<>();
|
||||
history.forEach((uuid, data) -> toSave.put(uuid.toString(), data));
|
||||
|
||||
|
||||
try (Writer writer = new FileWriter(historyFile)) {
|
||||
gson.toJson(toSave, writer);
|
||||
}
|
||||
|
|
@ -279,7 +283,7 @@ public class MuteServiceImpl implements MuteService {
|
|||
plugin.getLogger().warning("Ошибка сохранения истории мутов: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addToHistory(UUID uuid, String playerName, long duration, String reason, String mutedBy) {
|
||||
List<MuteData.MuteHistoryEntry> playerHistory = history.computeIfAbsent(uuid, k -> new ArrayList<>());
|
||||
playerHistory.add(new MuteData.MuteHistoryEntry(
|
||||
|
|
@ -294,7 +298,7 @@ public class MuteServiceImpl implements MuteService {
|
|||
));
|
||||
saveHistoryAsync();
|
||||
}
|
||||
|
||||
|
||||
private void updateHistoryUnmute(UUID uuid, String unmutedBy) {
|
||||
List<MuteData.MuteHistoryEntry> playerHistory = history.get(uuid);
|
||||
if (playerHistory != null && !playerHistory.isEmpty()) {
|
||||
|
|
@ -310,11 +314,11 @@ public class MuteServiceImpl implements MuteService {
|
|||
}
|
||||
saveHistoryAsync();
|
||||
}
|
||||
|
||||
|
||||
private void saveHistoryAsync() {
|
||||
FoliaUtil.runAsync(plugin, this::saveHistory);
|
||||
}
|
||||
|
||||
|
||||
private void saveAsync() {
|
||||
FoliaUtil.runAsync(plugin, () -> {
|
||||
save();
|
||||
|
|
|
|||
|
|
@ -12,28 +12,29 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Реализация сервиса кастомных ников
|
||||
*/
|
||||
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 Map<UUID, String> nicknames = new ConcurrentHashMap<>();
|
||||
private final File dataFile;
|
||||
private FileConfiguration data;
|
||||
|
||||
// Настройки
|
||||
private static final int MIN_LENGTH = 3;
|
||||
private static final int MAX_LENGTH = 16;
|
||||
|
||||
|
||||
public NickServiceImpl(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.dataFile = new File(plugin.getDataFolder(), "nicknames.yml");
|
||||
load();
|
||||
}
|
||||
|
||||
|
||||
private void load() {
|
||||
if (!dataFile.exists()) {
|
||||
try {
|
||||
|
|
@ -43,9 +44,9 @@ public class NickServiceImpl implements NickService {
|
|||
plugin.getLogger().warning("Не удалось создать nicknames.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data = YamlConfiguration.loadConfiguration(dataFile);
|
||||
|
||||
|
||||
// Загружаем ники
|
||||
if (data.contains("nicknames")) {
|
||||
for (String key : data.getConfigurationSection("nicknames").getKeys(false)) {
|
||||
|
|
@ -54,10 +55,10 @@ public class NickServiceImpl implements NickService {
|
|||
nicknames.put(uuid, nickname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
plugin.getLogger().info("Загружено " + nicknames.size() + " кастомных ников");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
// Сохраняем ники
|
||||
|
|
@ -65,21 +66,21 @@ public class NickServiceImpl implements NickService {
|
|||
for (Map.Entry<UUID, String> entry : nicknames.entrySet()) {
|
||||
data.set("nicknames." + entry.getKey().toString(), entry.getValue());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
data.save(dataFile);
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().warning("Не удалось сохранить nicknames.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setNickname(UUID player, String nickname) {
|
||||
// Валидация
|
||||
if (!isValidNickname(nickname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Проверка уникальности
|
||||
if (isNicknameTaken(nickname)) {
|
||||
// Проверяем не свой ли это ник
|
||||
|
|
@ -88,23 +89,23 @@ public class NickServiceImpl implements NickService {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Устанавливаем ник
|
||||
nicknames.put(player, nickname);
|
||||
|
||||
|
||||
// Обновляем display
|
||||
Player onlinePlayer = Bukkit.getPlayer(player);
|
||||
if (onlinePlayer != null) {
|
||||
updatePlayerDisplay(onlinePlayer);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void resetNickname(UUID player) {
|
||||
nicknames.remove(player);
|
||||
|
||||
|
||||
// Сбрасываем display
|
||||
Player onlinePlayer = Bukkit.getPlayer(player);
|
||||
if (onlinePlayer != null) {
|
||||
|
|
@ -112,59 +113,55 @@ public class NickServiceImpl implements NickService {
|
|||
onlinePlayer.playerListName(Component.text(onlinePlayer.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<String> getNickname(UUID player) {
|
||||
return Optional.ofNullable(nicknames.get(player));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isNicknameTaken(String nickname) {
|
||||
String cleanNick = stripColors(nickname).toLowerCase();
|
||||
|
||||
|
||||
// Проверяем существующие ники
|
||||
for (String existingNick : nicknames.values()) {
|
||||
if (stripColors(existingNick).equalsIgnoreCase(cleanNick)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Проверяем реальные ники онлайн игроков
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.getName().equalsIgnoreCase(cleanNick)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isValidNickname(String nickname) {
|
||||
if (nickname == null || nickname.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Убираем цвета для проверки длины
|
||||
String cleanNick = stripColors(nickname);
|
||||
|
||||
|
||||
// Проверка длины
|
||||
if (cleanNick.length() < MIN_LENGTH || cleanNick.length() > MAX_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Проверка символов (разрешены буквы, цифры, _, русские буквы)
|
||||
if (!cleanNick.matches("[a-zA-Zа-яА-Я0-9_]+")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return cleanNick.matches("[a-zA-Zа-яА-Я0-9_]+");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updatePlayerDisplay(Player player) {
|
||||
Optional<String> nickname = getNickname(player.getUniqueId());
|
||||
|
||||
|
||||
if (nickname.isPresent()) {
|
||||
// Парсим ник с цветами
|
||||
Component nickComponent = ChatFormatter.parse(nickname.get());
|
||||
|
|
@ -176,7 +173,7 @@ public class NickServiceImpl implements NickService {
|
|||
player.playerListName(Component.text(player.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Убирает цвета из строки
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,16 +11,16 @@ import java.util.UUID;
|
|||
*/
|
||||
public class PlayerDataServiceImpl implements PlayerDataService {
|
||||
private final CooldownService cooldownService;
|
||||
|
||||
|
||||
public PlayerDataServiceImpl(JavaPlugin plugin) {
|
||||
this.cooldownService = new CooldownServiceImpl();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clearPlayerData(UUID player) {
|
||||
cooldownService.removeCooldown(player);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void saveAll() {
|
||||
// Сохранение всех данных при выключении
|
||||
|
|
|
|||
|
|
@ -60,10 +60,10 @@ public class SpyServiceImpl implements SpyService {
|
|||
@Override
|
||||
public void sendToSpies(Player sender, Component message, boolean isGlobal) {
|
||||
if (spyEnabled.isEmpty()) return;
|
||||
|
||||
|
||||
String chatType = isGlobal ? "Global" : "Local";
|
||||
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}");
|
||||
|
||||
for (UUID spyUuid : spyEnabled) {
|
||||
|
|
|
|||
|
|
@ -7,33 +7,50 @@ import org.bukkit.entity.Player;
|
|||
*/
|
||||
public class ChatMessage {
|
||||
private final Player sender;
|
||||
private String content;
|
||||
private final boolean isGlobal;
|
||||
private final long timestamp;
|
||||
|
||||
private String content;
|
||||
|
||||
private ChatMessage(Player sender, String content, boolean isGlobal) {
|
||||
this.sender = sender;
|
||||
this.content = content;
|
||||
this.isGlobal = isGlobal;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
public static ChatMessage create(Player sender, String rawMessage) {
|
||||
// Определяем тип чата
|
||||
boolean isGlobal = rawMessage.startsWith("!") &&
|
||||
sender.hasPermission("chat.global.use");
|
||||
|
||||
String content = isGlobal ?
|
||||
rawMessage.substring(1).trim() :
|
||||
rawMessage.trim();
|
||||
|
||||
boolean isGlobal = rawMessage.startsWith("!") &&
|
||||
sender.hasPermission("chat.global.use");
|
||||
|
||||
String content = isGlobal ?
|
||||
rawMessage.substring(1).trim() :
|
||||
rawMessage.trim();
|
||||
|
||||
return new ChatMessage(sender, content, isGlobal);
|
||||
}
|
||||
|
||||
public Player getSender() { return sender; }
|
||||
public String getContent() { 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"; }
|
||||
|
||||
public Player getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,16 @@ import java.util.UUID;
|
|||
* Модель данных мута (Value Object)
|
||||
*/
|
||||
public class MuteData {
|
||||
private UUID uuid;
|
||||
private String playerName;
|
||||
public long endTime; // 0 = перманентный (public for JSON serialization)
|
||||
public String reason;
|
||||
public String mutedBy;
|
||||
public long mutedAt;
|
||||
|
||||
public MuteData() {} // For JSON deserialization
|
||||
|
||||
private UUID uuid;
|
||||
private String playerName;
|
||||
|
||||
public MuteData() {
|
||||
} // For JSON deserialization
|
||||
|
||||
public MuteData(UUID uuid, String playerName, long endTime, String reason, String mutedBy) {
|
||||
this.uuid = uuid;
|
||||
this.playerName = playerName;
|
||||
|
|
@ -23,7 +24,7 @@ public class MuteData {
|
|||
this.mutedBy = mutedBy;
|
||||
this.mutedAt = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
public MuteData(long endTime, String reason, String mutedBy, long mutedAt, String playerName) {
|
||||
this.endTime = endTime;
|
||||
this.reason = reason;
|
||||
|
|
@ -31,15 +32,35 @@ public class MuteData {
|
|||
this.mutedAt = mutedAt;
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
public UUID getUuid() { return uuid; }
|
||||
public String getPlayerName() { return playerName; }
|
||||
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; }
|
||||
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
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 String unmutedBy;
|
||||
public long unmutedAt;
|
||||
|
||||
public MuteHistoryEntry() {} // For JSON deserialization
|
||||
|
||||
public MuteHistoryEntry(String playerName, long duration, String reason,
|
||||
String mutedBy, long mutedAt, boolean unmuted,
|
||||
String unmutedBy, long unmutedAt) {
|
||||
|
||||
public MuteHistoryEntry() {
|
||||
} // For JSON deserialization
|
||||
|
||||
public MuteHistoryEntry(String playerName, long duration, String reason,
|
||||
String mutedBy, long mutedAt, boolean unmuted,
|
||||
String unmutedBy, long unmutedAt) {
|
||||
this.playerName = playerName;
|
||||
this.duration = duration;
|
||||
this.reason = reason;
|
||||
|
|
|
|||
|
|
@ -37,18 +37,19 @@ public class GradientModule {
|
|||
|
||||
/**
|
||||
* Инициализация модуля
|
||||
*
|
||||
* @return true если модуль успешно инициализирован
|
||||
*/
|
||||
public boolean init() {
|
||||
// Загружаем конфиги
|
||||
config = new GradientConfig(plugin);
|
||||
messages = new GradientMessages(plugin);
|
||||
|
||||
|
||||
if (!config.isEnabled()) {
|
||||
plugin.getLogger().info("Gradient модуль отключен в конфиге.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Проверяем PlayerPoints (опционально теперь)
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) {
|
||||
playerPointsAPI = PlayerPoints.getInstance().getAPI();
|
||||
|
|
@ -56,10 +57,10 @@ public class GradientModule {
|
|||
} else {
|
||||
plugin.getLogger().warning("Gradient: PlayerPoints не найден. Покупки будут бесплатными.");
|
||||
}
|
||||
|
||||
|
||||
// Инициализация хранилища
|
||||
dataManager = new GradientDataManager(plugin, config);
|
||||
|
||||
|
||||
// Подключение LuckPerms (опционально)
|
||||
try {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) {
|
||||
|
|
@ -71,15 +72,15 @@ public class GradientModule {
|
|||
} catch (NoClassDefFoundError e) {
|
||||
plugin.getLogger().info("Gradient: LuckPerms не найден. Префиксы LuckPerms будут недоступны.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Регистрация команд
|
||||
registerCommands();
|
||||
|
||||
|
||||
// Регистрация слушателей
|
||||
Bukkit.getPluginManager().registerEvents(new GradientPlayerListener(this), plugin);
|
||||
Bukkit.getPluginManager().registerEvents(new GradientGUIListener(this), plugin);
|
||||
|
||||
|
||||
enabled = true;
|
||||
plugin.getLogger().info("Gradient модуль успешно загружен!");
|
||||
return true;
|
||||
|
|
@ -91,13 +92,13 @@ public class GradientModule {
|
|||
plugin.getCommand("color").setExecutor(colorCommand);
|
||||
plugin.getCommand("color").setTabCompleter(colorCommand);
|
||||
}
|
||||
|
||||
|
||||
GradientPrefixCommand prefixCommand = new GradientPrefixCommand(this);
|
||||
if (plugin.getCommand("prefix") != null) {
|
||||
plugin.getCommand("prefix").setExecutor(prefixCommand);
|
||||
plugin.getCommand("prefix").setTabCompleter(prefixCommand);
|
||||
}
|
||||
|
||||
|
||||
GradientAdminCommand adminCommand = new GradientAdminCommand(this);
|
||||
if (plugin.getCommand("aprefix") != null) {
|
||||
plugin.getCommand("aprefix").setExecutor(adminCommand);
|
||||
|
|
@ -141,22 +142,23 @@ public class GradientModule {
|
|||
|
||||
/**
|
||||
* Получает отформатированное имя игрока с градиентом и LuckPerms префиксом
|
||||
*
|
||||
* @param useTabFormat true для §x§... формата (TAB), false для &#RRGGBB
|
||||
*/
|
||||
private String getFormattedName(Player player, boolean useTabFormat) {
|
||||
if (!enabled) return player.getName();
|
||||
|
||||
|
||||
GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId());
|
||||
|
||||
|
||||
// Собираем полную строку: префикс + ник
|
||||
StringBuilder fullText = new StringBuilder();
|
||||
|
||||
|
||||
// LuckPerms префикс
|
||||
String lpPrefix = null;
|
||||
if (luckPermsHook.isEnabled()) {
|
||||
lpPrefix = luckPermsHook.getActivePrefix(player);
|
||||
}
|
||||
|
||||
|
||||
// Определяем какой префикс использовать
|
||||
if (data.hasPrefix() && data.isPrefixEnabled()) {
|
||||
// Кастомный префикс
|
||||
|
|
@ -167,21 +169,21 @@ public class GradientModule {
|
|||
fullText.append(stripColors(lpPrefix));
|
||||
} else {
|
||||
// LP префикс со своими цветами, ник отдельно
|
||||
String nick = data.hasColors() && data.isColorEnabled()
|
||||
? applyGradientWithFormat(player.getName(), data.getColors(), useTabFormat)
|
||||
: player.getName();
|
||||
String nick = data.hasColors() && data.isColorEnabled()
|
||||
? applyGradientWithFormat(player.getName(), data.getColors(), useTabFormat)
|
||||
: player.getName();
|
||||
return lpPrefix + nick;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Добавляем ник
|
||||
fullText.append(player.getName());
|
||||
|
||||
|
||||
// Применяем единый градиент на всю строку
|
||||
if (data.hasColors() && data.isColorEnabled()) {
|
||||
return applyGradientWithFormat(fullText.toString(), data.getColors(), useTabFormat);
|
||||
}
|
||||
|
||||
|
||||
return fullText.toString();
|
||||
}
|
||||
|
||||
|
|
@ -211,12 +213,12 @@ public class GradientModule {
|
|||
*/
|
||||
public String getGradientNick(Player player) {
|
||||
if (!enabled) return player.getName();
|
||||
|
||||
|
||||
GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId());
|
||||
if (!data.hasColors() || !data.isColorEnabled()) {
|
||||
return player.getName();
|
||||
}
|
||||
|
||||
|
||||
return GradientUtil.applyGradient(player.getName(), data.getColors(), config.isUseLegacyRgbFormat());
|
||||
}
|
||||
|
||||
|
|
@ -226,9 +228,9 @@ public class GradientModule {
|
|||
*/
|
||||
public String getPrefix(Player player) {
|
||||
if (!enabled) return "";
|
||||
|
||||
|
||||
GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId());
|
||||
|
||||
|
||||
// Кастомный префикс
|
||||
if (data.hasPrefix() && data.isPrefixEnabled()) {
|
||||
String prefix = config.getPrefixFormat().replace("{prefix}", data.getPrefix());
|
||||
|
|
@ -237,7 +239,7 @@ public class GradientModule {
|
|||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
// LuckPerms префикс
|
||||
if (luckPermsHook.isEnabled()) {
|
||||
String lpPrefix = luckPermsHook.getActivePrefix(player);
|
||||
|
|
@ -249,7 +251,7 @@ public class GradientModule {
|
|||
return lpPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
@ -263,12 +265,35 @@ public class GradientModule {
|
|||
}
|
||||
|
||||
// Геттеры
|
||||
public JavaPlugin getPlugin() { return plugin; }
|
||||
public GradientConfig getConfig() { return config; }
|
||||
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; }
|
||||
public JavaPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public GradientConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ import java.util.List;
|
|||
*/
|
||||
public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final GradientModule module;
|
||||
private static final List<String> PRESET_COLORS = Arrays.asList(
|
||||
"#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3"
|
||||
);
|
||||
private final GradientModule module;
|
||||
|
||||
public GradientAdminCommand(GradientModule module) {
|
||||
this.module = module;
|
||||
|
|
@ -153,11 +153,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
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();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
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") + " <игрок>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
msg.send(sender, "player-not-found");
|
||||
|
|
@ -221,11 +221,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
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") + " <игрок>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
msg.send(sender, "player-not-found");
|
||||
|
|
@ -256,11 +256,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aПрефикс для игрока §f" + args[1] + (enable ? " §aвключён" : " §cвыключен"));
|
||||
|
|
@ -271,7 +271,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
sender.sendMessage("§cИспользование: /aprefix resetcolor <игрок>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
msg.send(sender, "player-not-found");
|
||||
|
|
@ -284,11 +284,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aЦвет для игрока §f" + args[1] + " §aсброшен");
|
||||
|
|
@ -299,7 +299,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
sender.sendMessage("§cИспользование: /aprefix resetprefix <игрок>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||
msg.send(sender, "player-not-found");
|
||||
|
|
@ -316,11 +316,11 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
Player onlineTarget = target.getPlayer();
|
||||
if (onlineTarget != null) {
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), onlineTarget,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, onlineTarget, data));
|
||||
}
|
||||
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(target.getUniqueId()));
|
||||
|
||||
sender.sendMessage("§aПрефикс для игрока §f" + args[1] + " §aсброшен");
|
||||
|
|
@ -330,7 +330,7 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
int count = 0;
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, player, data));
|
||||
count++;
|
||||
}
|
||||
|
|
@ -340,19 +340,19 @@ public class GradientAdminCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
@Override
|
||||
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 (args.length == 1) {
|
||||
return Arrays.asList("reload", "info", "setcolor", "setprefix", "coloron", "coloroff",
|
||||
"prefixon", "prefixoff", "resetcolor", "resetprefix", "updateall").stream()
|
||||
return Arrays.asList("reload", "info", "setcolor", "setprefix", "coloron", "coloroff",
|
||||
"prefixon", "prefixoff", "resetcolor", "resetprefix", "updateall").stream()
|
||||
.filter(s -> s.startsWith(args[0].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
if (args.length == 2) {
|
||||
String sub = args[0].toLowerCase();
|
||||
if (Arrays.asList("info", "setcolor", "setprefix", "coloron", "coloroff",
|
||||
if (Arrays.asList("info", "setcolor", "setprefix", "coloron", "coloroff",
|
||||
"prefixon", "prefixoff", "resetcolor", "resetprefix").contains(sub)) {
|
||||
return Bukkit.getOnlinePlayers().stream()
|
||||
.map(Player::getName)
|
||||
|
|
|
|||
|
|
@ -26,14 +26,13 @@ import java.util.function.BiFunction;
|
|||
*/
|
||||
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(
|
||||
"#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3",
|
||||
"#FF69B4", "#00FFFF", "#FFD700", "#FFFFFF", "#000000"
|
||||
);
|
||||
private static final Set<String> SUB_COMMANDS = Set.of("on", "off", "reset", "copy");
|
||||
private final GradientModule module;
|
||||
private final Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>();
|
||||
|
||||
public GradientColorCommand(GradientModule module) {
|
||||
this.module = module;
|
||||
|
|
@ -77,12 +76,12 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
|
|||
private boolean handleOn(Player player, String[] args) {
|
||||
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
|
||||
GradientMessages msg = module.getMessages();
|
||||
|
||||
|
||||
if (!data.hasColors()) {
|
||||
msg.send(player, "color-no-colors");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
data.setColorEnabled(true);
|
||||
saveAndUpdate(player, data);
|
||||
msg.send(player, "color-enabled");
|
||||
|
|
@ -100,12 +99,12 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
|
|||
private boolean handleReset(Player player, String[] args) {
|
||||
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
|
||||
GradientMessages msg = module.getMessages();
|
||||
|
||||
|
||||
if (!data.hasColors()) {
|
||||
msg.send(player, "color-no-colors");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
data.setColors(new ArrayList<>());
|
||||
data.setColorEnabled(false);
|
||||
saveAndUpdate(player, data);
|
||||
|
|
@ -116,18 +115,18 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
|
|||
private boolean handleCopy(Player player, String[] args) {
|
||||
GradientMessages msg = module.getMessages();
|
||||
GradientConfig cfg = module.getConfig();
|
||||
|
||||
|
||||
if (args.length < 2) {
|
||||
msg.send(player, "color-copy-usage");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Player target = Bukkit.getPlayer(args[1]);
|
||||
if (target == null) {
|
||||
msg.send(player, "player-not-found");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
GradientPlayerData targetData = module.getDataManager().getPlayerData(target.getUniqueId());
|
||||
if (!targetData.hasColors()) {
|
||||
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());
|
||||
|
||||
if (!player.hasPermission("gradient.bypass.cooldown") &&
|
||||
|
||||
if (!player.hasPermission("gradient.bypass.cooldown") &&
|
||||
!checkCooldown(player, cfg.getColorCooldown(), data.getLastColorChange())) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -148,7 +147,7 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
|
|||
return true;
|
||||
}
|
||||
|
||||
GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
|
||||
GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
|
||||
GradientConfirmGUI.ConfirmType.COLOR, colors, data.getPrefix(), price);
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open);
|
||||
return true;
|
||||
|
|
@ -170,7 +169,7 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
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())) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -191,7 +190,7 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
|
|||
return true;
|
||||
}
|
||||
|
||||
GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
|
||||
GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
|
||||
GradientConfirmGUI.ConfirmType.COLOR, colors, data.getPrefix(), price);
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open);
|
||||
return true;
|
||||
|
|
@ -222,35 +221,35 @@ public class GradientColorCommand implements CommandExecutor, TabCompleter {
|
|||
}
|
||||
|
||||
private void saveAndUpdate(Player player, GradientPlayerData data) {
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, player, data));
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(player.getUniqueId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
String input = args[0].toLowerCase();
|
||||
List<String> completions = new ArrayList<>(SUB_COMMANDS);
|
||||
completions.addAll(PRESET_COLORS);
|
||||
return completions.stream().filter(s -> s.toLowerCase().startsWith(input)).toList();
|
||||
}
|
||||
|
||||
|
||||
String firstArg = args[0].toLowerCase();
|
||||
|
||||
|
||||
if (args.length == 2 && firstArg.equals("copy")) {
|
||||
return Bukkit.getOnlinePlayers().stream().map(Player::getName)
|
||||
.filter(s -> s.toLowerCase().startsWith(args[1].toLowerCase())).toList();
|
||||
}
|
||||
|
||||
|
||||
if (!SUB_COMMANDS.contains(firstArg) && args.length <= module.getConfig().getMaxColors()) {
|
||||
return PRESET_COLORS.stream()
|
||||
.filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,12 @@ import java.util.regex.Pattern;
|
|||
*/
|
||||
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(
|
||||
"(?i)(&[0-9a-fk-or]|§[0-9a-fk-or]|#[0-9a-f]{6}|&#[0-9a-f]{6}|<#[0-9a-f]{6}>)");
|
||||
private static final Pattern ALLOWED_PREFIX_PATTERN = Pattern.compile("^[a-zA-Zа-яА-ЯёЁ0-9 _\\-]+$");
|
||||
private static final Set<String> SUB_COMMANDS = Set.of("on", "off", "reset");
|
||||
private final GradientModule module;
|
||||
private final Map<String, BiFunction<Player, String[], Boolean>> subCommands = new HashMap<>();
|
||||
|
||||
public GradientPrefixCommand(GradientModule module) {
|
||||
this.module = module;
|
||||
|
|
@ -77,12 +76,12 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
|
|||
private boolean handleOn(Player player, String[] args) {
|
||||
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
|
||||
GradientMessages msg = module.getMessages();
|
||||
|
||||
|
||||
if (!data.hasPrefix()) {
|
||||
msg.send(player, "prefix-no-prefix");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
data.setPrefixEnabled(true);
|
||||
if (module.getLuckPermsHook() != null) {
|
||||
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) {
|
||||
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
|
||||
GradientMessages msg = module.getMessages();
|
||||
|
||||
|
||||
if (!data.hasPrefix()) {
|
||||
msg.send(player, "prefix-no-prefix");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
data.setPrefix(null);
|
||||
data.setPrefixEnabled(false);
|
||||
if (module.getLuckPermsHook() != null) {
|
||||
|
|
@ -154,7 +153,7 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
|
|||
|
||||
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())) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -165,9 +164,9 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
|
|||
return true;
|
||||
}
|
||||
|
||||
GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
|
||||
GradientConfirmGUI.ConfirmType.PREFIX,
|
||||
data.hasColors() && data.isColorEnabled() ? data.getColors() : null,
|
||||
GradientConfirmGUI gui = new GradientConfirmGUI(module, player,
|
||||
GradientConfirmGUI.ConfirmType.PREFIX,
|
||||
data.hasColors() && data.isColorEnabled() ? data.getColors() : null,
|
||||
prefix, price);
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player, gui::open);
|
||||
return true;
|
||||
|
|
@ -203,15 +202,15 @@ public class GradientPrefixCommand implements CommandExecutor, TabCompleter {
|
|||
}
|
||||
|
||||
private void saveAndUpdate(Player player, GradientPlayerData data) {
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, player, data));
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(player.getUniqueId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
return SUB_COMMANDS.stream()
|
||||
.filter(s -> s.startsWith(args[0].toLowerCase()))
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class GradientConfig {
|
|||
plugin.saveResource("gradient-config.yml", false);
|
||||
}
|
||||
config = YamlConfiguration.loadConfiguration(configFile);
|
||||
|
||||
|
||||
// Загружаем дефолты
|
||||
InputStream defStream = plugin.getResource("gradient-config.yml");
|
||||
if (defStream != null) {
|
||||
|
|
@ -56,23 +56,70 @@ public class GradientConfig {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() { return config.getBoolean("enabled", true); }
|
||||
public int getMaxColors() { return config.getInt("max-colors", 7); }
|
||||
public int getMinColors() { return config.getInt("min-colors", 1); }
|
||||
public int getPricePerColor() { return config.getInt("price-per-color", 50); }
|
||||
public int getPrefixPrice() { return config.getInt("prefix-price", 500); }
|
||||
public boolean isPrefixOneTimePurchase() { return config.getBoolean("prefix-one-time-purchase", true); }
|
||||
public int 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 boolean isEnabled() {
|
||||
return config.getBoolean("enabled", true);
|
||||
}
|
||||
|
||||
public int getMaxColors() {
|
||||
return config.getInt("max-colors", 7);
|
||||
}
|
||||
|
||||
public int getMinColors() {
|
||||
return config.getInt("min-colors", 1);
|
||||
}
|
||||
|
||||
public int getPricePerColor() {
|
||||
return config.getInt("price-per-color", 50);
|
||||
}
|
||||
|
||||
public int getPrefixPrice() {
|
||||
return config.getInt("prefix-price", 500);
|
||||
}
|
||||
|
||||
public boolean isPrefixOneTimePurchase() {
|
||||
return config.getBoolean("prefix-one-time-purchase", true);
|
||||
}
|
||||
|
||||
public int 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() {
|
||||
return config.getStringList("prefix-blacklist");
|
||||
}
|
||||
|
|
@ -83,17 +130,17 @@ public class GradientConfig {
|
|||
.anyMatch(blacklisted -> lowerPrefix.contains(blacklisted.toLowerCase()));
|
||||
}
|
||||
|
||||
public boolean isUpdateDisplayName() {
|
||||
public boolean isUpdateDisplayName() {
|
||||
if (mainConfig.contains("display.update-display-name")) {
|
||||
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")) {
|
||||
return mainConfig.getBoolean("display.update-tab-list", true);
|
||||
}
|
||||
return config.getBoolean("display.update-tab-list", true);
|
||||
return config.getBoolean("display.update-tab-list", true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class GradientMessages {
|
|||
plugin.saveResource("gradient-messages.yml", false);
|
||||
}
|
||||
messages = YamlConfiguration.loadConfiguration(messagesFile);
|
||||
|
||||
|
||||
InputStream defStream = plugin.getResource("gradient-messages.yml");
|
||||
if (defStream != null) {
|
||||
YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class GradientDataManager {
|
|||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.useSqlite = config.getStorageType().equalsIgnoreCase("SQLITE");
|
||||
|
||||
|
||||
if (useSqlite) {
|
||||
initSqlite();
|
||||
} else {
|
||||
|
|
@ -40,20 +40,20 @@ public class GradientDataManager {
|
|||
try {
|
||||
File dbFile = new File(plugin.getDataFolder(), config.getSqliteFile());
|
||||
sqliteConnection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
|
||||
|
||||
|
||||
try (Statement stmt = sqliteConnection.createStatement()) {
|
||||
stmt.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS gradient_data (
|
||||
uuid TEXT PRIMARY KEY,
|
||||
prefix TEXT,
|
||||
colors TEXT,
|
||||
color_enabled INTEGER DEFAULT 1,
|
||||
prefix_enabled INTEGER DEFAULT 1,
|
||||
prefix_purchased INTEGER DEFAULT 0,
|
||||
last_color_change INTEGER DEFAULT 0,
|
||||
last_prefix_change INTEGER DEFAULT 0
|
||||
)
|
||||
""");
|
||||
CREATE TABLE IF NOT EXISTS gradient_data (
|
||||
uuid TEXT PRIMARY KEY,
|
||||
prefix TEXT,
|
||||
colors TEXT,
|
||||
color_enabled INTEGER DEFAULT 1,
|
||||
prefix_enabled INTEGER DEFAULT 1,
|
||||
prefix_purchased INTEGER DEFAULT 0,
|
||||
last_color_change INTEGER DEFAULT 0,
|
||||
last_prefix_change INTEGER DEFAULT 0
|
||||
)
|
||||
""");
|
||||
}
|
||||
plugin.getLogger().info("Gradient SQLite база данных инициализирована.");
|
||||
} catch (SQLException e) {
|
||||
|
|
@ -65,7 +65,7 @@ public class GradientDataManager {
|
|||
private void loadYamlData() {
|
||||
File dataFile = new File(plugin.getDataFolder(), "gradient-data.yml");
|
||||
if (!dataFile.exists()) return;
|
||||
|
||||
|
||||
FileConfiguration data = YamlConfiguration.loadConfiguration(dataFile);
|
||||
for (String uuidStr : data.getKeys(false)) {
|
||||
try {
|
||||
|
|
@ -79,7 +79,8 @@ public class GradientDataManager {
|
|||
playerData.setLastColorChange(data.getLong(uuidStr + ".last-color-change", 0));
|
||||
playerData.setLastPrefixChange(data.getLong(uuidStr + ".last-prefix-change", 0));
|
||||
cache.put(uuid, playerData);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +90,7 @@ public class GradientDataManager {
|
|||
|
||||
private GradientPlayerData loadPlayerData(UUID uuid) {
|
||||
GradientPlayerData data = new GradientPlayerData(uuid);
|
||||
|
||||
|
||||
if (useSqlite && sqliteConnection != null) {
|
||||
try (PreparedStatement stmt = sqliteConnection.prepareStatement(
|
||||
"SELECT prefix, colors, color_enabled, prefix_enabled, prefix_purchased, last_color_change, last_prefix_change FROM gradient_data WHERE uuid = ?")) {
|
||||
|
|
@ -111,14 +112,14 @@ public class GradientDataManager {
|
|||
plugin.getLogger().warning("Ошибка загрузки gradient данных: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public void savePlayerData(UUID uuid) {
|
||||
GradientPlayerData data = cache.get(uuid);
|
||||
if (data == null) return;
|
||||
|
||||
|
||||
if (useSqlite && sqliteConnection != null) {
|
||||
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 (?, ?, ?, ?, ?, ?, ?, ?)")) {
|
||||
|
|
@ -150,7 +151,7 @@ public class GradientDataManager {
|
|||
private void saveYamlData() {
|
||||
File dataFile = new File(plugin.getDataFolder(), "gradient-data.yml");
|
||||
FileConfiguration data = new YamlConfiguration();
|
||||
|
||||
|
||||
for (Map.Entry<UUID, GradientPlayerData> entry : cache.entrySet()) {
|
||||
String path = entry.getKey().toString();
|
||||
GradientPlayerData pd = entry.getValue();
|
||||
|
|
@ -162,7 +163,7 @@ public class GradientDataManager {
|
|||
data.set(path + ".last-color-change", pd.getLastColorChange());
|
||||
data.set(path + ".last-prefix-change", pd.getLastPrefixChange());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
data.save(dataFile);
|
||||
} catch (IOException e) {
|
||||
|
|
|
|||
|
|
@ -29,25 +29,71 @@ public class GradientPlayerData {
|
|||
this.lastPrefixChange = 0;
|
||||
}
|
||||
|
||||
public UUID getUuid() { return uuid; }
|
||||
public String getPrefix() { return prefix; }
|
||||
public void setPrefix(String prefix) { this.prefix = prefix; }
|
||||
public List<String> getColors() { return colors; }
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public List<String> getColors() {
|
||||
return colors;
|
||||
}
|
||||
|
||||
public void setColors(List<String> colors) {
|
||||
this.colors = colors != null ? new ArrayList<>(colors) : new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean hasPrefix() { return prefix != null && !prefix.isEmpty(); }
|
||||
public boolean hasColors() { return colors != null && !colors.isEmpty(); }
|
||||
public boolean isColorEnabled() { return colorEnabled; }
|
||||
public void setColorEnabled(boolean colorEnabled) { this.colorEnabled = colorEnabled; }
|
||||
public boolean isPrefixEnabled() { return prefixEnabled; }
|
||||
public void setPrefixEnabled(boolean prefixEnabled) { this.prefixEnabled = prefixEnabled; }
|
||||
public boolean isPrefixPurchased() { return prefixPurchased; }
|
||||
public void setPrefixPurchased(boolean prefixPurchased) { this.prefixPurchased = prefixPurchased; }
|
||||
public long getLastColorChange() { return lastColorChange; }
|
||||
public void setLastColorChange(long lastColorChange) { this.lastColorChange = lastColorChange; }
|
||||
public long getLastPrefixChange() { return lastPrefixChange; }
|
||||
public void setLastPrefixChange(long lastPrefixChange) { this.lastPrefixChange = lastPrefixChange; }
|
||||
public boolean hasPrefix() {
|
||||
return prefix != null && !prefix.isEmpty();
|
||||
}
|
||||
|
||||
public boolean hasColors() {
|
||||
return colors != null && !colors.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isColorEnabled() {
|
||||
return colorEnabled;
|
||||
}
|
||||
|
||||
public void setColorEnabled(boolean colorEnabled) {
|
||||
this.colorEnabled = colorEnabled;
|
||||
}
|
||||
|
||||
public boolean isPrefixEnabled() {
|
||||
return prefixEnabled;
|
||||
}
|
||||
|
||||
public void setPrefixEnabled(boolean prefixEnabled) {
|
||||
this.prefixEnabled = prefixEnabled;
|
||||
}
|
||||
|
||||
public boolean isPrefixPurchased() {
|
||||
return prefixPurchased;
|
||||
}
|
||||
|
||||
public void setPrefixPurchased(boolean prefixPurchased) {
|
||||
this.prefixPurchased = prefixPurchased;
|
||||
}
|
||||
|
||||
public long getLastColorChange() {
|
||||
return lastColorChange;
|
||||
}
|
||||
|
||||
public void setLastColorChange(long lastColorChange) {
|
||||
this.lastColorChange = lastColorChange;
|
||||
}
|
||||
|
||||
public long getLastPrefixChange() {
|
||||
return lastPrefixChange;
|
||||
}
|
||||
|
||||
public void setLastPrefixChange(long lastPrefixChange) {
|
||||
this.lastPrefixChange = lastPrefixChange;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,27 +23,22 @@ import java.util.List;
|
|||
/**
|
||||
* GUI подтверждения для градиентного модуля
|
||||
*/
|
||||
public class GradientConfirmGUI implements InventoryHolder {
|
||||
|
||||
public enum ConfirmType {
|
||||
COLOR, PREFIX
|
||||
}
|
||||
public final class GradientConfirmGUI implements InventoryHolder {
|
||||
|
||||
private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.hexCharacter('#')
|
||||
.hexColors()
|
||||
.build();
|
||||
|
||||
private final GradientModule module;
|
||||
private final Player player;
|
||||
private final Inventory inventory;
|
||||
private Inventory inventory;
|
||||
private final ConfirmType type;
|
||||
private final List<String> colors;
|
||||
private final String prefix;
|
||||
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) {
|
||||
this.module = module;
|
||||
this.player = player;
|
||||
|
|
@ -51,7 +46,11 @@ public class GradientConfirmGUI implements InventoryHolder {
|
|||
this.colors = colors;
|
||||
this.prefix = prefix;
|
||||
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));
|
||||
setupItems();
|
||||
}
|
||||
|
|
@ -65,12 +64,12 @@ public class GradientConfirmGUI implements InventoryHolder {
|
|||
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
|
||||
SkullMeta skullMeta = (SkullMeta) head.getItemMeta();
|
||||
skullMeta.setOwningPlayer(player);
|
||||
|
||||
|
||||
String preview = buildPreview();
|
||||
// Для GUI используем LegacyComponentSerializer с поддержкой HEX
|
||||
Component previewComponent = SERIALIZER.deserialize(preview);
|
||||
skullMeta.displayName(previewComponent.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
|
||||
List<Component> lore = new ArrayList<>();
|
||||
lore.add(Component.empty());
|
||||
lore.add(Component.text("Так будет выглядеть ваш ник", NamedTextColor.GRAY)
|
||||
|
|
@ -134,7 +133,7 @@ public class GradientConfirmGUI implements InventoryHolder {
|
|||
if (lpPrefix != null && !lpPrefix.isEmpty()) {
|
||||
// Конвертируем LP префикс в legacy формат
|
||||
lpPrefix = convertToLegacy(lpPrefix);
|
||||
|
||||
|
||||
// Если градиент на LP префикс включен - применяем градиент на всю строку
|
||||
if (colorsToUse != null && !colorsToUse.isEmpty() && module.getConfig().isGradientOnLuckPermsPrefix()) {
|
||||
String cleanLpPrefix = stripColors(lpPrefix);
|
||||
|
|
@ -187,14 +186,37 @@ public class GradientConfirmGUI implements InventoryHolder {
|
|||
}
|
||||
|
||||
public void open() {
|
||||
initInventory();
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Inventory getInventory() { return inventory; }
|
||||
public Player getPlayer() { return player; }
|
||||
public ConfirmType getType() { return type; }
|
||||
public List<String> getColors() { return colors; }
|
||||
public String getPrefix() { return prefix; }
|
||||
public int getPrice() { return price; }
|
||||
public @NotNull Inventory getInventory() {
|
||||
initInventory();
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public ConfirmType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public List<String> getColors() {
|
||||
return colors;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public int getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public enum ConfirmType {
|
||||
COLOR, PREFIX
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class GradientLuckPermsHook {
|
|||
|
||||
public GradientLuckPermsHook(JavaPlugin plugin) {
|
||||
this.enabled = false;
|
||||
|
||||
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) {
|
||||
try {
|
||||
this.luckPerms = LuckPermsProvider.get();
|
||||
|
|
@ -40,12 +40,12 @@ public class GradientLuckPermsHook {
|
|||
|
||||
public void setPrefix(Player player, String prefix) {
|
||||
if (!isEnabled()) return;
|
||||
|
||||
|
||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
if (user == null) return;
|
||||
|
||||
user.data().clear(node ->
|
||||
node instanceof PrefixNode && ((PrefixNode) node).getPriority() == GradientConstants.LUCKPERMS_PREFIX_PRIORITY
|
||||
user.data().clear(node ->
|
||||
node instanceof PrefixNode && ((PrefixNode) node).getPriority() == GradientConstants.LUCKPERMS_PREFIX_PRIORITY
|
||||
);
|
||||
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
|
|
@ -58,12 +58,12 @@ public class GradientLuckPermsHook {
|
|||
|
||||
public void setPrefix(UUID uuid, String prefix) {
|
||||
if (!isEnabled()) return;
|
||||
|
||||
|
||||
luckPerms.getUserManager().loadUser(uuid).thenAccept(user -> {
|
||||
if (user == null) return;
|
||||
|
||||
user.data().clear(node ->
|
||||
node instanceof PrefixNode && ((PrefixNode) node).getPriority() == GradientConstants.LUCKPERMS_PREFIX_PRIORITY
|
||||
user.data().clear(node ->
|
||||
node instanceof PrefixNode && ((PrefixNode) node).getPriority() == GradientConstants.LUCKPERMS_PREFIX_PRIORITY
|
||||
);
|
||||
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
|
|
@ -85,10 +85,10 @@ public class GradientLuckPermsHook {
|
|||
|
||||
public String getActivePrefix(Player player) {
|
||||
if (!isEnabled()) return null;
|
||||
|
||||
|
||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
if (user == null) return null;
|
||||
|
||||
|
||||
CachedMetaData metaData = user.getCachedData().getMetaData();
|
||||
return metaData.getPrefix();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,11 @@ import java.util.Map;
|
|||
*/
|
||||
public class GradientGUIListener implements Listener {
|
||||
|
||||
private final GradientModule module;
|
||||
|
||||
private static final Map<GradientConfirmGUI.ConfirmType, String> PRICE_MSG_KEYS = Map.of(
|
||||
GradientConfirmGUI.ConfirmType.COLOR, "not-enough-points-color",
|
||||
GradientConfirmGUI.ConfirmType.PREFIX, "not-enough-points-prefix"
|
||||
);
|
||||
private final GradientModule module;
|
||||
|
||||
public GradientGUIListener(GradientModule module) {
|
||||
this.module = module;
|
||||
|
|
@ -33,9 +32,9 @@ public class GradientGUIListener implements Listener {
|
|||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (!(event.getInventory().getHolder() instanceof GradientConfirmGUI gui)) return;
|
||||
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
|
||||
if (!(event.getWhoClicked() instanceof Player player) || !player.equals(gui.getPlayer())) return;
|
||||
|
||||
switch (event.getRawSlot()) {
|
||||
|
|
@ -46,10 +45,10 @@ public class GradientGUIListener implements Listener {
|
|||
|
||||
private void handleConfirm(Player player, GradientConfirmGUI gui) {
|
||||
player.closeInventory();
|
||||
|
||||
|
||||
GradientMessages msg = module.getMessages();
|
||||
int price = gui.getPrice();
|
||||
|
||||
|
||||
if (price > 0 && !player.hasPermission("gradient.bypass.cost")) {
|
||||
if (!module.hasPlayerPoints()) {
|
||||
player.sendMessage("§cPlayerPoints не установлен!");
|
||||
|
|
@ -85,14 +84,14 @@ public class GradientGUIListener implements Listener {
|
|||
if (module.getLuckPermsHook() != null) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player,
|
||||
FoliaUtil.runEntityTask(module.getPlugin(), player,
|
||||
() -> DisplayNameUtil.updateDisplayName(module, player, data));
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(player.getUniqueId()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class GradientPlayerListener implements Listener {
|
|||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
FoliaUtil.runAsync(module.getPlugin(),
|
||||
() -> module.getDataManager().savePlayerData(player.getUniqueId()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,14 @@ public final class DisplayNameUtil {
|
|||
.hexColors()
|
||||
.build();
|
||||
|
||||
private DisplayNameUtil() {}
|
||||
private DisplayNameUtil() {
|
||||
}
|
||||
|
||||
public static void updateDisplayName(GradientModule module, Player player, GradientPlayerData data) {
|
||||
GradientConfig cfg = module.getConfig();
|
||||
String prefix = null;
|
||||
String prefixFormat = cfg.getPrefixFormat();
|
||||
|
||||
|
||||
// Определяем префикс: сначала кастомный, потом LuckPerms
|
||||
if (data.isPrefixEnabled() && data.hasPrefix()) {
|
||||
// Есть кастомный префикс
|
||||
|
|
@ -37,9 +38,9 @@ public final class DisplayNameUtil {
|
|||
String lpPrefix = module.getLuckPermsHook().getActivePrefix(player);
|
||||
if (lpPrefix != null && !lpPrefix.isEmpty()) {
|
||||
String displayName = buildWithLuckPermsPrefix(
|
||||
lpPrefix,
|
||||
player.getName(),
|
||||
data.isColorEnabled() ? data.getColors() : null,
|
||||
lpPrefix,
|
||||
player.getName(),
|
||||
data.isColorEnabled() ? data.getColors() : null,
|
||||
cfg.isUseLegacyRgbFormat(),
|
||||
cfg.isContinuousGradient()
|
||||
);
|
||||
|
|
@ -51,7 +52,7 @@ public final class DisplayNameUtil {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Строим display name с кастомным префиксом или без префикса
|
||||
String displayName = GradientUtil.buildDisplayName(
|
||||
prefix,
|
||||
|
|
@ -62,7 +63,7 @@ public final class DisplayNameUtil {
|
|||
prefixFormat,
|
||||
cfg.isUseLegacyRgbFormat()
|
||||
);
|
||||
|
||||
|
||||
// Для display name нужен §x формат, конвертируем MiniMessage в legacy
|
||||
displayName = convertMiniMessageToLegacy(displayName);
|
||||
var component = SERIALIZER.deserialize(displayName);
|
||||
|
|
@ -75,12 +76,12 @@ public final class DisplayNameUtil {
|
|||
*/
|
||||
private static String convertMiniMessageToLegacy(String text) {
|
||||
if (text == null) return "";
|
||||
|
||||
|
||||
// Конвертируем <#RRGGBB> в §x§R§R§G§G§B§B
|
||||
Pattern pattern = Pattern.compile("<#([0-9a-fA-F]{6})>");
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
|
||||
while (matcher.find()) {
|
||||
String hex = matcher.group(1).toLowerCase();
|
||||
StringBuilder replacement = new StringBuilder("§x");
|
||||
|
|
@ -90,18 +91,18 @@ public final class DisplayNameUtil {
|
|||
matcher.appendReplacement(sb, replacement.toString());
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String buildWithLuckPermsPrefix(String lpPrefix, String nick,
|
||||
List<String> colors,
|
||||
boolean useLegacyFormat,
|
||||
boolean continuousGradient) {
|
||||
private static String buildWithLuckPermsPrefix(String lpPrefix, String nick,
|
||||
List<String> colors,
|
||||
boolean useLegacyFormat,
|
||||
boolean continuousGradient) {
|
||||
if (colors == null || colors.isEmpty()) {
|
||||
return lpPrefix + nick;
|
||||
}
|
||||
|
||||
|
||||
if (continuousGradient) {
|
||||
String cleanPrefix = stripColors(lpPrefix);
|
||||
String fullText = cleanPrefix + nick;
|
||||
|
|
@ -118,15 +119,15 @@ public final class DisplayNameUtil {
|
|||
|
||||
public static String buildColoredPrefix(GradientModule module, GradientPlayerData data) {
|
||||
if (!data.hasPrefix() || !data.isPrefixEnabled()) return null;
|
||||
|
||||
|
||||
GradientConfig cfg = module.getConfig();
|
||||
String prefix = cfg.getPrefixFormat().replace("{prefix}", data.getPrefix()).stripTrailing();
|
||||
|
||||
|
||||
// Применяем градиент только если цвета включены И есть цвета
|
||||
if (data.hasColors() && data.isColorEnabled() && cfg.isGradientOnPrefix()) {
|
||||
return GradientUtil.applyGradient(prefix, data.getColors(), cfg.isUseLegacyRgbFormat());
|
||||
}
|
||||
|
||||
|
||||
// Возвращаем префикс без цветов
|
||||
return prefix;
|
||||
}
|
||||
|
|
@ -137,12 +138,12 @@ public final class DisplayNameUtil {
|
|||
public static String getFullDisplayName(GradientModule module, Player player) {
|
||||
GradientPlayerData data = module.getDataManager().getPlayerData(player.getUniqueId());
|
||||
GradientConfig cfg = module.getConfig();
|
||||
|
||||
|
||||
String prefix = null;
|
||||
if (data.isPrefixEnabled() && data.hasPrefix()) {
|
||||
prefix = data.getPrefix();
|
||||
}
|
||||
|
||||
|
||||
return GradientUtil.buildDisplayName(
|
||||
prefix,
|
||||
player.getName(),
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ public final class FoliaUtil {
|
|||
IS_FOLIA = checkFolia();
|
||||
}
|
||||
|
||||
private FoliaUtil() {}
|
||||
private FoliaUtil() {
|
||||
}
|
||||
|
||||
private static boolean checkFolia() {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -5,15 +5,14 @@ package com.loki.lochat.gradient.util;
|
|||
*/
|
||||
public final class GradientConstants {
|
||||
|
||||
private GradientConstants() {}
|
||||
|
||||
public static final long MILLIS_PER_SECOND = 1000L;
|
||||
|
||||
// GUI слоты
|
||||
public static final int GUI_CONFIRM_SLOT = 11;
|
||||
public static final int GUI_CANCEL_SLOT = 15;
|
||||
public static final int GUI_PREVIEW_SLOT = 13;
|
||||
|
||||
// LuckPerms
|
||||
public static final int LUCKPERMS_PREFIX_PRIORITY = 100;
|
||||
|
||||
private GradientConstants() {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ public final class GradientUtil {
|
|||
|
||||
private static final Pattern HEX_PATTERN = Pattern.compile("^#[0-9A-Fa-f]{6}$");
|
||||
|
||||
private GradientUtil() {}
|
||||
private GradientUtil() {
|
||||
}
|
||||
|
||||
public static boolean isValidHex(String color) {
|
||||
return HEX_PATTERN.matcher(color).matches();
|
||||
|
|
@ -50,7 +51,7 @@ public final class GradientUtil {
|
|||
// Вычисляем позицию символа от 0.0 до 1.0
|
||||
double ratio = length > 1 ? (double) i / (length - 1) : 0.0;
|
||||
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());
|
||||
result.append(formatHex(hex, useLegacyFormat)).append(chars[i]);
|
||||
}
|
||||
|
|
@ -142,7 +143,7 @@ public final class GradientUtil {
|
|||
for (int i = 0; i < length; i++) {
|
||||
double ratio = length > 1 ? (double) i / (length - 1) : 0.0;
|
||||
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());
|
||||
result.append(formatHexForTab(hex)).append(chars[i]);
|
||||
}
|
||||
|
|
@ -151,8 +152,8 @@ public final class GradientUtil {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
public static String buildDisplayName(String prefix, String nick, List<String> colors,
|
||||
boolean gradientOnPrefix, boolean continuousGradient,
|
||||
public static String buildDisplayName(String prefix, String nick, List<String> colors,
|
||||
boolean gradientOnPrefix, boolean continuousGradient,
|
||||
String prefixFormat, boolean useLegacyFormat) {
|
||||
if (colors == null || colors.isEmpty()) {
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class LibertyBansHook {
|
|||
public LibertyBansHook(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
this.muteService = plugin.getServiceRegistry().get(MuteService.class);
|
||||
|
||||
|
||||
// Проверяем наличие LibertyBans
|
||||
if (plugin.getServer().getPluginManager().getPlugin("LibertyBans") != null) {
|
||||
plugin.getLogger().info("LibertyBans обнаружен. Используйте встроенную систему мутов LoChat (/lmute, /lunmute)");
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue