Initial commit: LoChat v1.0.0 with Gradient module

This commit is contained in:
loki5512344 2025-12-29 14:57:49 +01:00
commit 252b0a60db
86 changed files with 8922 additions and 0 deletions

View file

@ -0,0 +1,128 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class AntiSpamManager {
private final LoChat plugin;
private final Map<UUID, String> lastMessages = new ConcurrentHashMap<>();
private final Map<UUID, Long> lastMessageTime = new ConcurrentHashMap<>();
public AntiSpamManager(LoChat plugin) {
this.plugin = plugin;
}
public enum SpamResult {
ALLOWED,
TOO_MANY_CAPS,
REPEAT_CHARS,
SIMILAR_MESSAGE
}
public SpamResult checkMessage(UUID player, String message) {
if (!plugin.getConfigManager().isAntiSpamEnabled()) {
return SpamResult.ALLOWED;
}
// Проверка CAPS
if (hasTooManyCaps(message)) {
return SpamResult.TOO_MANY_CAPS;
}
// Проверка повторяющихся символов
if (hasRepeatChars(message)) {
return SpamResult.REPEAT_CHARS;
}
// Проверка похожих сообщений
if (isSimilarMessage(player, message)) {
return SpamResult.SIMILAR_MESSAGE;
}
// Сохраняем сообщение
lastMessages.put(player, message.toLowerCase());
lastMessageTime.put(player, System.currentTimeMillis());
return SpamResult.ALLOWED;
}
private boolean hasTooManyCaps(String message) {
if (message.length() < 5) return false;
int maxPercent = plugin.getConfigManager().getMaxCapsPercent();
long upperCount = message.chars().filter(Character::isUpperCase).count();
long letterCount = message.chars().filter(Character::isLetter).count();
if (letterCount == 0) return false;
int percent = (int) ((upperCount * 100) / letterCount);
return percent > maxPercent;
}
private boolean hasRepeatChars(String message) {
int maxRepeat = plugin.getConfigManager().getMaxRepeatChars();
int count = 1;
char lastChar = 0;
for (char c : message.toCharArray()) {
if (c == lastChar) {
count++;
if (count > maxRepeat) return true;
} else {
count = 1;
lastChar = c;
}
}
return false;
}
private boolean isSimilarMessage(UUID player, String message) {
String lastMsg = lastMessages.get(player);
Long lastTime = lastMessageTime.get(player);
if (lastMsg == null || lastTime == null) return false;
int delay = plugin.getConfigManager().getSimilarMessageDelay();
long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
if (elapsed > delay) return false;
// Проверка схожести (простая)
return message.toLowerCase().equals(lastMsg) ||
similarity(message.toLowerCase(), lastMsg) > 0.8;
}
private double similarity(String s1, String s2) {
int maxLen = Math.max(s1.length(), s2.length());
if (maxLen == 0) return 1.0;
int distance = levenshteinDistance(s1, s2);
return 1.0 - ((double) distance / maxLen);
}
private int levenshteinDistance(String s1, String s2) {
int[][] dp = new int[s1.length() + 1][s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) dp[i][0] = i;
for (int j = 0; j <= s2.length(); j++) dp[0][j] = j;
for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
int cost = s1.charAt(i - 1) == s2.charAt(j - 1) ? 0 : 1;
dp[i][j] = Math.min(Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + cost);
}
}
return dp[s1.length()][s2.length()];
}
public void clearPlayer(UUID player) {
lastMessages.remove(player);
lastMessageTime.remove(player);
}
}

View file

@ -0,0 +1,174 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import com.loki.lochat.utils.ChatFormatter;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class AutoMessageManager {
private final LoChat plugin;
private final Random random = new Random();
private final AtomicInteger currentIndex = new AtomicInteger(0);
private ScheduledTask task;
private Map<String, List<String>> messages;
private List<String> messageOrder;
private String prefix;
private String mode;
public AutoMessageManager(LoChat plugin) {
this.plugin = plugin;
loadMessages();
}
private void loadMessages() {
File file = new File(plugin.getDataFolder(), "automessages.yml");
if (!file.exists()) {
plugin.saveResource("automessages.yml", false);
}
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
// Настройки
prefix = config.getString("settings.prefix", "&6[&eINFO&6]&r");
mode = config.getString("settings.mode", "sequential").toLowerCase();
// Загружаем сообщения
messages = new LinkedHashMap<>();
ConfigurationSection msgSection = config.getConfigurationSection("messages");
if (msgSection != null) {
for (String key : msgSection.getKeys(false)) {
List<String> lines = new ArrayList<>();
if (msgSection.isList(key)) {
lines.addAll(msgSection.getStringList(key));
} else {
String single = msgSection.getString(key);
if (single != null) {
lines.add(single);
}
}
if (!lines.isEmpty()) {
messages.put(key, lines);
}
}
}
// Определяем порядок
messageOrder = new ArrayList<>();
if (mode.equals("custom")) {
String orderStr = config.getString("settings.order", "");
for (String item : orderStr.split(",")) {
String trimmed = item.trim();
if (!trimmed.isEmpty()) {
try {
int index = Integer.parseInt(trimmed) - 1;
List<String> keys = new ArrayList<>(messages.keySet());
if (index >= 0 && index < keys.size()) {
messageOrder.add(keys.get(index));
}
} catch (NumberFormatException e) {
if (messages.containsKey(trimmed)) {
messageOrder.add(trimmed);
}
}
}
}
}
if (messageOrder.isEmpty()) {
messageOrder.addAll(messages.keySet());
}
plugin.getLogger().info("Загружено " + messages.size() + " автосообщений");
}
public void start() {
if (!plugin.getConfigManager().isAutoMessagesEnabled()) {
return;
}
if (messages == null || messages.isEmpty()) {
plugin.getLogger().warning("Автосообщения не настроены!");
return;
}
int intervalSeconds = plugin.getConfigManager().getAutoMessagesInterval();
long intervalTicks = intervalSeconds * 20L;
task = plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(
plugin,
scheduledTask -> broadcastNextMessage(),
intervalTicks,
intervalTicks
);
plugin.getLogger().info("Автосообщения запущены (интервал: " + intervalSeconds + " сек, режим: " + mode + ")");
}
public void stop() {
if (task != null && !task.isCancelled()) {
task.cancel();
task = null;
}
}
private void broadcastNextMessage() {
if (messageOrder.isEmpty() || Bukkit.getOnlinePlayers().isEmpty()) {
return;
}
String messageKey;
if (mode.equals("random")) {
messageKey = messageOrder.get(random.nextInt(messageOrder.size()));
} else {
int index = currentIndex.getAndUpdate(i -> (i + 1) % messageOrder.size());
messageKey = messageOrder.get(index);
}
List<String> lines = messages.get(messageKey);
if (lines == null || lines.isEmpty()) return;
boolean isFirstLine = true;
for (String line : lines) {
// Заменяем смайлики через EmojiManager
String processed = ChatFormatter.replaceEmojis(line);
// Заменяем плейсхолдеры
processed = processed.replace("%online%", String.valueOf(Bukkit.getOnlinePlayers().size()));
// Добавляем префикс к первой непустой строке
Component formatted;
if (isFirstLine && !line.trim().isEmpty()) {
formatted = ChatFormatter.parse(prefix + " " + processed);
isFirstLine = false;
} else {
formatted = ChatFormatter.parse(processed);
}
for (var player : Bukkit.getOnlinePlayers()) {
player.sendMessage(formatted);
}
}
}
public void reload() {
stop();
loadMessages();
currentIndex.set(0);
start();
}
}

View file

@ -0,0 +1,115 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import com.loki.lochat.utils.ChatFormatter;
import com.loki.lochat.utils.DistanceUtil;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class ChatManager {
private final LoChat plugin;
private final Set<UUID> globalChatDisabled = ConcurrentHashMap.newKeySet();
public ChatManager(LoChat plugin) {
this.plugin = plugin;
}
public void sendGlobalMessage(Player sender, String message) {
if (!plugin.getConfigManager().isGlobalEnabled()) {
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("global.disabled")));
return;
}
// Обработка упоминаний @ник
Set<Player> mentionedPlayers = new HashSet<>();
String processedMessage = plugin.getMentionManager().processMentions(message, mentionedPlayers);
String format = plugin.getConfigManager().getGlobalFormat();
String prefix = plugin.getConfigManager().getGlobalPrefix();
boolean hasColor = sender.hasPermission("chat.global.color");
// Отправка каждому игроку персонализированное сообщение
for (Player player : Bukkit.getOnlinePlayers()) {
if (isGlobalChatDisabled(player.getUniqueId())) continue;
// Персонализируем сообщение для этого игрока (выделяем его ник)
String personalizedMsg = plugin.getMentionManager().getPersonalizedMessage(processedMessage, player);
Component formatted = ChatFormatter.formatGlobalMessage(format, prefix, sender, personalizedMsg, hasColor);
player.sendMessage(formatted);
// Проверяем упоминание ника без @ и уведомляем
plugin.getMentionManager().notifyIfMentioned(message, player, sender);
}
// Уведомление упомянутых через @
plugin.getMentionManager().notifyMentioned(mentionedPlayers);
plugin.getLogger().info("[G] " + sender.getName() + ": " + ChatFormatter.stripTags(message));
}
public void sendLocalMessage(Player sender, String message) {
if (!plugin.getConfigManager().isLocalEnabled()) {
return;
}
// Обработка упоминаний @ник
Set<Player> mentionedPlayers = new HashSet<>();
String processedMessage = plugin.getMentionManager().processMentions(message, mentionedPlayers);
int radius = plugin.getConfigManager().getLocalRadius();
String format = plugin.getConfigManager().getLocalFormat();
String prefix = plugin.getConfigManager().getLocalPrefix();
boolean hasColor = sender.hasPermission("chat.local.color");
boolean foundRecipient = false;
Set<Player> recipients = new HashSet<>();
for (Player player : Bukkit.getOnlinePlayers()) {
if (DistanceUtil.isInRange(sender, player, radius)) {
// Персонализируем сообщение для этого игрока
String personalizedMsg = plugin.getMentionManager().getPersonalizedMessage(processedMessage, player);
Component formatted = ChatFormatter.formatLocalMessage(format, prefix, sender, personalizedMsg, hasColor);
player.sendMessage(formatted);
recipients.add(player);
// Проверяем упоминание ника без @
plugin.getMentionManager().notifyIfMentioned(message, player, sender);
if (!player.equals(sender)) {
foundRecipient = true;
}
}
}
// Уведомление упомянутых через @ (только тех кто в радиусе)
mentionedPlayers.retainAll(recipients);
plugin.getMentionManager().notifyMentioned(mentionedPlayers);
if (!foundRecipient) {
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("local.no-players")));
}
}
public boolean toggleGlobalChat(UUID player) {
if (globalChatDisabled.contains(player)) {
globalChatDisabled.remove(player);
return true;
} else {
globalChatDisabled.add(player);
return false;
}
}
public boolean isGlobalChatDisabled(UUID player) {
return globalChatDisabled.contains(player);
}
}

View file

@ -0,0 +1,45 @@
package com.loki.lochat.managers;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class CooldownManager {
private final Map<UUID, Long> globalCooldowns = new ConcurrentHashMap<>();
private final Map<UUID, Long> localCooldowns = new ConcurrentHashMap<>();
public boolean isOnCooldown(UUID player, String chatType, int cooldownSeconds) {
Map<UUID, Long> cooldowns = chatType.equals("global") ? globalCooldowns : localCooldowns;
Long lastTime = cooldowns.get(player);
if (lastTime == null) {
return false;
}
long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
return elapsed < cooldownSeconds;
}
public int getRemainingCooldown(UUID player, String chatType, int cooldownSeconds) {
Map<UUID, Long> cooldowns = chatType.equals("global") ? globalCooldowns : localCooldowns;
Long lastTime = cooldowns.get(player);
if (lastTime == null) {
return 0;
}
long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
return Math.max(0, cooldownSeconds - (int) elapsed);
}
public void setCooldown(UUID player, String chatType) {
Map<UUID, Long> cooldowns = chatType.equals("global") ? globalCooldowns : localCooldowns;
cooldowns.put(player, System.currentTimeMillis());
}
public void removeCooldown(UUID player) {
globalCooldowns.remove(player);
localCooldowns.remove(player);
}
}

View file

@ -0,0 +1,100 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
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.util.HashMap;
import java.util.Map;
public class EmojiManager {
private final LoChat plugin;
private final Map<String, String> emojis = new HashMap<>();
private boolean enabled;
private boolean requirePermission;
public EmojiManager(LoChat plugin) {
this.plugin = plugin;
load();
}
public void load() {
File file = new File(plugin.getDataFolder(), "emojis.yml");
if (!file.exists()) {
plugin.saveResource("emojis.yml", false);
}
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
emojis.clear();
// Настройки
enabled = config.getBoolean("settings.enabled", true);
requirePermission = config.getBoolean("settings.require-permission", false);
// Загружаем все категории
for (String category : config.getKeys(false)) {
if (category.equals("settings")) continue;
ConfigurationSection section = config.getConfigurationSection(category);
if (section != null) {
for (String key : section.getKeys(false)) {
String value = section.getString(key);
if (value != null) {
emojis.put(key, value);
}
}
}
}
plugin.getLogger().info("Загружено " + emojis.size() + " смайликов");
}
public void reload() {
load();
}
/**
* Заменяет смайлики в сообщении
*/
public String process(String message, Player player) {
if (!enabled) return message;
// Проверка права
if (requirePermission && player != null && !player.hasPermission("chat.emoji.use")) {
return message;
}
String result = message;
for (Map.Entry<String, String> entry : emojis.entrySet()) {
result = result.replace(entry.getKey(), entry.getValue());
}
return result;
}
/**
* Заменяет смайлики без проверки прав (для автосообщений)
*/
public String process(String message) {
if (!enabled) return message;
String result = message;
for (Map.Entry<String, String> entry : emojis.entrySet()) {
result = result.replace(entry.getKey(), entry.getValue());
}
return result;
}
public Map<String, String> getEmojis() {
return emojis;
}
public boolean isEnabled() {
return enabled;
}
}

View file

@ -0,0 +1,61 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import java.util.List;
import java.util.regex.Pattern;
public class FilterManager {
private final LoChat plugin;
public FilterManager(LoChat plugin) {
this.plugin = plugin;
}
public enum FilterResult {
ALLOWED,
CENSORED,
BLOCKED,
WARNED
}
public FilterResult checkMessage(String message) {
if (!plugin.getConfigManager().isFilterEnabled()) {
return FilterResult.ALLOWED;
}
List<String> badWords = plugin.getConfigManager().getFilterWords();
String lowerMessage = message.toLowerCase();
for (String word : badWords) {
if (lowerMessage.contains(word.toLowerCase())) {
String action = plugin.getConfigManager().getFilterAction();
return switch (action) {
case "block" -> FilterResult.BLOCKED;
case "warn" -> FilterResult.WARNED;
default -> FilterResult.CENSORED;
};
}
}
return FilterResult.ALLOWED;
}
public String censorMessage(String message) {
if (!plugin.getConfigManager().isFilterEnabled()) {
return message;
}
List<String> badWords = plugin.getConfigManager().getFilterWords();
String replacement = plugin.getConfigManager().getFilterReplacement();
String result = message;
for (String word : badWords) {
Pattern pattern = Pattern.compile("(?i)" + Pattern.quote(word));
result = pattern.matcher(result).replaceAll(replacement);
}
return result;
}
}

View file

@ -0,0 +1,97 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class IgnoreManager {
private final LoChat plugin;
private final File ignoreFile;
private final Map<UUID, Set<UUID>> ignoreMap = new ConcurrentHashMap<>();
public IgnoreManager(LoChat plugin) {
this.plugin = plugin;
this.ignoreFile = new File(plugin.getDataFolder(), "ignores.yml");
load();
}
public void load() {
if (!ignoreFile.exists()) return;
YamlConfiguration config = YamlConfiguration.loadConfiguration(ignoreFile);
for (String key : config.getKeys(false)) {
try {
UUID uuid = UUID.fromString(key);
List<String> ignoredList = config.getStringList(key);
Set<UUID> ignored = ConcurrentHashMap.newKeySet();
for (String ignoredStr : ignoredList) {
try {
ignored.add(UUID.fromString(ignoredStr));
} catch (Exception ignored2) {}
}
if (!ignored.isEmpty()) {
ignoreMap.put(uuid, ignored);
}
} catch (Exception ignored) {}
}
}
public void save() {
YamlConfiguration config = new YamlConfiguration();
for (Map.Entry<UUID, Set<UUID>> entry : ignoreMap.entrySet()) {
List<String> ignoredList = new ArrayList<>();
for (UUID ignored : entry.getValue()) {
ignoredList.add(ignored.toString());
}
config.set(entry.getKey().toString(), ignoredList);
}
try {
config.save(ignoreFile);
} catch (IOException e) {
plugin.getLogger().severe("Не удалось сохранить игноры: " + e.getMessage());
}
}
public boolean isIgnoring(UUID player, UUID target) {
Set<UUID> ignored = ignoreMap.get(player);
return ignored != null && ignored.contains(target);
}
public boolean addIgnore(UUID player, UUID target) {
Set<UUID> ignored = ignoreMap.computeIfAbsent(player, k -> ConcurrentHashMap.newKeySet());
boolean added = ignored.add(target);
if (added) save();
return added;
}
public boolean removeIgnore(UUID player, UUID target) {
Set<UUID> ignored = ignoreMap.get(player);
if (ignored == null) return false;
boolean removed = ignored.remove(target);
if (removed) save();
return removed;
}
public Set<UUID> getIgnoredPlayers(UUID player) {
return ignoreMap.getOrDefault(player, Collections.emptySet());
}
public int getIgnoredCount(UUID player) {
Set<UUID> ignored = ignoreMap.get(player);
return ignored == null ? 0 : ignored.size();
}
public void clearIgnores(UUID player) {
ignoreMap.remove(player);
save();
}
}

View file

