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]"
|
prefix: "�D4FF[LoChat]"
|
||||||
|
|
||||||
# Базовые настройки чата
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# Детальные настройки (префиксы, цвета, форматы) в config/*.yml
|
# │ Режимы чата │
|
||||||
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
chat:
|
chat:
|
||||||
# Режим чата:
|
# Глобальный чат (все видят, активируется через "!")
|
||||||
# - Оба включены = локальный (по умолчанию) + глобальный (с "!")
|
|
||||||
# - Только global = единый чат без префиксов для всех
|
|
||||||
global:
|
global:
|
||||||
enabled: true
|
enabled: true
|
||||||
cooldown: 3
|
cooldown: 3
|
||||||
|
|
||||||
|
# Локальный чат (только в радиусе)
|
||||||
local:
|
local:
|
||||||
enabled: true
|
enabled: true
|
||||||
cooldown: 1
|
cooldown: 1
|
||||||
|
radius: 100
|
||||||
|
|
||||||
|
# Личные сообщения
|
||||||
pm:
|
pm:
|
||||||
enabled: true
|
enabled: true
|
||||||
cooldown: 2
|
cooldown: 2
|
||||||
|
|
||||||
# Hub команда
|
# Лимиты сообщений
|
||||||
hub_command:
|
min_message_length: 1
|
||||||
enabled: true
|
max_message_length: 2000
|
||||||
server: "hub"
|
clear_lines: 100
|
||||||
|
|
||||||
# Градиентные ники
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
lopreff:
|
# │ Внешний вид чата (префиксы, форматы, цвета) │
|
||||||
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
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"
|
||||||
|
|
||||||
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ Градиентные ники и префиксы │
|
||||||
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
gradient:
|
||||||
enabled: true
|
enabled: true
|
||||||
use-gradient-name: true
|
use-gradient-name: true
|
||||||
use-custom-prefix: true
|
use-custom-prefix: true
|
||||||
|
|
||||||
display:
|
# Настройки отображения
|
||||||
update-display-name: true
|
display:
|
||||||
update-tab-list: true
|
update-display-name: true
|
||||||
|
update-tab-list: true
|
||||||
|
|
||||||
# Градиенты (детали в config/gradient.yml)
|
# Лимиты
|
||||||
gradient:
|
|
||||||
storage-type: "file"
|
|
||||||
min-colors: 1
|
min-colors: 1
|
||||||
max-colors: 7
|
max-colors: 7
|
||||||
|
max-prefix-length: 16
|
||||||
|
|
||||||
|
# Цены (PlayerPoints)
|
||||||
price-per-color: 50
|
price-per-color: 50
|
||||||
prefix-price: 500
|
prefix-price: 500
|
||||||
prefix-one-time-purchase: true
|
prefix-one-time-purchase: true
|
||||||
use-permission-instead-of-cost: false
|
use-permission-instead-of-cost: false
|
||||||
max-prefix-length: 16
|
|
||||||
|
# Кулдауны (секунды)
|
||||||
color-cooldown: 60
|
color-cooldown: 60
|
||||||
prefix-cooldown: 120
|
prefix-cooldown: 120
|
||||||
|
|
||||||
|
# Форматирование
|
||||||
prefix-format: "[{prefix}] "
|
prefix-format: "[{prefix}] "
|
||||||
gradient-on-prefix: true
|
gradient-on-prefix: true
|
||||||
gradient-on-luckperms-prefix: true
|
gradient-on-luckperms-prefix: true
|
||||||
|
gradient-on-luckperms-suffix: true
|
||||||
continuous-gradient: true
|
continuous-gradient: true
|
||||||
use-legacy-rgb-format: true
|
use-legacy-rgb-format: true
|
||||||
|
|
||||||
# RP команды (детали в config/rp.yml)
|
# Хранилище (file / sqlite)
|
||||||
|
storage-type: "file"
|
||||||
|
sqlite-file: "gradient-data.db"
|
||||||
|
|
||||||
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ RP команды (/me, /do, /try, /roll) │
|
||||||
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
rp:
|
rp:
|
||||||
radius: 100
|
radius: 100
|
||||||
cooldowns:
|
cooldowns:
|
||||||
|
|
@ -61,6 +146,126 @@ rp:
|
||||||
do: 3
|
do: 3
|
||||||
roll: 2
|
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:
|
moderation:
|
||||||
|
# Дефолтные значения
|
||||||
|
default-mute-duration: "7d"
|
||||||
|
default-mute-reason: "Без причины"
|
||||||
|
default-ban-reason: "Без причины"
|
||||||
|
|
||||||
|
# Команда после мута (для голосового чата)
|
||||||
voice-mute-console-command: ""
|
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. ▶)
|
# {separator} — separator (e.g. ▶)
|
||||||
# {player_prefix} — LuckPerms / gradient prefix from LoPreff
|
# {player_prefix} — LuckPerms / gradient prefix from LoPreff
|
||||||
# {player} — display name + hover (click to /msg)
|
# {player} — display name + hover (click to /msg)
|
||||||
|
# {player_suffix} — LuckPerms / gradient suffix from LoPreff
|
||||||
# {message} — message body
|
# {message} — message body
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# Default: {emoji} {prefix} {separator} {player} : {message}
|
# Default: {emoji} {prefix} {separator} {player} : {message}
|
||||||
# Minimal: {player_prefix} {player} ▶ {message}
|
# Minimal: {player_prefix} {player} ▶ {message}
|
||||||
# Custom: ✦ {player_prefix} {player} ▶ {message}
|
# Custom: ✦ {player_prefix} {player} {player_suffix} ▶ {message}
|
||||||
|
|
||||||
chat-format:
|
chat-format:
|
||||||
global: "{emoji} {prefix} {separator} {player} : {message}"
|
global: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix} : {message}"
|
||||||
local: "{emoji} {prefix} {separator} {player} : {message}"
|
local: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix} : {message}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Hover shown when pointing at the player name in chat │
|
# │ Hover shown when pointing at the player name in chat │
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ events:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
# Настройки входа на сервер
|
# Настройки входа на сервер
|
||||||
|
# {player} - ник игрока
|
||||||
join:
|
join:
|
||||||
enabled: true
|
enabled: true
|
||||||
title: "🟢 Игрок зашел на сервер"
|
title: "🟢 Игрок зашел на сервер"
|
||||||
|
|
@ -48,6 +49,7 @@ events:
|
||||||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||||
|
|
||||||
# Настройки выхода с сервера
|
# Настройки выхода с сервера
|
||||||
|
# {player} - ник игрока
|
||||||
quit:
|
quit:
|
||||||
enabled: true
|
enabled: true
|
||||||
title: "🔴 Игрок покинул сервер"
|
title: "🔴 Игрок покинул сервер"
|
||||||
|
|
@ -56,11 +58,27 @@ events:
|
||||||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||||
|
|
||||||
# Настройки смерти игрока
|
# Настройки смерти игрока
|
||||||
|
# {player} - ник игрока
|
||||||
|
# {killer} - ник убийцы (если есть)
|
||||||
|
# {weapon} - название оружия (если есть)
|
||||||
|
# {death_message} - стандартное сообщение смерти
|
||||||
death:
|
death:
|
||||||
enabled: true
|
enabled: true
|
||||||
title: "💀 Смерть игрока"
|
# Убийство игроком
|
||||||
description: "**{player}** {death_message}"
|
player_kill:
|
||||||
color: "800080"
|
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"
|
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||||
|
|
||||||
# Настройки фильтрации
|
# Настройки фильтрации
|
||||||
|
|
|
||||||
|
|
@ -1,286 +1,81 @@
|
||||||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||||
# ║ LoChat Filters Configuration ║
|
# ║ LoChat — Фильтры чата ║
|
||||||
# ║ Конфигурация фильтров ║
|
|
||||||
# ║ Версия: 1.5.5-1.20.1 ║
|
|
||||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ ФИЛЬТР ЗАГЛАВНЫХ БУКВ │
|
# │ Мат-фильтр │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
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:
|
swear:
|
||||||
# Включить фильтр мата
|
|
||||||
enabled: true
|
enabled: true
|
||||||
|
replace: false # true = заменять на ***, false = блокировать сообщение
|
||||||
# Использовать внешний файл со словами
|
replacement: "***"
|
||||||
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
|
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ ФИЛЬТР ФЛУДА │
|
# │ 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:
|
flood:
|
||||||
# Включить антифлуд
|
|
||||||
enabled: true
|
enabled: true
|
||||||
|
max-same-messages: 3 # Сколько раз можно отправить одно и то же
|
||||||
# Максимальное количество сообщений в период
|
|
||||||
max-messages: 5
|
|
||||||
|
|
||||||
# Период времени (секунды)
|
|
||||||
time-period: 10
|
|
||||||
|
|
||||||
# Действие при флуде: block, warn, mute
|
|
||||||
action: "warn"
|
|
||||||
|
|
||||||
# Сообщение при блокировке
|
|
||||||
block-message: "&#FF6B6BНе флудите!"
|
|
||||||
|
|
||||||
# Время мута за флуд (секунды)
|
|
||||||
mute-duration: 180
|
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ ДОПОЛНИТЕЛЬНЫЕ ФИЛЬТРЫ │
|
# │ Капс-фильтр │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
# Блокирует сообщения с большим количеством заглавных букв
|
||||||
|
# Обход: lochat.bypass.caps
|
||||||
|
|
||||||
additional:
|
caps:
|
||||||
# Фильтр эмодзи
|
|
||||||
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:
|
|
||||||
# Логировать заблокированные сообщения
|
|
||||||
enabled: true
|
enabled: true
|
||||||
|
max-caps-percent: 70 # Максимум % заглавных букв
|
||||||
# Файл для логов
|
min-length: 5 # Минимальная длина для проверки
|
||||||
file: "plugins/LoChat/logs/filter.log"
|
|
||||||
|
|
||||||
# Формат лога
|
|
||||||
format: "[{time}] {player} ({filter}): {message}"
|
|
||||||
|
|
||||||
# Логировать в консоль
|
|
||||||
console: true
|
|
||||||
|
|
||||||
# Уведомлять администраторов
|
|
||||||
notify-admins: true
|
|
||||||
|
|
||||||
# Право для получения уведомлений
|
|
||||||
notify-permission: "lochat.filter.notify"
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||||
# ║ LoChat — messages.yml ║
|
# ║ 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):
|
# Color roles (reference when editing strings below):
|
||||||
# &#B798A8 — primary labels / body (dusty rose)
|
# ẲE9 — primary labels / body (dusty rose)
|
||||||
# ⚖C9 — accents / separators (mid violet)
|
# ⚖C9 — accents / separators (mid violet)
|
||||||
# ẲE9 — emphasis / values (deep violet)
|
# ẲE9 — emphasis / values (deep violet)
|
||||||
# &f / #E8E0F0 — message body white
|
# &f / #E8E0F0 — message body white
|
||||||
# &#CF6679 — errors (muted red, fits the palette)
|
# &#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) │
|
# │ Global chat (toggle messages, server-disabled notice) │
|
||||||
|
|
@ -18,7 +18,7 @@ prefix: "&#B798A8[⚖C9LB6BD6oẲE9CⅵDChB6BD6a⚖C9t&#B798A8
|
||||||
|
|
||||||
global:
|
global:
|
||||||
toggled-on: "⚖C9Глобальный чат ẲE9включён"
|
toggled-on: "⚖C9Глобальный чат ẲE9включён"
|
||||||
toggled-off: "⚖C9Глобальный чат &#B798A8отключён"
|
toggled-off: "⚖C9Глобальный чат ẲE9отключён"
|
||||||
disabled: "&#CF6679Глобальный чат отключён на этом сервере"
|
disabled: "&#CF6679Глобальный чат отключён на этом сервере"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
|
@ -26,19 +26,19 @@ global:
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
local:
|
local:
|
||||||
no-players: "&#B798A8Рядом нет игроков"
|
no-players: "ẲE9Рядом нет игроков"
|
||||||
nobody-heard: "⚖C9Вас никто не услышал &#B798A8— рядом нет игроков"
|
nobody-heard: "⚖C9Вас никто не услышал ẲE9— рядом нет игроков"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Private messages (/msg, /reply) │
|
# │ Private messages (/msg, /reply) │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
pm:
|
pm:
|
||||||
format-sent: "&#B798A8[⚖C9→&#B798A8] ⚖C9Вы &#B798A8→ {receiver_display}&#B798A8: &f{message}"
|
format-sent: "ẲE9[⚖C9→ẲE9] ⚖C9Вы ẲE9→ {receiver_display}ẲE9: &f{message}"
|
||||||
format-received: "&#B798A8[⚖C9←&#B798A8] {sender_display} &#B798A8→ ⚖C9Вы&#B798A8: &f{message}"
|
format-received: "ẲE9[⚖C9←ẲE9] {sender_display} ẲE9→ ⚖C9ВыẲE9: &f{message}"
|
||||||
use-gradient-names: true
|
use-gradient-names: true
|
||||||
sent: "&#B798A8[⚖C9→&#B798A8] ⚖C9Вы &#B798A8→ &f{player}&#B798A8: &f{message}"
|
sent: "ẲE9[⚖C9→ẲE9] ⚖C9Вы ẲE9→ &f{player}ẲE9: &f{message}"
|
||||||
received: "&#B798A8[⚖C9←&#B798A8] &f{player} &#B798A8→ ⚖C9Вы&#B798A8: &f{message}"
|
received: "ẲE9[⚖C9←ẲE9] &f{player} ẲE9→ ⚖C9ВыẲE9: &f{message}"
|
||||||
no-reply: "&#CF6679Некому ответить"
|
no-reply: "&#CF6679Некому ответить"
|
||||||
ignored: "&#CF6679Этот игрок вас игнорирует"
|
ignored: "&#CF6679Этот игрок вас игнорирует"
|
||||||
player-offline: "&#CF6679Игрок не в сети"
|
player-offline: "&#CF6679Игрок не в сети"
|
||||||
|
|
@ -51,12 +51,12 @@ pm:
|
||||||
ignore:
|
ignore:
|
||||||
added: "⚖C9Игрок ẲE9{player} ⚖C9добавлен в игнор"
|
added: "⚖C9Игрок ẲE9{player} ⚖C9добавлен в игнор"
|
||||||
removed: "⚖C9Игрок ẲE9{player} ⚖C9убран из игнора"
|
removed: "⚖C9Игрок ẲE9{player} ⚖C9убран из игнора"
|
||||||
already-ignored: "&#B798A8Игрок ẲE9{player} &#B798A8уже в игноре"
|
already-ignored: "ẲE9Игрок ẲE9{player} ẲE9уже в игноре"
|
||||||
not-ignored: "&#B798A8Игрок ẲE9{player} &#B798A8не в игноре"
|
not-ignored: "ẲE9Игрок ẲE9{player} ẲE9не в игноре"
|
||||||
self: "&#CF6679Нельзя игнорировать самого себя"
|
self: "&#CF6679Нельзя игнорировать самого себя"
|
||||||
list-empty: "&#B798A8Ваш список игнора пуст"
|
list-empty: "ẲE9Ваш список игнора пуст"
|
||||||
list-header: "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
list-header: "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
||||||
list-footer: "&#B798A8Всего: ẲE9{count} &#B798A8игроков"
|
list-footer: "ẲE9Всего: ẲE9{count} ẲE9игроков"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Announcements │
|
# │ Announcements │
|
||||||
|
|
@ -71,9 +71,9 @@ announce:
|
||||||
|
|
||||||
spy:
|
spy:
|
||||||
enabled: "⚖C9Режим шпиона ẲE9включён"
|
enabled: "⚖C9Режим шпиона ẲE9включён"
|
||||||
disabled: "⚖C9Режим шпиона &#B798A8отключён"
|
disabled: "⚖C9Режим шпиона ẲE9отключён"
|
||||||
format: "&#B798A8[⚖C9SPY&#B798A8] ẲE9{sender} &#B798A8→ ⚖C9{receiver}&#B798A8: &f{message}"
|
format: "ẲE9[⚖C9SPYẲE9] ẲE9{sender} ẲE9→ ⚖C9{receiver}ẲE9: &f{message}"
|
||||||
chat-format: "&#B798A8[⚖C9SPY&#B798A8] &#B798A8{type} ẲE9{sender}&#B798A8: &f{message}"
|
chat-format: "ẲE9[⚖C9SPYẲE9] ẲE9{type} ẲE9{sender}ẲE9: &f{message}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Message filters │
|
# │ Message filters │
|
||||||
|
|
@ -81,14 +81,14 @@ spy:
|
||||||
|
|
||||||
filter:
|
filter:
|
||||||
blocked: "&#CF6679Сообщение заблокировано"
|
blocked: "&#CF6679Сообщение заблокировано"
|
||||||
warning: "&#B798A8Предупреждение"
|
warning: "ẲE9Предупреждение"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Cooldowns │
|
# │ Cooldowns │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
cooldown:
|
cooldown:
|
||||||
wait: "&#B798A8Подождите ẲE9{time} &#B798A8сек"
|
wait: "ẲE9Подождите ẲE9{time} ẲE9сек"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Anti-spam (caps, repeat, similar messages) │
|
# │ Anti-spam (caps, repeat, similar messages) │
|
||||||
|
|
@ -104,7 +104,7 @@ antispam:
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
clearchat:
|
clearchat:
|
||||||
cleared: "⚖C9Чат очищен &#B798A8администратором ẲE9{player}"
|
cleared: "⚖C9Чат очищен ẲE9администратором ẲE9{player}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Command / usage errors │
|
# │ Command / usage errors │
|
||||||
|
|
@ -113,7 +113,7 @@ clearchat:
|
||||||
errors:
|
errors:
|
||||||
no-permission: "&#CF6679Нет прав"
|
no-permission: "&#CF6679Нет прав"
|
||||||
player-not-found: "&#CF6679Игрок не найден"
|
player-not-found: "&#CF6679Игрок не найден"
|
||||||
invalid-usage: "&#B798A8Использование: ẲE9{usage}"
|
invalid-usage: "ẲE9Использование: ẲE9{usage}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ General (permissions, reload, hub, etc.) │
|
# │ General (permissions, reload, hub, etc.) │
|
||||||
|
|
@ -124,7 +124,7 @@ general:
|
||||||
players-only: "&#CF6679Только для игроков!"
|
players-only: "&#CF6679Только для игроков!"
|
||||||
config-reloaded: "⚖C9Конфиг ẲE9перезагружен!"
|
config-reloaded: "⚖C9Конфиг ẲE9перезагружен!"
|
||||||
invalid-player: "&#CF6679Игрок ẲE9{player} &#CF6679не найден!"
|
invalid-player: "&#CF6679Игрок ẲE9{player} &#CF6679не найден!"
|
||||||
cooldown-active: "&#B798A8Подождите ẲE9{time}с"
|
cooldown-active: "ẲE9Подождите ẲE9{time}с"
|
||||||
command-disabled: "&#CF6679Команда отключена!"
|
command-disabled: "&#CF6679Команда отключена!"
|
||||||
|
|
||||||
hub:
|
hub:
|
||||||
|
|
@ -137,9 +137,9 @@ hub:
|
||||||
mute:
|
mute:
|
||||||
muted: "⚖C9Игрок ẲE9{player} ⚖C9замучен на ẲE9{time}"
|
muted: "⚖C9Игрок ẲE9{player} ⚖C9замучен на ẲE9{time}"
|
||||||
unmuted: "⚖C9Игрок ẲE9{player} ⚖C9размучен"
|
unmuted: "⚖C9Игрок ẲE9{player} ⚖C9размучен"
|
||||||
already-muted: "&#B798A8Игрок ẲE9{player} &#B798A8уже замучен"
|
already-muted: "ẲE9Игрок ẲE9{player} ẲE9уже замучен"
|
||||||
not-muted: "&#B798A8Игрок ẲE9{player} &#B798A8не замучен"
|
not-muted: "ẲE9Игрок ẲE9{player} ẲE9не замучен"
|
||||||
you-muted: "&#CF6679Вы замучены! &#B798A8Осталось: ẲE9{time}"
|
you-muted: "&#CF6679Вы замучены! ẲE9Осталось: ẲE9{time}"
|
||||||
permanent: "&#CF6679Вы замучены навсегда!"
|
permanent: "&#CF6679Вы замучены навсегда!"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
|
@ -149,32 +149,32 @@ mute:
|
||||||
gradient:
|
gradient:
|
||||||
color-set: "⚖C9Градиент ẲE9установлен!"
|
color-set: "⚖C9Градиент ẲE9установлен!"
|
||||||
color-enabled: "⚖C9Градиентный ник ẲE9включён"
|
color-enabled: "⚖C9Градиентный ник ẲE9включён"
|
||||||
color-disabled: "&#B798A8Градиентный ник ⚖C9отключён"
|
color-disabled: "ẲE9Градиентный ник ⚖C9отключён"
|
||||||
color-reset: "&#B798A8Градиент сброшен"
|
color-reset: "ẲE9Градиент сброшен"
|
||||||
prefix-set: "⚖C9Префикс ẲE9установлен!"
|
prefix-set: "⚖C9Префикс ẲE9установлен!"
|
||||||
prefix-reset: "&#B798A8Префикс сброшен"
|
prefix-reset: "ẲE9Префикс сброшен"
|
||||||
prefix-reset-success: "⚖C9Префикс успешно ẲE9сброшен!"
|
prefix-reset-success: "⚖C9Префикс успешно ẲE9сброшен!"
|
||||||
prefix-enabled: "⚖C9Префикс ẲE9включён"
|
prefix-enabled: "⚖C9Префикс ẲE9включён"
|
||||||
prefix-disabled: "&#B798A8Префикс ⚖C9отключён"
|
prefix-disabled: "ẲE9Префикс ⚖C9отключён"
|
||||||
invalid-hex: "&#CF6679Неверный HEX цвет: ẲE9{color}"
|
invalid-hex: "&#CF6679Неверный HEX цвет: ẲE9{color}"
|
||||||
invalid-color: "&#CF6679Неверный цвет: ẲE9{color}"
|
invalid-color: "&#CF6679Неверный цвет: ẲE9{color}"
|
||||||
too-many-colors: "&#CF6679Слишком много цветов! Максимум: ẲE9{max}"
|
too-many-colors: "&#CF6679Слишком много цветов! Максимум: ẲE9{max}"
|
||||||
too-few-colors: "&#CF6679Слишком мало цветов! Минимум: ẲE9{min}"
|
too-few-colors: "&#CF6679Слишком мало цветов! Минимум: ẲE9{min}"
|
||||||
not-enough-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: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||||
not-enough-points-color: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
not-enough-points-color: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||||
not-enough-points-prefix: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
not-enough-points-prefix: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||||
player-not-found: "&#CF6679Игрок не найден"
|
player-not-found: "&#CF6679Игрок не найден"
|
||||||
color-help: "&#B798A8Использование: ẲE9/color <HEX1> <HEX2>"
|
color-help: "ẲE9Использование: ẲE9/color <HEX1> <HEX2>"
|
||||||
color-success: "⚖C9Градиент успешно ẲE9установлен!"
|
color-success: "⚖C9Градиент успешно ẲE9установлен!"
|
||||||
color-no-colors: "&#B798A8У вас нет установленных цветов"
|
color-no-colors: "ẲE9У вас нет установленных цветов"
|
||||||
color-copy-usage: "&#B798A8Использование: ẲE9/color copy <игрок>"
|
color-copy-usage: "ẲE9Использование: ẲE9/color copy <игрок>"
|
||||||
color-copy-no-colors: "&#B798A8У игрока ẲE9{player} &#B798A8нет цветов"
|
color-copy-no-colors: "ẲE9У игрока ẲE9{player} ẲE9нет цветов"
|
||||||
prefix-help: "&#B798A8Использование: ẲE9/prefix <текст> &#B798A8или ẲE9/prefix reset"
|
prefix-help: "ẲE9Использование: ẲE9/prefix <текст> ẲE9или ẲE9/prefix reset"
|
||||||
prefix-success: "⚖C9Префикс установлен! &#B798A8Стоимость: ẲE9{price} &#B798A8поинтов"
|
prefix-success: "⚖C9Префикс установлен! ẲE9Стоимость: ẲE9{price} ẲE9поинтов"
|
||||||
prefix-success-free: "⚖C9Префикс ẲE9установлен!"
|
prefix-success-free: "⚖C9Префикс ẲE9установлен!"
|
||||||
prefix-no-prefix: "&#B798A8У вас нет префикса"
|
prefix-no-prefix: "ẲE9У вас нет префикса"
|
||||||
prefix-too-long: "&#CF6679Префикс слишком длинный! Максимум: ẲE9{max}"
|
prefix-too-long: "&#CF6679Префикс слишком длинный! Максимум: ẲE9{max}"
|
||||||
prefix-no-colors: "&#CF6679Префикс не может содержать цветовые коды!"
|
prefix-no-colors: "&#CF6679Префикс не может содержать цветовые коды!"
|
||||||
prefix-invalid-chars: "&#CF6679Недопустимые символы в префиксе!"
|
prefix-invalid-chars: "&#CF6679Недопустимые символы в префиксе!"
|
||||||
|
|
@ -182,30 +182,30 @@ gradient:
|
||||||
only-player: "&#CF6679Только для игроков!"
|
only-player: "&#CF6679Только для игроков!"
|
||||||
no-permission: "&#CF6679Нет прав!"
|
no-permission: "&#CF6679Нет прав!"
|
||||||
reload-success: "⚖C9Конфигурация ẲE9перезагружена!"
|
reload-success: "⚖C9Конфигурация ẲE9перезагружена!"
|
||||||
info-header: "ẲE9▬▬▬▬▬▬▬▬ &#B798A8{player} ẲE9▬▬▬▬▬▬▬▬"
|
info-header: "ẲE9▬▬▬▬▬▬▬▬ ẲE9{player} ẲE9▬▬▬▬▬▬▬▬"
|
||||||
info-prefix: "&#B798A8Префикс: &f{prefix}"
|
info-prefix: "ẲE9Префикс: &f{prefix}"
|
||||||
info-prefix-enabled: "&#B798A8Префикс активен: &f{enabled}"
|
info-prefix-enabled: "ẲE9Префикс активен: &f{enabled}"
|
||||||
info-colors: "&#B798A8Цвета: &f{colors}"
|
info-colors: "ẲE9Цвета: &f{colors}"
|
||||||
info-color-enabled: "&#B798A8Цвет активен: &f{enabled}"
|
info-color-enabled: "ẲE9Цвет активен: &f{enabled}"
|
||||||
info-prefix-purchased: "&#B798A8Куплен: &f{purchased}"
|
info-prefix-purchased: "ẲE9Куплен: &f{purchased}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Custom nicknames (/nick) │
|
# │ Custom nicknames (/nick) │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
nick:
|
nick:
|
||||||
current: "&#B798A8Ваш ник: ẲE9{nick}"
|
current: "ẲE9Ваш ник: ẲE9{nick}"
|
||||||
usage: "&#B798A8Использование: ẲE9/nick <ник> &#B798A8или ẲE9/nick reset"
|
usage: "ẲE9Использование: ẲE9/nick <ник> ẲE9или ẲE9/nick reset"
|
||||||
reset-usage: "&#B798A8Используйте ẲE9/nick reset &#B798A8для сброса"
|
reset-usage: "ẲE9Используйте ẲE9/nick reset ẲE9для сброса"
|
||||||
set-usage: "&#B798A8Используйте ẲE9/nick <ник> &#B798A8для установки"
|
set-usage: "ẲE9Используйте ẲE9/nick <ник> ẲE9для установки"
|
||||||
no-nick: "&#B798A8У вас нет кастомного ника"
|
no-nick: "ẲE9У вас нет кастомного ника"
|
||||||
reset-success: "⚖C9Ник ẲE9сброшен!"
|
reset-success: "⚖C9Ник ẲE9сброшен!"
|
||||||
set-success: "⚖C9Ник изменён на: &f{nick}"
|
set-success: "⚖C9Ник изменён на: &f{nick}"
|
||||||
invalid: "&#CF6679Невалидный ник!"
|
invalid: "&#CF6679Невалидный ник!"
|
||||||
requirements-header: "&#B798A8Требования:"
|
requirements-header: "ẲE9Требования:"
|
||||||
requirements-length: "⚖C9◆ &fДлина: 3-16 символов"
|
requirements-length: "⚖C9◆ &fДлина: 3-16 символов"
|
||||||
requirements-chars: "⚖C9◆ &fБуквы, цифры, _, русские буквы"
|
requirements-chars: "⚖C9◆ &fБуквы, цифры, _, русские буквы"
|
||||||
requirements-colors: "⚖C9◆ &fЦвета: ẲE9&#RRGGBB&#B798A8текст"
|
requirements-colors: "⚖C9◆ &fЦвета: ẲE9&#RRGGBBẲE9текст"
|
||||||
taken: "&#CF6679Этот ник уже занят!"
|
taken: "&#CF6679Этот ник уже занят!"
|
||||||
error: "&#CF6679Не удалось установить ник!"
|
error: "&#CF6679Не удалось установить ник!"
|
||||||
|
|
||||||
|
|
@ -214,12 +214,12 @@ nick:
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
rp:
|
rp:
|
||||||
me: "<color:#B798A8>* {player} {action}</color>"
|
me: "<color:#7858E9>* {player} {action}</color>"
|
||||||
try-format: "<color:#B798A8>* {player} пытается {action}...</color> {result}"
|
try-format: "<color:#7858E9>* {player} пытается {action}...</color> {result}"
|
||||||
try-success: "<color:#9878C9><bold>[Успех!]</bold></color>"
|
try-success: "<color:#9878C9><bold>[Успех!]</bold></color>"
|
||||||
try-fail: "<color:#CF6679><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>"
|
do-format: "<color:#7858E9>[<color:#7858E9>Сцена</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>"
|
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-min-error: "<color:#CF6679>Минимальное значение кубика: 2</color>"
|
||||||
roll-max-error: "<color:#CF6679>Максимальное значение: 1000000</color>"
|
roll-max-error: "<color:#CF6679>Максимальное значение: 1000000</color>"
|
||||||
roll-invalid-number: "<color:#CF6679>Укажите число: /roll [максимум]</color>"
|
roll-invalid-number: "<color:#CF6679>Укажите число: /roll [максимум]</color>"
|
||||||
|
|
|
||||||
|
|
@ -275,4 +275,38 @@ public class ConfigManager {
|
||||||
public boolean useCustomPrefix() {
|
public boolean useCustomPrefix() {
|
||||||
return config.getBoolean("lopreff.use-custom-prefix", true);
|
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
|
new ChatEventListener(plugin, serviceRegistry, filter), plugin
|
||||||
);
|
);
|
||||||
plugin.getServer().getPluginManager().registerEvents(
|
plugin.getServer().getPluginManager().registerEvents(
|
||||||
new PlayerEventListener(serviceRegistry, filter), plugin
|
new PlayerEventListener(plugin, serviceRegistry, filter), plugin
|
||||||
);
|
);
|
||||||
plugin.getServer().getPluginManager().registerEvents(
|
plugin.getServer().getPluginManager().registerEvents(
|
||||||
new ModerationListener(serviceRegistry), plugin
|
new ModerationListener(serviceRegistry), plugin
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,7 @@ import java.io.BufferedReader;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class SwearFilter {
|
public class SwearFilter {
|
||||||
|
|
@ -20,6 +18,22 @@ public class SwearFilter {
|
||||||
private final String replacement;
|
private final String replacement;
|
||||||
private final Set<Pattern> swearPatterns = new HashSet<>();
|
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) {
|
public SwearFilter(FileConfiguration config, JavaPlugin plugin) {
|
||||||
this.enabled = config.getBoolean("filters.swear.enabled", true);
|
this.enabled = config.getBoolean("filters.swear.enabled", true);
|
||||||
this.replaceMode = config.getBoolean("filters.swear.replace", false);
|
this.replaceMode = config.getBoolean("filters.swear.replace", false);
|
||||||
|
|
@ -37,14 +51,47 @@ public class SwearFilter {
|
||||||
reader.lines()
|
reader.lines()
|
||||||
.map(String::trim)
|
.map(String::trim)
|
||||||
.filter(line -> !line.isEmpty() && !line.startsWith("#"))
|
.filter(line -> !line.isEmpty() && !line.startsWith("#"))
|
||||||
.forEach(word -> swearPatterns.add(
|
.forEach(word -> {
|
||||||
Pattern.compile("\\b" + Pattern.quote(word) + "\\b", Pattern.CASE_INSENSITIVE)
|
// Создаем паттерн с учетом возможной замены букв
|
||||||
));
|
String regex = buildFlexiblePattern(word);
|
||||||
|
swearPatterns.add(Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE));
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
plugin.getLogger().warning("Failed to load badwords.txt: " + e.getMessage());
|
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) {
|
public FilterResult filter(Player player, String message) {
|
||||||
if (!enabled || player.hasPermission("lochat.bypass.swear")) {
|
if (!enabled || player.hasPermission("lochat.bypass.swear")) {
|
||||||
return FilterResult.ok(message);
|
return FilterResult.ok(message);
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,16 @@ public class GradientModule {
|
||||||
return prefixService.getPrefix(player, data);
|
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 префикс
|
* Получает только 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) {
|
public String getFullName(Player player, GradientPlayerData data) {
|
||||||
String prefix = getPrefix(player, data);
|
String prefix = getPrefix(player, data);
|
||||||
|
String suffix = getLuckPermsSuffix(player, data);
|
||||||
String nick = player.getName();
|
String nick = player.getName();
|
||||||
|
|
||||||
// Применяем градиент к нику если есть цвета
|
// Применяем градиент к нику если есть цвета
|
||||||
|
|
@ -90,7 +127,12 @@ public class PrefixService {
|
||||||
nick = GradientService.applyGradient(nick, data.getColors());
|
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) {
|
public String getFullNameForTab(Player player, GradientPlayerData data) {
|
||||||
String prefix = getPrefix(player, data);
|
String prefix = getPrefix(player, data);
|
||||||
|
String suffix = getLuckPermsSuffix(player, data);
|
||||||
String nick = player.getName();
|
String nick = player.getName();
|
||||||
|
|
||||||
// Применяем градиент в формате TAB
|
// Применяем градиент в формате TAB
|
||||||
|
|
@ -105,7 +148,12 @@ public class PrefixService {
|
||||||
nick = GradientService.applyGradientForTab(nick, data.getColors());
|
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() {
|
public boolean isLuckPermsAvailable() {
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,42 @@
|
||||||
package com.loki.lochat.listener;
|
package com.loki.lochat.listener;
|
||||||
|
|
||||||
|
import com.loki.lochat.LoChat;
|
||||||
import com.loki.lochat.api.service.MessagingService;
|
import com.loki.lochat.api.service.MessagingService;
|
||||||
import com.loki.lochat.api.service.NickService;
|
import com.loki.lochat.api.service.NickService;
|
||||||
import com.loki.lochat.api.service.PlayerService;
|
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.filter.AdvancedMessageFilter;
|
||||||
import com.loki.lochat.core.registry.ServiceRegistry;
|
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.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Слушатель событий игрока
|
* Слушатель событий игрока
|
||||||
*/
|
*/
|
||||||
public class PlayerEventListener implements Listener {
|
public class PlayerEventListener implements Listener {
|
||||||
|
private final LoChat plugin;
|
||||||
private final PlayerService playerService;
|
private final PlayerService playerService;
|
||||||
private final MessagingService messagingService;
|
private final MessagingService messagingService;
|
||||||
private final NickService nickService;
|
private final NickService nickService;
|
||||||
private final AdvancedMessageFilter advancedFilter;
|
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.playerService = registry.get(PlayerService.class);
|
||||||
this.messagingService = registry.get(MessagingService.class);
|
this.messagingService = registry.get(MessagingService.class);
|
||||||
this.nickService = registry.get(NickService.class);
|
this.nickService = registry.get(NickService.class);
|
||||||
this.advancedFilter = advancedFilter;
|
this.advancedFilter = advancedFilter;
|
||||||
|
this.configManager = plugin.getConfigManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
|
|
@ -33,6 +45,13 @@ public class PlayerEventListener implements Listener {
|
||||||
if (nickService != null) {
|
if (nickService != null) {
|
||||||
nickService.updatePlayerDisplay(player);
|
nickService.updatePlayerDisplay(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Кастомное сообщение входа
|
||||||
|
if (configManager.isJoinMessageEnabled()) {
|
||||||
|
String format = configManager.getJoinMessageFormat();
|
||||||
|
String message = format.replace("{player}", player.getName());
|
||||||
|
event.joinMessage(ChatFormatter.parse(message));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
|
|
@ -44,7 +63,110 @@ public class PlayerEventListener implements Listener {
|
||||||
messagingService.removeConversation(uuid);
|
messagingService.removeConversation(uuid);
|
||||||
messagingService.removeSpy(uuid);
|
messagingService.removeSpy(uuid);
|
||||||
|
|
||||||
// Очищаем flood / spam трекеры — иначе данные висят в памяти вечно
|
// Очищаем flood / spam трекеры
|
||||||
advancedFilter.clearPlayer(uuid);
|
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 prefix = buildPrefix();
|
||||||
Component separator = buildSeparator();
|
Component separator = buildSeparator();
|
||||||
Component playerPrefix = buildPlayerPrefix(source);
|
Component playerPrefix = buildPlayerPrefix(source);
|
||||||
|
Component playerSuffix = buildPlayerSuffix(source);
|
||||||
Component player = buildPlayerComponent(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,
|
private Component buildFormattedMessage(String format, Component emoji, Component prefix,
|
||||||
Component separator, Component playerPrefix,
|
Component separator, Component playerPrefix, Component playerSuffix,
|
||||||
Component player, Component message) {
|
Component player, Component message) {
|
||||||
Component result = Component.empty();
|
Component result = Component.empty();
|
||||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\{([^}]+)\\}");
|
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 "separator" -> result = result.append(separator);
|
||||||
case "player_prefix" -> result = result.append(playerPrefix);
|
case "player_prefix" -> result = result.append(playerPrefix);
|
||||||
case "player" -> result = result.append(player);
|
case "player" -> result = result.append(player);
|
||||||
|
case "player_suffix" -> result = result.append(playerSuffix);
|
||||||
case "message" -> result = result.append(message);
|
case "message" -> result = result.append(message);
|
||||||
default -> result = result.append(Component.text("{" + placeholder + "}"));
|
default -> result = result.append(Component.text("{" + placeholder + "}"));
|
||||||
}
|
}
|
||||||
|
|
@ -117,6 +119,20 @@ public class EnhancedChatRenderer implements ChatRenderer {
|
||||||
return Component.empty();
|
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() {
|
private Component buildPrefix() {
|
||||||
com.loki.lochat.config.AppearanceConfig appearanceCfg = cfg.getAppearanceConfig();
|
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]"
|
prefix: "�D4FF[LoChat]"
|
||||||
|
|
||||||
# Базовые настройки чата
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# Детальные настройки (префиксы, цвета, форматы) в config/*.yml
|
# │ Режимы чата │
|
||||||
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
chat:
|
chat:
|
||||||
# Режим чата:
|
# Глобальный чат (все видят, активируется через "!")
|
||||||
# - Оба включены = локальный (по умолчанию) + глобальный (с "!")
|
|
||||||
# - Только global = единый чат без префиксов для всех
|
|
||||||
global:
|
global:
|
||||||
enabled: true
|
enabled: true
|
||||||
cooldown: 3
|
cooldown: 3
|
||||||
|
|
||||||
|
# Локальный чат (только в радиусе)
|
||||||
local:
|
local:
|
||||||
enabled: true
|
enabled: true
|
||||||
cooldown: 1
|
cooldown: 1
|
||||||
|
radius: 100
|
||||||
|
|
||||||
|
# Личные сообщения
|
||||||
pm:
|
pm:
|
||||||
enabled: true
|
enabled: true
|
||||||
cooldown: 2
|
cooldown: 2
|
||||||
|
|
||||||
# Hub команда
|
# Лимиты сообщений
|
||||||
hub_command:
|
min_message_length: 1
|
||||||
enabled: true
|
max_message_length: 2000
|
||||||
server: "hub"
|
clear_lines: 100
|
||||||
|
|
||||||
# Градиентные ники
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
lopreff:
|
# │ Внешний вид чата (префиксы, форматы, цвета) │
|
||||||
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
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"
|
||||||
|
|
||||||
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ Градиентные ники и префиксы │
|
||||||
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
gradient:
|
||||||
enabled: true
|
enabled: true
|
||||||
use-gradient-name: true
|
use-gradient-name: true
|
||||||
use-custom-prefix: true
|
use-custom-prefix: true
|
||||||
|
|
||||||
display:
|
# Настройки отображения
|
||||||
update-display-name: true
|
display:
|
||||||
update-tab-list: true
|
update-display-name: true
|
||||||
|
update-tab-list: true
|
||||||
|
|
||||||
# Градиенты (детали в config/gradient.yml)
|
# Лимиты
|
||||||
gradient:
|
|
||||||
storage-type: "file"
|
|
||||||
min-colors: 1
|
min-colors: 1
|
||||||
max-colors: 7
|
max-colors: 7
|
||||||
|
max-prefix-length: 16
|
||||||
|
|
||||||
|
# Цены (PlayerPoints)
|
||||||
price-per-color: 50
|
price-per-color: 50
|
||||||
prefix-price: 500
|
prefix-price: 500
|
||||||
prefix-one-time-purchase: true
|
prefix-one-time-purchase: true
|
||||||
use-permission-instead-of-cost: false
|
use-permission-instead-of-cost: false
|
||||||
max-prefix-length: 16
|
|
||||||
|
# Кулдауны (секунды)
|
||||||
color-cooldown: 60
|
color-cooldown: 60
|
||||||
prefix-cooldown: 120
|
prefix-cooldown: 120
|
||||||
|
|
||||||
|
# Форматирование
|
||||||
prefix-format: "[{prefix}] "
|
prefix-format: "[{prefix}] "
|
||||||
gradient-on-prefix: true
|
gradient-on-prefix: true
|
||||||
gradient-on-luckperms-prefix: true
|
gradient-on-luckperms-prefix: true
|
||||||
|
gradient-on-luckperms-suffix: true
|
||||||
continuous-gradient: true
|
continuous-gradient: true
|
||||||
use-legacy-rgb-format: true
|
use-legacy-rgb-format: true
|
||||||
|
|
||||||
# RP команды (детали в config/rp.yml)
|
# Хранилище (file / sqlite)
|
||||||
|
storage-type: "file"
|
||||||
|
sqlite-file: "gradient-data.db"
|
||||||
|
|
||||||
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ RP команды (/me, /do, /try, /roll) │
|
||||||
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
rp:
|
rp:
|
||||||
radius: 100
|
radius: 100
|
||||||
cooldowns:
|
cooldowns:
|
||||||
|
|
@ -61,6 +146,126 @@ rp:
|
||||||
do: 3
|
do: 3
|
||||||
roll: 2
|
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:
|
moderation:
|
||||||
|
# Дефолтные значения
|
||||||
|
default-mute-duration: "7d"
|
||||||
|
default-mute-reason: "Без причины"
|
||||||
|
default-ban-reason: "Без причины"
|
||||||
|
|
||||||
|
# Команда после мута (для голосового чата)
|
||||||
voice-mute-console-command: ""
|
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. ▶)
|
# {separator} — separator (e.g. ▶)
|
||||||
# {player_prefix} — LuckPerms / gradient prefix from LoPreff
|
# {player_prefix} — LuckPerms / gradient prefix from LoPreff
|
||||||
# {player} — display name + hover (click to /msg)
|
# {player} — display name + hover (click to /msg)
|
||||||
|
# {player_suffix} — LuckPerms / gradient suffix from LoPreff
|
||||||
# {message} — message body
|
# {message} — message body
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# Default: {emoji} {prefix} {separator} {player} : {message}
|
# Default: {emoji} {prefix} {separator} {player} : {message}
|
||||||
# Minimal: {player_prefix} {player} ▶ {message}
|
# Minimal: {player_prefix} {player} ▶ {message}
|
||||||
# Custom: ✦ {player_prefix} {player} ▶ {message}
|
# Custom: ✦ {player_prefix} {player} {player_suffix} ▶ {message}
|
||||||
|
|
||||||
chat-format:
|
chat-format:
|
||||||
global: "{emoji} {prefix} {separator} {player} : {message}"
|
global: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix} : {message}"
|
||||||
local: "{emoji} {prefix} {separator} {player} : {message}"
|
local: "{emoji} {prefix} {separator} {player_prefix}{player}{player_suffix} : {message}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Hover shown when pointing at the player name in chat │
|
# │ Hover shown when pointing at the player name in chat │
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ events:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
# Настройки входа на сервер
|
# Настройки входа на сервер
|
||||||
|
# {player} - ник игрока
|
||||||
join:
|
join:
|
||||||
enabled: true
|
enabled: true
|
||||||
title: "🟢 Игрок зашел на сервер"
|
title: "🟢 Игрок зашел на сервер"
|
||||||
|
|
@ -48,6 +49,7 @@ events:
|
||||||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||||
|
|
||||||
# Настройки выхода с сервера
|
# Настройки выхода с сервера
|
||||||
|
# {player} - ник игрока
|
||||||
quit:
|
quit:
|
||||||
enabled: true
|
enabled: true
|
||||||
title: "🔴 Игрок покинул сервер"
|
title: "🔴 Игрок покинул сервер"
|
||||||
|
|
@ -56,11 +58,27 @@ events:
|
||||||
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||||
|
|
||||||
# Настройки смерти игрока
|
# Настройки смерти игрока
|
||||||
|
# {player} - ник игрока
|
||||||
|
# {killer} - ник убийцы (если есть)
|
||||||
|
# {weapon} - название оружия (если есть)
|
||||||
|
# {death_message} - стандартное сообщение смерти
|
||||||
death:
|
death:
|
||||||
enabled: true
|
enabled: true
|
||||||
title: "💀 Смерть игрока"
|
# Убийство игроком
|
||||||
description: "**{player}** {death_message}"
|
player_kill:
|
||||||
color: "800080"
|
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"
|
thumbnail: "https://mc-heads.net/avatar/{player}/64"
|
||||||
|
|
||||||
# Настройки фильтрации
|
# Настройки фильтрации
|
||||||
|
|
|
||||||
|
|
@ -1,286 +1,81 @@
|
||||||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||||
# ║ LoChat Filters Configuration ║
|
# ║ LoChat — Фильтры чата ║
|
||||||
# ║ Конфигурация фильтров ║
|
|
||||||
# ║ Версия: 1.5.5-1.20.1 ║
|
|
||||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ ФИЛЬТР ЗАГЛАВНЫХ БУКВ │
|
# │ Мат-фильтр │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
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:
|
swear:
|
||||||
# Включить фильтр мата
|
|
||||||
enabled: true
|
enabled: true
|
||||||
|
replace: false # true = заменять на ***, false = блокировать сообщение
|
||||||
# Использовать внешний файл со словами
|
replacement: "***"
|
||||||
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
|
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ ФИЛЬТР ФЛУДА │
|
# │ 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:
|
flood:
|
||||||
# Включить антифлуд
|
|
||||||
enabled: true
|
enabled: true
|
||||||
|
max-same-messages: 3 # Сколько раз можно отправить одно и то же
|
||||||
# Максимальное количество сообщений в период
|
|
||||||
max-messages: 5
|
|
||||||
|
|
||||||
# Период времени (секунды)
|
|
||||||
time-period: 10
|
|
||||||
|
|
||||||
# Действие при флуде: block, warn, mute
|
|
||||||
action: "warn"
|
|
||||||
|
|
||||||
# Сообщение при блокировке
|
|
||||||
block-message: "&#FF6B6BНе флудите!"
|
|
||||||
|
|
||||||
# Время мута за флуд (секунды)
|
|
||||||
mute-duration: 180
|
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ ДОПОЛНИТЕЛЬНЫЕ ФИЛЬТРЫ │
|
# │ Капс-фильтр │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
# Блокирует сообщения с большим количеством заглавных букв
|
||||||
|
# Обход: lochat.bypass.caps
|
||||||
|
|
||||||
additional:
|
caps:
|
||||||
# Фильтр эмодзи
|
|
||||||
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:
|
|
||||||
# Логировать заблокированные сообщения
|
|
||||||
enabled: true
|
enabled: true
|
||||||
|
max-caps-percent: 70 # Максимум % заглавных букв
|
||||||
# Файл для логов
|
min-length: 5 # Минимальная длина для проверки
|
||||||
file: "plugins/LoChat/logs/filter.log"
|
|
||||||
|
|
||||||
# Формат лога
|
|
||||||
format: "[{time}] {player} ({filter}): {message}"
|
|
||||||
|
|
||||||
# Логировать в консоль
|
|
||||||
console: true
|
|
||||||
|
|
||||||
# Уведомлять администраторов
|
|
||||||
notify-admins: true
|
|
||||||
|
|
||||||
# Право для получения уведомлений
|
|
||||||
notify-permission: "lochat.filter.notify"
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||||
# ║ LoChat — messages.yml ║
|
# ║ 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):
|
# Color roles (reference when editing strings below):
|
||||||
# &#B798A8 — primary labels / body (dusty rose)
|
# ẲE9 — primary labels / body (dusty rose)
|
||||||
# ⚖C9 — accents / separators (mid violet)
|
# ⚖C9 — accents / separators (mid violet)
|
||||||
# ẲE9 — emphasis / values (deep violet)
|
# ẲE9 — emphasis / values (deep violet)
|
||||||
# &f / #E8E0F0 — message body white
|
# &f / #E8E0F0 — message body white
|
||||||
# &#CF6679 — errors (muted red, fits the palette)
|
# &#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) │
|
# │ Global chat (toggle messages, server-disabled notice) │
|
||||||
|
|
@ -18,7 +18,7 @@ prefix: "&#B798A8[⚖C9LB6BD6oẲE9CⅵDChB6BD6a⚖C9t&#B798A8
|
||||||
|
|
||||||
global:
|
global:
|
||||||
toggled-on: "⚖C9Глобальный чат ẲE9включён"
|
toggled-on: "⚖C9Глобальный чат ẲE9включён"
|
||||||
toggled-off: "⚖C9Глобальный чат &#B798A8отключён"
|
toggled-off: "⚖C9Глобальный чат ẲE9отключён"
|
||||||
disabled: "&#CF6679Глобальный чат отключён на этом сервере"
|
disabled: "&#CF6679Глобальный чат отключён на этом сервере"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
|
@ -26,19 +26,19 @@ global:
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
local:
|
local:
|
||||||
no-players: "&#B798A8Рядом нет игроков"
|
no-players: "ẲE9Рядом нет игроков"
|
||||||
nobody-heard: "⚖C9Вас никто не услышал &#B798A8— рядом нет игроков"
|
nobody-heard: "⚖C9Вас никто не услышал ẲE9— рядом нет игроков"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Private messages (/msg, /reply) │
|
# │ Private messages (/msg, /reply) │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
pm:
|
pm:
|
||||||
format-sent: "&#B798A8[⚖C9→&#B798A8] ⚖C9Вы &#B798A8→ {receiver_display}&#B798A8: &f{message}"
|
format-sent: "ẲE9[⚖C9→ẲE9] ⚖C9Вы ẲE9→ {receiver_display}ẲE9: &f{message}"
|
||||||
format-received: "&#B798A8[⚖C9←&#B798A8] {sender_display} &#B798A8→ ⚖C9Вы&#B798A8: &f{message}"
|
format-received: "ẲE9[⚖C9←ẲE9] {sender_display} ẲE9→ ⚖C9ВыẲE9: &f{message}"
|
||||||
use-gradient-names: true
|
use-gradient-names: true
|
||||||
sent: "&#B798A8[⚖C9→&#B798A8] ⚖C9Вы &#B798A8→ &f{player}&#B798A8: &f{message}"
|
sent: "ẲE9[⚖C9→ẲE9] ⚖C9Вы ẲE9→ &f{player}ẲE9: &f{message}"
|
||||||
received: "&#B798A8[⚖C9←&#B798A8] &f{player} &#B798A8→ ⚖C9Вы&#B798A8: &f{message}"
|
received: "ẲE9[⚖C9←ẲE9] &f{player} ẲE9→ ⚖C9ВыẲE9: &f{message}"
|
||||||
no-reply: "&#CF6679Некому ответить"
|
no-reply: "&#CF6679Некому ответить"
|
||||||
ignored: "&#CF6679Этот игрок вас игнорирует"
|
ignored: "&#CF6679Этот игрок вас игнорирует"
|
||||||
player-offline: "&#CF6679Игрок не в сети"
|
player-offline: "&#CF6679Игрок не в сети"
|
||||||
|
|
@ -51,12 +51,12 @@ pm:
|
||||||
ignore:
|
ignore:
|
||||||
added: "⚖C9Игрок ẲE9{player} ⚖C9добавлен в игнор"
|
added: "⚖C9Игрок ẲE9{player} ⚖C9добавлен в игнор"
|
||||||
removed: "⚖C9Игрок ẲE9{player} ⚖C9убран из игнора"
|
removed: "⚖C9Игрок ẲE9{player} ⚖C9убран из игнора"
|
||||||
already-ignored: "&#B798A8Игрок ẲE9{player} &#B798A8уже в игноре"
|
already-ignored: "ẲE9Игрок ẲE9{player} ẲE9уже в игноре"
|
||||||
not-ignored: "&#B798A8Игрок ẲE9{player} &#B798A8не в игноре"
|
not-ignored: "ẲE9Игрок ẲE9{player} ẲE9не в игноре"
|
||||||
self: "&#CF6679Нельзя игнорировать самого себя"
|
self: "&#CF6679Нельзя игнорировать самого себя"
|
||||||
list-empty: "&#B798A8Ваш список игнора пуст"
|
list-empty: "ẲE9Ваш список игнора пуст"
|
||||||
list-header: "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
list-header: "ẲE9▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬"
|
||||||
list-footer: "&#B798A8Всего: ẲE9{count} &#B798A8игроков"
|
list-footer: "ẲE9Всего: ẲE9{count} ẲE9игроков"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Announcements │
|
# │ Announcements │
|
||||||
|
|
@ -71,9 +71,9 @@ announce:
|
||||||
|
|
||||||
spy:
|
spy:
|
||||||
enabled: "⚖C9Режим шпиона ẲE9включён"
|
enabled: "⚖C9Режим шпиона ẲE9включён"
|
||||||
disabled: "⚖C9Режим шпиона &#B798A8отключён"
|
disabled: "⚖C9Режим шпиона ẲE9отключён"
|
||||||
format: "&#B798A8[⚖C9SPY&#B798A8] ẲE9{sender} &#B798A8→ ⚖C9{receiver}&#B798A8: &f{message}"
|
format: "ẲE9[⚖C9SPYẲE9] ẲE9{sender} ẲE9→ ⚖C9{receiver}ẲE9: &f{message}"
|
||||||
chat-format: "&#B798A8[⚖C9SPY&#B798A8] &#B798A8{type} ẲE9{sender}&#B798A8: &f{message}"
|
chat-format: "ẲE9[⚖C9SPYẲE9] ẲE9{type} ẲE9{sender}ẲE9: &f{message}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Message filters │
|
# │ Message filters │
|
||||||
|
|
@ -81,14 +81,14 @@ spy:
|
||||||
|
|
||||||
filter:
|
filter:
|
||||||
blocked: "&#CF6679Сообщение заблокировано"
|
blocked: "&#CF6679Сообщение заблокировано"
|
||||||
warning: "&#B798A8Предупреждение"
|
warning: "ẲE9Предупреждение"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Cooldowns │
|
# │ Cooldowns │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
cooldown:
|
cooldown:
|
||||||
wait: "&#B798A8Подождите ẲE9{time} &#B798A8сек"
|
wait: "ẲE9Подождите ẲE9{time} ẲE9сек"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Anti-spam (caps, repeat, similar messages) │
|
# │ Anti-spam (caps, repeat, similar messages) │
|
||||||
|
|
@ -104,7 +104,7 @@ antispam:
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
clearchat:
|
clearchat:
|
||||||
cleared: "⚖C9Чат очищен &#B798A8администратором ẲE9{player}"
|
cleared: "⚖C9Чат очищен ẲE9администратором ẲE9{player}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Command / usage errors │
|
# │ Command / usage errors │
|
||||||
|
|
@ -113,7 +113,7 @@ clearchat:
|
||||||
errors:
|
errors:
|
||||||
no-permission: "&#CF6679Нет прав"
|
no-permission: "&#CF6679Нет прав"
|
||||||
player-not-found: "&#CF6679Игрок не найден"
|
player-not-found: "&#CF6679Игрок не найден"
|
||||||
invalid-usage: "&#B798A8Использование: ẲE9{usage}"
|
invalid-usage: "ẲE9Использование: ẲE9{usage}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ General (permissions, reload, hub, etc.) │
|
# │ General (permissions, reload, hub, etc.) │
|
||||||
|
|
@ -124,7 +124,7 @@ general:
|
||||||
players-only: "&#CF6679Только для игроков!"
|
players-only: "&#CF6679Только для игроков!"
|
||||||
config-reloaded: "⚖C9Конфиг ẲE9перезагружен!"
|
config-reloaded: "⚖C9Конфиг ẲE9перезагружен!"
|
||||||
invalid-player: "&#CF6679Игрок ẲE9{player} &#CF6679не найден!"
|
invalid-player: "&#CF6679Игрок ẲE9{player} &#CF6679не найден!"
|
||||||
cooldown-active: "&#B798A8Подождите ẲE9{time}с"
|
cooldown-active: "ẲE9Подождите ẲE9{time}с"
|
||||||
command-disabled: "&#CF6679Команда отключена!"
|
command-disabled: "&#CF6679Команда отключена!"
|
||||||
|
|
||||||
hub:
|
hub:
|
||||||
|
|
@ -137,9 +137,9 @@ hub:
|
||||||
mute:
|
mute:
|
||||||
muted: "⚖C9Игрок ẲE9{player} ⚖C9замучен на ẲE9{time}"
|
muted: "⚖C9Игрок ẲE9{player} ⚖C9замучен на ẲE9{time}"
|
||||||
unmuted: "⚖C9Игрок ẲE9{player} ⚖C9размучен"
|
unmuted: "⚖C9Игрок ẲE9{player} ⚖C9размучен"
|
||||||
already-muted: "&#B798A8Игрок ẲE9{player} &#B798A8уже замучен"
|
already-muted: "ẲE9Игрок ẲE9{player} ẲE9уже замучен"
|
||||||
not-muted: "&#B798A8Игрок ẲE9{player} &#B798A8не замучен"
|
not-muted: "ẲE9Игрок ẲE9{player} ẲE9не замучен"
|
||||||
you-muted: "&#CF6679Вы замучены! &#B798A8Осталось: ẲE9{time}"
|
you-muted: "&#CF6679Вы замучены! ẲE9Осталось: ẲE9{time}"
|
||||||
permanent: "&#CF6679Вы замучены навсегда!"
|
permanent: "&#CF6679Вы замучены навсегда!"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
|
@ -149,32 +149,32 @@ mute:
|
||||||
gradient:
|
gradient:
|
||||||
color-set: "⚖C9Градиент ẲE9установлен!"
|
color-set: "⚖C9Градиент ẲE9установлен!"
|
||||||
color-enabled: "⚖C9Градиентный ник ẲE9включён"
|
color-enabled: "⚖C9Градиентный ник ẲE9включён"
|
||||||
color-disabled: "&#B798A8Градиентный ник ⚖C9отключён"
|
color-disabled: "ẲE9Градиентный ник ⚖C9отключён"
|
||||||
color-reset: "&#B798A8Градиент сброшен"
|
color-reset: "ẲE9Градиент сброшен"
|
||||||
prefix-set: "⚖C9Префикс ẲE9установлен!"
|
prefix-set: "⚖C9Префикс ẲE9установлен!"
|
||||||
prefix-reset: "&#B798A8Префикс сброшен"
|
prefix-reset: "ẲE9Префикс сброшен"
|
||||||
prefix-reset-success: "⚖C9Префикс успешно ẲE9сброшен!"
|
prefix-reset-success: "⚖C9Префикс успешно ẲE9сброшен!"
|
||||||
prefix-enabled: "⚖C9Префикс ẲE9включён"
|
prefix-enabled: "⚖C9Префикс ẲE9включён"
|
||||||
prefix-disabled: "&#B798A8Префикс ⚖C9отключён"
|
prefix-disabled: "ẲE9Префикс ⚖C9отключён"
|
||||||
invalid-hex: "&#CF6679Неверный HEX цвет: ẲE9{color}"
|
invalid-hex: "&#CF6679Неверный HEX цвет: ẲE9{color}"
|
||||||
invalid-color: "&#CF6679Неверный цвет: ẲE9{color}"
|
invalid-color: "&#CF6679Неверный цвет: ẲE9{color}"
|
||||||
too-many-colors: "&#CF6679Слишком много цветов! Максимум: ẲE9{max}"
|
too-many-colors: "&#CF6679Слишком много цветов! Максимум: ẲE9{max}"
|
||||||
too-few-colors: "&#CF6679Слишком мало цветов! Минимум: ẲE9{min}"
|
too-few-colors: "&#CF6679Слишком мало цветов! Минимум: ẲE9{min}"
|
||||||
not-enough-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: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||||
not-enough-points-color: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
not-enough-points-color: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||||
not-enough-points-prefix: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
not-enough-points-prefix: "&#CF6679Недостаточно поинтов! Нужно: ẲE9{price}"
|
||||||
player-not-found: "&#CF6679Игрок не найден"
|
player-not-found: "&#CF6679Игрок не найден"
|
||||||
color-help: "&#B798A8Использование: ẲE9/color <HEX1> <HEX2>"
|
color-help: "ẲE9Использование: ẲE9/color <HEX1> <HEX2>"
|
||||||
color-success: "⚖C9Градиент успешно ẲE9установлен!"
|
color-success: "⚖C9Градиент успешно ẲE9установлен!"
|
||||||
color-no-colors: "&#B798A8У вас нет установленных цветов"
|
color-no-colors: "ẲE9У вас нет установленных цветов"
|
||||||
color-copy-usage: "&#B798A8Использование: ẲE9/color copy <игрок>"
|
color-copy-usage: "ẲE9Использование: ẲE9/color copy <игрок>"
|
||||||
color-copy-no-colors: "&#B798A8У игрока ẲE9{player} &#B798A8нет цветов"
|
color-copy-no-colors: "ẲE9У игрока ẲE9{player} ẲE9нет цветов"
|
||||||
prefix-help: "&#B798A8Использование: ẲE9/prefix <текст> &#B798A8или ẲE9/prefix reset"
|
prefix-help: "ẲE9Использование: ẲE9/prefix <текст> ẲE9или ẲE9/prefix reset"
|
||||||
prefix-success: "⚖C9Префикс установлен! &#B798A8Стоимость: ẲE9{price} &#B798A8поинтов"
|
prefix-success: "⚖C9Префикс установлен! ẲE9Стоимость: ẲE9{price} ẲE9поинтов"
|
||||||
prefix-success-free: "⚖C9Префикс ẲE9установлен!"
|
prefix-success-free: "⚖C9Префикс ẲE9установлен!"
|
||||||
prefix-no-prefix: "&#B798A8У вас нет префикса"
|
prefix-no-prefix: "ẲE9У вас нет префикса"
|
||||||
prefix-too-long: "&#CF6679Префикс слишком длинный! Максимум: ẲE9{max}"
|
prefix-too-long: "&#CF6679Префикс слишком длинный! Максимум: ẲE9{max}"
|
||||||
prefix-no-colors: "&#CF6679Префикс не может содержать цветовые коды!"
|
prefix-no-colors: "&#CF6679Префикс не может содержать цветовые коды!"
|
||||||
prefix-invalid-chars: "&#CF6679Недопустимые символы в префиксе!"
|
prefix-invalid-chars: "&#CF6679Недопустимые символы в префиксе!"
|
||||||
|
|
@ -182,30 +182,30 @@ gradient:
|
||||||
only-player: "&#CF6679Только для игроков!"
|
only-player: "&#CF6679Только для игроков!"
|
||||||
no-permission: "&#CF6679Нет прав!"
|
no-permission: "&#CF6679Нет прав!"
|
||||||
reload-success: "⚖C9Конфигурация ẲE9перезагружена!"
|
reload-success: "⚖C9Конфигурация ẲE9перезагружена!"
|
||||||
info-header: "ẲE9▬▬▬▬▬▬▬▬ &#B798A8{player} ẲE9▬▬▬▬▬▬▬▬"
|
info-header: "ẲE9▬▬▬▬▬▬▬▬ ẲE9{player} ẲE9▬▬▬▬▬▬▬▬"
|
||||||
info-prefix: "&#B798A8Префикс: &f{prefix}"
|
info-prefix: "ẲE9Префикс: &f{prefix}"
|
||||||
info-prefix-enabled: "&#B798A8Префикс активен: &f{enabled}"
|
info-prefix-enabled: "ẲE9Префикс активен: &f{enabled}"
|
||||||
info-colors: "&#B798A8Цвета: &f{colors}"
|
info-colors: "ẲE9Цвета: &f{colors}"
|
||||||
info-color-enabled: "&#B798A8Цвет активен: &f{enabled}"
|
info-color-enabled: "ẲE9Цвет активен: &f{enabled}"
|
||||||
info-prefix-purchased: "&#B798A8Куплен: &f{purchased}"
|
info-prefix-purchased: "ẲE9Куплен: &f{purchased}"
|
||||||
|
|
||||||
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
# │ Custom nicknames (/nick) │
|
# │ Custom nicknames (/nick) │
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
nick:
|
nick:
|
||||||
current: "&#B798A8Ваш ник: ẲE9{nick}"
|
current: "ẲE9Ваш ник: ẲE9{nick}"
|
||||||
usage: "&#B798A8Использование: ẲE9/nick <ник> &#B798A8или ẲE9/nick reset"
|
usage: "ẲE9Использование: ẲE9/nick <ник> ẲE9или ẲE9/nick reset"
|
||||||
reset-usage: "&#B798A8Используйте ẲE9/nick reset &#B798A8для сброса"
|
reset-usage: "ẲE9Используйте ẲE9/nick reset ẲE9для сброса"
|
||||||
set-usage: "&#B798A8Используйте ẲE9/nick <ник> &#B798A8для установки"
|
set-usage: "ẲE9Используйте ẲE9/nick <ник> ẲE9для установки"
|
||||||
no-nick: "&#B798A8У вас нет кастомного ника"
|
no-nick: "ẲE9У вас нет кастомного ника"
|
||||||
reset-success: "⚖C9Ник ẲE9сброшен!"
|
reset-success: "⚖C9Ник ẲE9сброшен!"
|
||||||
set-success: "⚖C9Ник изменён на: &f{nick}"
|
set-success: "⚖C9Ник изменён на: &f{nick}"
|
||||||
invalid: "&#CF6679Невалидный ник!"
|
invalid: "&#CF6679Невалидный ник!"
|
||||||
requirements-header: "&#B798A8Требования:"
|
requirements-header: "ẲE9Требования:"
|
||||||
requirements-length: "⚖C9◆ &fДлина: 3-16 символов"
|
requirements-length: "⚖C9◆ &fДлина: 3-16 символов"
|
||||||
requirements-chars: "⚖C9◆ &fБуквы, цифры, _, русские буквы"
|
requirements-chars: "⚖C9◆ &fБуквы, цифры, _, русские буквы"
|
||||||
requirements-colors: "⚖C9◆ &fЦвета: ẲE9&#RRGGBB&#B798A8текст"
|
requirements-colors: "⚖C9◆ &fЦвета: ẲE9&#RRGGBBẲE9текст"
|
||||||
taken: "&#CF6679Этот ник уже занят!"
|
taken: "&#CF6679Этот ник уже занят!"
|
||||||
error: "&#CF6679Не удалось установить ник!"
|
error: "&#CF6679Не удалось установить ник!"
|
||||||
|
|
||||||
|
|
@ -214,12 +214,12 @@ nick:
|
||||||
# └─────────────────────────────────────────────────────────────────────────────┘
|
# └─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
rp:
|
rp:
|
||||||
me: "<color:#B798A8>* {player} {action}</color>"
|
me: "<color:#7858E9>* {player} {action}</color>"
|
||||||
try-format: "<color:#B798A8>* {player} пытается {action}...</color> {result}"
|
try-format: "<color:#7858E9>* {player} пытается {action}...</color> {result}"
|
||||||
try-success: "<color:#9878C9><bold>[Успех!]</bold></color>"
|
try-success: "<color:#9878C9><bold>[Успех!]</bold></color>"
|
||||||
try-fail: "<color:#CF6679><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>"
|
do-format: "<color:#7858E9>[<color:#7858E9>Сцена</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>"
|
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-min-error: "<color:#CF6679>Минимальное значение кубика: 2</color>"
|
||||||
roll-max-error: "<color:#CF6679>Максимальное значение: 1000000</color>"
|
roll-max-error: "<color:#CF6679>Максимальное значение: 1000000</color>"
|
||||||
roll-invalid-number: "<color:#CF6679>Укажите число: /roll [максимум]</color>"
|
roll-invalid-number: "<color:#CF6679>Укажите число: /roll [максимум]</color>"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue