feat: add mute/unmute commands with MuteManager

This commit is contained in:
loki5512344 2025-12-30 21:19:07 +01:00
parent 55c965603f
commit c4d2768423
27 changed files with 559 additions and 2352 deletions

View file

@ -28,6 +28,7 @@ public final class LoChat extends JavaPlugin {
private EmojiManager emojiManager;
private ChatColorManager chatColorManager;
private CustomCommandManager customCommandManager;
private MuteManager muteManager;
private GradientModule gradientModule;
private com.loki.lochat.listeners.DisplayNameListener displayNameListener;
@ -50,6 +51,7 @@ public final class LoChat extends JavaPlugin {
spyManager = new SpyManager(this);
chatColorManager = new ChatColorManager(this);
customCommandManager = new CustomCommandManager(this);
muteManager = new MuteManager(this);
chatManager = new ChatManager(this);
autoMessageManager = new AutoMessageManager(this);
@ -90,6 +92,9 @@ public final class LoChat extends JavaPlugin {
if (chatColorManager != null) {
chatColorManager.saveData();
}
if (muteManager != null) {
muteManager.saveData();
}
if (gradientModule != null) {
gradientModule.shutdown();
}
@ -107,6 +112,8 @@ public final class LoChat extends JavaPlugin {
getCommand("announce").setExecutor(new AnnounceCommand(this));
getCommand("chatspy").setExecutor(new ChatSpyCommand(this));
getCommand("clearchat").setExecutor(new ClearChatCommand(this));
getCommand("mute").setExecutor(new MuteCommand(this));
getCommand("unmute").setExecutor(new UnmuteCommand(this));
getCommand("chatcolor").setExecutor(new ChatColorCommand(this));
LoChatCommand loChatCommand = new LoChatCommand(this);
@ -195,6 +202,10 @@ public final class LoChat extends JavaPlugin {
return customCommandManager;
}
public MuteManager getMuteManager() {
return muteManager;
}
public com.loki.lochat.listeners.DisplayNameListener getDisplayNameListener() {
return displayNameListener;
}

View file

@ -0,0 +1,122 @@
package com.loki.lochat.commands;
import com.loki.lochat.LoChat;
import com.loki.lochat.utils.ChatFormatter;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MuteCommand implements CommandExecutor, TabCompleter {
private final LoChat plugin;
public MuteCommand(LoChat plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!sender.hasPermission("chat.mute")) {
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getNoPermission()));
return true;
}
if (args.length < 2) {
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getInvalidUsage("/mute <игрок> <время> [причина]")));
sender.sendMessage(ChatFormatter.parse("<gray>Время: 1m, 1h, 1d, permanent"));
return true;
}
String playerName = args[0];
String timeStr = args[1];
String reason = args.length > 2 ? String.join(" ", Arrays.copyOfRange(args, 2, args.length)) : "Нарушение правил чата";
Player target = Bukkit.getPlayer(playerName);
if (target == null) {
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getPlayerNotFound()));
return true;
}
// Парсим время
long duration = parseTime(timeStr);
if (duration == -1) {
sender.sendMessage(ChatFormatter.parse("<red>Неверный формат времени! Используйте: 1m, 1h, 1d, permanent"));
return true;
}
// Мутим игрока
plugin.getMuteManager().mutePlayer(target.getUniqueId(), duration, reason, sender.getName());
// Уведомления
String timeDisplay = duration == 0 ? "навсегда" : formatTime(duration);
sender.sendMessage(ChatFormatter.parse(
plugin.getMessageConfig().get("mute.muted", "{player}", target.getName(), "{time}", timeDisplay)
));
if (target.isOnline()) {
target.sendMessage(ChatFormatter.parse(
plugin.getMessageConfig().get("mute.you-muted", "{time}", timeDisplay)
));
}
return true;
}
private long parseTime(String timeStr) {
if (timeStr.equalsIgnoreCase("permanent") || timeStr.equalsIgnoreCase("perm")) {
return 0; // 0 = permanent
}
try {
char unit = timeStr.charAt(timeStr.length() - 1);
int amount = Integer.parseInt(timeStr.substring(0, timeStr.length() - 1));
return switch (unit) {
case 'm' -> amount * 60L * 1000L; // минуты
case 'h' -> amount * 60L * 60L * 1000L; // часы
case 'd' -> amount * 24L * 60L * 60L * 1000L; // дни
default -> -1;
};
} catch (NumberFormatException | StringIndexOutOfBoundsException e) {
return -1;
}
}
private String formatTime(long millis) {
long seconds = millis / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
if (days > 0) return days + "д";
if (hours > 0) return hours + "ч";
if (minutes > 0) return minutes + "м";
return seconds + "с";
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return Bukkit.getOnlinePlayers().stream()
.map(Player::getName)
.filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase()))
.collect(Collectors.toList());
} else if (args.length == 2) {
List<String> times = Arrays.asList("1m", "5m", "10m", "30m", "1h", "2h", "6h", "12h", "1d", "3d", "7d", "permanent");
return times.stream()
.filter(time -> time.toLowerCase().startsWith(args[1].toLowerCase()))
.collect(Collectors.toList());
}
return new ArrayList<>();
}
}

View file

@ -0,0 +1,76 @@
package com.loki.lochat.commands;
import com.loki.lochat.LoChat;
import com.loki.lochat.utils.ChatFormatter;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.stream.Collectors;
public class UnmuteCommand implements CommandExecutor, TabCompleter {
private final LoChat plugin;
public UnmuteCommand(LoChat plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!sender.hasPermission("chat.mute")) {
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getNoPermission()));
return true;
}
if (args.length != 1) {
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getInvalidUsage("/unmute <игрок>")));
return true;
}
String playerName = args[0];
Player target = Bukkit.getPlayer(playerName);
if (target == null) {
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getPlayerNotFound()));
return true;
}
if (!plugin.getMuteManager().isMuted(target.getUniqueId())) {
sender.sendMessage(ChatFormatter.parse(
plugin.getMessageConfig().get("mute.not-muted", "{player}", target.getName())
));
return true;
}
// Размучиваем
plugin.getMuteManager().unmutePlayer(target.getUniqueId());
// Уведомления
sender.sendMessage(ChatFormatter.parse(
plugin.getMessageConfig().get("mute.unmuted", "{player}", target.getName())
));
if (target.isOnline()) {
target.sendMessage(ChatFormatter.parse("<green>Вы были размучены!"));
}
return true;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
return Bukkit.getOnlinePlayers().stream()
.map(Player::getName)
.filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase()))
.collect(Collectors.toList());
}
return null;
}
}

View file

@ -57,6 +57,17 @@ public class PlaceholderAPIHook extends PlaceholderExpansion {
}
case "spy_enabled" -> String.valueOf(plugin.getSpyManager().isSpying(uuid));
// Mute placeholders
case "muted" -> String.valueOf(plugin.getMuteManager().isMuted(uuid));
case "mute_time" -> {
if (!plugin.getMuteManager().isMuted(uuid)) yield "";
yield plugin.getMuteManager().formatRemainingTime(uuid);
}
case "mute_reason" -> {
var muteData = plugin.getMuteManager().getMuteData(uuid);
yield muteData != null ? muteData.reason : "";
}
// Gradient placeholders (совместимость с LoPreff)
case "gradient_full", "full" -> {
Player onlinePlayer = player.getPlayer();

View file

@ -34,6 +34,19 @@ public class ChatListener implements Listener {
}
private void processChat(Player player, String message) {
// Проверка мута
if (plugin.getMuteManager().isMuted(player.getUniqueId())) {
String timeLeft = plugin.getMuteManager().formatRemainingTime(player.getUniqueId());
if (timeLeft.equals("навсегда")) {
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("mute.permanent")));
} else {
player.sendMessage(ChatFormatter.parse(
plugin.getMessageConfig().get("mute.you-muted", "{time}", timeLeft)
));
}
return;
}
String globalSymbol = plugin.getConfigManager().getGlobalSymbol();
boolean isGlobal = message.startsWith(globalSymbol) && player.hasPermission("chat.global.use");
String chatType = isGlobal ? "global" : "local";

View file

@ -0,0 +1,147 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class MuteManager {
private final LoChat plugin;
private final Map<UUID, MuteData> mutedPlayers;
private File dataFile;
private FileConfiguration dataConfig;
public MuteManager(LoChat plugin) {
this.plugin = plugin;
this.mutedPlayers = new HashMap<>();
loadData();
}
private void loadData() {
dataFile = new File(plugin.getDataFolder(), "mutes.yml");
if (!dataFile.exists()) {
try {
dataFile.createNewFile();
} catch (IOException e) {
plugin.getLogger().severe("Не удалось создать файл mutes.yml: " + e.getMessage());
}
}
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
// Загружаем муты из файла
for (String key : dataConfig.getKeys(false)) {
try {
UUID uuid = UUID.fromString(key);
long expiry = dataConfig.getLong(key + ".expiry");
String reason = dataConfig.getString(key + ".reason", "Нарушение правил");
String mutedBy = dataConfig.getString(key + ".muted_by", "Система");
// Проверяем не истёк ли мут
if (expiry > 0 && System.currentTimeMillis() > expiry) {
dataConfig.set(key, null);
continue;
}
mutedPlayers.put(uuid, new MuteData(expiry, reason, mutedBy));
} catch (IllegalArgumentException ignored) {
// Неверный UUID, пропускаем
}
}
saveData();
}
public void saveData() {
for (Map.Entry<UUID, MuteData> entry : mutedPlayers.entrySet()) {
String key = entry.getKey().toString();
MuteData data = entry.getValue();
dataConfig.set(key + ".expiry", data.expiry);
dataConfig.set(key + ".reason", data.reason);
dataConfig.set(key + ".muted_by", data.mutedBy);
}
try {
dataConfig.save(dataFile);
} catch (IOException e) {
plugin.getLogger().severe("Не удалось сохранить mutes.yml: " + e.getMessage());
}
}
public void mutePlayer(UUID playerId, long duration, String reason, String mutedBy) {
long expiry = duration == 0 ? 0 : System.currentTimeMillis() + duration;
mutedPlayers.put(playerId, new MuteData(expiry, reason, mutedBy));
saveData();
}
public void unmutePlayer(UUID playerId) {
mutedPlayers.remove(playerId);
dataConfig.set(playerId.toString(), null);
saveData();
}
public boolean isMuted(UUID playerId) {
MuteData data = mutedPlayers.get(playerId);
if (data == null) return false;
// Проверяем не истёк ли мут
if (data.expiry > 0 && System.currentTimeMillis() > data.expiry) {
unmutePlayer(playerId);
return false;
}
return true;
}
public MuteData getMuteData(UUID playerId) {
return mutedPlayers.get(playerId);
}
public long getRemainingTime(UUID playerId) {
MuteData data = mutedPlayers.get(playerId);
if (data == null || data.expiry == 0) return 0;
long remaining = data.expiry - System.currentTimeMillis();
return Math.max(0, remaining);
}
public String formatRemainingTime(UUID playerId) {
long remaining = getRemainingTime(playerId);
if (remaining == 0) {
MuteData data = getMuteData(playerId);
if (data != null && data.expiry == 0) {
return "навсегда";
}
return "0с";
}
long seconds = remaining / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
if (days > 0) return days + "д " + (hours % 24) + "ч";
if (hours > 0) return hours + "ч " + (minutes % 60) + "м";
if (minutes > 0) return minutes + "м " + (seconds % 60) + "с";
return seconds + "с";
}
public static class MuteData {
public final long expiry; // 0 = permanent
public final String reason;
public final String mutedBy;
public MuteData(long expiry, String reason, String mutedBy) {
this.expiry = expiry;
this.reason = reason;
this.mutedBy = mutedBy;
}
}
}