@ -0,0 +1,141 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MentionManager {
private final LoChat plugin;
private static final Pattern MENTION_PATTERN = Pattern.compile("@(\\w+)");
// Хранит для какого игрока какие части сообщения выделить
private final Map<Player, Set<String>> highlightedNicks = new HashMap<>();
public MentionManager(LoChat plugin) {
this.plugin = plugin;
}
/**
* Обрабатывает упоминания в сообщении
* Возвращает сообщение с подсвеченными никами
*/
public String processMentions(String message, Set<Player> mentionedPlayers) {
if (!plugin.getConfigManager().isMentionsEnabled()) {
return message;
}
highlightedNicks.clear();
String highlight = plugin.getConfigManager().getMentionHighlight();
Matcher matcher = MENTION_PATTERN.matcher(message);
StringBuilder result = new StringBuilder();
while (matcher.find()) {
String name = matcher.group(1);
Player mentioned = Bukkit.getPlayer(name);
if (mentioned != null && mentioned.isOnline()) {
mentionedPlayers.add(mentioned);
String replacement = highlight.replace("{player}", mentioned.getName());
matcher.appendReplacement(result, replacement);
// Запоминаем что этот игрок упомянут
highlightedNicks.computeIfAbsent(mentioned, k -> new HashSet<>()).add(mentioned.getName());
}
}
matcher.appendTail(result);
return result.toString();
}
/**
* Создаёт персонализированное сообщение для игрока
* Если его ник упомянут — выделяет его особым образом
*/
public String getPersonalizedMessage(String message, Player viewer) {
if (!plugin.getConfigManager().isMentionsEnabled()) {
return message;
}
String viewerName = viewer.getName();
String result = message;
// Проверяем упоминание через @ник
String highlight = plugin.getConfigManager().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 = plugin.getConfigManager().getSelfMentionHighlight();
result = nickMatcher.replaceAll(selfHighlight.replace("{player}", viewerName));
}
return result;
}
/**
* Проверяет, упомянут ли игрок в сообщении (по нику без @)
*/
public boolean isPlayerMentioned(String message, Player player) {
String name = player.getName();
Pattern pattern = Pattern.compile("(?i)\\b" + Pattern.quote(name) + "\\b");
return pattern.matcher(message).find();
}
/**
* Уведомляет упомянутых игроков звуком
*/
public void notifyMentioned(Set<Player> players) {
if (!plugin.getConfigManager().isMentionSoundEnabled()) {
return;
}
String soundName = plugin.getConfigManager().getMentionSoundType();
Sound sound;
try {
sound = Sound.valueOf(soundName);
} catch (IllegalArgumentException e) {
sound = Sound.BLOCK_NOTE_BLOCK_PLING;
}
for (Player player : players) {
player.playSound(player.getLocation(), sound, 1.0f, 1.0f);
}
}
/**
* Уведомляет игрока если его ник упомянут (без @)
*/
public void notifyIfMentioned(String message, Player viewer, Player sender) {
if (viewer.equals(sender)) return;
if (!plugin.getConfigManager().isMentionSoundEnabled()) return;
if (isPlayerMentioned(message, viewer)) {
String soundName = plugin.getConfigManager().getMentionSoundType();
try {
Sound sound = Sound.valueOf(soundName);
viewer.playSound(viewer.getLocation(), sound, 1.0f, 1.0f);
} catch (IllegalArgumentException ignored) {}
}
}
}

View file

@ -0,0 +1,136 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class MuteManager {
private final LoChat plugin;
private final File muteFile;
private final Map<UUID, Long> mutedPlayers = new ConcurrentHashMap<>();
private final Map<UUID, String> muteReasons = new ConcurrentHashMap<>();
public MuteManager(LoChat plugin) {
this.plugin = plugin;
this.muteFile = new File(plugin.getDataFolder(), "mutes.yml");
load();
}
public void load() {
if (!muteFile.exists()) return;
YamlConfiguration config = YamlConfiguration.loadConfiguration(muteFile);
for (String key : config.getKeys(false)) {
try {
UUID uuid = UUID.fromString(key);
long muteEnd = config.getLong(key + ".end");
String reason = config.getString(key + ".reason");
// Пропускаем истёкшие муты
if (muteEnd != 0 && System.currentTimeMillis() > muteEnd) continue;
mutedPlayers.put(uuid, muteEnd);
if (reason != null) muteReasons.put(uuid, reason);
} catch (Exception ignored) {}
}
}
public void save() {
YamlConfiguration config = new YamlConfiguration();
for (Map.Entry<UUID, Long> entry : mutedPlayers.entrySet()) {
String key = entry.getKey().toString();
config.set(key + ".end", entry.getValue());
String reason = muteReasons.get(entry.getKey());
if (reason != null) config.set(key + ".reason", reason);
}
try {
config.save(muteFile);
} catch (IOException e) {
plugin.getLogger().severe("Не удалось сохранить муты: " + e.getMessage());
}
}
public boolean isMuted(UUID player) {
Long muteEnd = mutedPlayers.get(player);
if (muteEnd == null) return false;
if (muteEnd == 0) return true;
if (System.currentTimeMillis() > muteEnd) {
mutedPlayers.remove(player);
muteReasons.remove(player);
save();
return false;
}
return true;
}
public void mute(UUID player, long durationSeconds, String reason) {
long muteEnd = durationSeconds <= 0 ? 0 : System.currentTimeMillis() + (durationSeconds * 1000);
mutedPlayers.put(player, muteEnd);
if (reason != null && !reason.isEmpty()) {
muteReasons.put(player, reason);
}
save();
}
public void unmute(UUID player) {
mutedPlayers.remove(player);
muteReasons.remove(player);
save();
}
public String getRemainingTime(UUID player) {
Long muteEnd = mutedPlayers.get(player);
if (muteEnd == null) return null;
if (muteEnd == 0) return "навсегда";
long remaining = (muteEnd - System.currentTimeMillis()) / 1000;
if (remaining <= 0) return null;
return formatTime(remaining);
}
public String getReason(UUID player) {
return muteReasons.get(player);
}
public boolean isAlreadyMuted(UUID player) {
return mutedPlayers.containsKey(player);
}
private String formatTime(long seconds) {
if (seconds < 60) return seconds + " сек";
if (seconds < 3600) return (seconds / 60) + " мин";
if (seconds < 86400) return (seconds / 3600) + " ч";
return (seconds / 86400) + " д";
}
public static long parseTime(String time) {
if (time == null || time.isEmpty()) return -1;
try {
char unit = time.charAt(time.length() - 1);
long value = Long.parseLong(time.substring(0, time.length() - 1));
return switch (Character.toLowerCase(unit)) {
case 's' -> value;
case 'm' -> value * 60;
case 'h' -> value * 3600;
case 'd' -> value * 86400;
default -> Long.parseLong(time);
};
} catch (NumberFormatException e) {
return -1;
}
}
}

View file

@ -0,0 +1,27 @@
package com.loki.lochat.managers;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class PMManager {
// UUID игрока -> UUID последнего собеседника
private final Map<UUID, UUID> lastConversation = new ConcurrentHashMap<>();
public void setLastConversation(UUID player, UUID target) {
lastConversation.put(player, target);
}
public UUID getLastConversation(UUID player) {
return lastConversation.get(player);
}
public void removeConversation(UUID player) {
lastConversation.remove(player);
}
public boolean hasConversation(UUID player) {
return lastConversation.containsKey(player);
}
}

View file

@ -0,0 +1,52 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import com.loki.lochat.utils.ChatFormatter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class SpyManager {
private final LoChat plugin;
private final Set<UUID> spyEnabled = ConcurrentHashMap.newKeySet();
public SpyManager(LoChat plugin) {
this.plugin = plugin;
}
public boolean toggleSpy(UUID player) {
if (spyEnabled.contains(player)) {
spyEnabled.remove(player);
return false;
} else {
spyEnabled.add(player);
return true;
}
}
public boolean isSpying(UUID player) {
return spyEnabled.contains(player);
}
public void broadcastPM(Player sender, Player receiver, String message) {
String format = plugin.getMessageConfig().get("spy.format");
for (UUID spyUuid : spyEnabled) {
Player spy = Bukkit.getPlayer(spyUuid);
if (spy != null && spy.isOnline() && !spy.equals(sender) && !spy.equals(receiver)) {
spy.sendMessage(ChatFormatter.parse(format
.replace("{sender}", sender.getName())
.replace("{receiver}", receiver.getName())
.replace("{message}", message)));
}
}
}
public void removeSpy(UUID player) {
spyEnabled.remove(player);
}
}