diff --git a/src/main/java/com/slyph/cloverchat/CloverChatPlugin.java b/src/main/java/com/slyph/cloverchat/CloverChatPlugin.java index 93543d3..1142840 100644 --- a/src/main/java/com/slyph/cloverchat/CloverChatPlugin.java +++ b/src/main/java/com/slyph/cloverchat/CloverChatPlugin.java @@ -4,6 +4,7 @@ import com.slyph.cloverchat.command.ReloadCommand; import com.slyph.cloverchat.command.completer.PrivateMessageTabCompleter; import com.slyph.cloverchat.command.completer.ReloadTabCompleter; +import com.slyph.cloverchat.feature.automessage.AutoMessageService; import com.slyph.cloverchat.feature.headmessage.HeadMessageService; import com.slyph.cloverchat.feature.updatechecker.UpdateCheckerService; import com.slyph.cloverchat.listener.ChatListener; @@ -38,8 +39,10 @@ public final class CloverChatPlugin extends JavaPlugin { private boolean placeholderApiHooked; private HeadMessageService headMessageService; private UpdateCheckerService updateCheckerService; + private AutoMessageService autoMessageService; private FileConfiguration messagesConfiguration; private FileConfiguration hoversConfiguration; + private FileConfiguration autoMessagesConfiguration; private boolean modernChatBridgeEnabled; private String activeLanguage = DEFAULT_LANGUAGE; @@ -50,6 +53,7 @@ public void onEnable() { placeholderApiHooked = getServer().getPluginManager().getPlugin("PlaceholderAPI") != null; headMessageService = new HeadMessageService(this); updateCheckerService = new UpdateCheckerService(this); + autoMessageService = new AutoMessageService(this); ChatListener chatListener = new ChatListener(this); modernChatBridgeEnabled = new ModernChatBridge(this, chatListener).register(); @@ -75,6 +79,7 @@ public void onEnable() { } updateCheckerService.start(); + autoMessageService.start(); logStartupBanner(); } @@ -86,6 +91,9 @@ public void onDisable() { if (updateCheckerService != null) { updateCheckerService.stop(); } + if (autoMessageService != null) { + autoMessageService.stop(); + } } public FileConfiguration configuration() { @@ -100,6 +108,10 @@ public FileConfiguration hovers() { return hoversConfiguration; } + public FileConfiguration autoMessages() { + return autoMessagesConfiguration; + } + public boolean isPlaceholderApiHooked() { return placeholderApiHooked; } @@ -146,6 +158,9 @@ public void reloadPluginConfiguration() { if (updateCheckerService != null) { updateCheckerService.restart(); } + if (autoMessageService != null) { + autoMessageService.restart(); + } } private void loadAdditionalConfigurations() { @@ -161,8 +176,10 @@ private void loadAdditionalConfigurations() { File messagesFile = ensureLanguageResourceFile(activeLanguage, "messages.yml"); File hoversFile = ensureLanguageResourceFile(activeLanguage, "hovers.yml"); + File autoMessagesFile = ensureRootResourceFile("auto-messages.yml"); messagesConfiguration = YamlConfiguration.loadConfiguration(messagesFile); hoversConfiguration = YamlConfiguration.loadConfiguration(hoversFile); + autoMessagesConfiguration = YamlConfiguration.loadConfiguration(autoMessagesFile); } private void ensureLanguageResources(String language) { @@ -178,6 +195,14 @@ private File ensureLanguageResourceFile(String language, String fileName) { return file; } + private File ensureRootResourceFile(String fileName) { + File file = new File(getDataFolder(), fileName); + if (!file.exists()) { + saveResource(fileName, false); + } + return file; + } + private void migrateLegacyLanguageFiles() { File legacyMessages = new File(getDataFolder(), "messages.yml"); File legacyHovers = new File(getDataFolder(), "hovers.yml"); @@ -212,6 +237,7 @@ private void logStartupBanner() { String version = getDescription().getVersion(); String placeholderApiStatus = placeholderApiHooked ? "Подключен" : "Не найден"; String updateCheckerStatus = configuration().getBoolean("update-checker.enabled", true) ? "Включена" : "Выключена"; + String autoMessagesStatus = autoMessages() != null && autoMessages().getBoolean("enabled", false) ? "Включены" : "Выключены"; getLogger().info(""); getLogger().info(LOG_TOP); @@ -223,7 +249,8 @@ private void logStartupBanner() { getLogger().info(boxLine("Чат режим: " + (modernChatBridgeEnabled ? "AsyncChatEvent (1.19+)" : "AsyncPlayerChatEvent"))); getLogger().info(boxLine("PlaceholderAPI: " + placeholderApiStatus)); getLogger().info(boxLine("Проверка обновлений: " + updateCheckerStatus)); - getLogger().info(boxLine("Конфиги: config.yml | langs/" + activeLanguage + "/")); + getLogger().info(boxLine("Автосообщения: " + autoMessagesStatus)); + getLogger().info(boxLine("Конфиги: config.yml | auto-messages.yml | langs/" + activeLanguage + "/")); getLogger().info(LOG_BOTTOM); getLogger().info(""); } diff --git a/src/main/java/com/slyph/cloverchat/feature/automessage/AutoMessageService.java b/src/main/java/com/slyph/cloverchat/feature/automessage/AutoMessageService.java new file mode 100644 index 0000000..e69e169 --- /dev/null +++ b/src/main/java/com/slyph/cloverchat/feature/automessage/AutoMessageService.java @@ -0,0 +1,179 @@ +package com.slyph.cloverchat.feature.automessage; + +import com.slyph.cloverchat.CloverChatPlugin; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Random; + +public final class AutoMessageService { + + private final CloverChatPlugin plugin; + private final Random random = new Random(); + private BukkitTask task; + private int nextMessageIndex; + + public AutoMessageService(CloverChatPlugin plugin) { + this.plugin = plugin; + } + + public void start() { + stop(); + + FileConfiguration configuration = plugin.autoMessages(); + if (configuration == null || !configuration.getBoolean("enabled", false)) { + return; + } + + long intervalSeconds = Math.max(5L, configuration.getLong("interval-seconds", 180L)); + long firstDelaySeconds = Math.max(0L, configuration.getLong("first-delay-seconds", 20L)); + long intervalTicks = intervalSeconds * 20L; + long firstDelayTicks = firstDelaySeconds * 20L; + + task = Bukkit.getScheduler().runTaskTimer(plugin, this::broadcastNextMessage, firstDelayTicks, intervalTicks); + } + + public void restart() { + start(); + } + + public void stop() { + if (task != null) { + task.cancel(); + task = null; + } + nextMessageIndex = 0; + } + + private void broadcastNextMessage() { + FileConfiguration configuration = plugin.autoMessages(); + if (configuration == null || !configuration.getBoolean("enabled", false)) { + return; + } + + if (configuration.getBoolean("require-players-online", true) && Bukkit.getOnlinePlayers().isEmpty()) { + return; + } + + List entries = readEntries(configuration.getMapList("messages")); + if (entries.isEmpty()) { + return; + } + + AutoMessageEntry entry = selectEntry(entries, configuration.getBoolean("random-order", false)); + if (entry == null || entry.lines.isEmpty()) { + return; + } + + int onlineCount = Bukkit.getOnlinePlayers().size(); + if (onlineCount < entry.minOnline) { + return; + } + + for (Player player : Bukkit.getOnlinePlayers()) { + if (!entry.permission.isEmpty() && !player.hasPermission(entry.permission)) { + continue; + } + plugin.sendConfiguredLines(player, player, entry.lines); + } + } + + private AutoMessageEntry selectEntry(List entries, boolean randomOrder) { + if (entries.isEmpty()) { + return null; + } + + if (randomOrder) { + return entries.get(random.nextInt(entries.size())); + } + + if (nextMessageIndex >= entries.size()) { + nextMessageIndex = 0; + } + + AutoMessageEntry entry = entries.get(nextMessageIndex); + nextMessageIndex++; + if (nextMessageIndex >= entries.size()) { + nextMessageIndex = 0; + } + return entry; + } + + private List readEntries(List> mapList) { + List entries = new ArrayList<>(); + if (mapList == null || mapList.isEmpty()) { + return entries; + } + + for (Map map : mapList) { + if (map == null || map.isEmpty()) { + continue; + } + + String permission = stringValue(map.get("permission")); + int minOnline = intValue(map.get("min-online"), 0); + List lines = listValue(map.get("lines")); + if (lines.isEmpty()) { + continue; + } + + entries.add(new AutoMessageEntry(permission, minOnline, lines)); + } + + return entries; + } + + private String stringValue(Object value) { + if (value == null) { + return ""; + } + return String.valueOf(value).trim(); + } + + private int intValue(Object value, int fallback) { + if (value == null) { + return fallback; + } + if (value instanceof Number) { + return ((Number) value).intValue(); + } + try { + return Integer.parseInt(String.valueOf(value).trim()); + } catch (Exception ignored) { + return fallback; + } + } + + private List listValue(Object value) { + List result = new ArrayList<>(); + if (!(value instanceof List)) { + return result; + } + List list = (List) value; + for (Object element : list) { + if (element == null) { + continue; + } + result.add(String.valueOf(element)); + } + return result; + } + + private static final class AutoMessageEntry { + + private final String permission; + private final int minOnline; + private final List lines; + + private AutoMessageEntry(String permission, int minOnline, List lines) { + this.permission = permission == null ? "" : permission; + this.minOnline = Math.max(0, minOnline); + this.lines = lines; + } + } +} diff --git a/src/main/resources/auto-messages.yml b/src/main/resources/auto-messages.yml new file mode 100644 index 0000000..61c3f3e --- /dev/null +++ b/src/main/resources/auto-messages.yml @@ -0,0 +1,54 @@ +# CloverChat • Автосообщения +# +# Как это работает: +# 1) Поставьте enabled: true +# 2) Укажите интервал отправки в секундах +# 3) Добавьте сообщения в блок messages +# +# В сообщениях поддерживаются HEX-цвета (например: &#FFAA00), PlaceholderAPI и обычные цвет-коды (&a, &7 и т.д.) + +enabled: true + +# Задержка перед первым автосообщением после старта сервера +first-delay-seconds: 30 + +# Интервал между автосообщениями (в секундах) +interval-seconds: 180 + +# true - случайный выбор сообщения +# false - по порядку, циклом +random-order: false + +# Если true, автосообщения не отправляются, когда на сервере нет игроков +require-players-online: true + +# Список автосообщений +messages: + - id: "welcome" + # Минимум игроков онлайн, чтобы это сообщение отправилось + min-online: 0 + # Если указать permission, сообщение увидят только игроки с этим правом + # Пример: "cloverchat.automessage.vip" + permission: "" + lines: + - "&7" + - "e765★ Чат Yffa6| e765Добро пожаловать на сервер, &#b2ffd8%player_name%" + - "defffНе забудьте ознакомиться с правилами и командами" + - "&7" + + - id: "social" + min-online: 0 + permission: "" + lines: + - "&7" + - "e765★ Чат Yffa6| e765Присоединяйтесь к нашему сообществу" + - "defffСайт: &#b2ffd8example.com" + - "&7" + + - id: "vip" + min-online: 0 + permission: "cloverchat.automessage.vip" + lines: + - "&7" + - "&#ffcb1b★ VIP &#ffd98a| &#fff2d9Спасибо за поддержку сервера" + - "&7"