chore: clean up documentation and rebuild with badwords filter
- Remove outdated CODE_REVIEW_RU.md and REFACTORING_SERVICES.md documentation - Add badwords.txt resource file for swear filter functionality - Rebuild compiled classes with updated filter and configuration logic - Update all configuration files (appearance, discord, filters, messages) - Rebuild core components: ConfigManager, PluginInitializer, SwearFilter, GradientModule, PrefixService, PlayerEventListener, EnhancedChatRenderer - Consolidate build artifacts with source changes for consistency
This commit is contained in:
parent
bba480002f
commit
4f6eaf35e9
28 changed files with 1152 additions and 1364 deletions
|
|
@ -1,356 +0,0 @@
|
|||
# 🔍 Code Review: Проблемы архитектуры (SOLID, DRY, KISS)
|
||||
|
||||
## 🔴 Критические проблемы
|
||||
|
||||
### 1. DRY: Дублирование кода в конфигах
|
||||
**Файлы:** `AppearanceConfig.java`, `MessagesConfig.java`, `FiltersConfig.java`
|
||||
|
||||
**Проблема:**
|
||||
- Каждый конфиг содержит 30-50 геттеров с одинаковой структурой
|
||||
- ~300 строк повторяющегося кода
|
||||
- При изменении логики нужно править в 3 местах
|
||||
|
||||
**Решение:**
|
||||
```java
|
||||
// Создать базовый класс с generic методами
|
||||
public abstract class BaseConfig {
|
||||
protected String getString(String path, String def) { ... }
|
||||
protected int getInt(String path, int def) { ... }
|
||||
protected boolean getBoolean(String path, boolean def) { ... }
|
||||
}
|
||||
|
||||
// Использовать в конфигах
|
||||
public class MessagesConfig extends BaseConfig {
|
||||
public String getNoPermission() {
|
||||
return getString("general.no_permission", "&#CF6679Нет прав!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. SRP: ConfigManager делает слишком много
|
||||
**Файл:** `ConfigManager.java`
|
||||
|
||||
**Проблема:**
|
||||
- Управляет 5 конфигами
|
||||
- Содержит логику обновления версий
|
||||
- Имеет 30+ геттеров для настроек
|
||||
- Нарушает Single Responsibility Principle
|
||||
|
||||
**Решение:**
|
||||
```java
|
||||
// Разделить на отдельные классы
|
||||
class ConfigManager {
|
||||
private final AppearanceConfig appearance;
|
||||
private final MessagesConfig messages;
|
||||
// Только управление конфигами
|
||||
}
|
||||
|
||||
class ConfigUpdater {
|
||||
// Логика обновления версий
|
||||
void updateConfig(FileConfiguration config) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. KISS: ColorConverter неэффективен
|
||||
**Файл:** `ColorConverter.java`
|
||||
|
||||
**Проблема:**
|
||||
```java
|
||||
private static String convertAmpersandColors(String message) {
|
||||
return message
|
||||
.replaceAll("&0", "<black>")
|
||||
.replaceAll("&1", "<dark_blue>")
|
||||
// ... 16 вызовов replaceAll
|
||||
}
|
||||
```
|
||||
- Каждый `replaceAll` компилирует regex
|
||||
- O(n * 16) сложность
|
||||
- Дублирование для `§` и `&`
|
||||
|
||||
**Решение:**
|
||||
```java
|
||||
private static final Map<String, String> COLOR_MAP = Map.ofEntries(
|
||||
Map.entry("&0", "<black>"),
|
||||
Map.entry("§0", "<black>"),
|
||||
Map.entry("&1", "<dark_blue>"),
|
||||
Map.entry("§1", "<dark_blue>")
|
||||
// ...
|
||||
);
|
||||
|
||||
private static String convertColors(String message) {
|
||||
for (Map.Entry<String, String> entry : COLOR_MAP.entrySet()) {
|
||||
message = message.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return message;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. DRY: Дублирование проверок permissions
|
||||
**Файл:** `AdvancedMessageFilter.java`
|
||||
|
||||
**Проблема:**
|
||||
```java
|
||||
if (!player.hasPermission("lochat.bypass.swear") && !player.hasPermission("lochat.bypass.filter"))
|
||||
if (!player.hasPermission("lochat.bypass.flood") && !player.hasPermission("lochat.bypass.filter"))
|
||||
if (!player.hasPermission("lochat.bypass.spam") && !player.hasPermission("lochat.bypass.filter"))
|
||||
```
|
||||
|
||||
**Решение:**
|
||||
```java
|
||||
private boolean canBypassFilter(Player player, String filterType) {
|
||||
return player.hasPermission("lochat.bypass." + filterType)
|
||||
|| player.hasPermission("lochat.bypass.filter");
|
||||
}
|
||||
|
||||
// Использование
|
||||
if (!canBypassFilter(player, "swear")) {
|
||||
FilterResult swear = swearFilter.filter(player, message);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. OCP: EnhancedChatRenderer не расширяем
|
||||
**Файл:** `EnhancedChatRenderer.java`
|
||||
|
||||
**Проблема:**
|
||||
```java
|
||||
switch (placeholder) {
|
||||
case "emoji" -> result = result.append(emoji);
|
||||
case "prefix" -> result = result.append(prefix);
|
||||
// Добавление нового плейсхолдера требует изменения кода
|
||||
}
|
||||
```
|
||||
|
||||
**Решение:**
|
||||
```java
|
||||
// Strategy pattern для плейсхолдеров
|
||||
interface PlaceholderResolver {
|
||||
Component resolve(Player player, boolean isGlobal);
|
||||
}
|
||||
|
||||
Map<String, PlaceholderResolver> resolvers = Map.of(
|
||||
"emoji", (p, g) -> buildEmojiComponent(g),
|
||||
"prefix", (p, g) -> buildPrefix(g),
|
||||
"player", (p, g) -> buildPlayerComponent(p)
|
||||
);
|
||||
|
||||
// Использование
|
||||
Component resolved = resolvers.getOrDefault(placeholder,
|
||||
(p, g) -> Component.text("{" + placeholder + "}"))
|
||||
.resolve(player, isGlobal);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. ISP: MuteServiceImpl не реализован полностью
|
||||
**Файл:** `MuteServiceImpl.java`
|
||||
|
||||
**Проблема:**
|
||||
```java
|
||||
@Override
|
||||
public void save() {
|
||||
// TODO: Implement save to file
|
||||
}
|
||||
|
||||
private void load() {
|
||||
// TODO: Implement load from file
|
||||
}
|
||||
```
|
||||
|
||||
**Решение:**
|
||||
- Либо реализовать методы
|
||||
- Либо разделить интерфейс на `MuteService` и `PersistentMuteService`
|
||||
|
||||
---
|
||||
|
||||
### 7. Отсутствует зависимость VoiceChat
|
||||
**Файл:** `MuteServiceImpl.java`
|
||||
|
||||
**Проблема:**
|
||||
```java
|
||||
import de.maxhenkel.voicechat.api.BukkitVoicechatService; // ❌ Не найден
|
||||
```
|
||||
|
||||
**Решение:**
|
||||
```gradle
|
||||
// build.gradle.kts
|
||||
dependencies {
|
||||
compileOnly("de.maxhenkel.voicechat:voicechat-api:2.5.0")
|
||||
}
|
||||
```
|
||||
|
||||
Или сделать опциональной зависимостью:
|
||||
```java
|
||||
private void initVoiceChat() {
|
||||
try {
|
||||
Class.forName("de.maxhenkel.voicechat.api.BukkitVoicechatService");
|
||||
// Инициализация
|
||||
} catch (ClassNotFoundException e) {
|
||||
plugin.getLogger().info("VoiceChat not found, voice mute disabled");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. SRP: ChatEventListener слишком сложный
|
||||
**Файл:** `ChatEventListener.java`
|
||||
|
||||
**Проблема:**
|
||||
- Метод `onChat` содержит 80+ строк
|
||||
- Обрабатывает: режим чата, фильтрацию, радиус, Discord, статистику
|
||||
- Нарушает Single Responsibility
|
||||
|
||||
**Решение:**
|
||||
```java
|
||||
class ChatEventListener {
|
||||
private final ChatModeHandler modeHandler;
|
||||
private final MessageFilterHandler filterHandler;
|
||||
private final LocalChatHandler localHandler;
|
||||
private final DiscordHandler discordHandler;
|
||||
private final StatsHandler statsHandler;
|
||||
|
||||
@EventHandler
|
||||
public void onChat(AsyncChatEvent event) {
|
||||
Player sender = event.getPlayer();
|
||||
String message = extractMessage(event);
|
||||
|
||||
// Делегируем обработку
|
||||
ChatMode mode = modeHandler.determineMode(message);
|
||||
if (!filterHandler.filter(sender, message)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == ChatMode.LOCAL) {
|
||||
localHandler.handleLocal(event, sender);
|
||||
}
|
||||
|
||||
discordHandler.sendToDiscord(sender, message, mode);
|
||||
statsHandler.recordMessage(sender, mode);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. DRY: Дублирование конвертации цветов
|
||||
**Файл:** `ColorConverter.java`
|
||||
|
||||
**Проблема:**
|
||||
```java
|
||||
private static String convertSectionColors(String message) { ... }
|
||||
private static String convertAmpersandColors(String message) { ... }
|
||||
```
|
||||
Идентичная логика, только разные символы.
|
||||
|
||||
**Решение:**
|
||||
```java
|
||||
private static String convertColors(String message, char symbol) {
|
||||
return message
|
||||
.replaceAll(symbol + "0", "<black>")
|
||||
.replaceAll(symbol + "1", "<dark_blue>")
|
||||
// ...
|
||||
}
|
||||
|
||||
public static String convertLegacyFormats(String message) {
|
||||
message = convertColors(message, '§');
|
||||
message = convertColors(message, '&');
|
||||
return message;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 10. DIP: Прямая зависимость от LoChat
|
||||
**Файлы:** `EnhancedChatRenderer.java`, `ChatEventListener.java`, и др.
|
||||
|
||||
**Проблема:**
|
||||
```java
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
```
|
||||
Нарушает Dependency Inversion Principle.
|
||||
|
||||
**Решение:**
|
||||
```java
|
||||
// Создать интерфейс
|
||||
interface ChatPlugin {
|
||||
ConfigManager getConfigManager();
|
||||
GradientModule getGradientModule();
|
||||
DiscordIntegration getDiscordIntegration();
|
||||
}
|
||||
|
||||
// LoChat реализует интерфейс
|
||||
class LoChat extends JavaPlugin implements ChatPlugin { ... }
|
||||
|
||||
// Использование
|
||||
class EnhancedChatRenderer {
|
||||
private final ChatPlugin plugin;
|
||||
|
||||
public EnhancedChatRenderer(ChatPlugin plugin, boolean isGlobal) {
|
||||
this.plugin = plugin;
|
||||
// Нет каста
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Статистика проблем
|
||||
|
||||
| Принцип | Нарушений | Критичность |
|
||||
|---------|-----------|-------------|
|
||||
| DRY | 4 | 🔴 Высокая |
|
||||
| SRP | 3 | 🔴 Высокая |
|
||||
| KISS | 2 | 🟡 Средняя |
|
||||
| OCP | 1 | 🟡 Средняя |
|
||||
| DIP | 1 | 🟡 Средняя |
|
||||
| ISP | 1 | 🟢 Низкая |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Что сделано хорошо
|
||||
|
||||
1. **ServiceRegistry** - правильная реализация DI
|
||||
2. **Разделение на модули** - gradient, integrations, core
|
||||
3. **Использование интерфейсов** - api.service.*
|
||||
4. **PluginInitializer/PluginShutdown** - разделение логики инициализации
|
||||
5. **BaseConfig** - базовый класс для конфигов (уже есть!)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Приоритеты исправления
|
||||
|
||||
### Высокий приоритет
|
||||
1. Исправить отсутствующую зависимость VoiceChat
|
||||
2. Упростить ColorConverter (KISS)
|
||||
3. Вынести проверки permissions в отдельный метод (DRY)
|
||||
|
||||
### Средний приоритет
|
||||
4. Разделить ChatEventListener на handler'ы (SRP)
|
||||
5. Убрать касты к LoChat через интерфейс (DIP)
|
||||
6. Сделать EnhancedChatRenderer расширяемым (OCP)
|
||||
|
||||
### Низкий приоритет
|
||||
7. Реализовать save/load в MuteServiceImpl (ISP)
|
||||
8. Упростить ConfigManager (SRP)
|
||||
9. Объединить методы конвертации цветов (DRY)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Итого
|
||||
|
||||
Проект имеет хорошую базовую архитектуру (ServiceRegistry, модули, интерфейсы), но есть проблемы с:
|
||||
- **Дублированием кода** (DRY) - особенно в конфигах и фильтрах
|
||||
- **Слишком большими классами** (SRP) - ConfigManager, ChatEventListener
|
||||
- **Неэффективными алгоритмами** (KISS) - ColorConverter
|
||||
|
||||
Рекомендую начать с исправления критических проблем (VoiceChat, ColorConverter, permissions), затем постепенно рефакторить остальное.
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
# 🔧 Рефакторинг сервисов - уменьшение количества файлов
|
||||
|
||||
## Текущая ситуация
|
||||
- **11 интерфейсов** в `api/service/`
|
||||
- **12 реализаций** в `core/service/`
|
||||
- **23 файла** только для сервисов
|
||||
- Некоторые сервисы по 30 строк кода
|
||||
|
||||
## Проблема
|
||||
Слишком много мелких файлов, которые можно объединить по функциональности.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 План рефакторинга
|
||||
|
||||
### 1. Объединить простые сервисы в один
|
||||
|
||||
**Было:**
|
||||
```
|
||||
PMService.java (28 строк)
|
||||
SpyService.java (69 строк)
|
||||
IgnoreService.java (97 строк)
|
||||
```
|
||||
|
||||
**Станет:**
|
||||
```java
|
||||
// MessagingService.java - всё что связано с общением
|
||||
public interface MessagingService {
|
||||
// PM
|
||||
void setLastConversation(UUID sender, UUID receiver);
|
||||
UUID getLastConversation(UUID player);
|
||||
|
||||
// Spy
|
||||
boolean toggleSpy(UUID player);
|
||||
boolean isSpying(UUID player);
|
||||
void broadcastPM(Player sender, Player receiver, String message);
|
||||
|
||||
// Ignore
|
||||
void addIgnore(UUID player, UUID target);
|
||||
void removeIgnore(UUID player, UUID target);
|
||||
boolean isIgnoring(UUID player, UUID target);
|
||||
Set<UUID> getIgnoreList(UUID player);
|
||||
}
|
||||
```
|
||||
|
||||
**Экономия:** 3 интерфейса + 3 реализации = **6 файлов → 2 файла**
|
||||
|
||||
---
|
||||
|
||||
### 2. Объединить Mute + Punishment
|
||||
|
||||
**Было:**
|
||||
```
|
||||
MuteService.java + MuteServiceImpl.java (212 строк)
|
||||
PunishmentService.java + PunishmentServiceImpl.java (173 строки)
|
||||
MuteHistoryManager.java (77 строк)
|
||||
```
|
||||
|
||||
**Станет:**
|
||||
```java
|
||||
// ModerationService.java - всё что связано с модерацией
|
||||
public interface ModerationService {
|
||||
// Mutes
|
||||
void mute(UUID uuid, String name, long duration, String reason, String by);
|
||||
boolean unmute(UUID uuid, String by);
|
||||
boolean isMuted(UUID uuid);
|
||||
MuteData getMuteData(UUID uuid);
|
||||
|
||||
// Bans
|
||||
void ban(UUID uuid, String name, long duration, String reason, String by);
|
||||
boolean unban(UUID uuid, String by);
|
||||
boolean isBanned(UUID uuid);
|
||||
BanData getBanData(UUID uuid);
|
||||
|
||||
// Warns
|
||||
void warn(UUID uuid, String name, String reason, String by);
|
||||
List<WarnData> getWarns(UUID uuid);
|
||||
|
||||
// History
|
||||
List<ModerationEntry> getHistory(UUID uuid);
|
||||
List<ModerationEntry> getHistoryByModerator(String name);
|
||||
}
|
||||
```
|
||||
|
||||
**Экономия:** 3 интерфейса + 3 реализации = **6 файлов → 2 файла**
|
||||
|
||||
---
|
||||
|
||||
### 3. Объединить Cooldown + PlayerData
|
||||
|
||||
**Было:**
|
||||
```
|
||||
CooldownService.java + CooldownServiceImpl.java (40 строк)
|
||||
PlayerDataService.java + PlayerDataServiceImpl.java (102 строки)
|
||||
```
|
||||
|
||||
**Станет:**
|
||||
```java
|
||||
// PlayerService.java - всё что связано с данными игрока
|
||||
public interface PlayerService {
|
||||
// Cooldowns
|
||||
boolean hasCooldown(UUID player, String type);
|
||||
void setCooldown(UUID player, String type, long duration);
|
||||
long getRemainingCooldown(UUID player, String type);
|
||||
void clearCooldowns(UUID player);
|
||||
|
||||
// Statistics
|
||||
void recordMessage(UUID player, String chatType);
|
||||
PlayerStats getStats(UUID player);
|
||||
void saveAll();
|
||||
}
|
||||
```
|
||||
|
||||
**Экономия:** 2 интерфейса + 2 реализации = **4 файла → 2 файла**
|
||||
|
||||
---
|
||||
|
||||
### 4. Оставить как есть (нормальный размер)
|
||||
|
||||
```
|
||||
ChatService.java + ChatServiceImpl.java (114 строк) ✅
|
||||
MessageService.java + MessageServiceImpl.java (36 строк) ✅
|
||||
MentionService.java + MentionServiceImpl.java (104 строки) ✅
|
||||
NickService.java + NickServiceImpl.java (155 строк) ✅
|
||||
```
|
||||
|
||||
Эти сервисы имеют чёткую ответственность и нормальный размер.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Результат рефакторинга
|
||||
|
||||
| До | После | Экономия |
|
||||
|----|-------|----------|
|
||||
| 11 интерфейсов | 7 интерфейсов | -4 |
|
||||
| 12 реализаций | 8 реализаций | -4 |
|
||||
| **23 файла** | **15 файлов** | **-8 файлов** |
|
||||
|
||||
---
|
||||
|
||||
## 🔨 Пошаговая реализация
|
||||
|
||||
### Шаг 1: Создать MessagingService
|
||||
|
||||
```java
|
||||
// api/service/MessagingService.java
|
||||
public interface MessagingService {
|
||||
// PM
|
||||
void setLastConversation(UUID sender, UUID receiver);
|
||||
UUID getLastConversation(UUID player);
|
||||
|
||||
// Spy
|
||||
boolean toggleSpy(UUID player);
|
||||
boolean isSpying(UUID player);
|
||||
void broadcastPM(Player sender, Player receiver, String message);
|
||||
void sendToSpies(Player sender, Component message, boolean isGlobal);
|
||||
void removeSpy(UUID player);
|
||||
|
||||
// Ignore
|
||||
void addIgnore(UUID player, UUID target);
|
||||
void removeIgnore(UUID player, UUID target);
|
||||
boolean isIgnoring(UUID player, UUID target);
|
||||
Set<UUID> getIgnoreList(UUID player);
|
||||
void save();
|
||||
}
|
||||
|
||||
// core/service/MessagingServiceImpl.java
|
||||
public class MessagingServiceImpl implements MessagingService {
|
||||
private final JavaPlugin plugin;
|
||||
private final MessageConfig messageConfig;
|
||||
|
||||
// PM state
|
||||
private final Map<UUID, UUID> lastConversation = new ConcurrentHashMap<>();
|
||||
|
||||
// Spy state
|
||||
private final Set<UUID> spyEnabled = ConcurrentHashMap.newKeySet();
|
||||
|
||||
// Ignore state
|
||||
private final Map<UUID, Set<UUID>> ignoreMap = new ConcurrentHashMap<>();
|
||||
|
||||
public MessagingServiceImpl(JavaPlugin plugin, MessageConfig messageConfig) {
|
||||
this.plugin = plugin;
|
||||
this.messageConfig = messageConfig;
|
||||
loadIgnoreData();
|
||||
}
|
||||
|
||||
// Реализация всех методов...
|
||||
}
|
||||
```
|
||||
|
||||
### Шаг 2: Обновить ServiceRegistry
|
||||
|
||||
```java
|
||||
// Было
|
||||
register(PMService.class, new PMServiceImpl());
|
||||
register(SpyService.class, new SpyServiceImpl(messageConfig));
|
||||
register(IgnoreService.class, new IgnoreServiceImpl(plugin));
|
||||
|
||||
// Стало
|
||||
MessagingService messaging = new MessagingServiceImpl(plugin, messageConfig);
|
||||
register(MessagingService.class, messaging);
|
||||
|
||||
// Для обратной совместимости (опционально)
|
||||
register(PMService.class, messaging);
|
||||
register(SpyService.class, messaging);
|
||||
register(IgnoreService.class, messaging);
|
||||
```
|
||||
|
||||
### Шаг 3: Удалить старые файлы
|
||||
|
||||
```bash
|
||||
# Удалить интерфейсы
|
||||
rm src/main/java/com/loki/lochat/api/service/PMService.java
|
||||
rm src/main/java/com/loki/lochat/api/service/SpyService.java
|
||||
rm src/main/java/com/loki/lochat/api/service/IgnoreService.java
|
||||
|
||||
# Удалить реализации
|
||||
rm src/main/java/com/loki/lochat/core/service/PMServiceImpl.java
|
||||
rm src/main/java/com/loki/lochat/core/service/SpyServiceImpl.java
|
||||
rm src/main/java/com/loki/lochat/core/service/IgnoreServiceImpl.java
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Альтернативный подход (если не хочешь ломать API)
|
||||
|
||||
Можно оставить старые интерфейсы, но сделать их делегатами:
|
||||
|
||||
```java
|
||||
// Старый интерфейс остаётся
|
||||
public interface PMService {
|
||||
void setLastConversation(UUID sender, UUID receiver);
|
||||
UUID getLastConversation(UUID player);
|
||||
}
|
||||
|
||||
// Но реализация делегирует в MessagingService
|
||||
public class PMServiceAdapter implements PMService {
|
||||
private final MessagingService messaging;
|
||||
|
||||
public PMServiceAdapter(MessagingService messaging) {
|
||||
this.messaging = messaging;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastConversation(UUID sender, UUID receiver) {
|
||||
messaging.setLastConversation(sender, receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getLastConversation(UUID player) {
|
||||
return messaging.getLastConversation(player);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Это позволит:
|
||||
- Сохранить обратную совместимость
|
||||
- Уменьшить количество реализаций (3 → 1)
|
||||
- Постепенно мигрировать код на новый API
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Рекомендация
|
||||
|
||||
**Начни с MessagingService** - это самое простое объединение:
|
||||
1. PM, Spy, Ignore логически связаны (общение между игроками)
|
||||
2. Все три сервиса маленькие (28-97 строк)
|
||||
3. Объединение даст ~200 строк - нормальный размер
|
||||
|
||||
**Потом ModerationService** - это сложнее:
|
||||
1. Mute + Punishment + History = ~460 строк
|
||||
2. Нужно будет рефакторить внутреннюю структуру
|
||||
3. Но логически это одна область (модерация)
|
||||
|
||||
**PlayerService оставь на потом** - там всё норм.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Итого
|
||||
|
||||
Объединение сервисов:
|
||||
- ✅ Уменьшит количество файлов с 23 до 15
|
||||
- ✅ Упростит навигацию по коду
|
||||
- ✅ Сгруппирует связанную функциональность
|
||||
- ⚠️ Потребует обновления кода, который использует старые сервисы
|
||||
|
||||
Начни с MessagingService - это быстро и безопасно.
|
||||
58
bin/main/badwords.txt
Normal file
58
bin/main/badwords.txt
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# Список запрещенных слов (по одному на строку)
|
||||
# Строки начинающиеся с # игнорируются
|
||||
# Фильтр автоматически ловит замены букв (х->x, о->o и т.д.)
|
||||
|
||||
# Основной мат
|
||||
хуй
|
||||
хуя
|
||||
хуе
|
||||
хую
|
||||
хуем
|
||||
хуи
|
||||
пизда
|
||||
пизде
|
||||
пизду
|
||||
пиздой
|
||||
пизды
|
||||
ебать
|
||||
ебал
|
||||
ебет
|
||||
ебут
|
||||
ебала
|
||||
ебали
|
||||
ебаный
|
||||
ебанный
|
||||
ебучий
|
||||
ебучая
|
||||
ебучее
|
||||
блять
|
||||
блядь
|
||||
бляди
|
||||
блядей
|
||||
сука
|
||||
суки
|
||||
сучка
|
||||
сучки
|
||||
пидор
|
||||
пидора
|
||||
пидоры
|
||||
пидорас
|
||||
пидорасы
|
||||
гандон
|
||||
гандоны
|
||||
мудак
|
||||
мудаки
|
||||
мудила
|
||||
мудилы
|
||||
долбоеб
|
||||
долбоебы
|
||||
уебан
|
||||
уебаны
|
||||
уебок
|
||||
уебки
|
||||
говно
|
||||
говна
|
||||
говном
|
||||
дерьмо
|
||||
дерьма
|
||||
дерьмом
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,58 +1,143 @@
|
|||
# LoChat Configuration v1.5.5
|
||||
config-version: 4
|
||||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ LoChat Configuration ║
|
||||
# ║ Единый конфиг плагина ║
|
||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
config-version: 5
|
||||
prefix: "�D4FF[LoChat]"
|
||||
|
||||
# Базовые настройки чата
|
||||
# Детальные настройки (префиксы, цвета, форматы) в config/*.yml
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Режимы чата │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
chat:
|
||||
# Режим чата:
|
||||
# - Оба включены = локальный (по умолчанию) + глобальный (с "!")
|
||||
# - Только global = единый чат без префиксов для всех
|
||||
# Глобальный чат (все видят, активируется через "!")
|
||||
global:
|
||||
enabled: true
|
||||
cooldown: 3
|
||||
|
||||
# Локальный чат (только в радиусе)
|
||||
local:
|
||||
enabled: true
|
||||
cooldown: 1
|
||||
radius: 100
|
||||
|
||||
# Личные сообщения
|
||||
pm:
|
||||
enabled: true
|
||||
cooldown: 2
|
||||
|
||||
# Лимиты сообщений
|
||||
min_message_length: 1
|
||||
max_message_length: 2000
|
||||
clear_lines: 100
|
||||
|
||||
# Hub команда
|
||||
hub_command:
|
||||
enabled: true
|
||||
server: "hub"
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Внешний вид чата (префиксы, форматы, цвета) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
appearance:
|
||||
# Префиксы чата (GLOBAL / LOCAL)
|
||||
prefixes:
|
||||
global:
|
||||
emoji: "✦"
|
||||
text: "GLOBAL"
|
||||
colors: ["#B798A8", "#7858E9"]
|
||||
separator:
|
||||
text: " ▶ "
|
||||
color: "#9878C9"
|
||||
message-color: "#E8E0F0"
|
||||
|
||||
local:
|
||||
emoji: "◆"
|
||||
text: "LOCAL"
|
||||
colors: ["#9878C9", "#7858E9"]
|
||||
separator:
|
||||
text: " ▶ "
|
||||
color: "#8B6BD6"
|
||||
message-color: "#E8E0F0"
|
||||
|
||||
# Формат сообщений
|
||||
# {emoji} {prefix} {separator} {player_prefix} {player} {player_suffix} {message}
|
||||
chat-format:
|
||||
global: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix}: {message}"
|
||||
local: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix}: {message}"
|
||||
|
||||
# Hover при наведении на ник
|
||||
hover:
|
||||
enabled: true
|
||||
format:
|
||||
- "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
||||
- "&#B798A8✦ &f{player}"
|
||||
- ""
|
||||
- "⚖C9⏱ &fПинг: ẲE9{ping}ms"
|
||||
- "⚖C9❤ &fЗдоровье: ẲE9{health}/20"
|
||||
- "⚖C9🍖 &fГолод: ẲE9{food}/20"
|
||||
- ""
|
||||
- "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
||||
- "&#B798A8✦ &fНажми чтобы написать"
|
||||
|
||||
# Эмодзи (текстовые замены)
|
||||
emojis:
|
||||
":heart:": "❤"
|
||||
":star:": "★"
|
||||
":diamond:": "♦"
|
||||
":check:": "✓"
|
||||
":cross:": "✗"
|
||||
":arrow:": "→"
|
||||
":smile:": ":)"
|
||||
":sad:": ":("
|
||||
":shrug:": "¯\\_(ツ)_/¯"
|
||||
|
||||
# Цвета системных сообщений
|
||||
colors:
|
||||
nobody_heard: "#9878C9"
|
||||
error: "#CF6679"
|
||||
success: "#9878C9"
|
||||
warning: "#B798A8"
|
||||
info: "#A485BC"
|
||||
|
||||
# Градиентные ники
|
||||
lopreff:
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Градиентные ники и префиксы │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
gradient:
|
||||
enabled: true
|
||||
use-gradient-name: true
|
||||
use-custom-prefix: true
|
||||
|
||||
display:
|
||||
update-display-name: true
|
||||
update-tab-list: true
|
||||
|
||||
# Градиенты (детали в config/gradient.yml)
|
||||
gradient:
|
||||
storage-type: "file"
|
||||
|
||||
# Настройки отображения
|
||||
display:
|
||||
update-display-name: true
|
||||
update-tab-list: true
|
||||
|
||||
# Лимиты
|
||||
min-colors: 1
|
||||
max-colors: 7
|
||||
max-prefix-length: 16
|
||||
|
||||
# Цены (PlayerPoints)
|
||||
price-per-color: 50
|
||||
prefix-price: 500
|
||||
prefix-one-time-purchase: true
|
||||
use-permission-instead-of-cost: false
|
||||
max-prefix-length: 16
|
||||
|
||||
# Кулдауны (секунды)
|
||||
color-cooldown: 60
|
||||
prefix-cooldown: 120
|
||||
|
||||
# Форматирование
|
||||
prefix-format: "[{prefix}] "
|
||||
gradient-on-prefix: true
|
||||
gradient-on-luckperms-prefix: true
|
||||
gradient-on-luckperms-suffix: true
|
||||
continuous-gradient: true
|
||||
use-legacy-rgb-format: true
|
||||
|
||||
# Хранилище (file / sqlite)
|
||||
storage-type: "file"
|
||||
sqlite-file: "gradient-data.db"
|
||||
|
||||
# RP команды (детали в config/rp.yml)
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ RP команды (/me, /do, /try, /roll) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
rp:
|
||||
radius: 100
|
||||
cooldowns:
|
||||
|
|
@ -61,6 +146,126 @@ rp:
|
|||
do: 3
|
||||
roll: 2
|
||||
|
||||
# Модерация: после /lmute выполнить команду от консоли (SimpleVoiceChat: voice mute {player})
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Фильтры чата │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
filters:
|
||||
# Мат-фильтр
|
||||
swear:
|
||||
enabled: true
|
||||
replace: false
|
||||
replacement: "***"
|
||||
words:
|
||||
- "хуй"
|
||||
- "пизда"
|
||||
- "ебать"
|
||||
|
||||
# URL фильтр
|
||||
url:
|
||||
enabled: true
|
||||
replacement: "[ссылка скрыта]"
|
||||
|
||||
# IP фильтр
|
||||
ip:
|
||||
enabled: true
|
||||
replacement: "[IP скрыт]"
|
||||
|
||||
# Скрытые URL (discord.gg и т.д.)
|
||||
hidden-urls:
|
||||
enabled: true
|
||||
patterns:
|
||||
- "discord\\.gg"
|
||||
- "dsc\\.gg"
|
||||
|
||||
# Анти-спам
|
||||
spam:
|
||||
enabled: true
|
||||
max-repeating-chars: 5
|
||||
|
||||
# Анти-флуд
|
||||
flood:
|
||||
enabled: true
|
||||
max-same-messages: 3
|
||||
|
||||
# Капс
|
||||
caps:
|
||||
enabled: true
|
||||
max-caps-percent: 70
|
||||
min-length: 5
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Модерация (муты, баны, варны) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
moderation:
|
||||
# Дефолтные значения
|
||||
default-mute-duration: "7d"
|
||||
default-mute-reason: "Без причины"
|
||||
default-ban-reason: "Без причины"
|
||||
|
||||
# Команда после мута (для голосового чата)
|
||||
voice-mute-console-command: ""
|
||||
|
||||
# Сообщение при кике забаненного
|
||||
ban-kick-message: "&#CF6679Вы забанены! &#B798A8Причина: ẲE9{reason}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Звуки │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
sounds:
|
||||
# Упоминание в чате
|
||||
mention:
|
||||
enabled: true
|
||||
sound: "BLOCK_NOTE_BLOCK_PLING"
|
||||
volume: 1.0
|
||||
pitch: 1.5
|
||||
|
||||
# Личное сообщение
|
||||
pm:
|
||||
enabled: true
|
||||
sound: "ENTITY_EXPERIENCE_ORB_PICKUP"
|
||||
volume: 0.8
|
||||
pitch: 1.2
|
||||
|
||||
# Команды
|
||||
command:
|
||||
enabled: false
|
||||
sound: "UI_BUTTON_CLICK"
|
||||
volume: 0.5
|
||||
pitch: 1.0
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Сообщения входа/выхода/смерти │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
messages:
|
||||
# Сообщение при входе
|
||||
# {player} - ник игрока
|
||||
join:
|
||||
enabled: true
|
||||
format: "⚖C9✦ &#B798A8{player} ẲE9зашел на сервер"
|
||||
|
||||
# Сообщение при выходе
|
||||
quit:
|
||||
enabled: true
|
||||
format: "⚖C9✦ &#B798A8{player} ẲE9вышел с сервера"
|
||||
|
||||
# Сообщение при смерти
|
||||
# {player} - ник игрока
|
||||
# {killer} - ник убийцы (если есть)
|
||||
# {weapon} - название оружия (если есть)
|
||||
# {death_message} - стандартное сообщение смерти
|
||||
death:
|
||||
enabled: true
|
||||
# Убийство игроком
|
||||
player_kill: "&#CF6679☠ &#B798A8{player} ẲE9был убит игроком &#B798A8{killer} ⚖C9({weapon})"
|
||||
# Смерть от моба
|
||||
mob_kill: "&#CF6679☠ &#B798A8{player} ẲE9был убит мобом &#B798A8{killer}"
|
||||
# Обычная смерть
|
||||
default: "&#CF6679☠ &#B798A8{player} ẲE9{death_message}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Прочее │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Hub команда
|
||||
hub_command:
|
||||
enabled: true
|
||||
server: "hub"
|
||||
|
|
|
|||
|
|
@ -44,16 +44,17 @@ prefixes:
|
|||
# {separator} — separator (e.g. ▶)
|
||||
# {player_prefix} — LuckPerms / gradient prefix from LoPreff
|
||||
# {player} — display name + hover (click to /msg)
|
||||
# {player_suffix} — LuckPerms / gradient suffix from LoPreff
|
||||
# {message} — message body
|
||||
#
|
||||
# Examples:
|
||||
# Default: {emoji} {prefix} {separator} {player} : {message}
|
||||
# Minimal: {player_prefix} {player} ▶ {message}
|
||||
# Custom: ✦ {player_prefix} {player} ▶ {message}
|
||||
# Custom: ✦ {player_prefix} {player} {player_suffix} ▶ {message}
|
||||
|
||||
chat-format:
|
||||
global: "{emoji} {prefix} {separator} {player} : {message}"
|
||||
local: "{emoji} {prefix} {separator} {player} : {message}"
|
||||
global: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix} : {message}"
|
||||
local: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix} : {message}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Hover shown when pointing at the player name in chat │
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ events:
|
|||
enabled: true
|
||||
|
||||
# Настройки входа на сервер
|
||||
# {player} - ник игрока
|
||||
join:
|
||||
enabled: true
|
||||
title: "🟢 Игрок зашел на сервер"
|
||||
|
|
@ -47,7 +48,8 @@ events:
|
|||
color: "00FF00"
|
||||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||
|
||||
# Настройки выхода с сервера
|
||||
# Настройки выхода с сервера
|
||||
# {player} - ник игрока
|
||||
quit:
|
||||
enabled: true
|
||||
title: "🔴 Игрок покинул сервер"
|
||||
|
|
@ -56,11 +58,27 @@ events:
|
|||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||
|
||||
# Настройки смерти игрока
|
||||
# {player} - ник игрока
|
||||
# {killer} - ник убийцы (если есть)
|
||||
# {weapon} - название оружия (если есть)
|
||||
# {death_message} - стандартное сообщение смерти
|
||||
death:
|
||||
enabled: true
|
||||
title: "💀 Смерть игрока"
|
||||
description: "**{player}** {death_message}"
|
||||
color: "800080"
|
||||
# Убийство игроком
|
||||
player_kill:
|
||||
title: "⚔️ PvP убийство"
|
||||
description: "**{player}** был убит игроком **{killer}** с помощью **{weapon}**"
|
||||
color: "FF0000"
|
||||
# Смерть от моба
|
||||
mob_kill:
|
||||
title: "💀 Смерть от моба"
|
||||
description: "**{player}** был убит мобом **{killer}**"
|
||||
color: "800080"
|
||||
# Обычная смерть
|
||||
default:
|
||||
title: "💀 Смерть игрока"
|
||||
description: "**{player}** {death_message}"
|
||||
color: "800080"
|
||||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||
|
||||
# Настройки фильтрации
|
||||
|
|
|
|||
|
|
@ -1,286 +1,81 @@
|
|||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ LoChat Filters Configuration ║
|
||||
# ║ Конфигурация фильтров ║
|
||||
# ║ Версия: 1.5.5-1.20.1 ║
|
||||
# ║ LoChat — Фильтры чата ║
|
||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР ЗАГЛАВНЫХ БУКВ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
caps:
|
||||
# Включить фильтр заглавных букв
|
||||
enabled: true
|
||||
|
||||
# Максимальный процент заглавных букв (0-100)
|
||||
max-percent: 70
|
||||
|
||||
# Минимальная длина сообщения для проверки
|
||||
min-length: 5
|
||||
|
||||
# Автоматически переводить в нижний регистр
|
||||
auto-lowercase: true
|
||||
|
||||
# Действие при нарушении: block, warn, lowercase
|
||||
action: "lowercase"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BСлишком много заглавных букв!"
|
||||
|
||||
# Сообщение-предупреждение
|
||||
warn-message: "&#FFA726Не используйте слишком много заглавных букв"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР РЕКЛАМЫ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
advertising:
|
||||
# Включить фильтр рекламы
|
||||
enabled: true
|
||||
|
||||
# Блокировать скрытые URL (bit.ly, tinyurl и т.д.)
|
||||
block-hidden-urls: true
|
||||
|
||||
# Блокировать домены
|
||||
block-domains: true
|
||||
|
||||
# Блокировать IP адреса
|
||||
block-ips: true
|
||||
|
||||
# Действие при обнаружении: block, warn, replace
|
||||
action: "block"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BРеклама запрещена!"
|
||||
|
||||
# Замена для заблокированного контента
|
||||
replacement: "[РЕКЛАМА УДАЛЕНА]"
|
||||
|
||||
# Белый список доменов (разрешенные)
|
||||
whitelist:
|
||||
- "youtube.com"
|
||||
- "youtu.be"
|
||||
- "discord.gg"
|
||||
- "twitch.tv"
|
||||
- "imgur.com"
|
||||
- "gyazo.com"
|
||||
- "prntscr.com"
|
||||
|
||||
# Черный список доменов (запрещенные)
|
||||
blacklist:
|
||||
- "scam-site.com"
|
||||
- "virus-site.ru"
|
||||
- "fake-minecraft.net"
|
||||
|
||||
# Регулярные выражения для поиска рекламы
|
||||
patterns:
|
||||
- "(?i)\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}(?::[0-9]{1,5})?\\b" # IP адреса
|
||||
- "(?i)\\b[a-z0-9.-]+\\.(com|net|org|ru|de|uk)\\b" # Домены
|
||||
- "(?i)\\b(server|сервер)\\s*[:-]?\\s*[a-z0-9.-]+\\b" # Серверы
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР IP АДРЕСОВ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
ip:
|
||||
# Включить фильтр IP адресов
|
||||
enabled: true
|
||||
|
||||
# Блокировать сообщение или заменять IP
|
||||
block: false
|
||||
|
||||
# Замена для IP адресов
|
||||
replacement: "[IP СКРЫТ]"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BIP адреса запрещены!"
|
||||
|
||||
# Белый список IP (разрешенные)
|
||||
whitelist:
|
||||
- "127.0.0.1"
|
||||
- "localhost"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР ПОВТОРОВ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
repeat:
|
||||
# Включить фильтр повторяющихся символов
|
||||
enabled: true
|
||||
|
||||
# Максимальное количество повторов подряд
|
||||
max-repeats: 3
|
||||
|
||||
# Действие: block, warn, replace
|
||||
action: "replace"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BНе повторяйте символы!"
|
||||
|
||||
# Автоматически сокращать повторы
|
||||
auto-reduce: true
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР СПАМА │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
spam:
|
||||
# Включить антиспам
|
||||
enabled: true
|
||||
|
||||
# Максимальное количество одинаковых сообщений
|
||||
max-similar-messages: 3
|
||||
|
||||
# Время для сброса счетчика (секунды)
|
||||
reset-time: 60
|
||||
|
||||
# Процент схожести сообщений (0-100)
|
||||
similarity-threshold: 80
|
||||
|
||||
# Действие при спаме: block, warn, mute
|
||||
action: "warn"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BНе спамьте!"
|
||||
|
||||
# Время мута за спам (секунды)
|
||||
mute-duration: 300
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР МАТА │
|
||||
# │ Мат-фильтр │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Использует badwords.txt для списка слов
|
||||
# Автоматически ловит замены букв: х->x, о->o, е->e и т.д.
|
||||
# Обход: lochat.bypass.swear
|
||||
|
||||
swear:
|
||||
# Включить фильтр мата
|
||||
enabled: true
|
||||
|
||||
# Использовать внешний файл со словами
|
||||
use-external-file: true
|
||||
|
||||
# Файл со словами (относительно папки плагина)
|
||||
words-file: "filter-words.json"
|
||||
|
||||
# Действие: block, warn, replace, mute
|
||||
action: "replace"
|
||||
|
||||
# Символ для замены
|
||||
replacement-char: "*"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BМат запрещен!"
|
||||
|
||||
# Время мута за мат (секунды)
|
||||
mute-duration: 600
|
||||
|
||||
# Встроенный список слов (если не используется внешний файл)
|
||||
words:
|
||||
- "плохое_слово1"
|
||||
- "плохое_слово2"
|
||||
|
||||
# Проверять фрагменты слов
|
||||
check-fragments: true
|
||||
|
||||
# Игнорировать регистр
|
||||
ignore-case: true
|
||||
|
||||
# Проверять транслитерацию
|
||||
check-transliteration: true
|
||||
replace: false # true = заменять на ***, false = блокировать сообщение
|
||||
replacement: "***"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР ФЛУДА │
|
||||
# │ URL фильтр │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует ссылки в чате
|
||||
# Обход: lochat.bypass.urlfilter
|
||||
|
||||
url:
|
||||
enabled: true
|
||||
replacement: "[ссылка скрыта]"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ IP фильтр │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует IP адреса в чате
|
||||
# Обход: lochat.bypass.ipfilter
|
||||
|
||||
ip:
|
||||
enabled: true
|
||||
replacement: "[IP скрыт]"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Скрытые URL (discord.gg и т.д.) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует популярные сокращенные ссылки
|
||||
# Обход: lochat.bypass.hiddenurls
|
||||
|
||||
hidden-urls:
|
||||
enabled: true
|
||||
patterns:
|
||||
- "discord\\.gg"
|
||||
- "dsc\\.gg"
|
||||
- "bit\\.ly"
|
||||
- "tinyurl\\.com"
|
||||
- "goo\\.gl"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Анти-спам │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует повторяющиеся символы (ааааааа, хххххх)
|
||||
# Обход: lochat.bypass.spam
|
||||
|
||||
spam:
|
||||
enabled: true
|
||||
max-repeating-chars: 5 # Максимум повторений одного символа
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Анти-флуд │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует одинаковые сообщения подряд
|
||||
# Обход: lochat.bypass.flood
|
||||
|
||||
flood:
|
||||
# Включить антифлуд
|
||||
enabled: true
|
||||
|
||||
# Максимальное количество сообщений в период
|
||||
max-messages: 5
|
||||
|
||||
# Период времени (секунды)
|
||||
time-period: 10
|
||||
|
||||
# Действие при флуде: block, warn, mute
|
||||
action: "warn"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BНе флудите!"
|
||||
|
||||
# Время мута за флуд (секунды)
|
||||
mute-duration: 180
|
||||
max-same-messages: 3 # Сколько раз можно отправить одно и то же
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ДОПОЛНИТЕЛЬНЫЕ ФИЛЬТРЫ │
|
||||
# │ Капс-фильтр │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует сообщения с большим количеством заглавных букв
|
||||
# Обход: lochat.bypass.caps
|
||||
|
||||
additional:
|
||||
# Фильтр эмодзи
|
||||
emoji:
|
||||
enabled: false
|
||||
max-per-message: 5
|
||||
block-message: "&#FF6B6BСлишком много эмодзи!"
|
||||
|
||||
# Фильтр длинных сообщений
|
||||
length:
|
||||
enabled: true
|
||||
max-length: 256
|
||||
action: "truncate" # truncate или block
|
||||
block-message: "&#FF6B6BСообщение слишком длинное!"
|
||||
|
||||
# Фильтр пустых сообщений
|
||||
empty:
|
||||
enabled: true
|
||||
block-message: "&#FF6B6BПустые сообщения запрещены!"
|
||||
|
||||
# Фильтр только пробелов
|
||||
whitespace:
|
||||
enabled: true
|
||||
block-message: "&#FF6B6BСообщение не может состоять только из пробелов!"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ НАСТРОЙКИ ОБХОДА │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
bypass:
|
||||
# Права для обхода фильтров
|
||||
permissions:
|
||||
caps: "lochat.bypass.caps"
|
||||
advertising: "lochat.bypass.advertising"
|
||||
ip: "lochat.bypass.ip"
|
||||
repeat: "lochat.bypass.repeat"
|
||||
spam: "lochat.bypass.spam"
|
||||
swear: "lochat.bypass.swear"
|
||||
flood: "lochat.bypass.flood"
|
||||
all: "lochat.bypass.filter"
|
||||
|
||||
# Группы, которые обходят все фильтры
|
||||
groups:
|
||||
- "admin"
|
||||
- "moderator"
|
||||
|
||||
# Миры, где фильтры отключены
|
||||
worlds:
|
||||
- "creative_world"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ЛОГИРОВАНИЕ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
logging:
|
||||
# Логировать заблокированные сообщения
|
||||
caps:
|
||||
enabled: true
|
||||
|
||||
# Файл для логов
|
||||
file: "plugins/LoChat/logs/filter.log"
|
||||
|
||||
# Формат лога
|
||||
format: "[{time}] {player} ({filter}): {message}"
|
||||
|
||||
# Логировать в консоль
|
||||
console: true
|
||||
|
||||
# Уведомлять администраторов
|
||||
notify-admins: true
|
||||
|
||||
# Право для получения уведомлений
|
||||
notify-permission: "lochat.filter.notify"
|
||||
max-caps-percent: 70 # Максимум % заглавных букв
|
||||
min-length: 5 # Минимальная длина для проверки
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ LoChat — messages.yml ║
|
||||
# ║ Default palette (Spacelegacy): #B798A8 (dusty rose) → #7858E9 (violet) ║
|
||||
# ║ Default palette (Spacelegacy): #7858E9 (dusty rose) → #7858E9 (violet) ║
|
||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
#
|
||||
# Color roles (reference when editing strings below):
|
||||
# &#B798A8 — primary labels / body (dusty rose)
|
||||
# ẲE9 — primary labels / body (dusty rose)
|
||||
# ⚖C9 — accents / separators (mid violet)
|
||||
# ẲE9 — emphasis / values (deep violet)
|
||||
# &f / #E8E0F0 — message body white
|
||||
# &#CF6679 — errors (muted red, fits the palette)
|
||||
|
||||
prefix: "&#B798A8[⚖C9LB6BD6oẲE9CⅵDChB6BD6a⚖C9t&#B798A8]"
|
||||
prefix: "ẲE9[⚖C9LB6BD6oẲE9CⅵDChB6BD6a⚖C9tẲE9]"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Global chat (toggle messages, server-disabled notice) │
|
||||
|
|
@ -18,7 +18,7 @@ prefix: "&#B798A8[⚖C9LB6BD6oẲE9CⅵDChB6BD6a⚖C9t&#B798A8
|
|||
|
||||
global:
|
||||
toggled-on: "⚖C9Глобальный чат ẲE9включён"
|
||||
toggled-off: "⚖C9Глобальный чат &#B798A8отключён"
|
||||
toggled-off: "⚖C9Глобальный чат ẲE9отключён"
|
||||
disabled: "&#CF6679Глобальный чат отключён на этом сервере"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
|
|
@ -26,19 +26,19 @@ global:
|
|||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
local:
|
||||
no-players: "&#B798A8Рядом нет игроков"
|
||||
nobody-heard: "⚖C9Вас никто не услышал &#B798A8— рядом нет игроков"
|
||||
no-players: "ẲE9Рядом нет игроков"
|
||||
nobody-heard: "⚖C9Вас никто не услышал ẲE9— рядом нет игроков"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Private messages (/msg, /reply) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
pm:
|
||||
format-sent: "&#B798A8[⚖C9→&#B798A8] ⚖C9Вы &#B798A8→ {receiver_display}&#B798A8: &f{message}"
|
||||
format-received: "&#B798A8[⚖C9←&#B798A8] {sender_display} &#B798A8→ ⚖C9Вы&#B798A8: &f{message}"
|
||||
format-sent: "ẲE9[⚖C9→ẲE9] ⚖C9Вы ẲE9→ {receiver_display}ẲE9: &f{message}"
|
||||
format-received: "ẲE9[⚖C9←ẲE9] {sender_display} ẲE9→ ⚖C9ВыẲE9: &f{message}"
|
||||
use-gradient-names: true
|
||||
sent: "&#B798A8[⚖C9→&#B798A8] ⚖C9Вы &#B798A8→ &f{player}&#B798A8: &f{message}"
|
||||
received: "&#B798A8[⚖C9←&#B798A8] &f{player} &#B798A8→ ⚖C9Вы&#B798A8: &f{message}"
|
||||
sent: "ẲE9[⚖C9→ẲE9] ⚖C9Вы ẲE9→ &f{player}ẲE9: &f{message}"
|
||||
received: "ẲE9[⚖C9←ẲE9] &f{player} ẲE9→ ⚖C9ВыẲE9: &f{message}"
|
||||
no-reply: "&#CF6679Некому ответить"
|
||||
ignored: "&#CF6679Этот игрок вас игнорирует"
|
||||
player-offline: "&#CF6679Игрок не в сети"
|
||||
|
|
@ -51,12 +51,12 @@ pm:
|
|||
ignore:
|
||||
added: "⚖C9Игрок ẲE9{player} ⚖C9добавлен в игнор"
|
||||
removed: "⚖C9Игрок ẲE9{player} ⚖C9убран из игнора"
|
||||
already-ignored: "&#B798A8Игрок ẲE9{player} &#B798A8уже в игноре"
|
||||
not-ignored: "&#B798A8Игрок ẲE9{player} &#B798A8не в игноре"
|
||||
already-ignored: "ẲE9Игрок ẲE9{player} ẲE9уже в игноре"
|
||||
not-ignored: "ẲE9Игрок ẲE9{player} ẲE9не в игноре"
|
||||
self: "&#CF6679Нельзя игнорировать самого себя"
|
||||
list-empty: "&#B798A8Ваш список игнора пуст"
|
||||
list-empty: "ẲE9Ваш список игнора пуст"
|
||||
list-header: "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
||||
list-footer: "&#B798A8Всего: ẲE9{count} &#B798A8игроков"
|
||||
list-footer: "ẲE9Всего: ẲE9{count} ẲE9игроков"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Announcements │
|
||||
|
|
@ -71,9 +71,9 @@ announce:
|
|||
|
||||
spy:
|
||||
enabled: "⚖C9Режим шпиона ẲE9включён"
|
||||
disabled: "⚖C9Режим шпиона &#B798A8отключён"
|
||||
format: "&#B798A8[⚖C9SPY&#B798A8] ẲE9{sender} &#B798A8→ ⚖C9{receiver}&#B798A8: &f{message}"
|
||||
chat-format: "&#B798A8[⚖C9SPY&#B798A8] &#B798A8{type} ẲE9{sender}&#B798A8: &f{message}"
|
||||
disabled: "⚖C9Режим шпиона ẲE9отключён"
|
||||
format: "ẲE9[⚖C9SPYẲE9] ẲE9{sender} ẲE9→ ⚖C9{receiver}ẲE9: &f{message}"
|
||||
chat-format: "ẲE9[⚖C9SPYẲE9] ẲE9{type} ẲE9{sender}ẲE9: &f{message}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Message filters │
|
||||
|
|
@ -81,14 +81,14 @@ spy:
|
|||
|
||||
filter:
|
||||
blocked: "&#CF6679Сообщение заблокировано"
|
||||
warning: "&#B798A8Предупреждение"
|
||||
warning: "ẲE9Предупреждение"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Cooldowns │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
cooldown:
|
||||
wait: "&#B798A8Подождите ẲE9{time} &#B798A8сек"
|
||||
wait: "ẲE9Подождите ẲE9{time} ẲE9сек"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Anti-spam (caps, repeat, similar messages) │
|
||||
|
|
@ -104,7 +104,7 @@ antispam:
|
|||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
clearchat:
|
||||
cleared: "⚖C9Чат очищен &#B798A8администратором ẲE9{player}"
|
||||
cleared: "⚖C9Чат очищен ẲE9администратором ẲE9{player}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Command / usage errors │
|
||||
|
|
@ -113,7 +113,7 @@ clearchat:
|
|||
errors:
|
||||
no-permission: "&#CF6679Нет прав"
|
||||
player-not-found: "&#CF6679Игрок не найден"
|
||||
invalid-usage: "&#B798A8Использование: ẲE9{usage}"
|
||||
invalid-usage: "ẲE9Использование: ẲE9{usage}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ General (permissions, reload, hub, etc.) │
|
||||
|
|
@ -124,7 +124,7 @@ general:
|
|||
players-only: "&#CF6679Только для игроков!"
|
||||
config-reloaded: "⚖C9Конфиг ẲE9перезагружен!"
|
||||
invalid-player: "&#CF6679Игрок ẲE9{player} &#CF6679не найден!"
|
||||
cooldown-active: "&#B798A8Подождите ẲE9{time}с"
|
||||
cooldown-active: "ẲE9Подождите ẲE9{time}с"
|
||||
command-disabled: "&#CF6679Команда отключена!"
|
||||
|
||||
hub:
|
||||
|
|
@ -137,9 +137,9 @@ hub:
|
|||
mute:
|
||||
muted: "⚖C9Игрок ẲE9{player} ⚖C9замучен на ẲE9{time}"
|
||||
unmuted: "⚖C9Игрок ẲE9{player} ⚖C9размучен"
|
||||
already-muted: "&#B798A8Игрок ẲE9{player} &#B798A8уже замучен"
|
||||
not-muted: "&#B798A8Игрок ẲE9{player} &#B798A8не замучен"
|
||||
you-muted: "&#CF6679Вы замучены! &#B798A8Осталось: ẲE9{time}"
|
||||
already-muted: "ẲE9Игрок ẲE9{player} ẲE9уже замучен"
|
||||
not-muted: "ẲE9Игрок ẲE9{player} ẲE9не замучен"
|
||||
you-muted: "&#CF6679Вы замучены! ẲE9Осталось: ẲE9{time}"
|
||||
permanent: "&#CF6679Вы замучены навсегда!"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
|
|
@ -149,32 +149,32 @@ mute:
|
|||
gradient:
|
||||
color-set: "⚖C9Градиент ẲE9установлен!"
|
||||
color-enabled: "⚖C9Градиентный ник ẲE9включён"
|
||||
color-disabled: "&#B798A8Градиентный ник ⚖C9отключён"
|
||||
color-reset: "&#B798A8Градиент сброшен"
|
||||
color-disabled: "ẲE9Градиентный ник ⚖C9отключён"
|
||||
color-reset: "ẲE9Градиент сброшен"
|
||||
prefix-set: "⚖C9Префикс ẲE9установлен!"
|
||||
prefix-reset: "&#B798A8Префикс сброшен"
|
||||
prefix-reset: "ẲE9Префикс сброшен"
|
||||
prefix-reset-success: "⚖C9Префикс успешно ẲE9сброшен!"
|
||||
prefix-enabled: "⚖C9Префикс ẲE9включён"
|
||||
prefix-disabled: "&#B798A8Префикс ⚖C9отключён"
|
||||
prefix-disabled: "ẲE9Префикс ⚖C9отключён"
|
||||
invalid-hex: "&#CF6679Неверный HEX цвет: ẲE9{color}"
|
||||
invalid-color: "&#CF6679Неверный цвет: ẲE9{color}"
|
||||
too-many-colors: "&#CF6679Слишком много цветов! Максимум: ẲE9{max}"
|
||||
too-few-colors: "&#CF6679Слишком мало цветов! Минимум: ẲE9{min}"
|
||||
not-enough-colors: "&#CF6679Слишком мало цветов! Минимум: ẲE9{min}"
|
||||
cooldown: "&#B798A8Подождите ẲE9{time} &#B798A8сек"
|
||||
cooldown: "ẲE9Подождите ẲE9{time} ẲE9сек"
|
||||
not-enough-points: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||
not-enough-points-color: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||
not-enough-points-prefix: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||
player-not-found: "&#CF6679Игрок не найден"
|
||||
color-help: "&#B798A8Использование: ẲE9/color <HEX1> <HEX2>"
|
||||
color-help: "ẲE9Использование: ẲE9/color <HEX1> <HEX2>"
|
||||
color-success: "⚖C9Градиент успешно ẲE9установлен!"
|
||||
color-no-colors: "&#B798A8У вас нет установленных цветов"
|
||||
color-copy-usage: "&#B798A8Использование: ẲE9/color copy <игрок>"
|
||||
color-copy-no-colors: "&#B798A8У игрока ẲE9{player} &#B798A8нет цветов"
|
||||
prefix-help: "&#B798A8Использование: ẲE9/prefix <текст> &#B798A8или ẲE9/prefix reset"
|
||||
prefix-success: "⚖C9Префикс установлен! &#B798A8Стоимость: ẲE9{price} &#B798A8поинтов"
|
||||
color-no-colors: "ẲE9У вас нет установленных цветов"
|
||||
color-copy-usage: "ẲE9Использование: ẲE9/color copy <игрок>"
|
||||
color-copy-no-colors: "ẲE9У игрока ẲE9{player} ẲE9нет цветов"
|
||||
prefix-help: "ẲE9Использование: ẲE9/prefix <текст> ẲE9или ẲE9/prefix reset"
|
||||
prefix-success: "⚖C9Префикс установлен! ẲE9Стоимость: ẲE9{price} ẲE9поинтов"
|
||||
prefix-success-free: "⚖C9Префикс ẲE9установлен!"
|
||||
prefix-no-prefix: "&#B798A8У вас нет префикса"
|
||||
prefix-no-prefix: "ẲE9У вас нет префикса"
|
||||
prefix-too-long: "&#CF6679Префикс слишком длинный! Максимум: ẲE9{max}"
|
||||
prefix-no-colors: "&#CF6679Префикс не может содержать цветовые коды!"
|
||||
prefix-invalid-chars: "&#CF6679Недопустимые символы в префиксе!"
|
||||
|
|
@ -182,30 +182,30 @@ gradient:
|
|||
only-player: "&#CF6679Только для игроков!"
|
||||
no-permission: "&#CF6679Нет прав!"
|
||||
reload-success: "⚖C9Конфигурация ẲE9перезагружена!"
|
||||
info-header: "ẲE9▬▬▬▬▬▬▬▬ &#B798A8{player} ẲE9▬▬▬▬▬▬▬▬"
|
||||
info-prefix: "&#B798A8Префикс: &f{prefix}"
|
||||
info-prefix-enabled: "&#B798A8Префикс активен: &f{enabled}"
|
||||
info-colors: "&#B798A8Цвета: &f{colors}"
|
||||
info-color-enabled: "&#B798A8Цвет активен: &f{enabled}"
|
||||
info-prefix-purchased: "&#B798A8Куплен: &f{purchased}"
|
||||
info-header: "ẲE9▬▬▬▬▬▬▬▬ ẲE9{player} ẲE9▬▬▬▬▬▬▬▬"
|
||||
info-prefix: "ẲE9Префикс: &f{prefix}"
|
||||
info-prefix-enabled: "ẲE9Префикс активен: &f{enabled}"
|
||||
info-colors: "ẲE9Цвета: &f{colors}"
|
||||
info-color-enabled: "ẲE9Цвет активен: &f{enabled}"
|
||||
info-prefix-purchased: "ẲE9Куплен: &f{purchased}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Custom nicknames (/nick) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
nick:
|
||||
current: "&#B798A8Ваш ник: ẲE9{nick}"
|
||||
usage: "&#B798A8Использование: ẲE9/nick <ник> &#B798A8или ẲE9/nick reset"
|
||||
reset-usage: "&#B798A8Используйте ẲE9/nick reset &#B798A8для сброса"
|
||||
set-usage: "&#B798A8Используйте ẲE9/nick <ник> &#B798A8для установки"
|
||||
no-nick: "&#B798A8У вас нет кастомного ника"
|
||||
current: "ẲE9Ваш ник: ẲE9{nick}"
|
||||
usage: "ẲE9Использование: ẲE9/nick <ник> ẲE9или ẲE9/nick reset"
|
||||
reset-usage: "ẲE9Используйте ẲE9/nick reset ẲE9для сброса"
|
||||
set-usage: "ẲE9Используйте ẲE9/nick <ник> ẲE9для установки"
|
||||
no-nick: "ẲE9У вас нет кастомного ника"
|
||||
reset-success: "⚖C9Ник ẲE9сброшен!"
|
||||
set-success: "⚖C9Ник изменён на: &f{nick}"
|
||||
invalid: "&#CF6679Невалидный ник!"
|
||||
requirements-header: "&#B798A8Требования:"
|
||||
requirements-header: "ẲE9Требования:"
|
||||
requirements-length: "⚖C9◆ &fДлина: 3-16 символов"
|
||||
requirements-chars: "⚖C9◆ &fБуквы, цифры, _, русские буквы"
|
||||
requirements-colors: "⚖C9◆ &fЦвета: ẲE9&#RRGGBB&#B798A8текст"
|
||||
requirements-colors: "⚖C9◆ &fЦвета: ẲE9&#RRGGBBẲE9текст"
|
||||
taken: "&#CF6679Этот ник уже занят!"
|
||||
error: "&#CF6679Не удалось установить ник!"
|
||||
|
||||
|
|
@ -214,12 +214,12 @@ nick:
|
|||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
rp:
|
||||
me: "<color:#B798A8>* {player} {action}</color>"
|
||||
try-format: "<color:#B798A8>* {player} пытается {action}...</color> {result}"
|
||||
me: "<color:#7858E9>* {player} {action}</color>"
|
||||
try-format: "<color:#7858E9>* {player} пытается {action}...</color> {result}"
|
||||
try-success: "<color:#9878C9><bold>[Успех!]</bold></color>"
|
||||
try-fail: "<color:#CF6679><bold>[Провал!]</bold></color>"
|
||||
do-format: "<color:#7858E9>[<color:#B798A8>Сцена</color>]</color> <white>{description}</white> <color:#9878C9>({player})</color>"
|
||||
roll-format: "<color:#B798A8>* {player} бросает кубик и получает </color><color:#7858E9><bold>{result}</bold></color><color:#B798A8> из </color><color:#9878C9>{max}</color>"
|
||||
do-format: "<color:#7858E9>[<color:#7858E9>Сцена</color>]</color> <white>{description}</white> <color:#9878C9>({player})</color>"
|
||||
roll-format: "<color:#7858E9>* {player} бросает кубик и получает </color><color:#7858E9><bold>{result}</bold></color><color:#7858E9> из </color><color:#9878C9>{max}</color>"
|
||||
roll-min-error: "<color:#CF6679>Минимальное значение кубика: 2</color>"
|
||||
roll-max-error: "<color:#CF6679>Максимальное значение: 1000000</color>"
|
||||
roll-invalid-number: "<color:#CF6679>Укажите число: /roll [максимум]</color>"
|
||||
|
|
|
|||
|
|
@ -275,4 +275,38 @@ public class ConfigManager {
|
|||
public boolean useCustomPrefix() {
|
||||
return config.getBoolean("lopreff.use-custom-prefix", true);
|
||||
}
|
||||
|
||||
// ========== Кастомные сообщения ==========
|
||||
|
||||
public boolean isJoinMessageEnabled() {
|
||||
return config.getBoolean("messages.join.enabled", true);
|
||||
}
|
||||
|
||||
public String getJoinMessageFormat() {
|
||||
return config.getString("messages.join.format", "⚖C9✦ &#B798A8{player} ẲE9зашел на сервер");
|
||||
}
|
||||
|
||||
public boolean isQuitMessageEnabled() {
|
||||
return config.getBoolean("messages.quit.enabled", true);
|
||||
}
|
||||
|
||||
public String getQuitMessageFormat() {
|
||||
return config.getString("messages.quit.format", "⚖C9✦ &#B798A8{player} ẲE9вышел с сервера");
|
||||
}
|
||||
|
||||
public boolean isDeathMessageEnabled() {
|
||||
return config.getBoolean("messages.death.enabled", true);
|
||||
}
|
||||
|
||||
public String getDeathPlayerKillFormat() {
|
||||
return config.getString("messages.death.player_kill", "&#CF6679☠ &#B798A8{player} ẲE9был убит игроком &#B798A8{killer} ⚖C9({weapon})");
|
||||
}
|
||||
|
||||
public String getDeathMobKillFormat() {
|
||||
return config.getString("messages.death.mob_kill", "&#CF6679☠ &#B798A8{player} ẲE9был убит мобом &#B798A8{killer}");
|
||||
}
|
||||
|
||||
public String getDeathDefaultFormat() {
|
||||
return config.getString("messages.death.default", "&#CF6679☠ &#B798A8{player} ẲE9{death_message}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public class PluginInitializer {
|
|||
new ChatEventListener(plugin, serviceRegistry, filter), plugin
|
||||
);
|
||||
plugin.getServer().getPluginManager().registerEvents(
|
||||
new PlayerEventListener(serviceRegistry, filter), plugin
|
||||
new PlayerEventListener(plugin, serviceRegistry, filter), plugin
|
||||
);
|
||||
plugin.getServer().getPluginManager().registerEvents(
|
||||
new ModerationListener(serviceRegistry), plugin
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ import java.io.BufferedReader;
|
|||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SwearFilter {
|
||||
|
|
@ -19,6 +17,22 @@ public class SwearFilter {
|
|||
private final boolean replaceMode;
|
||||
private final String replacement;
|
||||
private final Set<Pattern> swearPatterns = new HashSet<>();
|
||||
|
||||
// Карта замены латиницы на кириллицу для обхода фильтра
|
||||
private static final Map<Character, Character> LATIN_TO_CYRILLIC = Map.ofEntries(
|
||||
Map.entry('a', 'а'), Map.entry('A', 'А'),
|
||||
Map.entry('e', 'е'), Map.entry('E', 'Е'),
|
||||
Map.entry('o', 'о'), Map.entry('O', 'О'),
|
||||
Map.entry('p', 'р'), Map.entry('P', 'Р'),
|
||||
Map.entry('c', 'с'), Map.entry('C', 'С'),
|
||||
Map.entry('y', 'у'), Map.entry('Y', 'У'),
|
||||
Map.entry('x', 'х'), Map.entry('X', 'Х'),
|
||||
Map.entry('k', 'к'), Map.entry('K', 'К'),
|
||||
Map.entry('m', 'м'), Map.entry('M', 'М'),
|
||||
Map.entry('h', 'н'), Map.entry('H', 'Н'),
|
||||
Map.entry('t', 'т'), Map.entry('T', 'Т'),
|
||||
Map.entry('b', 'в'), Map.entry('B', 'В')
|
||||
);
|
||||
|
||||
public SwearFilter(FileConfiguration config, JavaPlugin plugin) {
|
||||
this.enabled = config.getBoolean("filters.swear.enabled", true);
|
||||
|
|
@ -37,13 +51,46 @@ public class SwearFilter {
|
|||
reader.lines()
|
||||
.map(String::trim)
|
||||
.filter(line -> !line.isEmpty() && !line.startsWith("#"))
|
||||
.forEach(word -> swearPatterns.add(
|
||||
Pattern.compile("\\b" + Pattern.quote(word) + "\\b", Pattern.CASE_INSENSITIVE)
|
||||
));
|
||||
.forEach(word -> {
|
||||
// Создаем паттерн с учетом возможной замены букв
|
||||
String regex = buildFlexiblePattern(word);
|
||||
swearPatterns.add(Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE));
|
||||
});
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Failed to load badwords.txt: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает гибкий паттерн, который ловит замены букв (х->x, о->o и т.д.)
|
||||
*/
|
||||
private String buildFlexiblePattern(String word) {
|
||||
StringBuilder pattern = new StringBuilder();
|
||||
|
||||
for (char c : word.toLowerCase().toCharArray()) {
|
||||
// Для каждой буквы создаем группу с возможными заменами
|
||||
switch (c) {
|
||||
case 'а' -> pattern.append("[аaА@]");
|
||||
case 'е' -> pattern.append("[еeЕ3]");
|
||||
case 'о' -> pattern.append("[оoО0]");
|
||||
case 'р' -> pattern.append("[рpР]");
|
||||
case 'с' -> pattern.append("[сcС]");
|
||||
case 'у' -> pattern.append("[уyУ]");
|
||||
case 'х' -> pattern.append("[хxХ]");
|
||||
case 'к' -> pattern.append("[кkК]");
|
||||
case 'м' -> pattern.append("[мmМ]");
|
||||
case 'н' -> pattern.append("[нhНN]");
|
||||
case 'т' -> pattern.append("[тtТ]");
|
||||
case 'в' -> pattern.append("[вbВ]");
|
||||
case 'и' -> pattern.append("[иiИ1]");
|
||||
case 'з' -> pattern.append("[з3З]");
|
||||
case 'б' -> pattern.append("[б6Б]");
|
||||
default -> pattern.append(Pattern.quote(String.valueOf(c)));
|
||||
}
|
||||
}
|
||||
|
||||
return pattern.toString();
|
||||
}
|
||||
|
||||
public FilterResult filter(Player player, String message) {
|
||||
if (!enabled || player.hasPermission("lochat.bypass.swear")) {
|
||||
|
|
|
|||
|
|
@ -149,6 +149,16 @@ public class GradientModule {
|
|||
return prefixService.getPrefix(player, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает суффикс игрока из LuckPerms с градиентом
|
||||
*/
|
||||
public String getSuffix(Player player) {
|
||||
if (!enabled) return "";
|
||||
|
||||
GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId());
|
||||
return prefixService.getLuckPermsSuffix(player, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает только LuckPerms префикс
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -79,10 +79,47 @@ public class PrefixService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Получает полное имя игрока: префикс + ник с градиентом
|
||||
* Получает суффикс из LuckPerms
|
||||
*/
|
||||
public String getLuckPermsSuffix(Player player, GradientPlayerData data) {
|
||||
if (!luckPermsAvailable) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
LuckPerms luckPerms = LuckPermsProvider.get();
|
||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
|
||||
if (user == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
CachedMetaData metaData = user.getCachedData().getMetaData();
|
||||
String suffix = metaData.getSuffix();
|
||||
|
||||
if (suffix == null || suffix.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Применяем градиент если нужно
|
||||
if (data != null && data.hasColors() && data.isColorEnabled() && config.isGradientOnLuckPermsPrefix()) {
|
||||
String cleanSuffix = GradientService.stripColors(suffix);
|
||||
return GradientService.applyGradient(cleanSuffix, data.getColors());
|
||||
}
|
||||
|
||||
return suffix;
|
||||
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает полное имя игрока: префикс + ник с градиентом + суффикс
|
||||
*/
|
||||
public String getFullName(Player player, GradientPlayerData data) {
|
||||
String prefix = getPrefix(player, data);
|
||||
String suffix = getLuckPermsSuffix(player, data);
|
||||
String nick = player.getName();
|
||||
|
||||
// Применяем градиент к нику если есть цвета
|
||||
|
|
@ -90,7 +127,12 @@ public class PrefixService {
|
|||
nick = GradientService.applyGradient(nick, data.getColors());
|
||||
}
|
||||
|
||||
return prefix.isEmpty() ? nick : prefix + " " + nick;
|
||||
StringBuilder result = new StringBuilder();
|
||||
if (!prefix.isEmpty()) result.append(prefix).append(" ");
|
||||
result.append(nick);
|
||||
if (!suffix.isEmpty()) result.append(" ").append(suffix);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -98,6 +140,7 @@ public class PrefixService {
|
|||
*/
|
||||
public String getFullNameForTab(Player player, GradientPlayerData data) {
|
||||
String prefix = getPrefix(player, data);
|
||||
String suffix = getLuckPermsSuffix(player, data);
|
||||
String nick = player.getName();
|
||||
|
||||
// Применяем градиент в формате TAB
|
||||
|
|
@ -105,7 +148,12 @@ public class PrefixService {
|
|||
nick = GradientService.applyGradientForTab(nick, data.getColors());
|
||||
}
|
||||
|
||||
return prefix.isEmpty() ? nick : prefix + " " + nick;
|
||||
StringBuilder result = new StringBuilder();
|
||||
if (!prefix.isEmpty()) result.append(prefix).append(" ");
|
||||
result.append(nick);
|
||||
if (!suffix.isEmpty()) result.append(" ").append(suffix);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public boolean isLuckPermsAvailable() {
|
||||
|
|
|
|||
|
|
@ -1,30 +1,42 @@
|
|||
package com.loki.lochat.listener;
|
||||
|
||||
import com.loki.lochat.LoChat;
|
||||
import com.loki.lochat.api.service.MessagingService;
|
||||
import com.loki.lochat.api.service.NickService;
|
||||
import com.loki.lochat.api.service.PlayerService;
|
||||
import com.loki.lochat.config.ConfigManager;
|
||||
import com.loki.lochat.core.filter.AdvancedMessageFilter;
|
||||
import com.loki.lochat.core.registry.ServiceRegistry;
|
||||
import com.loki.lochat.utils.ChatFormatter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Слушатель событий игрока
|
||||
*/
|
||||
public class PlayerEventListener implements Listener {
|
||||
private final LoChat plugin;
|
||||
private final PlayerService playerService;
|
||||
private final MessagingService messagingService;
|
||||
private final NickService nickService;
|
||||
private final AdvancedMessageFilter advancedFilter;
|
||||
private final ConfigManager configManager;
|
||||
|
||||
public PlayerEventListener(ServiceRegistry registry, AdvancedMessageFilter advancedFilter) {
|
||||
public PlayerEventListener(LoChat plugin, ServiceRegistry registry, AdvancedMessageFilter advancedFilter) {
|
||||
this.plugin = plugin;
|
||||
this.playerService = registry.get(PlayerService.class);
|
||||
this.messagingService = registry.get(MessagingService.class);
|
||||
this.nickService = registry.get(NickService.class);
|
||||
this.advancedFilter = advancedFilter;
|
||||
this.advancedFilter = advancedFilter;
|
||||
this.configManager = plugin.getConfigManager();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
|
@ -33,6 +45,13 @@ public class PlayerEventListener implements Listener {
|
|||
if (nickService != null) {
|
||||
nickService.updatePlayerDisplay(player);
|
||||
}
|
||||
|
||||
// Кастомное сообщение входа
|
||||
if (configManager.isJoinMessageEnabled()) {
|
||||
String format = configManager.getJoinMessageFormat();
|
||||
String message = format.replace("{player}", player.getName());
|
||||
event.joinMessage(ChatFormatter.parse(message));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
|
@ -44,7 +63,110 @@ public class PlayerEventListener implements Listener {
|
|||
messagingService.removeConversation(uuid);
|
||||
messagingService.removeSpy(uuid);
|
||||
|
||||
// Очищаем flood / spam трекеры — иначе данные висят в памяти вечно
|
||||
// Очищаем flood / spam трекеры
|
||||
advancedFilter.clearPlayer(uuid);
|
||||
|
||||
// Кастомное сообщение выхода
|
||||
if (configManager.isQuitMessageEnabled()) {
|
||||
String format = configManager.getQuitMessageFormat();
|
||||
String message = format.replace("{player}", player.getName());
|
||||
event.quitMessage(ChatFormatter.parse(message));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDeath(PlayerDeathEvent event) {
|
||||
if (!configManager.isDeathMessageEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
Player killer = player.getKiller();
|
||||
|
||||
String message;
|
||||
|
||||
if (killer != null) {
|
||||
// Убийство игроком
|
||||
ItemStack weapon = killer.getInventory().getItemInMainHand();
|
||||
String weaponName = getWeaponName(weapon);
|
||||
|
||||
message = configManager.getDeathPlayerKillFormat()
|
||||
.replace("{player}", player.getName())
|
||||
.replace("{killer}", killer.getName())
|
||||
.replace("{weapon}", weaponName);
|
||||
} else {
|
||||
// Проверяем убийцу-моба
|
||||
Entity lastDamager = player.getLastDamageCause() != null ?
|
||||
player.getLastDamageCause().getEntity() : null;
|
||||
|
||||
if (lastDamager instanceof LivingEntity mob && !(lastDamager instanceof Player)) {
|
||||
String mobName = getMobName(mob);
|
||||
message = configManager.getDeathMobKillFormat()
|
||||
.replace("{player}", player.getName())
|
||||
.replace("{killer}", mobName);
|
||||
} else {
|
||||
// Обычная смерть
|
||||
Component deathMsg = event.deathMessage();
|
||||
String deathText = deathMsg != null ? ChatFormatter.toPlain(deathMsg) : "умер";
|
||||
message = configManager.getDeathDefaultFormat()
|
||||
.replace("{player}", player.getName())
|
||||
.replace("{death_message}", deathText);
|
||||
}
|
||||
}
|
||||
|
||||
event.deathMessage(ChatFormatter.parse(message));
|
||||
}
|
||||
|
||||
private String getWeaponName(ItemStack item) {
|
||||
if (item == null || item.getType().isAir()) {
|
||||
return "Руки";
|
||||
}
|
||||
|
||||
if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
|
||||
return ChatFormatter.toPlain(item.getItemMeta().displayName());
|
||||
}
|
||||
|
||||
return translateMaterial(item.getType().name());
|
||||
}
|
||||
|
||||
private String getMobName(LivingEntity mob) {
|
||||
if (mob.customName() != null) {
|
||||
return ChatFormatter.toPlain(mob.customName());
|
||||
}
|
||||
return translateEntityType(mob.getType().name());
|
||||
}
|
||||
|
||||
private String translateMaterial(String material) {
|
||||
return switch (material) {
|
||||
case "DIAMOND_SWORD" -> "Алмазный меч";
|
||||
case "IRON_SWORD" -> "Железный меч";
|
||||
case "GOLDEN_SWORD" -> "Золотой меч";
|
||||
case "STONE_SWORD" -> "Каменный меч";
|
||||
case "WOODEN_SWORD" -> "Деревянный меч";
|
||||
case "NETHERITE_SWORD" -> "Незеритовый меч";
|
||||
case "BOW" -> "Лук";
|
||||
case "CROSSBOW" -> "Арбалет";
|
||||
case "TRIDENT" -> "Трезубец";
|
||||
case "DIAMOND_AXE" -> "Алмазный топор";
|
||||
case "IRON_AXE" -> "Железный топор";
|
||||
case "NETHERITE_AXE" -> "Незеритовый топор";
|
||||
default -> material.replace("_", " ").toLowerCase();
|
||||
};
|
||||
}
|
||||
|
||||
private String translateEntityType(String entityType) {
|
||||
return switch (entityType) {
|
||||
case "ZOMBIE" -> "Зомби";
|
||||
case "SKELETON" -> "Скелет";
|
||||
case "CREEPER" -> "Крипер";
|
||||
case "SPIDER" -> "Паук";
|
||||
case "ENDERMAN" -> "Эндермен";
|
||||
case "BLAZE" -> "Ифрит";
|
||||
case "WITCH" -> "Ведьма";
|
||||
case "PIGLIN" -> "Пиглин";
|
||||
case "HOGLIN" -> "Хоглин";
|
||||
case "WITHER_SKELETON" -> "Скелет-иссушитель";
|
||||
default -> entityType.replace("_", " ").toLowerCase();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,13 +57,14 @@ public class EnhancedChatRenderer implements ChatRenderer {
|
|||
Component prefix = buildPrefix();
|
||||
Component separator = buildSeparator();
|
||||
Component playerPrefix = buildPlayerPrefix(source);
|
||||
Component playerSuffix = buildPlayerSuffix(source);
|
||||
Component player = buildPlayerComponent(source);
|
||||
|
||||
return buildFormattedMessage(format, emoji, prefix, separator, playerPrefix, player, processed);
|
||||
return buildFormattedMessage(format, emoji, prefix, separator, playerPrefix, playerSuffix, player, processed);
|
||||
}
|
||||
|
||||
private Component buildFormattedMessage(String format, Component emoji, Component prefix,
|
||||
Component separator, Component playerPrefix,
|
||||
Component separator, Component playerPrefix, Component playerSuffix,
|
||||
Component player, Component message) {
|
||||
Component result = Component.empty();
|
||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\{([^}]+)\\}");
|
||||
|
|
@ -83,6 +84,7 @@ public class EnhancedChatRenderer implements ChatRenderer {
|
|||
case "separator" -> result = result.append(separator);
|
||||
case "player_prefix" -> result = result.append(playerPrefix);
|
||||
case "player" -> result = result.append(player);
|
||||
case "player_suffix" -> result = result.append(playerSuffix);
|
||||
case "message" -> result = result.append(message);
|
||||
default -> result = result.append(Component.text("{" + placeholder + "}"));
|
||||
}
|
||||
|
|
@ -117,6 +119,20 @@ public class EnhancedChatRenderer implements ChatRenderer {
|
|||
return Component.empty();
|
||||
}
|
||||
|
||||
private Component buildPlayerSuffix(Player player) {
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
com.loki.lochat.gradient.GradientModule gradientModule = loChat.getGradientModule();
|
||||
|
||||
if (gradientModule != null && gradientModule.isEnabled()) {
|
||||
String suffix = gradientModule.getSuffix(player);
|
||||
if (!suffix.isEmpty()) {
|
||||
return com.loki.lochat.utils.ChatFormatter.parse(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
return Component.empty();
|
||||
}
|
||||
|
||||
private Component buildPrefix() {
|
||||
com.loki.lochat.config.AppearanceConfig appearanceCfg = cfg.getAppearanceConfig();
|
||||
|
||||
|
|
|
|||
58
src/main/resources/badwords.txt
Normal file
58
src/main/resources/badwords.txt
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# Список запрещенных слов (по одному на строку)
|
||||
# Строки начинающиеся с # игнорируются
|
||||
# Фильтр автоматически ловит замены букв (х->x, о->o и т.д.)
|
||||
|
||||
# Основной мат
|
||||
хуй
|
||||
хуя
|
||||
хуе
|
||||
хую
|
||||
хуем
|
||||
хуи
|
||||
пизда
|
||||
пизде
|
||||
пизду
|
||||
пиздой
|
||||
пизды
|
||||
ебать
|
||||
ебал
|
||||
ебет
|
||||
ебут
|
||||
ебала
|
||||
ебали
|
||||
ебаный
|
||||
ебанный
|
||||
ебучий
|
||||
ебучая
|
||||
ебучее
|
||||
блять
|
||||
блядь
|
||||
бляди
|
||||
блядей
|
||||
сука
|
||||
суки
|
||||
сучка
|
||||
сучки
|
||||
пидор
|
||||
пидора
|
||||
пидоры
|
||||
пидорас
|
||||
пидорасы
|
||||
гандон
|
||||
гандоны
|
||||
мудак
|
||||
мудаки
|
||||
мудила
|
||||
мудилы
|
||||
долбоеб
|
||||
долбоебы
|
||||
уебан
|
||||
уебаны
|
||||
уебок
|
||||
уебки
|
||||
говно
|
||||
говна
|
||||
говном
|
||||
дерьмо
|
||||
дерьма
|
||||
дерьмом
|
||||
|
|
@ -1,58 +1,143 @@
|
|||
# LoChat Configuration v1.5.5
|
||||
config-version: 4
|
||||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ LoChat Configuration ║
|
||||
# ║ Единый конфиг плагина ║
|
||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
config-version: 5
|
||||
prefix: "�D4FF[LoChat]"
|
||||
|
||||
# Базовые настройки чата
|
||||
# Детальные настройки (префиксы, цвета, форматы) в config/*.yml
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Режимы чата │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
chat:
|
||||
# Режим чата:
|
||||
# - Оба включены = локальный (по умолчанию) + глобальный (с "!")
|
||||
# - Только global = единый чат без префиксов для всех
|
||||
# Глобальный чат (все видят, активируется через "!")
|
||||
global:
|
||||
enabled: true
|
||||
cooldown: 3
|
||||
|
||||
# Локальный чат (только в радиусе)
|
||||
local:
|
||||
enabled: true
|
||||
cooldown: 1
|
||||
radius: 100
|
||||
|
||||
# Личные сообщения
|
||||
pm:
|
||||
enabled: true
|
||||
cooldown: 2
|
||||
|
||||
# Лимиты сообщений
|
||||
min_message_length: 1
|
||||
max_message_length: 2000
|
||||
clear_lines: 100
|
||||
|
||||
# Hub команда
|
||||
hub_command:
|
||||
enabled: true
|
||||
server: "hub"
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Внешний вид чата (префиксы, форматы, цвета) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
appearance:
|
||||
# Префиксы чата (GLOBAL / LOCAL)
|
||||
prefixes:
|
||||
global:
|
||||
emoji: "✦"
|
||||
text: "GLOBAL"
|
||||
colors: ["#B798A8", "#7858E9"]
|
||||
separator:
|
||||
text: " ▶ "
|
||||
color: "#9878C9"
|
||||
message-color: "#E8E0F0"
|
||||
|
||||
local:
|
||||
emoji: "◆"
|
||||
text: "LOCAL"
|
||||
colors: ["#9878C9", "#7858E9"]
|
||||
separator:
|
||||
text: " ▶ "
|
||||
color: "#8B6BD6"
|
||||
message-color: "#E8E0F0"
|
||||
|
||||
# Формат сообщений
|
||||
# {emoji} {prefix} {separator} {player_prefix} {player} {player_suffix} {message}
|
||||
chat-format:
|
||||
global: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix}: {message}"
|
||||
local: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix}: {message}"
|
||||
|
||||
# Hover при наведении на ник
|
||||
hover:
|
||||
enabled: true
|
||||
format:
|
||||
- "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
||||
- "&#B798A8✦ &f{player}"
|
||||
- ""
|
||||
- "⚖C9⏱ &fПинг: ẲE9{ping}ms"
|
||||
- "⚖C9❤ &fЗдоровье: ẲE9{health}/20"
|
||||
- "⚖C9🍖 &fГолод: ẲE9{food}/20"
|
||||
- ""
|
||||
- "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
||||
- "&#B798A8✦ &fНажми чтобы написать"
|
||||
|
||||
# Эмодзи (текстовые замены)
|
||||
emojis:
|
||||
":heart:": "❤"
|
||||
":star:": "★"
|
||||
":diamond:": "♦"
|
||||
":check:": "✓"
|
||||
":cross:": "✗"
|
||||
":arrow:": "→"
|
||||
":smile:": ":)"
|
||||
":sad:": ":("
|
||||
":shrug:": "¯\\_(ツ)_/¯"
|
||||
|
||||
# Цвета системных сообщений
|
||||
colors:
|
||||
nobody_heard: "#9878C9"
|
||||
error: "#CF6679"
|
||||
success: "#9878C9"
|
||||
warning: "#B798A8"
|
||||
info: "#A485BC"
|
||||
|
||||
# Градиентные ники
|
||||
lopreff:
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Градиентные ники и префиксы │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
gradient:
|
||||
enabled: true
|
||||
use-gradient-name: true
|
||||
use-custom-prefix: true
|
||||
|
||||
display:
|
||||
update-display-name: true
|
||||
update-tab-list: true
|
||||
|
||||
# Градиенты (детали в config/gradient.yml)
|
||||
gradient:
|
||||
storage-type: "file"
|
||||
|
||||
# Настройки отображения
|
||||
display:
|
||||
update-display-name: true
|
||||
update-tab-list: true
|
||||
|
||||
# Лимиты
|
||||
min-colors: 1
|
||||
max-colors: 7
|
||||
max-prefix-length: 16
|
||||
|
||||
# Цены (PlayerPoints)
|
||||
price-per-color: 50
|
||||
prefix-price: 500
|
||||
prefix-one-time-purchase: true
|
||||
use-permission-instead-of-cost: false
|
||||
max-prefix-length: 16
|
||||
|
||||
# Кулдауны (секунды)
|
||||
color-cooldown: 60
|
||||
prefix-cooldown: 120
|
||||
|
||||
# Форматирование
|
||||
prefix-format: "[{prefix}] "
|
||||
gradient-on-prefix: true
|
||||
gradient-on-luckperms-prefix: true
|
||||
gradient-on-luckperms-suffix: true
|
||||
continuous-gradient: true
|
||||
use-legacy-rgb-format: true
|
||||
|
||||
# Хранилище (file / sqlite)
|
||||
storage-type: "file"
|
||||
sqlite-file: "gradient-data.db"
|
||||
|
||||
# RP команды (детали в config/rp.yml)
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ RP команды (/me, /do, /try, /roll) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
rp:
|
||||
radius: 100
|
||||
cooldowns:
|
||||
|
|
@ -61,6 +146,126 @@ rp:
|
|||
do: 3
|
||||
roll: 2
|
||||
|
||||
# Модерация: после /lmute выполнить команду от консоли (SimpleVoiceChat: voice mute {player})
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Фильтры чата │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
filters:
|
||||
# Мат-фильтр
|
||||
swear:
|
||||
enabled: true
|
||||
replace: false
|
||||
replacement: "***"
|
||||
words:
|
||||
- "хуй"
|
||||
- "пизда"
|
||||
- "ебать"
|
||||
|
||||
# URL фильтр
|
||||
url:
|
||||
enabled: true
|
||||
replacement: "[ссылка скрыта]"
|
||||
|
||||
# IP фильтр
|
||||
ip:
|
||||
enabled: true
|
||||
replacement: "[IP скрыт]"
|
||||
|
||||
# Скрытые URL (discord.gg и т.д.)
|
||||
hidden-urls:
|
||||
enabled: true
|
||||
patterns:
|
||||
- "discord\\.gg"
|
||||
- "dsc\\.gg"
|
||||
|
||||
# Анти-спам
|
||||
spam:
|
||||
enabled: true
|
||||
max-repeating-chars: 5
|
||||
|
||||
# Анти-флуд
|
||||
flood:
|
||||
enabled: true
|
||||
max-same-messages: 3
|
||||
|
||||
# Капс
|
||||
caps:
|
||||
enabled: true
|
||||
max-caps-percent: 70
|
||||
min-length: 5
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Модерация (муты, баны, варны) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
moderation:
|
||||
# Дефолтные значения
|
||||
default-mute-duration: "7d"
|
||||
default-mute-reason: "Без причины"
|
||||
default-ban-reason: "Без причины"
|
||||
|
||||
# Команда после мута (для голосового чата)
|
||||
voice-mute-console-command: ""
|
||||
|
||||
# Сообщение при кике забаненного
|
||||
ban-kick-message: "&#CF6679Вы забанены! &#B798A8Причина: ẲE9{reason}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Звуки │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
sounds:
|
||||
# Упоминание в чате
|
||||
mention:
|
||||
enabled: true
|
||||
sound: "BLOCK_NOTE_BLOCK_PLING"
|
||||
volume: 1.0
|
||||
pitch: 1.5
|
||||
|
||||
# Личное сообщение
|
||||
pm:
|
||||
enabled: true
|
||||
sound: "ENTITY_EXPERIENCE_ORB_PICKUP"
|
||||
volume: 0.8
|
||||
pitch: 1.2
|
||||
|
||||
# Команды
|
||||
command:
|
||||
enabled: false
|
||||
sound: "UI_BUTTON_CLICK"
|
||||
volume: 0.5
|
||||
pitch: 1.0
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Сообщения входа/выхода/смерти │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
messages:
|
||||
# Сообщение при входе
|
||||
# {player} - ник игрока
|
||||
join:
|
||||
enabled: true
|
||||
format: "⚖C9✦ &#B798A8{player} ẲE9зашел на сервер"
|
||||
|
||||
# Сообщение при выходе
|
||||
quit:
|
||||
enabled: true
|
||||
format: "⚖C9✦ &#B798A8{player} ẲE9вышел с сервера"
|
||||
|
||||
# Сообщение при смерти
|
||||
# {player} - ник игрока
|
||||
# {killer} - ник убийцы (если есть)
|
||||
# {weapon} - название оружия (если есть)
|
||||
# {death_message} - стандартное сообщение смерти
|
||||
death:
|
||||
enabled: true
|
||||
# Убийство игроком
|
||||
player_kill: "&#CF6679☠ &#B798A8{player} ẲE9был убит игроком &#B798A8{killer} ⚖C9({weapon})"
|
||||
# Смерть от моба
|
||||
mob_kill: "&#CF6679☠ &#B798A8{player} ẲE9был убит мобом &#B798A8{killer}"
|
||||
# Обычная смерть
|
||||
default: "&#CF6679☠ &#B798A8{player} ẲE9{death_message}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Прочее │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Hub команда
|
||||
hub_command:
|
||||
enabled: true
|
||||
server: "hub"
|
||||
|
|
|
|||
|
|
@ -44,16 +44,17 @@ prefixes:
|
|||
# {separator} — separator (e.g. ▶)
|
||||
# {player_prefix} — LuckPerms / gradient prefix from LoPreff
|
||||
# {player} — display name + hover (click to /msg)
|
||||
# {player_suffix} — LuckPerms / gradient suffix from LoPreff
|
||||
# {message} — message body
|
||||
#
|
||||
# Examples:
|
||||
# Default: {emoji} {prefix} {separator} {player} : {message}
|
||||
# Minimal: {player_prefix} {player} ▶ {message}
|
||||
# Custom: ✦ {player_prefix} {player} ▶ {message}
|
||||
# Custom: ✦ {player_prefix} {player} {player_suffix} ▶ {message}
|
||||
|
||||
chat-format:
|
||||
global: "{emoji} {prefix} {separator} {player} : {message}"
|
||||
local: "{emoji} {prefix} {separator} {player} : {message}"
|
||||
global: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix} : {message}"
|
||||
local: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix} : {message}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Hover shown when pointing at the player name in chat │
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ events:
|
|||
enabled: true
|
||||
|
||||
# Настройки входа на сервер
|
||||
# {player} - ник игрока
|
||||
join:
|
||||
enabled: true
|
||||
title: "🟢 Игрок зашел на сервер"
|
||||
|
|
@ -47,7 +48,8 @@ events:
|
|||
color: "00FF00"
|
||||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||
|
||||
# Настройки выхода с сервера
|
||||
# Настройки выхода с сервера
|
||||
# {player} - ник игрока
|
||||
quit:
|
||||
enabled: true
|
||||
title: "🔴 Игрок покинул сервер"
|
||||
|
|
@ -56,11 +58,27 @@ events:
|
|||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||
|
||||
# Настройки смерти игрока
|
||||
# {player} - ник игрока
|
||||
# {killer} - ник убийцы (если есть)
|
||||
# {weapon} - название оружия (если есть)
|
||||
# {death_message} - стандартное сообщение смерти
|
||||
death:
|
||||
enabled: true
|
||||
title: "💀 Смерть игрока"
|
||||
description: "**{player}** {death_message}"
|
||||
color: "800080"
|
||||
# Убийство игроком
|
||||
player_kill:
|
||||
title: "⚔️ PvP убийство"
|
||||
description: "**{player}** был убит игроком **{killer}** с помощью **{weapon}**"
|
||||
color: "FF0000"
|
||||
# Смерть от моба
|
||||
mob_kill:
|
||||
title: "💀 Смерть от моба"
|
||||
description: "**{player}** был убит мобом **{killer}**"
|
||||
color: "800080"
|
||||
# Обычная смерть
|
||||
default:
|
||||
title: "💀 Смерть игрока"
|
||||
description: "**{player}** {death_message}"
|
||||
color: "800080"
|
||||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||
|
||||
# Настройки фильтрации
|
||||
|
|
|
|||
|
|
@ -1,286 +1,81 @@
|
|||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ LoChat Filters Configuration ║
|
||||
# ║ Конфигурация фильтров ║
|
||||
# ║ Версия: 1.5.5-1.20.1 ║
|
||||
# ║ LoChat — Фильтры чата ║
|
||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР ЗАГЛАВНЫХ БУКВ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
caps:
|
||||
# Включить фильтр заглавных букв
|
||||
enabled: true
|
||||
|
||||
# Максимальный процент заглавных букв (0-100)
|
||||
max-percent: 70
|
||||
|
||||
# Минимальная длина сообщения для проверки
|
||||
min-length: 5
|
||||
|
||||
# Автоматически переводить в нижний регистр
|
||||
auto-lowercase: true
|
||||
|
||||
# Действие при нарушении: block, warn, lowercase
|
||||
action: "lowercase"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BСлишком много заглавных букв!"
|
||||
|
||||
# Сообщение-предупреждение
|
||||
warn-message: "&#FFA726Не используйте слишком много заглавных букв"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР РЕКЛАМЫ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
advertising:
|
||||
# Включить фильтр рекламы
|
||||
enabled: true
|
||||
|
||||
# Блокировать скрытые URL (bit.ly, tinyurl и т.д.)
|
||||
block-hidden-urls: true
|
||||
|
||||
# Блокировать домены
|
||||
block-domains: true
|
||||
|
||||
# Блокировать IP адреса
|
||||
block-ips: true
|
||||
|
||||
# Действие при обнаружении: block, warn, replace
|
||||
action: "block"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BРеклама запрещена!"
|
||||
|
||||
# Замена для заблокированного контента
|
||||
replacement: "[РЕКЛАМА УДАЛЕНА]"
|
||||
|
||||
# Белый список доменов (разрешенные)
|
||||
whitelist:
|
||||
- "youtube.com"
|
||||
- "youtu.be"
|
||||
- "discord.gg"
|
||||
- "twitch.tv"
|
||||
- "imgur.com"
|
||||
- "gyazo.com"
|
||||
- "prntscr.com"
|
||||
|
||||
# Черный список доменов (запрещенные)
|
||||
blacklist:
|
||||
- "scam-site.com"
|
||||
- "virus-site.ru"
|
||||
- "fake-minecraft.net"
|
||||
|
||||
# Регулярные выражения для поиска рекламы
|
||||
patterns:
|
||||
- "(?i)\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}(?::[0-9]{1,5})?\\b" # IP адреса
|
||||
- "(?i)\\b[a-z0-9.-]+\\.(com|net|org|ru|de|uk)\\b" # Домены
|
||||
- "(?i)\\b(server|сервер)\\s*[:-]?\\s*[a-z0-9.-]+\\b" # Серверы
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР IP АДРЕСОВ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
ip:
|
||||
# Включить фильтр IP адресов
|
||||
enabled: true
|
||||
|
||||
# Блокировать сообщение или заменять IP
|
||||
block: false
|
||||
|
||||
# Замена для IP адресов
|
||||
replacement: "[IP СКРЫТ]"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BIP адреса запрещены!"
|
||||
|
||||
# Белый список IP (разрешенные)
|
||||
whitelist:
|
||||
- "127.0.0.1"
|
||||
- "localhost"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР ПОВТОРОВ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
repeat:
|
||||
# Включить фильтр повторяющихся символов
|
||||
enabled: true
|
||||
|
||||
# Максимальное количество повторов подряд
|
||||
max-repeats: 3
|
||||
|
||||
# Действие: block, warn, replace
|
||||
action: "replace"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BНе повторяйте символы!"
|
||||
|
||||
# Автоматически сокращать повторы
|
||||
auto-reduce: true
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР СПАМА │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
spam:
|
||||
# Включить антиспам
|
||||
enabled: true
|
||||
|
||||
# Максимальное количество одинаковых сообщений
|
||||
max-similar-messages: 3
|
||||
|
||||
# Время для сброса счетчика (секунды)
|
||||
reset-time: 60
|
||||
|
||||
# Процент схожести сообщений (0-100)
|
||||
similarity-threshold: 80
|
||||
|
||||
# Действие при спаме: block, warn, mute
|
||||
action: "warn"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BНе спамьте!"
|
||||
|
||||
# Время мута за спам (секунды)
|
||||
mute-duration: 300
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР МАТА │
|
||||
# │ Мат-фильтр │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Использует badwords.txt для списка слов
|
||||
# Автоматически ловит замены букв: х->x, о->o, е->e и т.д.
|
||||
# Обход: lochat.bypass.swear
|
||||
|
||||
swear:
|
||||
# Включить фильтр мата
|
||||
enabled: true
|
||||
|
||||
# Использовать внешний файл со словами
|
||||
use-external-file: true
|
||||
|
||||
# Файл со словами (относительно папки плагина)
|
||||
words-file: "filter-words.json"
|
||||
|
||||
# Действие: block, warn, replace, mute
|
||||
action: "replace"
|
||||
|
||||
# Символ для замены
|
||||
replacement-char: "*"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BМат запрещен!"
|
||||
|
||||
# Время мута за мат (секунды)
|
||||
mute-duration: 600
|
||||
|
||||
# Встроенный список слов (если не используется внешний файл)
|
||||
words:
|
||||
- "плохое_слово1"
|
||||
- "плохое_слово2"
|
||||
|
||||
# Проверять фрагменты слов
|
||||
check-fragments: true
|
||||
|
||||
# Игнорировать регистр
|
||||
ignore-case: true
|
||||
|
||||
# Проверять транслитерацию
|
||||
check-transliteration: true
|
||||
replace: false # true = заменять на ***, false = блокировать сообщение
|
||||
replacement: "***"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ФИЛЬТР ФЛУДА │
|
||||
# │ URL фильтр │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует ссылки в чате
|
||||
# Обход: lochat.bypass.urlfilter
|
||||
|
||||
url:
|
||||
enabled: true
|
||||
replacement: "[ссылка скрыта]"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ IP фильтр │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует IP адреса в чате
|
||||
# Обход: lochat.bypass.ipfilter
|
||||
|
||||
ip:
|
||||
enabled: true
|
||||
replacement: "[IP скрыт]"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Скрытые URL (discord.gg и т.д.) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует популярные сокращенные ссылки
|
||||
# Обход: lochat.bypass.hiddenurls
|
||||
|
||||
hidden-urls:
|
||||
enabled: true
|
||||
patterns:
|
||||
- "discord\\.gg"
|
||||
- "dsc\\.gg"
|
||||
- "bit\\.ly"
|
||||
- "tinyurl\\.com"
|
||||
- "goo\\.gl"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Анти-спам │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует повторяющиеся символы (ааааааа, хххххх)
|
||||
# Обход: lochat.bypass.spam
|
||||
|
||||
spam:
|
||||
enabled: true
|
||||
max-repeating-chars: 5 # Максимум повторений одного символа
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Анти-флуд │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует одинаковые сообщения подряд
|
||||
# Обход: lochat.bypass.flood
|
||||
|
||||
flood:
|
||||
# Включить антифлуд
|
||||
enabled: true
|
||||
|
||||
# Максимальное количество сообщений в период
|
||||
max-messages: 5
|
||||
|
||||
# Период времени (секунды)
|
||||
time-period: 10
|
||||
|
||||
# Действие при флуде: block, warn, mute
|
||||
action: "warn"
|
||||
|
||||
# Сообщение при блокировке
|
||||
block-message: "&#FF6B6BНе флудите!"
|
||||
|
||||
# Время мута за флуд (секунды)
|
||||
mute-duration: 180
|
||||
max-same-messages: 3 # Сколько раз можно отправить одно и то же
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ДОПОЛНИТЕЛЬНЫЕ ФИЛЬТРЫ │
|
||||
# │ Капс-фильтр │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
# Блокирует сообщения с большим количеством заглавных букв
|
||||
# Обход: lochat.bypass.caps
|
||||
|
||||
additional:
|
||||
# Фильтр эмодзи
|
||||
emoji:
|
||||
enabled: false
|
||||
max-per-message: 5
|
||||
block-message: "&#FF6B6BСлишком много эмодзи!"
|
||||
|
||||
# Фильтр длинных сообщений
|
||||
length:
|
||||
enabled: true
|
||||
max-length: 256
|
||||
action: "truncate" # truncate или block
|
||||
block-message: "&#FF6B6BСообщение слишком длинное!"
|
||||
|
||||
# Фильтр пустых сообщений
|
||||
empty:
|
||||
enabled: true
|
||||
block-message: "&#FF6B6BПустые сообщения запрещены!"
|
||||
|
||||
# Фильтр только пробелов
|
||||
whitespace:
|
||||
enabled: true
|
||||
block-message: "&#FF6B6BСообщение не может состоять только из пробелов!"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ НАСТРОЙКИ ОБХОДА │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
bypass:
|
||||
# Права для обхода фильтров
|
||||
permissions:
|
||||
caps: "lochat.bypass.caps"
|
||||
advertising: "lochat.bypass.advertising"
|
||||
ip: "lochat.bypass.ip"
|
||||
repeat: "lochat.bypass.repeat"
|
||||
spam: "lochat.bypass.spam"
|
||||
swear: "lochat.bypass.swear"
|
||||
flood: "lochat.bypass.flood"
|
||||
all: "lochat.bypass.filter"
|
||||
|
||||
# Группы, которые обходят все фильтры
|
||||
groups:
|
||||
- "admin"
|
||||
- "moderator"
|
||||
|
||||
# Миры, где фильтры отключены
|
||||
worlds:
|
||||
- "creative_world"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ ЛОГИРОВАНИЕ │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
logging:
|
||||
# Логировать заблокированные сообщения
|
||||
caps:
|
||||
enabled: true
|
||||
|
||||
# Файл для логов
|
||||
file: "plugins/LoChat/logs/filter.log"
|
||||
|
||||
# Формат лога
|
||||
format: "[{time}] {player} ({filter}): {message}"
|
||||
|
||||
# Логировать в консоль
|
||||
console: true
|
||||
|
||||
# Уведомлять администраторов
|
||||
notify-admins: true
|
||||
|
||||
# Право для получения уведомлений
|
||||
notify-permission: "lochat.filter.notify"
|
||||
max-caps-percent: 70 # Максимум % заглавных букв
|
||||
min-length: 5 # Минимальная длина для проверки
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ LoChat — messages.yml ║
|
||||
# ║ Default palette (Spacelegacy): #B798A8 (dusty rose) → #7858E9 (violet) ║
|
||||
# ║ Default palette (Spacelegacy): #7858E9 (dusty rose) → #7858E9 (violet) ║
|
||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
#
|
||||
# Color roles (reference when editing strings below):
|
||||
# &#B798A8 — primary labels / body (dusty rose)
|
||||
# ẲE9 — primary labels / body (dusty rose)
|
||||
# ⚖C9 — accents / separators (mid violet)
|
||||
# ẲE9 — emphasis / values (deep violet)
|
||||
# &f / #E8E0F0 — message body white
|
||||
# &#CF6679 — errors (muted red, fits the palette)
|
||||
|
||||
prefix: "&#B798A8[⚖C9LB6BD6oẲE9CⅵDChB6BD6a⚖C9t&#B798A8]"
|
||||
prefix: "ẲE9[⚖C9LB6BD6oẲE9CⅵDChB6BD6a⚖C9tẲE9]"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Global chat (toggle messages, server-disabled notice) │
|
||||
|
|
@ -18,7 +18,7 @@ prefix: "&#B798A8[⚖C9LB6BD6oẲE9CⅵDChB6BD6a⚖C9t&#B798A8
|
|||
|
||||
global:
|
||||
toggled-on: "⚖C9Глобальный чат ẲE9включён"
|
||||
toggled-off: "⚖C9Глобальный чат &#B798A8отключён"
|
||||
toggled-off: "⚖C9Глобальный чат ẲE9отключён"
|
||||
disabled: "&#CF6679Глобальный чат отключён на этом сервере"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
|
|
@ -26,19 +26,19 @@ global:
|
|||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
local:
|
||||
no-players: "&#B798A8Рядом нет игроков"
|
||||
nobody-heard: "⚖C9Вас никто не услышал &#B798A8— рядом нет игроков"
|
||||
no-players: "ẲE9Рядом нет игроков"
|
||||
nobody-heard: "⚖C9Вас никто не услышал ẲE9— рядом нет игроков"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Private messages (/msg, /reply) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
pm:
|
||||
format-sent: "&#B798A8[⚖C9→&#B798A8] ⚖C9Вы &#B798A8→ {receiver_display}&#B798A8: &f{message}"
|
||||
format-received: "&#B798A8[⚖C9←&#B798A8] {sender_display} &#B798A8→ ⚖C9Вы&#B798A8: &f{message}"
|
||||
format-sent: "ẲE9[⚖C9→ẲE9] ⚖C9Вы ẲE9→ {receiver_display}ẲE9: &f{message}"
|
||||
format-received: "ẲE9[⚖C9←ẲE9] {sender_display} ẲE9→ ⚖C9ВыẲE9: &f{message}"
|
||||
use-gradient-names: true
|
||||
sent: "&#B798A8[⚖C9→&#B798A8] ⚖C9Вы &#B798A8→ &f{player}&#B798A8: &f{message}"
|
||||
received: "&#B798A8[⚖C9←&#B798A8] &f{player} &#B798A8→ ⚖C9Вы&#B798A8: &f{message}"
|
||||
sent: "ẲE9[⚖C9→ẲE9] ⚖C9Вы ẲE9→ &f{player}ẲE9: &f{message}"
|
||||
received: "ẲE9[⚖C9←ẲE9] &f{player} ẲE9→ ⚖C9ВыẲE9: &f{message}"
|
||||
no-reply: "&#CF6679Некому ответить"
|
||||
ignored: "&#CF6679Этот игрок вас игнорирует"
|
||||
player-offline: "&#CF6679Игрок не в сети"
|
||||
|
|
@ -51,12 +51,12 @@ pm:
|
|||
ignore:
|
||||
added: "⚖C9Игрок ẲE9{player} ⚖C9добавлен в игнор"
|
||||
removed: "⚖C9Игрок ẲE9{player} ⚖C9убран из игнора"
|
||||
already-ignored: "&#B798A8Игрок ẲE9{player} &#B798A8уже в игноре"
|
||||
not-ignored: "&#B798A8Игрок ẲE9{player} &#B798A8не в игноре"
|
||||
already-ignored: "ẲE9Игрок ẲE9{player} ẲE9уже в игноре"
|
||||
not-ignored: "ẲE9Игрок ẲE9{player} ẲE9не в игноре"
|
||||
self: "&#CF6679Нельзя игнорировать самого себя"
|
||||
list-empty: "&#B798A8Ваш список игнора пуст"
|
||||
list-empty: "ẲE9Ваш список игнора пуст"
|
||||
list-header: "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
||||
list-footer: "&#B798A8Всего: ẲE9{count} &#B798A8игроков"
|
||||
list-footer: "ẲE9Всего: ẲE9{count} ẲE9игроков"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Announcements │
|
||||
|
|
@ -71,9 +71,9 @@ announce:
|
|||
|
||||
spy:
|
||||
enabled: "⚖C9Режим шпиона ẲE9включён"
|
||||
disabled: "⚖C9Режим шпиона &#B798A8отключён"
|
||||
format: "&#B798A8[⚖C9SPY&#B798A8] ẲE9{sender} &#B798A8→ ⚖C9{receiver}&#B798A8: &f{message}"
|
||||
chat-format: "&#B798A8[⚖C9SPY&#B798A8] &#B798A8{type} ẲE9{sender}&#B798A8: &f{message}"
|
||||
disabled: "⚖C9Режим шпиона ẲE9отключён"
|
||||
format: "ẲE9[⚖C9SPYẲE9] ẲE9{sender} ẲE9→ ⚖C9{receiver}ẲE9: &f{message}"
|
||||
chat-format: "ẲE9[⚖C9SPYẲE9] ẲE9{type} ẲE9{sender}ẲE9: &f{message}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Message filters │
|
||||
|
|
@ -81,14 +81,14 @@ spy:
|
|||
|
||||
filter:
|
||||
blocked: "&#CF6679Сообщение заблокировано"
|
||||
warning: "&#B798A8Предупреждение"
|
||||
warning: "ẲE9Предупреждение"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Cooldowns │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
cooldown:
|
||||
wait: "&#B798A8Подождите ẲE9{time} &#B798A8сек"
|
||||
wait: "ẲE9Подождите ẲE9{time} ẲE9сек"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Anti-spam (caps, repeat, similar messages) │
|
||||
|
|
@ -104,7 +104,7 @@ antispam:
|
|||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
clearchat:
|
||||
cleared: "⚖C9Чат очищен &#B798A8администратором ẲE9{player}"
|
||||
cleared: "⚖C9Чат очищен ẲE9администратором ẲE9{player}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Command / usage errors │
|
||||
|
|
@ -113,7 +113,7 @@ clearchat:
|
|||
errors:
|
||||
no-permission: "&#CF6679Нет прав"
|
||||
player-not-found: "&#CF6679Игрок не найден"
|
||||
invalid-usage: "&#B798A8Использование: ẲE9{usage}"
|
||||
invalid-usage: "ẲE9Использование: ẲE9{usage}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ General (permissions, reload, hub, etc.) │
|
||||
|
|
@ -124,7 +124,7 @@ general:
|
|||
players-only: "&#CF6679Только для игроков!"
|
||||
config-reloaded: "⚖C9Конфиг ẲE9перезагружен!"
|
||||
invalid-player: "&#CF6679Игрок ẲE9{player} &#CF6679не найден!"
|
||||
cooldown-active: "&#B798A8Подождите ẲE9{time}с"
|
||||
cooldown-active: "ẲE9Подождите ẲE9{time}с"
|
||||
command-disabled: "&#CF6679Команда отключена!"
|
||||
|
||||
hub:
|
||||
|
|
@ -137,9 +137,9 @@ hub:
|
|||
mute:
|
||||
muted: "⚖C9Игрок ẲE9{player} ⚖C9замучен на ẲE9{time}"
|
||||
unmuted: "⚖C9Игрок ẲE9{player} ⚖C9размучен"
|
||||
already-muted: "&#B798A8Игрок ẲE9{player} &#B798A8уже замучен"
|
||||
not-muted: "&#B798A8Игрок ẲE9{player} &#B798A8не замучен"
|
||||
you-muted: "&#CF6679Вы замучены! &#B798A8Осталось: ẲE9{time}"
|
||||
already-muted: "ẲE9Игрок ẲE9{player} ẲE9уже замучен"
|
||||
not-muted: "ẲE9Игрок ẲE9{player} ẲE9не замучен"
|
||||
you-muted: "&#CF6679Вы замучены! ẲE9Осталось: ẲE9{time}"
|
||||
permanent: "&#CF6679Вы замучены навсегда!"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
|
|
@ -149,32 +149,32 @@ mute:
|
|||
gradient:
|
||||
color-set: "⚖C9Градиент ẲE9установлен!"
|
||||
color-enabled: "⚖C9Градиентный ник ẲE9включён"
|
||||
color-disabled: "&#B798A8Градиентный ник ⚖C9отключён"
|
||||
color-reset: "&#B798A8Градиент сброшен"
|
||||
color-disabled: "ẲE9Градиентный ник ⚖C9отключён"
|
||||
color-reset: "ẲE9Градиент сброшен"
|
||||
prefix-set: "⚖C9Префикс ẲE9установлен!"
|
||||
prefix-reset: "&#B798A8Префикс сброшен"
|
||||
prefix-reset: "ẲE9Префикс сброшен"
|
||||
prefix-reset-success: "⚖C9Префикс успешно ẲE9сброшен!"
|
||||
prefix-enabled: "⚖C9Префикс ẲE9включён"
|
||||
prefix-disabled: "&#B798A8Префикс ⚖C9отключён"
|
||||
prefix-disabled: "ẲE9Префикс ⚖C9отключён"
|
||||
invalid-hex: "&#CF6679Неверный HEX цвет: ẲE9{color}"
|
||||
invalid-color: "&#CF6679Неверный цвет: ẲE9{color}"
|
||||
too-many-colors: "&#CF6679Слишком много цветов! Максимум: ẲE9{max}"
|
||||
too-few-colors: "&#CF6679Слишком мало цветов! Минимум: ẲE9{min}"
|
||||
not-enough-colors: "&#CF6679Слишком мало цветов! Минимум: ẲE9{min}"
|
||||
cooldown: "&#B798A8Подождите ẲE9{time} &#B798A8сек"
|
||||
cooldown: "ẲE9Подождите ẲE9{time} ẲE9сек"
|
||||
not-enough-points: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||
not-enough-points-color: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||
not-enough-points-prefix: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||
player-not-found: "&#CF6679Игрок не найден"
|
||||
color-help: "&#B798A8Использование: ẲE9/color <HEX1> <HEX2>"
|
||||
color-help: "ẲE9Использование: ẲE9/color <HEX1> <HEX2>"
|
||||
color-success: "⚖C9Градиент успешно ẲE9установлен!"
|
||||
color-no-colors: "&#B798A8У вас нет установленных цветов"
|
||||
color-copy-usage: "&#B798A8Использование: ẲE9/color copy <игрок>"
|
||||
color-copy-no-colors: "&#B798A8У игрока ẲE9{player} &#B798A8нет цветов"
|
||||
prefix-help: "&#B798A8Использование: ẲE9/prefix <текст> &#B798A8или ẲE9/prefix reset"
|
||||
prefix-success: "⚖C9Префикс установлен! &#B798A8Стоимость: ẲE9{price} &#B798A8поинтов"
|
||||
color-no-colors: "ẲE9У вас нет установленных цветов"
|
||||
color-copy-usage: "ẲE9Использование: ẲE9/color copy <игрок>"
|
||||
color-copy-no-colors: "ẲE9У игрока ẲE9{player} ẲE9нет цветов"
|
||||
prefix-help: "ẲE9Использование: ẲE9/prefix <текст> ẲE9или ẲE9/prefix reset"
|
||||
prefix-success: "⚖C9Префикс установлен! ẲE9Стоимость: ẲE9{price} ẲE9поинтов"
|
||||
prefix-success-free: "⚖C9Префикс ẲE9установлен!"
|
||||
prefix-no-prefix: "&#B798A8У вас нет префикса"
|
||||
prefix-no-prefix: "ẲE9У вас нет префикса"
|
||||
prefix-too-long: "&#CF6679Префикс слишком длинный! Максимум: ẲE9{max}"
|
||||
prefix-no-colors: "&#CF6679Префикс не может содержать цветовые коды!"
|
||||
prefix-invalid-chars: "&#CF6679Недопустимые символы в префиксе!"
|
||||
|
|
@ -182,30 +182,30 @@ gradient:
|
|||
only-player: "&#CF6679Только для игроков!"
|
||||
no-permission: "&#CF6679Нет прав!"
|
||||
reload-success: "⚖C9Конфигурация ẲE9перезагружена!"
|
||||
info-header: "ẲE9▬▬▬▬▬▬▬▬ &#B798A8{player} ẲE9▬▬▬▬▬▬▬▬"
|
||||
info-prefix: "&#B798A8Префикс: &f{prefix}"
|
||||
info-prefix-enabled: "&#B798A8Префикс активен: &f{enabled}"
|
||||
info-colors: "&#B798A8Цвета: &f{colors}"
|
||||
info-color-enabled: "&#B798A8Цвет активен: &f{enabled}"
|
||||
info-prefix-purchased: "&#B798A8Куплен: &f{purchased}"
|
||||
info-header: "ẲE9▬▬▬▬▬▬▬▬ ẲE9{player} ẲE9▬▬▬▬▬▬▬▬"
|
||||
info-prefix: "ẲE9Префикс: &f{prefix}"
|
||||
info-prefix-enabled: "ẲE9Префикс активен: &f{enabled}"
|
||||
info-colors: "ẲE9Цвета: &f{colors}"
|
||||
info-color-enabled: "ẲE9Цвет активен: &f{enabled}"
|
||||
info-prefix-purchased: "ẲE9Куплен: &f{purchased}"
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Custom nicknames (/nick) │
|
||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
nick:
|
||||
current: "&#B798A8Ваш ник: ẲE9{nick}"
|
||||
usage: "&#B798A8Использование: ẲE9/nick <ник> &#B798A8или ẲE9/nick reset"
|
||||
reset-usage: "&#B798A8Используйте ẲE9/nick reset &#B798A8для сброса"
|
||||
set-usage: "&#B798A8Используйте ẲE9/nick <ник> &#B798A8для установки"
|
||||
no-nick: "&#B798A8У вас нет кастомного ника"
|
||||
current: "ẲE9Ваш ник: ẲE9{nick}"
|
||||
usage: "ẲE9Использование: ẲE9/nick <ник> ẲE9или ẲE9/nick reset"
|
||||
reset-usage: "ẲE9Используйте ẲE9/nick reset ẲE9для сброса"
|
||||
set-usage: "ẲE9Используйте ẲE9/nick <ник> ẲE9для установки"
|
||||
no-nick: "ẲE9У вас нет кастомного ника"
|
||||
reset-success: "⚖C9Ник ẲE9сброшен!"
|
||||
set-success: "⚖C9Ник изменён на: &f{nick}"
|
||||
invalid: "&#CF6679Невалидный ник!"
|
||||
requirements-header: "&#B798A8Требования:"
|
||||
requirements-header: "ẲE9Требования:"
|
||||
requirements-length: "⚖C9◆ &fДлина: 3-16 символов"
|
||||
requirements-chars: "⚖C9◆ &fБуквы, цифры, _, русские буквы"
|
||||
requirements-colors: "⚖C9◆ &fЦвета: ẲE9&#RRGGBB&#B798A8текст"
|
||||
requirements-colors: "⚖C9◆ &fЦвета: ẲE9&#RRGGBBẲE9текст"
|
||||
taken: "&#CF6679Этот ник уже занят!"
|
||||
error: "&#CF6679Не удалось установить ник!"
|
||||
|
||||
|
|
@ -214,12 +214,12 @@ nick:
|
|||
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
rp:
|
||||
me: "<color:#B798A8>* {player} {action}</color>"
|
||||
try-format: "<color:#B798A8>* {player} пытается {action}...</color> {result}"
|
||||
me: "<color:#7858E9>* {player} {action}</color>"
|
||||
try-format: "<color:#7858E9>* {player} пытается {action}...</color> {result}"
|
||||
try-success: "<color:#9878C9><bold>[Успех!]</bold></color>"
|
||||
try-fail: "<color:#CF6679><bold>[Провал!]</bold></color>"
|
||||
do-format: "<color:#7858E9>[<color:#B798A8>Сцена</color>]</color> <white>{description}</white> <color:#9878C9>({player})</color>"
|
||||
roll-format: "<color:#B798A8>* {player} бросает кубик и получает </color><color:#7858E9><bold>{result}</bold></color><color:#B798A8> из </color><color:#9878C9>{max}</color>"
|
||||
do-format: "<color:#7858E9>[<color:#7858E9>Сцена</color>]</color> <white>{description}</white> <color:#9878C9>({player})</color>"
|
||||
roll-format: "<color:#7858E9>* {player} бросает кубик и получает </color><color:#7858E9><bold>{result}</bold></color><color:#7858E9> из </color><color:#9878C9>{max}</color>"
|
||||
roll-min-error: "<color:#CF6679>Минимальное значение кубика: 2</color>"
|
||||
roll-max-error: "<color:#CF6679>Максимальное значение: 1000000</color>"
|
||||
roll-invalid-number: "<color:#CF6679>Укажите число: /roll [максимум]</color>"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue