diff --git a/build.gradle b/build.gradle
index 580b170..152d866 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,7 +3,7 @@ plugins {
}
group = 'com.loki'
-version = '1.0.0'
+version = '1.5.0'
repositories {
mavenCentral()
@@ -29,14 +29,20 @@ java {
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
+ // Параллельная компиляция
+ options.fork = true
+ options.forkOptions.jvmArgs += ['-XX:+UseParallelGC']
}
test {
useJUnitPlatform()
+ // Параллельное выполнение тестов
+ maxParallelForks = Runtime.runtime.availableProcessors()
+ forkEvery = 100
}
jar {
- archiveFileName = 'LoChat-1.0.0.jar'
+ archiveFileName = 'LoChat-1.5.0.jar'
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..ffbcc4b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,13 @@
+# Параллельная сборка
+org.gradle.parallel=true
+org.gradle.workers.max=8
+org.gradle.configureondemand=true
+
+# Кэширование
+org.gradle.caching=true
+
+# JVM настройки для Gradle
+org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError
+
+# Kotlin DSL
+kotlin.code.style=official
\ No newline at end of file
diff --git a/src/main/java/com/loki/lochat/LoChat.java b/src/main/java/com/loki/lochat/LoChat.java
index 20fbbba..d1acd81 100644
--- a/src/main/java/com/loki/lochat/LoChat.java
+++ b/src/main/java/com/loki/lochat/LoChat.java
@@ -26,6 +26,8 @@ public final class LoChat extends JavaPlugin {
private MentionManager mentionManager;
private SpyManager spyManager;
private EmojiManager emojiManager;
+ private ChatColorManager chatColorManager;
+ private CustomCommandManager customCommandManager;
private GradientModule gradientModule;
@Override
@@ -45,6 +47,8 @@ public final class LoChat extends JavaPlugin {
cooldownManager = new CooldownManager();
mentionManager = new MentionManager(this);
spyManager = new SpyManager(this);
+ chatColorManager = new ChatColorManager(this);
+ customCommandManager = new CustomCommandManager(this);
chatManager = new ChatManager(this);
autoMessageManager = new AutoMessageManager(this);
@@ -80,6 +84,9 @@ public final class LoChat extends JavaPlugin {
if (ignoreManager != null) {
ignoreManager.save();
}
+ if (chatColorManager != null) {
+ chatColorManager.saveData();
+ }
if (gradientModule != null) {
gradientModule.shutdown();
}
@@ -97,6 +104,7 @@ public final class LoChat extends JavaPlugin {
getCommand("announce").setExecutor(new AnnounceCommand(this));
getCommand("chatspy").setExecutor(new ChatSpyCommand(this));
getCommand("clearchat").setExecutor(new ClearChatCommand(this));
+ getCommand("chatcolor").setExecutor(new ChatColorCommand(this));
LoChatCommand loChatCommand = new LoChatCommand(this);
getCommand("lochat").setExecutor(loChatCommand);
@@ -112,6 +120,9 @@ public final class LoChat extends JavaPlugin {
if (gradientModule != null) {
gradientModule.reload();
}
+ if (customCommandManager != null) {
+ customCommandManager.reload();
+ }
}
public static LoChat getInstance() {
@@ -169,4 +180,12 @@ public final class LoChat extends JavaPlugin {
public GradientModule getGradientModule() {
return gradientModule;
}
+
+ public ChatColorManager getChatColorManager() {
+ return chatColorManager;
+ }
+
+ public CustomCommandManager getCustomCommandManager() {
+ return customCommandManager;
+ }
}
diff --git a/src/main/java/com/loki/lochat/commands/AnnounceCommand.java b/src/main/java/com/loki/lochat/commands/AnnounceCommand.java
index 2c46457..a993d21 100644
--- a/src/main/java/com/loki/lochat/commands/AnnounceCommand.java
+++ b/src/main/java/com/loki/lochat/commands/AnnounceCommand.java
@@ -43,16 +43,24 @@ public class AnnounceCommand implements CommandExecutor {
for (Player player : Bukkit.getOnlinePlayers()) {
player.sendMessage(formatted);
- // ActionBar
- player.sendActionBar(formatted);
+ // ActionBar (если включен)
+ if (plugin.getConfigManager().isAnnouncementActionBarEnabled()) {
+ player.sendActionBar(formatted);
+ }
- // Title
- Title title = Title.title(
- ChatFormatter.parse("ОБЪЯВЛЕНИЕ"),
- ChatFormatter.parse(message),
- Title.Times.times(Duration.ofMillis(500), Duration.ofSeconds(3), Duration.ofMillis(500))
- );
- player.showTitle(title);
+ // 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)
+ )
+ );
+ player.showTitle(title);
+ }
}
plugin.getLogger().info("[ANNOUNCE] " + sender.getName() + ": " + ChatFormatter.stripTags(message));
diff --git a/src/main/java/com/loki/lochat/commands/ChatColorCommand.java b/src/main/java/com/loki/lochat/commands/ChatColorCommand.java
new file mode 100644
index 0000000..4c43009
--- /dev/null
+++ b/src/main/java/com/loki/lochat/commands/ChatColorCommand.java
@@ -0,0 +1,86 @@
+package com.loki.lochat.commands;
+
+import com.loki.lochat.LoChat;
+import com.loki.lochat.utils.ChatFormatter;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ChatColorCommand implements CommandExecutor, TabCompleter {
+
+ private final LoChat plugin;
+
+ public ChatColorCommand(LoChat plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
+ if (!(sender instanceof Player player)) {
+ sender.sendMessage("Только для игроков!");
+ return true;
+ }
+
+ if (!player.hasPermission("lochat.chatcolor")) {
+ player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getNoPermission()));
+ return true;
+ }
+
+ if (args.length == 0) {
+ player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getInvalidUsage("/chatcolor <цвет>")));
+ player.sendMessage(ChatFormatter.parse("Доступные цвета: red, blue, green, yellow, gold, aqua, light_purple, white, gray, dark_gray"));
+ return true;
+ }
+
+ String color = args[0].toLowerCase();
+
+ // Проверяем валидность цвета
+ if (!isValidColor(color)) {
+ player.sendMessage(ChatFormatter.parse("Неверный цвет! Используйте один из доступных цветов."));
+ return true;
+ }
+
+ // Сохраняем цвет чата игрока
+ plugin.getChatColorManager().setChatColor(player.getUniqueId(), color);
+ player.sendMessage(ChatFormatter.parse("Цвет чата установлен на <" + color + ">" + color + "!"));
+
+ return true;
+ }
+
+ private boolean isValidColor(String color) {
+ List validColors = Arrays.asList(
+ "red", "blue", "green", "yellow", "gold", "aqua",
+ "light_purple", "white", "gray", "dark_gray", "black",
+ "dark_red", "dark_green", "dark_blue", "dark_aqua", "dark_purple"
+ );
+ return validColors.contains(color);
+ }
+
+ @Override
+ public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ if (args.length == 1) {
+ List colors = Arrays.asList(
+ "red", "blue", "green", "yellow", "gold", "aqua",
+ "light_purple", "white", "gray", "dark_gray"
+ );
+ List completions = new ArrayList<>();
+ String input = args[0].toLowerCase();
+
+ for (String color : colors) {
+ if (color.startsWith(input)) {
+ completions.add(color);
+ }
+ }
+ return completions;
+ }
+ return new ArrayList<>();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/loki/lochat/commands/CustomCommand.java b/src/main/java/com/loki/lochat/commands/CustomCommand.java
new file mode 100644
index 0000000..6570d75
--- /dev/null
+++ b/src/main/java/com/loki/lochat/commands/CustomCommand.java
@@ -0,0 +1,38 @@
+package com.loki.lochat.commands;
+
+import com.loki.lochat.managers.CustomCommandManager;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CustomCommand extends Command {
+
+ private final CustomCommandManager manager;
+
+ public CustomCommand(String name, CustomCommandManager manager) {
+ super(name);
+ this.manager = manager;
+ this.setDescription("Кастомная команда LoChat");
+ this.setUsage("/" + name);
+ }
+
+ @Override
+ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
+ if (!(sender instanceof Player player)) {
+ sender.sendMessage("Только для игроков!");
+ return true;
+ }
+
+ return manager.executeCustomCommand(commandLabel, player, args);
+ }
+
+ @Override
+ public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
+ // Базовое автодополнение - можно расширить при необходимости
+ return new ArrayList<>();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/loki/lochat/commands/LoChatCommand.java b/src/main/java/com/loki/lochat/commands/LoChatCommand.java
index 8b3bd09..a4e4105 100644
--- a/src/main/java/com/loki/lochat/commands/LoChatCommand.java
+++ b/src/main/java/com/loki/lochat/commands/LoChatCommand.java
@@ -1,6 +1,7 @@
package com.loki.lochat.commands;
import com.loki.lochat.LoChat;
+import com.loki.lochat.utils.ChatFormatter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@@ -8,6 +9,7 @@ import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.ArrayList;
import java.util.List;
public class LoChatCommand implements CommandExecutor, TabCompleter {
@@ -21,35 +23,75 @@ public class LoChatCommand implements CommandExecutor, TabCompleter {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
+ if (!sender.hasPermission("lochat.admin")) {
+ sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getNoPermission()));
+ return true;
+ }
+
if (args.length == 0) {
- sender.sendMessage("§e=== LoChat v" + plugin.getDescription().getVersion() + " ===");
- sender.sendMessage("§e/lochat reload §7— перезагрузить конфиги");
+ sender.sendMessage(ChatFormatter.parse("LoChat v" + plugin.getDescription().getVersion() + ""));
+ sender.sendMessage(ChatFormatter.parse("Команды:"));
+ sender.sendMessage(ChatFormatter.parse("/lochat reload - Перезагрузить конфиги"));
+ sender.sendMessage(ChatFormatter.parse("/lochat commands - Список кастомных команд"));
+ sender.sendMessage(ChatFormatter.parse("/lochat commands reload - Перезагрузить кастомные команды"));
return true;
}
- if (args[0].equalsIgnoreCase("reload")) {
- if (!sender.hasPermission("lochat.admin")) {
- sender.sendMessage(plugin.getMessageConfig().get("errors.no-permission"));
- return true;
+ switch (args[0].toLowerCase()) {
+ case "reload" -> {
+ plugin.reload();
+ sender.sendMessage(ChatFormatter.parse("Конфигурация перезагружена!"));
}
-
- plugin.reload();
- sender.sendMessage("§aLoChat перезагружен!");
- return true;
+ case "commands" -> {
+ if (args.length > 1 && args[1].equalsIgnoreCase("reload")) {
+ plugin.getCustomCommandManager().reload();
+ sender.sendMessage(ChatFormatter.parse("Кастомные команды перезагружены!"));
+ } else {
+ var commands = plugin.getCustomCommandManager().getCommands();
+ sender.sendMessage(ChatFormatter.parse("Кастомные команды (" + commands.size() + "):"));
+ for (var cmd : commands.values()) {
+ sender.sendMessage(ChatFormatter.parse("/" + cmd.name + " (" + cmd.type + ")"));
+ if (!cmd.aliases.isEmpty()) {
+ sender.sendMessage(ChatFormatter.parse(" Алиасы: " + String.join(", ", cmd.aliases) + ""));
+ }
+ }
+ }
+ }
+ default -> sender.sendMessage(ChatFormatter.parse("Неизвестная команда. Используйте /lochat для помощи."));
}
- sender.sendMessage("§cНеизвестная команда. Используй /lochat reload");
return true;
}
@Override
public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) {
- if (args.length == 1 && sender.hasPermission("lochat.admin")) {
- return List.of("reload").stream()
- .filter(s -> s.startsWith(args[0].toLowerCase()))
- .toList();
+ if (!sender.hasPermission("lochat.admin")) {
+ return new ArrayList<>();
}
- return List.of();
+
+ if (args.length == 1) {
+ List completions = new ArrayList<>();
+ String input = args[0].toLowerCase();
+
+ for (String cmd : List.of("reload", "commands")) {
+ if (cmd.startsWith(input)) {
+ completions.add(cmd);
+ }
+ }
+ return completions;
+ }
+
+ if (args.length == 2 && args[0].equalsIgnoreCase("commands")) {
+ List completions = new ArrayList<>();
+ String input = args[1].toLowerCase();
+
+ if ("reload".startsWith(input)) {
+ completions.add("reload");
+ }
+ return completions;
+ }
+
+ return new ArrayList<>();
}
}
diff --git a/src/main/java/com/loki/lochat/config/ConfigManager.java b/src/main/java/com/loki/lochat/config/ConfigManager.java
index 1e26d55..cd6247e 100644
--- a/src/main/java/com/loki/lochat/config/ConfigManager.java
+++ b/src/main/java/com/loki/lochat/config/ConfigManager.java
@@ -14,6 +14,76 @@ public class ConfigManager {
this.plugin = plugin;
plugin.saveDefaultConfig();
this.config = plugin.getConfig();
+
+ // Проверяем версию конфига и обновляем при необходимости
+ updateConfig();
+ }
+
+ 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("Конфиг успешно обновлен!");
+ }
+ }
+
+ private void addMissingConfigOptions() {
+ // Добавляем настройки объявлений если их нет
+ if (!config.contains("announcements")) {
+ config.set("announcements.show-title", true);
+ config.set("announcements.title-header", "ОБЪЯВЛЕНИЕ");
+ 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);
+ config.set("mentions.sound-type", "BLOCK_NOTE_BLOCK_PLING");
+ config.set("mentions.highlight", "@{player}");
+ config.set("mentions.self-highlight", "{player}");
+ }
+
+ if (!config.contains("filter.enabled")) {
+ config.set("filter.enabled", true);
+ config.set("filter.words", java.util.Arrays.asList("хуй", "пизд", "блять", "ебать", "сука"));
+ config.set("filter.action", "censor");
+ config.set("filter.replacement", "***");
+ }
+
+ if (!config.contains("antispam.enabled")) {
+ config.set("antispam.enabled", true);
+ config.set("antispam.max-caps-percent", 70);
+ config.set("antispam.max-repeat-chars", 5);
+ config.set("antispam.similar-message-delay", 30);
+ }
+
+ if (!config.contains("automessages.enabled")) {
+ config.set("automessages.enabled", true);
+ config.set("automessages.interval", 300);
+ config.set("automessages.random", false);
+ }
+
+ if (!config.contains("lopreff.enabled")) {
+ config.set("lopreff.enabled", true);
+ config.set("lopreff.use-gradient-name", true);
+ config.set("lopreff.use-custom-prefix", true);
+ }
}
public void reload() {
@@ -153,6 +223,23 @@ public class ConfigManager {
return config.getString("formats.announcement", "[ОБЪЯВЛЕНИЕ] ");
}
+ // Announcements
+ public boolean isAnnouncementTitleEnabled() {
+ return config.getBoolean("announcements.show-title", true);
+ }
+
+ public String getAnnouncementTitleHeader() {
+ return config.getString("announcements.title-header", "ОБЪЯВЛЕНИЕ");
+ }
+
+ public boolean isAnnouncementActionBarEnabled() {
+ return config.getBoolean("announcements.show-actionbar", true);
+ }
+
+ public int getAnnouncementTitleDuration() {
+ return config.getInt("announcements.title-duration", 3);
+ }
+
// LoPreff integration
public boolean isLopreffEnabled() {
return config.getBoolean("lopreff.enabled", true);
diff --git a/src/main/java/com/loki/lochat/gradient/config/GradientConfig.java b/src/main/java/com/loki/lochat/gradient/config/GradientConfig.java
index fadba7a..9e1c7d5 100644
--- a/src/main/java/com/loki/lochat/gradient/config/GradientConfig.java
+++ b/src/main/java/com/loki/lochat/gradient/config/GradientConfig.java
@@ -79,4 +79,8 @@ public class GradientConfig {
return getPrefixBlacklist().stream()
.anyMatch(blacklisted -> lowerPrefix.contains(blacklisted.toLowerCase()));
}
+
+ // Display settings
+ public boolean isUpdateDisplayName() { return config.getBoolean("display.update-display-name", true); }
+ public boolean isUpdateTabList() { return config.getBoolean("display.update-tab-list", true); }
}
diff --git a/src/main/java/com/loki/lochat/gradient/listeners/GradientPlayerListener.java b/src/main/java/com/loki/lochat/gradient/listeners/GradientPlayerListener.java
index 310650c..f6f23f0 100644
--- a/src/main/java/com/loki/lochat/gradient/listeners/GradientPlayerListener.java
+++ b/src/main/java/com/loki/lochat/gradient/listeners/GradientPlayerListener.java
@@ -32,7 +32,10 @@ public class GradientPlayerListener implements Listener {
FoliaUtil.runEntityTask(module.getPlugin(), player, () -> {
if (!player.isOnline()) return;
- DisplayNameUtil.updateDisplayName(module, player, data);
+ // Обновляем display name если включено
+ if (module.getConfig().isUpdateDisplayName()) {
+ DisplayNameUtil.updateDisplayName(module, player, data);
+ }
if (data.hasPrefix() && data.isPrefixEnabled()) {
module.getLuckPermsHook().setPrefix(player,
diff --git a/src/main/java/com/loki/lochat/managers/ChatColorManager.java b/src/main/java/com/loki/lochat/managers/ChatColorManager.java
new file mode 100644
index 0000000..191ff4c
--- /dev/null
+++ b/src/main/java/com/loki/lochat/managers/ChatColorManager.java
@@ -0,0 +1,93 @@
+package com.loki.lochat.managers;
+
+import com.loki.lochat.LoChat;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class ChatColorManager {
+
+ private final LoChat plugin;
+ private final Map chatColors;
+ private File dataFile;
+ private FileConfiguration dataConfig;
+
+ public ChatColorManager(LoChat plugin) {
+ this.plugin = plugin;
+ this.chatColors = new HashMap<>();
+ loadData();
+ }
+
+ private void loadData() {
+ dataFile = new File(plugin.getDataFolder(), "chatcolors.yml");
+ if (!dataFile.exists()) {
+ try {
+ dataFile.createNewFile();
+ } catch (IOException e) {
+ plugin.getLogger().severe("Не удалось создать файл chatcolors.yml: " + e.getMessage());
+ }
+ }
+
+ dataConfig = YamlConfiguration.loadConfiguration(dataFile);
+
+ // Загружаем цвета из файла
+ for (String key : dataConfig.getKeys(false)) {
+ try {
+ UUID uuid = UUID.fromString(key);
+ String color = dataConfig.getString(key);
+ if (color != null) {
+ chatColors.put(uuid, color);
+ }
+ } catch (IllegalArgumentException ignored) {
+ // Неверный UUID, пропускаем
+ }
+ }
+ }
+
+ public void saveData() {
+ for (Map.Entry entry : chatColors.entrySet()) {
+ dataConfig.set(entry.getKey().toString(), entry.getValue());
+ }
+
+ try {
+ dataConfig.save(dataFile);
+ } catch (IOException e) {
+ plugin.getLogger().severe("Не удалось сохранить chatcolors.yml: " + e.getMessage());
+ }
+ }
+
+ public void setChatColor(UUID playerId, String color) {
+ chatColors.put(playerId, color);
+ saveData();
+ }
+
+ public String getChatColor(UUID playerId) {
+ return chatColors.get(playerId);
+ }
+
+ public boolean hasChatColor(UUID playerId) {
+ return chatColors.containsKey(playerId);
+ }
+
+ public void removeChatColor(UUID playerId) {
+ chatColors.remove(playerId);
+ dataConfig.set(playerId.toString(), null);
+ saveData();
+ }
+
+ /**
+ * Применяет цвет чата к сообщению
+ */
+ public String applyChatColor(UUID playerId, String message) {
+ String color = getChatColor(playerId);
+ if (color != null) {
+ return "<" + color + ">" + message + "" + color + ">";
+ }
+ return message;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/loki/lochat/managers/CustomCommandManager.java b/src/main/java/com/loki/lochat/managers/CustomCommandManager.java
new file mode 100644
index 0000000..ffad8fb
--- /dev/null
+++ b/src/main/java/com/loki/lochat/managers/CustomCommandManager.java
@@ -0,0 +1,278 @@
+package com.loki.lochat.managers;
+
+import com.loki.lochat.LoChat;
+import com.loki.lochat.commands.CustomCommand;
+import com.loki.lochat.utils.ChatFormatter;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.title.Title;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandMap;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.Player;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CustomCommandManager {
+
+ private final LoChat plugin;
+ private final Map commands;
+ private File commandsFile;
+ private FileConfiguration commandsConfig;
+
+ public CustomCommandManager(LoChat plugin) {
+ this.plugin = plugin;
+ this.commands = new HashMap<>();
+ loadCommands();
+ }
+
+ private void loadCommands() {
+ commandsFile = new File(plugin.getDataFolder(), "custom-commands.yml");
+ if (!commandsFile.exists()) {
+ plugin.saveResource("custom-commands.yml", false);
+ }
+
+ commandsConfig = YamlConfiguration.loadConfiguration(commandsFile);
+
+ // Очищаем старые команды
+ commands.clear();
+
+ // Загружаем команды из конфига
+ for (String commandName : commandsConfig.getKeys(false)) {
+ ConfigurationSection section = commandsConfig.getConfigurationSection(commandName);
+ if (section == null) continue;
+
+ CustomCommandData data = new CustomCommandData(
+ commandName,
+ section.getString("permission"),
+ section.getString("message", ""),
+ section.getStringList("aliases"),
+ section.getString("type", "chat"),
+ section.getString("target", "sender")
+ );
+
+ commands.put(commandName, data);
+
+ // Регистрируем команду
+ registerCommand(data);
+ }
+
+ plugin.getLogger().info("Загружено " + commands.size() + " кастомных команд");
+ }
+
+ private void registerCommand(CustomCommandData data) {
+ try {
+ // Получаем CommandMap через рефлексию
+ Field commandMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
+ commandMapField.setAccessible(true);
+ CommandMap commandMap = (CommandMap) commandMapField.get(Bukkit.getServer());
+
+ // Создаем и регистрируем команду
+ CustomCommand command = new CustomCommand(data.name, this);
+ commandMap.register("lochat", command);
+
+ // Регистрируем алиасы
+ for (String alias : data.aliases) {
+ CustomCommand aliasCommand = new CustomCommand(alias, this);
+ commandMap.register("lochat", aliasCommand);
+ }
+
+ } catch (Exception e) {
+ plugin.getLogger().severe("Ошибка регистрации команды " + data.name + ": " + e.getMessage());
+ }
+ }
+
+ public void reload() {
+ loadCommands();
+ }
+
+ public boolean executeCustomCommand(String commandName, Player player, String[] args) {
+ CustomCommandData data = commands.get(commandName);
+ if (data == null) {
+ // Проверяем алиасы
+ for (CustomCommandData cmd : commands.values()) {
+ if (cmd.aliases.contains(commandName)) {
+ data = cmd;
+ break;
+ }
+ }
+ }
+
+ if (data == null) return false;
+
+ // Проверяем права
+ if (data.permission != null && !player.hasPermission(data.permission)) {
+ player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getNoPermission()));
+ return true;
+ }
+
+ // Обрабатываем плейсхолдеры
+ String message = processPlaceholders(data.message, player, args);
+
+ // Выполняем команду в зависимости от типа
+ switch (data.type.toLowerCase()) {
+ case "chat" -> sendChatMessage(data.target, player, message);
+ case "broadcast" -> sendBroadcast(data.target, message);
+ case "title" -> sendTitle(data.target, player, message);
+ case "actionbar" -> sendActionBar(data.target, player, message);
+ default -> sendChatMessage(data.target, player, message);
+ }
+
+ return true;
+ }
+
+ private String processPlaceholders(String message, Player player, String[] args) {
+ String result = message;
+
+ // Базовые плейсхолдеры
+ result = result.replace("{player}", player.getName());
+ result = result.replace("{x}", String.valueOf(player.getLocation().getBlockX()));
+ result = result.replace("{y}", String.valueOf(player.getLocation().getBlockY()));
+ result = result.replace("{z}", String.valueOf(player.getLocation().getBlockZ()));
+ result = result.replace("{world}", player.getWorld().getName());
+
+ // Аргументы команды
+ for (int i = 0; i < args.length; i++) {
+ result = result.replace("{arg" + i + "}", args[i]);
+ }
+ result = result.replace("{args}", String.join(" ", args));
+
+ // PlaceholderAPI если доступен
+ if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
+ result = me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(player, result);
+ }
+
+ return result;
+ }
+
+ private void sendChatMessage(String target, Player sender, String message) {
+ Component component = ChatFormatter.parse(message);
+
+ switch (target.toLowerCase()) {
+ case "sender" -> sender.sendMessage(component);
+ case "all" -> {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ player.sendMessage(component);
+ }
+ }
+ default -> {
+ if (target.startsWith("permission:")) {
+ String permission = target.substring(11);
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.hasPermission(permission)) {
+ player.sendMessage(component);
+ }
+ }
+ } else {
+ sender.sendMessage(component);
+ }
+ }
+ }
+ }
+
+ private void sendBroadcast(String target, String message) {
+ Component component = ChatFormatter.parse(message);
+
+ switch (target.toLowerCase()) {
+ case "all" -> {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ player.sendMessage(component);
+ }
+ }
+ default -> {
+ if (target.startsWith("permission:")) {
+ String permission = target.substring(11);
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.hasPermission(permission)) {
+ player.sendMessage(component);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void sendTitle(String target, Player sender, String message) {
+ String[] parts = message.split("\\n", 2);
+ Component title = ChatFormatter.parse(parts[0]);
+ Component subtitle = parts.length > 1 ? ChatFormatter.parse(parts[1]) : Component.empty();
+
+ Title titleObj = Title.title(title, subtitle,
+ Title.Times.times(Duration.ofMillis(500), Duration.ofSeconds(3), Duration.ofMillis(500)));
+
+ switch (target.toLowerCase()) {
+ case "sender" -> sender.showTitle(titleObj);
+ case "all" -> {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ player.showTitle(titleObj);
+ }
+ }
+ default -> {
+ if (target.startsWith("permission:")) {
+ String permission = target.substring(11);
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.hasPermission(permission)) {
+ player.showTitle(titleObj);
+ }
+ }
+ } else {
+ sender.showTitle(titleObj);
+ }
+ }
+ }
+ }
+
+ private void sendActionBar(String target, Player sender, String message) {
+ Component component = ChatFormatter.parse(message);
+
+ switch (target.toLowerCase()) {
+ case "sender" -> sender.sendActionBar(component);
+ case "all" -> {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ player.sendActionBar(component);
+ }
+ }
+ default -> {
+ if (target.startsWith("permission:")) {
+ String permission = target.substring(11);
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.hasPermission(permission)) {
+ player.sendActionBar(component);
+ }
+ }
+ } else {
+ sender.sendActionBar(component);
+ }
+ }
+ }
+ }
+
+ public Map getCommands() {
+ return commands;
+ }
+
+ public static class CustomCommandData {
+ public final String name;
+ public final String permission;
+ public final String message;
+ public final List aliases;
+ public final String type;
+ public final String target;
+
+ public CustomCommandData(String name, String permission, String message,
+ List aliases, String type, String target) {
+ this.name = name;
+ this.permission = permission;
+ this.message = message;
+ this.aliases = aliases;
+ this.type = type;
+ this.target = target;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/loki/lochat/utils/ChatFormatter.java b/src/main/java/com/loki/lochat/utils/ChatFormatter.java
index 66ca977..ee80853 100644
--- a/src/main/java/com/loki/lochat/utils/ChatFormatter.java
+++ b/src/main/java/com/loki/lochat/utils/ChatFormatter.java
@@ -123,7 +123,7 @@ public class ChatFormatter {
/**
* Полная обработка сообщения игрока
- * Цвета + смайлики
+ * Цвета + смайлики + цвет чата
*/
public static String processPlayerMessage(String message, Player player, boolean hasColorPermission) {
String result = message;
@@ -137,6 +137,12 @@ public class ChatFormatter {
} else {
// Убираем цветовые коды
result = stripLegacyColors(result);
+
+ // Применяем цвет чата если установлен
+ LoChat plugin = LoChat.getInstance();
+ if (plugin != null && plugin.getChatColorManager() != null) {
+ result = plugin.getChatColorManager().applyChatColor(player.getUniqueId(), result);
+ }
}
return result;
@@ -235,6 +241,10 @@ public class ChatFormatter {
&& plugin.getGradientModule() != null && plugin.getGradientModule().isEnabled()) {
senderDisplay = plugin.getGradientModule().getFormattedName(sender);
receiverDisplay = plugin.getGradientModule().getFormattedName(receiver);
+
+ // Конвертируем legacy коды в MiniMessage формат
+ senderDisplay = convertAllColors(senderDisplay);
+ receiverDisplay = convertAllColors(receiverDisplay);
}
return parse(format
@@ -258,6 +268,10 @@ public class ChatFormatter {
&& plugin.getGradientModule() != null && plugin.getGradientModule().isEnabled()) {
senderDisplay = plugin.getGradientModule().getFormattedName(sender);
receiverDisplay = plugin.getGradientModule().getFormattedName(receiver);
+
+ // Конвертируем legacy коды в MiniMessage формат
+ senderDisplay = convertAllColors(senderDisplay);
+ receiverDisplay = convertAllColors(receiverDisplay);
}
return parse(format
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index ae85b25..1f4c151 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,5 +1,8 @@
# LoChat Configuration
# Author: loki
+# Config Version: 2
+
+config-version: 2
chat:
global:
@@ -67,3 +70,14 @@ automessages:
formats:
announcement: "[ОБЪЯВЛЕНИЕ] "
+
+# Настройки объявлений
+announcements:
+ # Показывать title при объявлении
+ show-title: true
+ # Заголовок title
+ title-header: "ОБЪЯВЛЕНИЕ"
+ # Показывать actionbar при объявлении
+ show-actionbar: true
+ # Время показа title (в секундах)
+ title-duration: 3
diff --git a/src/main/resources/custom-commands.yml b/src/main/resources/custom-commands.yml
new file mode 100644
index 0000000..571d508
--- /dev/null
+++ b/src/main/resources/custom-commands.yml
@@ -0,0 +1,51 @@
+# Кастомные команды LoChat
+# Здесь можно создавать свои команды с сообщениями и алиасами
+
+# Пример структуры:
+# command-name:
+# permission: "lochat.command.name" # Право для использования (опционально)
+# message: "Текст сообщения" # Сообщение которое отправится
+# aliases: ["alias1", "alias2"] # Алиасы команды (опционально)
+# type: "chat" # Тип: chat, broadcast, title, actionbar
+# target: "sender" # Кому отправить: sender, all, permission:право
+
+# Примеры команд:
+help:
+ message: "Добро пожаловать на сервер!\nИспользуйте /rules для просмотра правил"
+ aliases: ["помощь", "хелп"]
+ type: "chat"
+ target: "sender"
+
+rules:
+ message: "ПРАВИЛА СЕРВЕРА:\n1. Не гриферить\n2. Не читерить\n3. Уважать других игроков"
+ aliases: ["правила", "rule"]
+ type: "chat"
+ target: "sender"
+
+discord:
+ message: "Наш Discord сервер: discord.gg/example"
+ aliases: ["дискорд", "ds"]
+ type: "chat"
+ target: "sender"
+
+# Команда для админов
+restart-warning:
+ permission: "lochat.admin"
+ message: "ВНИМАНИЕ! Сервер будет перезагружен через 5 минут!"
+ aliases: ["рестарт", "reboot"]
+ type: "broadcast"
+ target: "all"
+
+# Команда с title
+welcome:
+ message: "Добро пожаловать!"
+ aliases: ["привет"]
+ type: "title"
+ target: "sender"
+
+# Команда с actionbar
+coords:
+ message: "Ваши координаты: {x}, {y}, {z}"
+ aliases: ["координаты", "pos"]
+ type: "actionbar"
+ target: "sender"
\ No newline at end of file
diff --git a/src/main/resources/gradient-config.yml b/src/main/resources/gradient-config.yml
index d2ea06b..19bf76d 100644
--- a/src/main/resources/gradient-config.yml
+++ b/src/main/resources/gradient-config.yml
@@ -43,6 +43,13 @@ continuous-gradient: true
# Использовать RRGGBB формат (true) или <#RRGGBB> (false)
use-legacy-rgb-format: true
+# Отображение над игроком
+display:
+ # Обновлять display name игрока (показывает префикс+ник над головой)
+ update-display-name: true
+ # Обновлять tab list
+ update-tab-list: true
+
# Тип хранилища: YAML или SQLITE
storage-type: YAML
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 6358bd7..f51017c 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,5 +1,5 @@
name: LoChat
-version: '1.0.0'
+version: '1.5.0'
main: com.loki.lochat.LoChat
api-version: '1.21'
folia-supported: true
@@ -31,28 +31,31 @@ commands:
description: Send private message
usage: /msg
permission: chat.pm.use
- aliases: [tell, w, pm]
+ aliases: [tell, w, pm, m, ьып]
reply:
description: Reply to last message
usage: /reply
permission: chat.pm.use
- aliases: [r]
+ aliases: [r, ответить]
ignore:
description: Ignore player
usage: /ignore
permission: chat.pm.ignore
+ aliases: [игнор]
unignore:
description: Unignore player
usage: /unignore
permission: chat.pm.ignore
+ aliases: [разигнор]
announce:
description: Send announcement
usage: /announce
permission: chat.announce.use
+ aliases: [объявление, анонс]
chatspy:
description: Toggle chat spy mode
@@ -66,6 +69,12 @@ commands:
permission: chat.clear
aliases: [cc]
+ chatcolor:
+ description: Set chat color
+ usage: /chatcolor
+ permission: lochat.chatcolor
+ aliases: [цветчата, chatcolour]
+
lochat:
description: LoChat admin command
usage: /lochat [reload]
@@ -75,12 +84,13 @@ commands:
description: Set gradient nick color
usage: /color [hex2] ...
permission: gradient.color
- aliases: [gradient]
+ aliases: [gradient, цвет, градиент]
prefix:
description: Set custom prefix
usage: /prefix
permission: gradient.prefix
+ aliases: [префикс]
aprefix:
description: Admin gradient commands
@@ -119,6 +129,8 @@ permissions:
default: op
chat.mention.use:
default: true
+ lochat.chatcolor:
+ default: true
gradient.color:
default: true
gradient.prefix: