Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/main/java/com/slyph/cloverchat/CloverChatPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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();
Expand All @@ -75,6 +79,7 @@ public void onEnable() {
}

updateCheckerService.start();
autoMessageService.start();
logStartupBanner();
}

Expand All @@ -86,6 +91,9 @@ public void onDisable() {
if (updateCheckerService != null) {
updateCheckerService.stop();
}
if (autoMessageService != null) {
autoMessageService.stop();
}
}

public FileConfiguration configuration() {
Expand All @@ -100,6 +108,10 @@ public FileConfiguration hovers() {
return hoversConfiguration;
}

public FileConfiguration autoMessages() {
return autoMessagesConfiguration;
}

public boolean isPlaceholderApiHooked() {
return placeholderApiHooked;
}
Expand Down Expand Up @@ -146,6 +158,9 @@ public void reloadPluginConfiguration() {
if (updateCheckerService != null) {
updateCheckerService.restart();
}
if (autoMessageService != null) {
autoMessageService.restart();
}
}

private void loadAdditionalConfigurations() {
Expand All @@ -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) {
Expand All @@ -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");
Expand Down Expand Up @@ -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);
Expand All @@ -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("");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<AutoMessageEntry> 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<AutoMessageEntry> 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<AutoMessageEntry> readEntries(List<Map<?, ?>> mapList) {
List<AutoMessageEntry> 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<String> 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<String> listValue(Object value) {
List<String> 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<String> lines;

private AutoMessageEntry(String permission, int minOnline, List<String> lines) {
this.permission = permission == null ? "" : permission;
this.minOnline = Math.max(0, minOnline);
this.lines = lines;
}
}
}
54 changes: 54 additions & 0 deletions src/main/resources/auto-messages.yml
Original file line number Diff line number Diff line change
@@ -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"
- "&#24e765★ Чат &#89ffa6| &#24e765Добро пожаловать на сервер, &#b2ffd8%player_name%"
- "&#7defffНе забудьте ознакомиться с правилами и командами"
- "&7"

- id: "social"
min-online: 0
permission: ""
lines:
- "&7"
- "&#24e765★ Чат &#89ffa6| &#24e765Присоединяйтесь к нашему сообществу"
- "&#7defffСайт: &#b2ffd8example.com"
- "&7"

- id: "vip"
min-online: 0
permission: "cloverchat.automessage.vip"
lines:
- "&7"
- "&#ffcb1b★ VIP &#ffd98a| &#fff2d9Спасибо за поддержку сервера"
- "&7"
Loading