feat: pizdec
This commit is contained in:
34
src/main/java/org/blz/adminmode/AdminMode.java
Normal file → Executable file
34
src/main/java/org/blz/adminmode/AdminMode.java
Normal file → Executable file
@@ -3,6 +3,8 @@ package org.blz.adminmode;
|
||||
import org.blz.adminmode.commands.AdminModeCommand;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.blz.adminmode.dialog.AdminDialogService;
|
||||
import org.blz.adminmode.dialog.DialogPreferenceStore;
|
||||
import org.blz.adminmode.dialog.MenuEmojiPreferenceStore;
|
||||
import org.blz.adminmode.integrations.CoreProtectIntegration;
|
||||
import org.blz.adminmode.integrations.LuckPermsIntegration;
|
||||
import org.blz.adminmode.listeners.AdminModeListener;
|
||||
@@ -10,8 +12,12 @@ import org.blz.adminmode.listeners.GameModeChangeListener;
|
||||
import org.blz.adminmode.listeners.MobTargetListener;
|
||||
import org.blz.adminmode.listeners.PlayerDeathListener;
|
||||
import org.blz.adminmode.listeners.PlayerSessionListener;
|
||||
import org.blz.adminmode.moderation.ModeratorAccessManager;
|
||||
import org.blz.adminmode.moderation.ModeManager;
|
||||
import org.blz.adminmode.moderation.ModeSessionLogger;
|
||||
import org.blz.adminmode.moderation.ModeratorPreferencesStore;
|
||||
import org.blz.adminmode.moderation.ModeratorWarningStore;
|
||||
import org.blz.adminmode.moderation.PlayerFreezeManager;
|
||||
import org.blz.adminmode.session.SessionStorage;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
@@ -22,6 +28,9 @@ public class AdminMode extends JavaPlugin {
|
||||
private ModeManager modeManager;
|
||||
private AdminModeCommand adminModeCommand;
|
||||
private AdminDialogService dialogService;
|
||||
private org.blz.adminmode.managers.BelzeBoolManager belzeBoolManager;
|
||||
private ModeratorAccessManager moderatorAccessManager;
|
||||
private PlayerFreezeManager freezeManager;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@@ -30,15 +39,24 @@ public class AdminMode extends JavaPlugin {
|
||||
|
||||
configManager = new ConfigManager(this);
|
||||
SessionStorage sessionStorage = new SessionStorage(this);
|
||||
moderatorAccessManager = new ModeratorAccessManager(this);
|
||||
ModeratorPreferencesStore preferencesStore = new ModeratorPreferencesStore(this);
|
||||
ModeratorWarningStore warningStore = new ModeratorWarningStore(this);
|
||||
LuckPermsIntegration luckPermsIntegration = new LuckPermsIntegration(this, configManager);
|
||||
CoreProtectIntegration coreProtectIntegration = new CoreProtectIntegration(this, configManager);
|
||||
ModeSessionLogger sessionLogger = new ModeSessionLogger(this, configManager);
|
||||
modeManager = new ModeManager(this, configManager, luckPermsIntegration, sessionStorage, sessionLogger);
|
||||
adminModeCommand = new AdminModeCommand(configManager, modeManager, coreProtectIntegration);
|
||||
dialogService = new AdminDialogService(this, configManager, adminModeCommand);
|
||||
modeManager = new ModeManager(this, configManager, luckPermsIntegration, sessionStorage, sessionLogger, preferencesStore);
|
||||
adminModeCommand = new AdminModeCommand(configManager, modeManager, coreProtectIntegration, moderatorAccessManager);
|
||||
DialogPreferenceStore dialogPreferenceStore = new DialogPreferenceStore(this);
|
||||
MenuEmojiPreferenceStore emojiPreferenceStore = new MenuEmojiPreferenceStore(this);
|
||||
dialogService = new AdminDialogService(this, configManager, adminModeCommand, dialogPreferenceStore, emojiPreferenceStore, preferencesStore, warningStore);
|
||||
adminModeCommand.setDialogService(dialogService);
|
||||
adminModeCommand.setDialogPreferenceStore(dialogPreferenceStore);
|
||||
getCommand("adminmode").setExecutor(adminModeCommand);
|
||||
getCommand("admfix").setExecutor(new org.blz.adminmode.commands.AdminFixCommand(adminModeCommand));
|
||||
getCommand("adminmode").setTabCompleter(adminModeCommand);
|
||||
org.blz.adminmode.commands.AdminFixCommand adminFixCommand = new org.blz.adminmode.commands.AdminFixCommand(adminModeCommand);
|
||||
getCommand("admfix").setExecutor(adminFixCommand);
|
||||
getCommand("admfix").setTabCompleter(adminFixCommand);
|
||||
|
||||
getServer().getPluginManager().registerEvents(new AdminModeListener(adminModeCommand, configManager, modeManager, dialogService),
|
||||
this);
|
||||
@@ -47,10 +65,13 @@ public class AdminMode extends JavaPlugin {
|
||||
this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerSessionListener(adminModeCommand, modeManager), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerDeathListener(modeManager), this);
|
||||
freezeManager = new PlayerFreezeManager(this);
|
||||
adminModeCommand.setFreezeManager(freezeManager);
|
||||
getServer().getPluginManager().registerEvents(freezeManager, this);
|
||||
|
||||
for (org.bukkit.entity.Player onlinePlayer : getServer().getOnlinePlayers()) {
|
||||
if (modeManager.hasSession(onlinePlayer.getUniqueId())) {
|
||||
getServer().getScheduler().runTaskLater(this, () -> adminModeCommand.recoverSession(onlinePlayer), 1L);
|
||||
getServer().getScheduler().runTaskLater(this, () -> adminModeCommand.resumeMode(onlinePlayer), 1L);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +79,8 @@ public class AdminMode extends JavaPlugin {
|
||||
new org.blz.adminmode.utils.WorldLoader(this, "pocket_dimension").loadWorld();
|
||||
|
||||
// Register Abilities
|
||||
new org.blz.adminmode.managers.BelzeBoolManager(this);
|
||||
belzeBoolManager = new org.blz.adminmode.managers.BelzeBoolManager(this);
|
||||
adminModeCommand.setBelzeBoolManager(belzeBoolManager);
|
||||
|
||||
getLogger().info("AdminMode успешно включен!");
|
||||
}
|
||||
|
||||
41
src/main/java/org/blz/adminmode/commands/AdminFixCommand.java
Normal file → Executable file
41
src/main/java/org/blz/adminmode/commands/AdminFixCommand.java
Normal file → Executable file
@@ -1,13 +1,19 @@
|
||||
package org.blz.adminmode.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
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;
|
||||
|
||||
public class AdminFixCommand implements CommandExecutor {
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class AdminFixCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final AdminModeCommand adminModeCommand;
|
||||
|
||||
@@ -18,26 +24,45 @@ public class AdminFixCommand implements CommandExecutor {
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!sender.hasPermission("adminmode.admin")) {
|
||||
sender.sendMessage(ChatColor.RED + "У вас нет прав для использования этой команды!");
|
||||
sender.sendMessage(Component.text("У вас нет прав для использования этой команды!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
sender.sendMessage(ChatColor.RED + "Использование: /admfix <игрок>");
|
||||
sender.sendMessage(Component.text("Использование: /admfix <игрок>", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
Player target = Bukkit.getPlayer(args[0]);
|
||||
if (target == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Игрок не найден!");
|
||||
sender.sendMessage(Component.text("Игрок не найден!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
adminModeCommand.forceDisableAbilities(target);
|
||||
if (!adminModeCommand.forceDisableAbilities(target)) {
|
||||
sender.sendMessage(Component.text("У игрока нет активных состояний AdminMode для сброса.", NamedTextColor.YELLOW));
|
||||
return true;
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.GREEN + "✓ Все способности отключены для игрока " + target.getName());
|
||||
target.sendMessage(ChatColor.YELLOW + "⚠ Ваши способности были сброшены администратором");
|
||||
sender.sendMessage(Component.text("✓ Все способности отключены для игрока " + target.getName(), NamedTextColor.GREEN));
|
||||
target.sendMessage(Component.text("⚠ Ваши способности были сброшены администратором", NamedTextColor.YELLOW));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (args.length != 1) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String prefix = args[0].toLowerCase();
|
||||
List<String> names = new ArrayList<>();
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (prefix.isEmpty() || player.getName().toLowerCase().startsWith(prefix)) {
|
||||
names.add(player.getName());
|
||||
}
|
||||
}
|
||||
names.sort(String.CASE_INSENSITIVE_ORDER);
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
483
src/main/java/org/blz/adminmode/commands/AdminModeCommand.java
Normal file → Executable file
483
src/main/java/org/blz/adminmode/commands/AdminModeCommand.java
Normal file → Executable file
@@ -5,38 +5,64 @@ import java.util.UUID;
|
||||
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.blz.adminmode.dialog.AdminDialogService;
|
||||
import org.blz.adminmode.dialog.DialogPreferenceStore;
|
||||
import org.blz.adminmode.integrations.CoreProtectIntegration;
|
||||
import org.blz.adminmode.managers.BelzeBoolManager;
|
||||
import org.blz.adminmode.moderation.ModeratorAccessManager;
|
||||
import org.blz.adminmode.moderation.ModeManager;
|
||||
import org.blz.adminmode.moderation.ModeratorProfile;
|
||||
import org.blz.adminmode.moderation.PlayerFreezeManager;
|
||||
import org.blz.adminmode.moderation.PlayerListAction;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
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 net.kyori.adventure.text.Component;
|
||||
|
||||
public class AdminModeCommand implements CommandExecutor {
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
public class AdminModeCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final ConfigManager configManager;
|
||||
private final ModeManager modeManager;
|
||||
private final CoreProtectIntegration coreProtectIntegration;
|
||||
private final ModeratorAccessManager moderatorAccessManager;
|
||||
private BelzeBoolManager belzeBoolManager;
|
||||
private PlayerFreezeManager freezeManager;
|
||||
private AdminDialogService dialogService;
|
||||
private DialogPreferenceStore dialogPreferenceStore;
|
||||
|
||||
public AdminModeCommand(
|
||||
ConfigManager configManager,
|
||||
ModeManager modeManager,
|
||||
CoreProtectIntegration coreProtectIntegration) {
|
||||
CoreProtectIntegration coreProtectIntegration,
|
||||
ModeratorAccessManager moderatorAccessManager) {
|
||||
this.configManager = configManager;
|
||||
this.modeManager = modeManager;
|
||||
this.coreProtectIntegration = coreProtectIntegration;
|
||||
this.moderatorAccessManager = moderatorAccessManager;
|
||||
}
|
||||
|
||||
public void setDialogService(AdminDialogService dialogService) {
|
||||
this.dialogService = dialogService;
|
||||
}
|
||||
|
||||
public void setDialogPreferenceStore(DialogPreferenceStore store) {
|
||||
this.dialogPreferenceStore = store;
|
||||
}
|
||||
|
||||
public void setBelzeBoolManager(BelzeBoolManager belzeBoolManager) {
|
||||
this.belzeBoolManager = belzeBoolManager;
|
||||
}
|
||||
|
||||
public void setFreezeManager(PlayerFreezeManager freezeManager) {
|
||||
this.freezeManager = freezeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("reload")) {
|
||||
@@ -54,16 +80,29 @@ public class AdminModeCommand implements CommandExecutor {
|
||||
sender.sendMessage(configManager.getPrefixedMessage(configManager.getMsgNoPermission()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§cИспользование: /adminmode disable <игрок>"));
|
||||
return true;
|
||||
}
|
||||
|
||||
forceDisableTarget(sender, args[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("restrict")) {
|
||||
handleRestrictCommand(sender, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("unrestrict")) {
|
||||
handleUnrestrictCommand(sender, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("status")) {
|
||||
handleStatusCommand(sender, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage("Эта команда доступна только игрокам!");
|
||||
return true;
|
||||
@@ -75,59 +114,49 @@ public class AdminModeCommand implements CommandExecutor {
|
||||
}
|
||||
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("dialog")) {
|
||||
if (!openRelevantDialog(player)) {
|
||||
player.sendMessage(configManager.getPrefixedMessage("§eDialog-панель сейчас недоступна."));
|
||||
if (!configManager.isDialogsEnabled()) {
|
||||
player.sendMessage(configManager.getPrefixedMessage("§cDialog-меню отключено администратором сервера."));
|
||||
return true;
|
||||
}
|
||||
if (!player.hasPermission("adminmode.use")) {
|
||||
player.sendMessage(configManager.getPrefixedMessage(configManager.getMsgNoPermission()));
|
||||
return true;
|
||||
}
|
||||
boolean nowEnabled = dialogPreferenceStore.toggle(player.getUniqueId());
|
||||
if (nowEnabled) {
|
||||
player.sendMessage(configManager.getPrefixedMessage("§aDialog-меню §2включено§a. Используйте §f/adminmode §aдля открытия панели."));
|
||||
} else {
|
||||
player.sendMessage(configManager.getPrefixedMessage("§7Dialog-меню §8отключено§7."));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 0 && (args[0].equalsIgnoreCase("enable") || args[0].equalsIgnoreCase("profile"))) {
|
||||
if (args.length < 2) {
|
||||
openRelevantDialog(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
ModeratorProfile profile = ModeratorProfile.fromInput(args[1]).orElse(null);
|
||||
if (profile == null) {
|
||||
player.sendMessage(configManager.getPrefixedMessage("§cНеизвестный профиль. Доступно: soft, hard."));
|
||||
return true;
|
||||
}
|
||||
|
||||
activateProfile(player, profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isInAdminMode(player.getUniqueId()) && getAvailableProfiles(player).isEmpty()) {
|
||||
if (!player.hasPermission("adminmode.use")) {
|
||||
player.sendMessage(configManager.getPrefixedMessage(configManager.getMsgNoPermission()));
|
||||
return true;
|
||||
}
|
||||
|
||||
openRelevantDialog(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean activateProfile(Player player, ModeratorProfile profile) {
|
||||
if (profile == null) {
|
||||
return openRelevantDialog(player);
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("on")) {
|
||||
return handleEnableMode(player);
|
||||
}
|
||||
|
||||
if (!profile.isAvailableFor(player)) {
|
||||
player.sendMessage(configManager.getPrefixedMessage(configManager.getMsgNoPermission()));
|
||||
return false;
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("off")) {
|
||||
return handleDisableMode(player);
|
||||
}
|
||||
|
||||
if (modeManager.hasSession(player.getUniqueId())) {
|
||||
ModeratorProfile activeProfile = getActiveProfile(player.getUniqueId());
|
||||
if (activeProfile == profile) {
|
||||
return openRelevantDialog(player);
|
||||
}
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("toggle")) {
|
||||
return handleHardToggle(player);
|
||||
}
|
||||
|
||||
if (!isInAdminMode(player.getUniqueId())) {
|
||||
return handleEnableMode(player);
|
||||
}
|
||||
|
||||
if (!openRelevantDialog(player)) {
|
||||
player.sendMessage(configManager.getPrefixedMessage(
|
||||
"§eУ вас уже активен профиль §f" + activeProfile.getDisplayName() + "§e. Сначала выйдите из режима."));
|
||||
return false;
|
||||
"§aВы в режиме администратора. Используйте §f/adminmode dialog §aдля включения GUI-панели."));
|
||||
}
|
||||
|
||||
return modeManager.enterMode(player, profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean exitMode(Player player) {
|
||||
@@ -138,12 +167,8 @@ public class AdminModeCommand implements CommandExecutor {
|
||||
return modeManager.recoverSession(player);
|
||||
}
|
||||
|
||||
public List<ModeratorProfile> getAvailableProfiles(Player player) {
|
||||
return modeManager.getAvailableProfiles(player);
|
||||
}
|
||||
|
||||
public ModeratorProfile getActiveProfile(UUID playerId) {
|
||||
return modeManager.getProfile(playerId);
|
||||
public boolean resumeMode(Player player) {
|
||||
return modeManager.resumeMode(player);
|
||||
}
|
||||
|
||||
public boolean isInAdminMode(UUID playerId) {
|
||||
@@ -155,37 +180,54 @@ public class AdminModeCommand implements CommandExecutor {
|
||||
}
|
||||
|
||||
public void applyAdminSettings(Player player, float flySpeed, float walkSpeed, boolean godMode) {
|
||||
if (!modeManager.hasSession(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!modeManager.hasSession(player.getUniqueId())) return;
|
||||
modeManager.applyAdminSettings(player, flySpeed, walkSpeed, godMode);
|
||||
player.sendMessage(configManager.getPrefixedMessage("§aНастройки режима обновлены."));
|
||||
}
|
||||
|
||||
public boolean performPlayerListAction(Player moderator, PlayerListAction action, String targetName) {
|
||||
Player target = validateActiveTarget(moderator, targetName);
|
||||
if (target == null) {
|
||||
public boolean toggleVanish(Player player) {
|
||||
return modeManager.toggleVanish(player);
|
||||
}
|
||||
|
||||
public boolean isVanished(UUID playerId) {
|
||||
return modeManager.isVanished(playerId);
|
||||
}
|
||||
|
||||
public boolean openBanList(Player player) {
|
||||
return dialogService != null && dialogService.openBanListDialog(player);
|
||||
}
|
||||
|
||||
public boolean toggleFreeze(Player player) {
|
||||
if (freezeManager == null) {
|
||||
return false;
|
||||
}
|
||||
return freezeManager.toggleFreeze(player);
|
||||
}
|
||||
|
||||
public boolean isFrozen(UUID playerId) {
|
||||
return freezeManager != null && freezeManager.isFrozen(playerId);
|
||||
}
|
||||
|
||||
public boolean performPlayerListAction(Player moderator, PlayerListAction action, String targetName) {
|
||||
Player target = validateActiveTarget(moderator, targetName);
|
||||
if (target == null) return false;
|
||||
|
||||
return switch (action) {
|
||||
case SPECTATE -> modeManager.spectatePlayer(moderator, target);
|
||||
case TELEPORT -> modeManager.teleportToPlayer(moderator, target);
|
||||
case INVSEE -> modeManager.openInvsee(moderator, target);
|
||||
case MANAGE -> {
|
||||
dialogService.openManagePlayerDialog(moderator, target);
|
||||
yield true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public boolean teleportToPlayer(Player moderator, String targetName) {
|
||||
Player target = validateActiveTarget(moderator, targetName);
|
||||
return target != null && modeManager.teleportToPlayer(moderator, target);
|
||||
}
|
||||
|
||||
public boolean teleportPlayerHere(Player moderator, String targetName) {
|
||||
if (!validateHardActionPlayer(moderator)) {
|
||||
if (!modeManager.hasSession(moderator.getUniqueId())) {
|
||||
moderator.sendMessage(configManager.getPrefixedMessage("§cСначала войдите в режим модерации."));
|
||||
return false;
|
||||
}
|
||||
|
||||
Player target = resolveOnlinePlayer(targetName, moderator);
|
||||
return target != null && modeManager.teleportPlayerHere(moderator, target);
|
||||
}
|
||||
@@ -195,77 +237,242 @@ public class AdminModeCommand implements CommandExecutor {
|
||||
sender.sendMessage(configManager.getPrefixedMessage(configManager.getMsgNoPermission()));
|
||||
return false;
|
||||
}
|
||||
|
||||
Player target = resolveOnlinePlayer(targetName, sender);
|
||||
if (target == null) {
|
||||
if (target == null) return false;
|
||||
if (!forceDisableAbilities(target)) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§eУ игрока нет активных состояний AdminMode для сброса."));
|
||||
return false;
|
||||
}
|
||||
|
||||
forceDisableAbilities(target);
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§aРежим и способности игрока §f" + target.getName() + "§a сброшены."));
|
||||
target.sendMessage(configManager.getPrefixedMessage("§eВаш режим модерации был принудительно отключен."));
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean executeCPLookup(Player player, String targetPlayer, int radius, String time) {
|
||||
if (!validateHardActionPlayer(player)) {
|
||||
return false;
|
||||
}
|
||||
if (!modeManager.hasSession(player.getUniqueId())) return false;
|
||||
return coreProtectIntegration.lookup(player, targetPlayer, radius, time);
|
||||
}
|
||||
|
||||
public boolean executeCPRollback(Player player, int radius, String time, String targetPlayer) {
|
||||
if (!validateHardActionPlayer(player)) {
|
||||
return false;
|
||||
}
|
||||
return coreProtectIntegration.rollback(player, radius, time, targetPlayer);
|
||||
public boolean executeCPLookup(Player player, String targetPlayer, String action, String block, String exclude,
|
||||
String world, int radius, String time) {
|
||||
if (!modeManager.hasSession(player.getUniqueId())) return false;
|
||||
return coreProtectIntegration.lookup(player, targetPlayer, action, block, exclude, world, radius, time);
|
||||
}
|
||||
|
||||
public boolean executeCPRollback(Player player, int radius, String time, String targetPlayer, String action, String block, String exclude) {
|
||||
if (!modeManager.hasSession(player.getUniqueId())) return false;
|
||||
return coreProtectIntegration.rollback(player, radius, time, targetPlayer, action, block, exclude);
|
||||
}
|
||||
|
||||
public boolean executeCPRollback(Player player, int radius, String time, String targetPlayer, String action, String block,
|
||||
String exclude, String world, String extraFilters) {
|
||||
if (!modeManager.hasSession(player.getUniqueId())) return false;
|
||||
return coreProtectIntegration.rollback(player, radius, time, targetPlayer, action, block, exclude, world, extraFilters);
|
||||
}
|
||||
|
||||
public boolean executeCPRestore(Player player, int radius, String time, String targetPlayer, String action, String block,
|
||||
String exclude, String world, String extraFilters) {
|
||||
if (!modeManager.hasSession(player.getUniqueId())) return false;
|
||||
return coreProtectIntegration.restore(player, radius, time, targetPlayer, action, block, exclude, world, extraFilters);
|
||||
}
|
||||
|
||||
public boolean toggleInspector(Player player) {
|
||||
if (!validateHardActionPlayer(player)) {
|
||||
return false;
|
||||
}
|
||||
if (!modeManager.hasSession(player.getUniqueId())) return false;
|
||||
return coreProtectIntegration.toggleInspector(player);
|
||||
}
|
||||
|
||||
public void forceDisableAbilities(Player player) {
|
||||
public boolean forceDisableAbilities(Player player) {
|
||||
boolean changed = false;
|
||||
|
||||
if (modeManager.hasSession(player.getUniqueId())) {
|
||||
modeManager.exitMode(player);
|
||||
return;
|
||||
changed = modeManager.exitMode(player);
|
||||
}
|
||||
|
||||
player.setInvulnerable(false);
|
||||
player.setFlying(false);
|
||||
player.setAllowFlight(false);
|
||||
player.setFlySpeed(0.1f);
|
||||
player.setWalkSpeed(0.2f);
|
||||
if (belzeBoolManager != null) {
|
||||
changed = belzeBoolManager.forceDisable(player) || changed;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean canUseHardActions(CommandSender sender) {
|
||||
return modeManager.canUseHardActions(sender);
|
||||
}
|
||||
|
||||
private boolean openRelevantDialog(Player player) {
|
||||
if (dialogService == null || !configManager.isDialogsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (modeManager.hasSession(player.getUniqueId())) {
|
||||
return dialogService.openCurrentPanel(player);
|
||||
}
|
||||
|
||||
return dialogService.openModeSelectDialog(player);
|
||||
public boolean canManageModeratorAccess(Player actor, Player target) {
|
||||
return actor != null
|
||||
&& target != null
|
||||
&& actor.hasPermission("adminmode.chief")
|
||||
&& !actor.getUniqueId().equals(target.getUniqueId())
|
||||
&& target.hasPermission("adminmode.use");
|
||||
}
|
||||
|
||||
private boolean validateHardActionPlayer(Player moderator) {
|
||||
if (!canUseHardActions(moderator)) {
|
||||
moderator.sendMessage(configManager.getPrefixedMessage("§cДля этого действия нужен активный профиль Hard Moder."));
|
||||
public boolean isModeratorRestricted(UUID playerId) {
|
||||
return moderatorAccessManager.isRestricted(playerId);
|
||||
}
|
||||
|
||||
public boolean restrictModerator(Player actor, OfflinePlayer target, String durationInput, String reason) {
|
||||
if (actor == null || target == null || !actor.hasPermission("adminmode.chief")) {
|
||||
return false;
|
||||
}
|
||||
return applyRestriction(actor, target, durationInput, reason);
|
||||
}
|
||||
|
||||
public boolean unrestrictModerator(Player actor, OfflinePlayer target) {
|
||||
if (actor == null || target == null || !actor.hasPermission("adminmode.chief")) {
|
||||
return false;
|
||||
}
|
||||
return clearRestriction(actor, target);
|
||||
}
|
||||
|
||||
private boolean handleEnableMode(Player player) {
|
||||
if (moderatorAccessManager.isRestricted(player.getUniqueId())) {
|
||||
player.sendMessage(configManager.getPrefixedMessage(moderatorAccessManager.describeRestriction(player.getUniqueId())));
|
||||
return true;
|
||||
}
|
||||
if (isInAdminMode(player.getUniqueId())) {
|
||||
if (!openRelevantDialog(player)) {
|
||||
player.sendMessage(configManager.getPrefixedMessage("§eAdmin mode уже включён."));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!modeManager.enterMode(player)) {
|
||||
player.sendMessage(configManager.getPrefixedMessage("§cНе удалось включить admin mode. Проверьте права и состояние игрока."));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleDisableMode(Player player) {
|
||||
if (!isInAdminMode(player.getUniqueId())) {
|
||||
player.sendMessage(configManager.getPrefixedMessage("§eAdmin mode уже выключен."));
|
||||
return true;
|
||||
}
|
||||
modeManager.exitMode(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleHardToggle(Player player) {
|
||||
if (isInAdminMode(player.getUniqueId())) {
|
||||
return handleDisableMode(player);
|
||||
}
|
||||
return handleEnableMode(player);
|
||||
}
|
||||
|
||||
private boolean applyRestriction(CommandSender sender, OfflinePlayer target, String durationInput, String reason) {
|
||||
Long expiresAt = ModeratorAccessManager.parseDurationToExpiry(durationInput);
|
||||
if (expiresAt == Long.MIN_VALUE) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§cНеверный срок. Примеры: 30s, 30m, 2h, 7d, 1y, perm"));
|
||||
return false;
|
||||
}
|
||||
|
||||
String targetName = target.getName() != null ? target.getName() : target.getUniqueId().toString();
|
||||
ModeratorAccessManager.RestrictionEntry entry = moderatorAccessManager.restrict(
|
||||
target,
|
||||
targetName,
|
||||
sender.getName(),
|
||||
expiresAt,
|
||||
reason);
|
||||
|
||||
Player onlineTarget = Bukkit.getPlayer(target.getUniqueId());
|
||||
if (onlineTarget != null) {
|
||||
forceDisableAbilities(onlineTarget);
|
||||
onlineTarget.sendMessage(configManager.getPrefixedMessage(moderatorAccessManager.describeRestriction(onlineTarget.getUniqueId())));
|
||||
}
|
||||
|
||||
sender.sendMessage(configManager.getPrefixedMessage(
|
||||
"§aДоступ к admin mode для §f" + entry.getPlayerName() + "§a " +
|
||||
(entry.isPermanent() ? "отключён навсегда." : "ограничен по времени.")));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean clearRestriction(CommandSender sender, OfflinePlayer target) {
|
||||
if (!moderatorAccessManager.clearRestriction(target.getUniqueId())) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§eДля этого игрока нет активного ограничения."));
|
||||
return false;
|
||||
}
|
||||
|
||||
String targetName = target.getName() != null ? target.getName() : target.getUniqueId().toString();
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§aОграничение для §f" + targetName + "§a снято."));
|
||||
Player onlineTarget = Bukkit.getPlayer(target.getUniqueId());
|
||||
if (onlineTarget != null) {
|
||||
onlineTarget.sendMessage(configManager.getPrefixedMessage("§aДоступ к admin mode снова разрешён."));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleRestrictCommand(CommandSender sender, String[] args) {
|
||||
if (!sender.hasPermission("adminmode.chief")) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage(configManager.getMsgNoPermission()));
|
||||
return;
|
||||
}
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§cИспользование: /adminmode restrict <игрок> <1s..1y|perm> [причина]"));
|
||||
return;
|
||||
}
|
||||
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
if (target.getUniqueId() == null) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§cНе удалось определить игрока."));
|
||||
return;
|
||||
}
|
||||
|
||||
applyRestriction(sender, target, args[2], joinArgs(args, 3));
|
||||
}
|
||||
|
||||
private void handleUnrestrictCommand(CommandSender sender, String[] args) {
|
||||
if (!sender.hasPermission("adminmode.chief")) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage(configManager.getMsgNoPermission()));
|
||||
return;
|
||||
}
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§cИспользование: /adminmode unrestrict <игрок>"));
|
||||
return;
|
||||
}
|
||||
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
clearRestriction(sender, target);
|
||||
}
|
||||
|
||||
private void handleStatusCommand(CommandSender sender, String[] args) {
|
||||
if (!sender.hasPermission("adminmode.chief")) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage(configManager.getMsgNoPermission()));
|
||||
return;
|
||||
}
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§cИспользование: /adminmode status <игрок>"));
|
||||
return;
|
||||
}
|
||||
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||
if (!moderatorAccessManager.isRestricted(target.getUniqueId())) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§aУ игрока нет ограничений на admin mode."));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§eСтатус для §f" + (target.getName() != null ? target.getName() : args[1]) + "§e: " +
|
||||
moderatorAccessManager.describeRestriction(target.getUniqueId())));
|
||||
}
|
||||
|
||||
private String joinArgs(String[] args, int startIndex) {
|
||||
if (startIndex >= args.length) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = startIndex; i < args.length; i++) {
|
||||
if (i > startIndex) {
|
||||
builder.append(' ');
|
||||
}
|
||||
builder.append(args[i]);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private boolean openRelevantDialog(Player player) {
|
||||
if (dialogService == null || !configManager.isDialogsEnabled()) return false;
|
||||
if (dialogPreferenceStore == null || !dialogPreferenceStore.isEnabled(player.getUniqueId())) return false;
|
||||
return dialogService.openAdminPanel(player);
|
||||
}
|
||||
|
||||
private Player validateActiveTarget(Player moderator, String targetName) {
|
||||
if (!modeManager.hasSession(moderator.getUniqueId())) {
|
||||
moderator.sendMessage(configManager.getPrefixedMessage("§cСначала войдите в режим модерации."));
|
||||
@@ -279,17 +486,83 @@ public class AdminModeCommand implements CommandExecutor {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§cУкажите ник игрока."));
|
||||
return null;
|
||||
}
|
||||
|
||||
Player target = Bukkit.getPlayerExact(targetName.trim());
|
||||
if (target == null) {
|
||||
target = Bukkit.getPlayer(targetName.trim());
|
||||
}
|
||||
|
||||
if (target == null) target = Bukkit.getPlayer(targetName.trim());
|
||||
if (target == null) {
|
||||
sender.sendMessage(configManager.getPrefixedMessage("§cИгрок не найден!"));
|
||||
return null;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (command.getName().equalsIgnoreCase("adminmode")) {
|
||||
return completeAdminMode(sender, args);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<String> completeAdminMode(CommandSender sender, String[] args) {
|
||||
if (args.length == 1) {
|
||||
List<String> suggestions = new ArrayList<>();
|
||||
suggestions.add("on");
|
||||
suggestions.add("off");
|
||||
suggestions.add("toggle");
|
||||
suggestions.add("dialog");
|
||||
suggestions.add("disable");
|
||||
suggestions.add("restrict");
|
||||
suggestions.add("unrestrict");
|
||||
suggestions.add("status");
|
||||
suggestions.add("reload");
|
||||
return filterPrefix(suggestions, args[0]);
|
||||
}
|
||||
|
||||
String subcommand = args[0].toLowerCase();
|
||||
if (args.length == 2) {
|
||||
return switch (subcommand) {
|
||||
case "disable" -> filterPrefix(getOnlinePlayerNames(), args[1]);
|
||||
case "restrict", "status" -> filterPrefix(getKnownPlayerNames(), args[1]);
|
||||
case "unrestrict" -> filterPrefix(moderatorAccessManager.getRestrictedPlayerNames(), args[1]);
|
||||
default -> Collections.emptyList();
|
||||
};
|
||||
}
|
||||
|
||||
if (args.length == 3 && subcommand.equals("restrict")) {
|
||||
return filterPrefix(List.of("30s", "1m", "30m", "2h", "1d", "7d", "1y", "perm"), args[2]);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<String> getOnlinePlayerNames() {
|
||||
List<String> names = new ArrayList<>();
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
names.add(player.getName());
|
||||
}
|
||||
names.sort(String.CASE_INSENSITIVE_ORDER);
|
||||
return names;
|
||||
}
|
||||
|
||||
private List<String> getKnownPlayerNames() {
|
||||
List<String> names = new ArrayList<>(getOnlinePlayerNames());
|
||||
for (OfflinePlayer offlinePlayer : Bukkit.getOfflinePlayers()) {
|
||||
if (offlinePlayer.getName() != null && !offlinePlayer.getName().isBlank() && !names.contains(offlinePlayer.getName())) {
|
||||
names.add(offlinePlayer.getName());
|
||||
}
|
||||
}
|
||||
names.sort(String.CASE_INSENSITIVE_ORDER);
|
||||
return names;
|
||||
}
|
||||
|
||||
private List<String> filterPrefix(List<String> source, String prefix) {
|
||||
String normalized = prefix == null ? "" : prefix.toLowerCase();
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String value : source) {
|
||||
if (normalized.isEmpty() || value.toLowerCase().startsWith(normalized)) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
436
src/main/java/org/blz/adminmode/config/ConfigManager.java
Normal file → Executable file
436
src/main/java/org/blz/adminmode/config/ConfigManager.java
Normal file → Executable file
@@ -1,11 +1,10 @@
|
||||
package org.blz.adminmode.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.blz.adminmode.moderation.ModeratorProfile;
|
||||
import org.blz.adminmode.moderation.PunishmentDuration;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
@@ -17,20 +16,28 @@ public class ConfigManager {
|
||||
|
||||
private boolean enabled;
|
||||
private boolean useLuckPerms;
|
||||
private Map<ModeratorProfile, List<String>> luckPermsGroups;
|
||||
private List<String> adminLuckPermsGroups;
|
||||
private boolean removeGroupsOnDisable;
|
||||
private boolean dialogsEnabled;
|
||||
private String baseGroup;
|
||||
private String softGroup;
|
||||
private String hardGroup;
|
||||
private Material softPanelMaterial;
|
||||
private Material hardPanelMaterial;
|
||||
private String adminGroup;
|
||||
private Material panelMaterial;
|
||||
private Material cpInspectorMaterial;
|
||||
private boolean coreProtectEnabled;
|
||||
private int coreProtectDefaultRadius;
|
||||
private String coreProtectDefaultTime;
|
||||
private boolean sessionLoggingEnabled;
|
||||
private String sessionLogFile;
|
||||
private boolean moderationActionsAsConsole;
|
||||
private String warnCommandTemplate;
|
||||
private String muteCommandTemplate;
|
||||
private String unmuteCommandTemplate;
|
||||
private String banCommandTemplate;
|
||||
private String kickCommandTemplate;
|
||||
private List<String> punishmentDurationOptions;
|
||||
private String defaultWarnDuration;
|
||||
private String defaultMuteDuration;
|
||||
private String defaultBanDuration;
|
||||
|
||||
private boolean preventItemDrop;
|
||||
private boolean preventItemPickup;
|
||||
@@ -46,6 +53,7 @@ public class ConfigManager {
|
||||
private boolean mobsIgnorePlayer;
|
||||
private boolean allowFlightInSurvival;
|
||||
private boolean godMode;
|
||||
private boolean chiefCreativeMode;
|
||||
private float customFlySpeed;
|
||||
private float customWalkSpeed;
|
||||
private List<String> allowedGameModes;
|
||||
@@ -63,8 +71,7 @@ public class ConfigManager {
|
||||
private String msgBlockPlaceDenied;
|
||||
private String msgReloaded;
|
||||
private String msgPrefix;
|
||||
private String msgEnterSoft;
|
||||
private String msgEnterHard;
|
||||
private String msgEnter;
|
||||
private String msgExitMode;
|
||||
private String msgCoreProtectUnavailable;
|
||||
private String msgSessionRecovered;
|
||||
@@ -79,17 +86,20 @@ public class ConfigManager {
|
||||
config = plugin.getConfig();
|
||||
|
||||
enabled = config.getBoolean("admin_mode.enabled", true);
|
||||
|
||||
useLuckPerms = config.getBoolean("admin_mode.luckperms.enabled", true);
|
||||
removeGroupsOnDisable = config.getBoolean("admin_mode.luckperms.remove_on_disable", true);
|
||||
dialogsEnabled = config.getBoolean("admin_mode.dialogs.enabled", true);
|
||||
|
||||
baseGroup = config.getString("groups.base", "moder");
|
||||
softGroup = config.getString("groups.soft", "soft_moder_adm");
|
||||
hardGroup = config.getString("groups.hard", "hard_moder_adm");
|
||||
adminGroup = config.getString("groups.admin", "admin_moder");
|
||||
|
||||
softPanelMaterial = readMaterial("items.soft_panel_material", Material.COMPASS);
|
||||
hardPanelMaterial = readMaterial("items.hard_panel_material", Material.NETHER_STAR);
|
||||
List<String> groups = config.getStringList("admin_mode.luckperms.groups");
|
||||
if (groups.isEmpty()) {
|
||||
groups = List.of(adminGroup);
|
||||
}
|
||||
adminLuckPermsGroups = new ArrayList<>(groups);
|
||||
|
||||
panelMaterial = readMaterial("items.panel_material", Material.NETHER_STAR);
|
||||
cpInspectorMaterial = readMaterial("items.cp_inspector_material", Material.STICK);
|
||||
|
||||
coreProtectEnabled = config.getBoolean("coreprotect.enabled", true);
|
||||
@@ -98,42 +108,38 @@ public class ConfigManager {
|
||||
|
||||
sessionLoggingEnabled = config.getBoolean("logging.enabled", true);
|
||||
sessionLogFile = config.getString("logging.log_file", "logs/sessions.log");
|
||||
moderationActionsAsConsole = config.getBoolean("moderation_actions.dispatch_as_console", true);
|
||||
punishmentDurationOptions = readPunishmentDurations();
|
||||
defaultWarnDuration = readDefaultPunishmentDuration("warn", "7d");
|
||||
defaultMuteDuration = readDefaultPunishmentDuration("mute", "1h");
|
||||
defaultBanDuration = readDefaultPunishmentDuration("ban", "7d");
|
||||
warnCommandTemplate = readModerationCommand("warn",
|
||||
"warn {target} {reason}", "warn {target} {duration} {reason}", true);
|
||||
muteCommandTemplate = readModerationCommand("mute",
|
||||
"mute {target} {reason}", "mute {target} {duration} actor:{moderator} {reason}", true);
|
||||
unmuteCommandTemplate = readModerationCommand("unmute",
|
||||
"unmute {target} actor:{moderator} {reason}",
|
||||
"moderationcommands:unmute {target} actor:{moderator} {reason}", false);
|
||||
banCommandTemplate = readModerationCommand("ban",
|
||||
"ban {target} {reason}", "ban {target} {duration} actor:{moderator} {reason}", true);
|
||||
kickCommandTemplate = readModerationCommand("kick",
|
||||
"kick {target} {reason}", "kick {target} actor:{moderator} {reason}", false);
|
||||
|
||||
List<String> legacyGroups = config.getStringList("admin_mode.luckperms.groups");
|
||||
List<String> softGroups = config.getStringList("admin_mode.luckperms.profile_groups.soft_moder");
|
||||
List<String> hardGroups = config.getStringList("admin_mode.luckperms.profile_groups.hard_moder");
|
||||
if (softGroups.isEmpty()) {
|
||||
if (!legacyGroups.isEmpty()) {
|
||||
softGroups = new ArrayList<>(legacyGroups);
|
||||
} else {
|
||||
softGroups = new ArrayList<>(List.of(softGroup));
|
||||
}
|
||||
}
|
||||
if (hardGroups.isEmpty()) {
|
||||
if (!legacyGroups.isEmpty()) {
|
||||
hardGroups = new ArrayList<>(legacyGroups);
|
||||
} else {
|
||||
hardGroups = new ArrayList<>(List.of(hardGroup));
|
||||
}
|
||||
}
|
||||
luckPermsGroups = new EnumMap<>(ModeratorProfile.class);
|
||||
luckPermsGroups.put(ModeratorProfile.SOFT_MODER, new ArrayList<>(softGroups));
|
||||
luckPermsGroups.put(ModeratorProfile.HARD_MODER, new ArrayList<>(hardGroups));
|
||||
|
||||
preventItemDrop = config.getBoolean("admin_mode.restrictions.prevent_item_drop", true);
|
||||
preventItemDrop = config.getBoolean("admin_mode.restrictions.prevent_item_drop", false);
|
||||
preventItemPickup = config.getBoolean("admin_mode.restrictions.prevent_item_pickup", false);
|
||||
preventContainerTransfer = config.getBoolean("admin_mode.restrictions.prevent_container_transfer", true);
|
||||
preventItemUse = config.getBoolean("admin_mode.restrictions.prevent_item_use", true);
|
||||
preventItemUse = config.getBoolean("admin_mode.restrictions.prevent_item_use", false);
|
||||
allowOwnInventory = config.getBoolean("admin_mode.restrictions.allow_own_inventory", true);
|
||||
allowedBlocks = config.getStringList("admin_mode.restrictions.allowed_blocks");
|
||||
allowedPlaceBlocks = config.getStringList("admin_mode.restrictions.allowed_place_blocks");
|
||||
givePresetBlocks = config.getBoolean("admin_mode.restrictions.give_preset_blocks", true);
|
||||
givePresetBlocks = config.getBoolean("admin_mode.restrictions.give_preset_blocks", false);
|
||||
presetBlocks = config.getStringList("admin_mode.restrictions.preset_blocks");
|
||||
|
||||
forceSpectator = config.getBoolean("admin_mode.gamemode.force_spectator", false);
|
||||
mobsIgnorePlayer = config.getBoolean("admin_mode.gamemode.mobs_ignore_player", true);
|
||||
allowFlightInSurvival = config.getBoolean("admin_mode.gamemode.allow_flight_in_survival", true);
|
||||
godMode = config.getBoolean("admin_mode.gamemode.god_mode", true);
|
||||
chiefCreativeMode = config.getBoolean("admin_mode.gamemode.chief_creative", true);
|
||||
customFlySpeed = (float) config.getDouble("admin_mode.gamemode.custom_fly_speed", 0.2);
|
||||
customWalkSpeed = (float) config.getDouble("admin_mode.gamemode.custom_walk_speed", 0.2);
|
||||
allowedGameModes = config.getStringList("admin_mode.gamemode.allowed_gamemodes");
|
||||
@@ -143,8 +149,7 @@ public class ConfigManager {
|
||||
msgPermissionsGranted = config.getString("admin_mode.messages.permissions_granted",
|
||||
"⚠ Вам выданы временные права администратора!");
|
||||
msgDisabled = config.getString("admin_mode.messages.disabled", "✓ Режим администратора отключен!");
|
||||
msgDisabledSubtitle = config.getString("admin_mode.messages.disabled_subtitle",
|
||||
"Ваше состояние восстановлено.");
|
||||
msgDisabledSubtitle = config.getString("admin_mode.messages.disabled_subtitle", "Ваше состояние восстановлено.");
|
||||
msgPermissionsRemoved = config.getString("admin_mode.messages.permissions_removed",
|
||||
"✓ Права администратора отозваны!");
|
||||
msgNoPermission = config.getString("admin_mode.messages.no_permission",
|
||||
@@ -160,241 +165,158 @@ public class ConfigManager {
|
||||
msgReloaded = config.getString("admin_mode.messages.reloaded", "✓ Конфигурация AdminMode перезагружена!");
|
||||
|
||||
msgPrefix = config.getString("messages.prefix", "§8[§bAdminMode§8] ");
|
||||
msgEnterSoft = config.getString("messages.enter_soft", "§aВошёл в режим §bSOFT MODER");
|
||||
msgEnterHard = config.getString("messages.enter_hard", "§aВошёл в режим §cHARD MODER");
|
||||
msgEnter = config.getString("messages.enter", "§aВошёл в режим §cADMIN MODE");
|
||||
msgExitMode = config.getString("messages.exit", "§7Режим деактивирован. Состояние восстановлено.");
|
||||
msgCoreProtectUnavailable = config.getString("messages.cp_unavailable",
|
||||
"§cCoreProtect не найден. Hard режим работает без CP.");
|
||||
"§cCoreProtect не найден или отключён.");
|
||||
msgSessionRecovered = config.getString("messages.session_recovered",
|
||||
"§eВаша активная сессия модерации была восстановлена и корректно завершена.");
|
||||
|
||||
validatePresetBlocks();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
// --- Getters ---
|
||||
|
||||
public boolean isUseLuckPerms() {
|
||||
return useLuckPerms;
|
||||
}
|
||||
|
||||
public List<String> getLuckPermsGroups() {
|
||||
return getLuckPermsGroups(ModeratorProfile.SOFT_MODER);
|
||||
}
|
||||
|
||||
public List<String> getLuckPermsGroups(ModeratorProfile profile) {
|
||||
return new ArrayList<>(luckPermsGroups.getOrDefault(profile, List.of()));
|
||||
}
|
||||
|
||||
public boolean isRemoveGroupsOnDisable() {
|
||||
return removeGroupsOnDisable;
|
||||
}
|
||||
|
||||
public boolean isDialogsEnabled() {
|
||||
return dialogsEnabled;
|
||||
}
|
||||
|
||||
public String getBaseGroup() {
|
||||
return baseGroup;
|
||||
}
|
||||
|
||||
public String getSoftGroup() {
|
||||
return softGroup;
|
||||
}
|
||||
|
||||
public String getHardGroup() {
|
||||
return hardGroup;
|
||||
}
|
||||
|
||||
public String getActiveGroup(ModeratorProfile profile) {
|
||||
return profile != null && profile.isHardProfile() ? hardGroup : softGroup;
|
||||
}
|
||||
|
||||
public Material getSoftPanelMaterial() {
|
||||
return softPanelMaterial;
|
||||
}
|
||||
|
||||
public Material getHardPanelMaterial() {
|
||||
return hardPanelMaterial;
|
||||
}
|
||||
|
||||
public Material getCpInspectorMaterial() {
|
||||
return cpInspectorMaterial;
|
||||
}
|
||||
|
||||
public boolean isCoreProtectEnabled() {
|
||||
return coreProtectEnabled;
|
||||
}
|
||||
|
||||
public int getCoreProtectDefaultRadius() {
|
||||
return coreProtectDefaultRadius;
|
||||
}
|
||||
|
||||
public String getCoreProtectDefaultTime() {
|
||||
return coreProtectDefaultTime;
|
||||
}
|
||||
|
||||
public boolean isSessionLoggingEnabled() {
|
||||
return sessionLoggingEnabled;
|
||||
}
|
||||
|
||||
public String getSessionLogFile() {
|
||||
return sessionLogFile;
|
||||
}
|
||||
|
||||
public boolean isPreventItemDrop() {
|
||||
return preventItemDrop;
|
||||
}
|
||||
|
||||
public boolean isPreventItemPickup() {
|
||||
return preventItemPickup;
|
||||
}
|
||||
|
||||
public boolean isPreventContainerTransfer() {
|
||||
return preventContainerTransfer;
|
||||
}
|
||||
|
||||
public boolean isPreventItemUse() {
|
||||
return preventItemUse;
|
||||
}
|
||||
|
||||
public boolean isAllowOwnInventory() {
|
||||
return allowOwnInventory;
|
||||
}
|
||||
|
||||
public List<String> getAllowedBlocks() {
|
||||
return allowedBlocks;
|
||||
}
|
||||
|
||||
public List<String> getAllowedPlaceBlocks() {
|
||||
return allowedPlaceBlocks;
|
||||
}
|
||||
|
||||
public boolean isGivePresetBlocks() {
|
||||
return givePresetBlocks;
|
||||
}
|
||||
|
||||
public List<String> getPresetBlocks() {
|
||||
return presetBlocks;
|
||||
}
|
||||
|
||||
public boolean isForceSpectator() {
|
||||
return forceSpectator;
|
||||
}
|
||||
|
||||
public boolean isMobsIgnorePlayer() {
|
||||
return mobsIgnorePlayer;
|
||||
}
|
||||
|
||||
public boolean isAllowFlightInSurvival() {
|
||||
return allowFlightInSurvival;
|
||||
}
|
||||
|
||||
public boolean isGodMode() {
|
||||
return godMode;
|
||||
}
|
||||
|
||||
public float getCustomFlySpeed() {
|
||||
return customFlySpeed;
|
||||
}
|
||||
|
||||
public float getCustomWalkSpeed() {
|
||||
return customWalkSpeed;
|
||||
}
|
||||
|
||||
public List<String> getAllowedGameModes() {
|
||||
return allowedGameModes;
|
||||
}
|
||||
|
||||
public String getMsgEnabled() {
|
||||
return msgEnabled;
|
||||
}
|
||||
|
||||
public String getMsgEnabledSubtitle() {
|
||||
return msgEnabledSubtitle;
|
||||
}
|
||||
|
||||
public String getMsgPermissionsGranted() {
|
||||
return msgPermissionsGranted;
|
||||
}
|
||||
|
||||
public String getMsgDisabled() {
|
||||
return msgDisabled;
|
||||
}
|
||||
|
||||
public String getMsgDisabledSubtitle() {
|
||||
return msgDisabledSubtitle;
|
||||
}
|
||||
|
||||
public String getMsgPermissionsRemoved() {
|
||||
return msgPermissionsRemoved;
|
||||
}
|
||||
|
||||
public String getMsgNoPermission() {
|
||||
return msgNoPermission;
|
||||
}
|
||||
|
||||
public String getMsgItemDropDenied() {
|
||||
return msgItemDropDenied;
|
||||
}
|
||||
|
||||
public String getMsgContainerTransferDenied() {
|
||||
return msgContainerTransferDenied;
|
||||
}
|
||||
|
||||
public String getMsgItemUseDenied() {
|
||||
return msgItemUseDenied;
|
||||
}
|
||||
|
||||
public String getMsgBlockPlaceDenied() {
|
||||
return msgBlockPlaceDenied;
|
||||
}
|
||||
|
||||
public String getMsgReloaded() {
|
||||
return msgReloaded;
|
||||
}
|
||||
|
||||
public String getMsgPrefix() {
|
||||
return msgPrefix;
|
||||
}
|
||||
|
||||
public String getMsgEnterSoft() {
|
||||
return msgEnterSoft;
|
||||
}
|
||||
|
||||
public String getMsgEnterHard() {
|
||||
return msgEnterHard;
|
||||
}
|
||||
|
||||
public String getMsgExitMode() {
|
||||
return msgExitMode;
|
||||
}
|
||||
|
||||
public String getMsgCoreProtectUnavailable() {
|
||||
return msgCoreProtectUnavailable;
|
||||
}
|
||||
|
||||
public String getMsgSessionRecovered() {
|
||||
return msgSessionRecovered;
|
||||
public boolean isEnabled() { return enabled; }
|
||||
public boolean isUseLuckPerms() { return useLuckPerms; }
|
||||
public List<String> getLuckPermsGroups() { return new ArrayList<>(adminLuckPermsGroups); }
|
||||
public boolean isRemoveGroupsOnDisable() { return removeGroupsOnDisable; }
|
||||
public boolean isDialogsEnabled() { return dialogsEnabled; }
|
||||
public String getBaseGroup() { return baseGroup; }
|
||||
public String getAdminGroup() { return adminGroup; }
|
||||
public Material getPanelMaterial() { return panelMaterial; }
|
||||
public Material getCpInspectorMaterial() { return cpInspectorMaterial; }
|
||||
public boolean isCoreProtectEnabled() { return coreProtectEnabled; }
|
||||
public int getCoreProtectDefaultRadius() { return coreProtectDefaultRadius; }
|
||||
public String getCoreProtectDefaultTime() { return coreProtectDefaultTime; }
|
||||
public boolean isSessionLoggingEnabled() { return sessionLoggingEnabled; }
|
||||
public String getSessionLogFile() { return sessionLogFile; }
|
||||
public boolean isModerationActionsAsConsole() { return moderationActionsAsConsole; }
|
||||
public String getWarnCommandTemplate() { return warnCommandTemplate; }
|
||||
public String getMuteCommandTemplate() { return muteCommandTemplate; }
|
||||
public String getUnmuteCommandTemplate() { return unmuteCommandTemplate; }
|
||||
public String getBanCommandTemplate() { return banCommandTemplate; }
|
||||
public String getKickCommandTemplate() { return kickCommandTemplate; }
|
||||
public List<String> getPunishmentDurationOptions() { return new ArrayList<>(punishmentDurationOptions); }
|
||||
public String getDefaultWarnDuration() { return defaultWarnDuration; }
|
||||
public String getDefaultMuteDuration() { return defaultMuteDuration; }
|
||||
public String getDefaultBanDuration() { return defaultBanDuration; }
|
||||
public boolean isPunishmentDurationAllowed(String value) {
|
||||
String normalized = PunishmentDuration.normalizeToken(value);
|
||||
return !normalized.isEmpty() && punishmentDurationOptions.contains(normalized);
|
||||
}
|
||||
public boolean isPreventItemDrop() { return preventItemDrop; }
|
||||
public boolean isPreventItemPickup() { return preventItemPickup; }
|
||||
public boolean isPreventContainerTransfer() { return preventContainerTransfer; }
|
||||
public boolean isPreventItemUse() { return preventItemUse; }
|
||||
public boolean isAllowOwnInventory() { return allowOwnInventory; }
|
||||
public List<String> getAllowedBlocks() { return allowedBlocks; }
|
||||
public List<String> getAllowedPlaceBlocks() { return allowedPlaceBlocks; }
|
||||
public boolean isGivePresetBlocks() { return givePresetBlocks; }
|
||||
public List<String> getPresetBlocks() { return presetBlocks; }
|
||||
public boolean isForceSpectator() { return forceSpectator; }
|
||||
public boolean isMobsIgnorePlayer() { return mobsIgnorePlayer; }
|
||||
public boolean isAllowFlightInSurvival() { return allowFlightInSurvival; }
|
||||
public boolean isGodMode() { return godMode; }
|
||||
public boolean isChiefCreativeMode() { return chiefCreativeMode; }
|
||||
public float getCustomFlySpeed() { return customFlySpeed; }
|
||||
public float getCustomWalkSpeed() { return customWalkSpeed; }
|
||||
public List<String> getAllowedGameModes() { return allowedGameModes; }
|
||||
public String getMsgEnabled() { return msgEnabled; }
|
||||
public String getMsgEnabledSubtitle() { return msgEnabledSubtitle; }
|
||||
public String getMsgPermissionsGranted() { return msgPermissionsGranted; }
|
||||
public String getMsgDisabled() { return msgDisabled; }
|
||||
public String getMsgDisabledSubtitle() { return msgDisabledSubtitle; }
|
||||
public String getMsgPermissionsRemoved() { return msgPermissionsRemoved; }
|
||||
public String getMsgNoPermission() { return msgNoPermission; }
|
||||
public String getMsgItemDropDenied() { return msgItemDropDenied; }
|
||||
public String getMsgContainerTransferDenied() { return msgContainerTransferDenied; }
|
||||
public String getMsgItemUseDenied() { return msgItemUseDenied; }
|
||||
public String getMsgBlockPlaceDenied() { return msgBlockPlaceDenied; }
|
||||
public String getMsgReloaded() { return msgReloaded; }
|
||||
public String getMsgPrefix() { return msgPrefix; }
|
||||
public String getMsgEnter() { return msgEnter; }
|
||||
public String getMsgExitMode() { return msgExitMode; }
|
||||
public String getMsgCoreProtectUnavailable() { return msgCoreProtectUnavailable; }
|
||||
public String getMsgSessionRecovered() { return msgSessionRecovered; }
|
||||
|
||||
public String getPrefixedMessage(String message) {
|
||||
if (message == null || message.isEmpty()) {
|
||||
return msgPrefix;
|
||||
}
|
||||
if (message == null || message.isEmpty()) return msgPrefix;
|
||||
return msgPrefix + message;
|
||||
}
|
||||
|
||||
private Material readMaterial(String path, Material fallback) {
|
||||
String value = config.getString(path);
|
||||
if (value == null || value.isBlank()) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (value == null || value.isBlank()) return fallback;
|
||||
try {
|
||||
return Material.valueOf(value.trim().toUpperCase());
|
||||
} catch (IllegalArgumentException exception) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getLogger().warning("Неизвестный material в конфиге " + path + ": " + value);
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePresetBlocks() {
|
||||
for (String blockString : presetBlocks) {
|
||||
try {
|
||||
String[] parts = blockString.split(":");
|
||||
Material.valueOf(parts[0].trim().toUpperCase());
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Неверный блок в preset_blocks: " + blockString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> readPunishmentDurations() {
|
||||
List<String> configured = config.getStringList("moderation_actions.durations.options");
|
||||
if (configured.isEmpty()) {
|
||||
configured = List.of("1h", "1d", "7d", "30d", "permanent");
|
||||
}
|
||||
|
||||
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||
for (String value : configured) {
|
||||
String token = PunishmentDuration.normalizeToken(value);
|
||||
if (token.isEmpty()) {
|
||||
plugin.getLogger().warning("Неизвестный срок наказания в config.yml: " + value);
|
||||
} else {
|
||||
normalized.add(token);
|
||||
}
|
||||
}
|
||||
if (normalized.isEmpty()) {
|
||||
normalized.addAll(List.of("1h", "1d", "7d", "30d", "permanent"));
|
||||
}
|
||||
return new ArrayList<>(normalized);
|
||||
}
|
||||
|
||||
private String readDefaultPunishmentDuration(String action, String fallback) {
|
||||
String configured = config.getString("moderation_actions.durations.defaults." + action, fallback);
|
||||
String normalized = PunishmentDuration.normalizeToken(configured);
|
||||
if (!normalized.isEmpty() && punishmentDurationOptions.contains(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
plugin.getLogger().warning("Срок по умолчанию для " + action + " отсутствует в списке options: " + configured);
|
||||
return punishmentDurationOptions.contains(fallback) ? fallback : punishmentDurationOptions.getFirst();
|
||||
}
|
||||
|
||||
private String readModerationCommand(String action, String legacyTemplate, String newTemplate, boolean requiresDuration) {
|
||||
String path = "moderation_actions.commands." + action;
|
||||
String configured = config.getString(path, newTemplate);
|
||||
if (configured == null || configured.isBlank()) {
|
||||
return "";
|
||||
}
|
||||
configured = configured.trim();
|
||||
if (configured.equals(legacyTemplate)) {
|
||||
plugin.getLogger().info("Шаблон команды " + action + " обновлён в памяти до формата наказаний со сроком/автором.");
|
||||
configured = newTemplate;
|
||||
}
|
||||
if (requiresDuration && !configured.contains("{duration}")) {
|
||||
plugin.getLogger().warning("Команда " + action + " отключена: шаблон " + path + " должен содержать {duration}.");
|
||||
return "";
|
||||
}
|
||||
if (!configured.contains("{target}")) {
|
||||
plugin.getLogger().warning("Команда " + action + " отключена: шаблон " + path + " должен содержать {target}.");
|
||||
return "";
|
||||
}
|
||||
return configured;
|
||||
}
|
||||
}
|
||||
|
||||
86
src/main/java/org/blz/adminmode/data/AdminModeDataManager.java
Normal file → Executable file
86
src/main/java/org/blz/adminmode/data/AdminModeDataManager.java
Normal file → Executable file
@@ -1,29 +1,23 @@
|
||||
package org.blz.adminmode.data;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.blz.adminmode.utils.ItemStackCodec;
|
||||
import org.blz.adminmode.utils.PotionEffectCodec;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
import org.bukkit.util.io.BukkitObjectOutputStream;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@@ -187,16 +181,7 @@ public class AdminModeDataManager {
|
||||
|
||||
private String serializeItemArray(ItemStack[] items) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
|
||||
dataOutput.writeInt(items.length);
|
||||
|
||||
for (ItemStack item : items) {
|
||||
dataOutput.writeObject(item);
|
||||
}
|
||||
|
||||
dataOutput.close();
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
return ItemStackCodec.serializeItems(items);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
@@ -205,17 +190,7 @@ public class AdminModeDataManager {
|
||||
|
||||
private ItemStack[] deserializeItemArray(String data) {
|
||||
try {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(data));
|
||||
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
|
||||
int length = dataInput.readInt();
|
||||
ItemStack[] items = new ItemStack[length];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
items[i] = (ItemStack) dataInput.readObject();
|
||||
}
|
||||
|
||||
dataInput.close();
|
||||
return items;
|
||||
return ItemStackCodec.deserializeItems(data);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new ItemStack[0];
|
||||
@@ -224,11 +199,7 @@ public class AdminModeDataManager {
|
||||
|
||||
private String serializeItem(ItemStack item) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
|
||||
dataOutput.writeObject(item);
|
||||
dataOutput.close();
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
return ItemStackCodec.serializeItem(item);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
@@ -238,56 +209,23 @@ public class AdminModeDataManager {
|
||||
private ItemStack deserializeItem(String data) {
|
||||
try {
|
||||
if (data.isEmpty()) {
|
||||
return new ItemStack(Material.AIR);
|
||||
return ItemStack.empty();
|
||||
}
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(data));
|
||||
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
|
||||
ItemStack item = (ItemStack) dataInput.readObject();
|
||||
dataInput.close();
|
||||
return item;
|
||||
return ItemStackCodec.deserializeItem(data);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new ItemStack(Material.AIR);
|
||||
return ItemStack.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private String serializePotionEffects(Collection<PotionEffect> effects) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (PotionEffect effect : effects) {
|
||||
sb.append(effect.getType().getName()).append(":")
|
||||
.append(effect.getDuration()).append(":")
|
||||
.append(effect.getAmplifier()).append(":")
|
||||
.append(effect.isAmbient()).append(":")
|
||||
.append(effect.hasParticles()).append(":")
|
||||
.append(effect.hasIcon()).append(";");
|
||||
}
|
||||
return sb.toString();
|
||||
return PotionEffectCodec.serialize(effects);
|
||||
}
|
||||
|
||||
private Collection<PotionEffect> deserializePotionEffects(String data) {
|
||||
Collection<PotionEffect> effects = new ArrayList<>();
|
||||
if (data.isEmpty()) return effects;
|
||||
|
||||
String[] effectStrings = data.split(";");
|
||||
for (String effectStr : effectStrings) {
|
||||
if (effectStr.isEmpty()) continue;
|
||||
|
||||
try {
|
||||
String[] parts = effectStr.split(":");
|
||||
PotionEffectType type = PotionEffectType.getByName(parts[0]);
|
||||
int duration = Integer.parseInt(parts[1]);
|
||||
int amplifier = Integer.parseInt(parts[2]);
|
||||
boolean ambient = Boolean.parseBoolean(parts[3]);
|
||||
boolean particles = Boolean.parseBoolean(parts[4]);
|
||||
boolean icon = Boolean.parseBoolean(parts[5]);
|
||||
|
||||
effects.add(new PotionEffect(type, duration, amplifier, ambient, particles, icon));
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Ошибка десериализации эффекта: " + effectStr);
|
||||
}
|
||||
}
|
||||
|
||||
return effects;
|
||||
return PotionEffectCodec.deserialize(data,
|
||||
encodedEffect -> plugin.getLogger().warning(
|
||||
"Ошибка десериализации эффекта: " + encodedEffect));
|
||||
}
|
||||
|
||||
public static class PlayerStateData {
|
||||
|
||||
1479
src/main/java/org/blz/adminmode/dialog/AdminDialogService.java
Normal file → Executable file
1479
src/main/java/org/blz/adminmode/dialog/AdminDialogService.java
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
63
src/main/java/org/blz/adminmode/dialog/DialogPreferenceStore.java
Executable file
63
src/main/java/org/blz/adminmode/dialog/DialogPreferenceStore.java
Executable file
@@ -0,0 +1,63 @@
|
||||
package org.blz.adminmode.dialog;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Persists which players have personally enabled the Dialog-based admin panel.
|
||||
* Stored in <data-folder>/dialog_prefs.dat (one UUID per line).
|
||||
* Default: disabled for every player until they explicitly toggle on.
|
||||
*/
|
||||
public class DialogPreferenceStore {
|
||||
|
||||
private final File file;
|
||||
private final Set<UUID> enabledPlayers = new HashSet<>();
|
||||
|
||||
public DialogPreferenceStore(Plugin plugin) {
|
||||
file = new File(plugin.getDataFolder(), "dialog_prefs.dat");
|
||||
load();
|
||||
}
|
||||
|
||||
public boolean isEnabled(UUID playerId) {
|
||||
return enabledPlayers.contains(playerId);
|
||||
}
|
||||
|
||||
/** Toggles the preference and persists. Returns the new state (true = enabled). */
|
||||
public boolean toggle(UUID playerId) {
|
||||
if (enabledPlayers.remove(playerId)) {
|
||||
save();
|
||||
return false;
|
||||
}
|
||||
enabledPlayers.add(playerId);
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void load() {
|
||||
if (!file.exists()) return;
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) continue;
|
||||
try {
|
||||
enabledPlayers.add(UUID.fromString(line));
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
file.getParentFile().mkdirs();
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||
for (UUID uuid : enabledPlayers) {
|
||||
writer.write(uuid.toString());
|
||||
writer.newLine();
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
72
src/main/java/org/blz/adminmode/dialog/MenuEmojiPreferenceStore.java
Executable file
72
src/main/java/org/blz/adminmode/dialog/MenuEmojiPreferenceStore.java
Executable file
@@ -0,0 +1,72 @@
|
||||
package org.blz.adminmode.dialog;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Stores players who disabled emojis in the moderation dialogs.
|
||||
* Default: emojis are enabled.
|
||||
*/
|
||||
public class MenuEmojiPreferenceStore {
|
||||
|
||||
private final File file;
|
||||
private final Set<UUID> disabledPlayers = new HashSet<>();
|
||||
|
||||
public MenuEmojiPreferenceStore(Plugin plugin) {
|
||||
this.file = new File(plugin.getDataFolder(), "menu_emoji_prefs.dat");
|
||||
load();
|
||||
}
|
||||
|
||||
public boolean isEnabled(UUID playerId) {
|
||||
return !disabledPlayers.contains(playerId);
|
||||
}
|
||||
|
||||
public boolean toggle(UUID playerId) {
|
||||
if (disabledPlayers.remove(playerId)) {
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
disabledPlayers.add(playerId);
|
||||
save();
|
||||
return false;
|
||||
}
|
||||
|
||||
private void load() {
|
||||
if (!file.exists()) return;
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) continue;
|
||||
try {
|
||||
disabledPlayers.add(UUID.fromString(line));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
File parent = file.getParentFile();
|
||||
if (parent != null) {
|
||||
parent.mkdirs();
|
||||
}
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||
for (UUID uuid : disabledPlayers) {
|
||||
writer.write(uuid.toString());
|
||||
writer.newLine();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
113
src/main/java/org/blz/adminmode/integrations/CoreProtectIntegration.java
Normal file → Executable file
113
src/main/java/org/blz/adminmode/integrations/CoreProtectIntegration.java
Normal file → Executable file
@@ -29,31 +29,67 @@ public class CoreProtectIntegration {
|
||||
}
|
||||
|
||||
public boolean lookup(Player player, String targetPlayer, int radius, String time) {
|
||||
return lookup(player, targetPlayer, "", "", "", "", radius, time);
|
||||
}
|
||||
|
||||
public boolean lookup(Player player, String targetPlayer, String action, String block, String exclude,
|
||||
String world, int radius, String time) {
|
||||
if (!isAvailable()) {
|
||||
player.sendMessage(configManager.getPrefixedMessage(configManager.getMsgCoreProtectUnavailable()));
|
||||
return false;
|
||||
}
|
||||
|
||||
StringBuilder command = new StringBuilder("co lookup");
|
||||
appendPlayerFilter(command, targetPlayer);
|
||||
command.append(" r:").append(normalizeRadius(radius));
|
||||
command.append(" t:").append(normalizeTime(time));
|
||||
appendCommonFilters(command, targetPlayer, action, block, exclude, world, radius, time);
|
||||
return Bukkit.dispatchCommand(player, command.toString());
|
||||
}
|
||||
|
||||
public boolean rollback(Player player, int radius, String time, String targetPlayer) {
|
||||
public boolean rollback(Player player, int radius, String time, String targetPlayer, String action, String block, String exclude) {
|
||||
return rollback(player, radius, time, targetPlayer, action, block, exclude, "", "");
|
||||
}
|
||||
|
||||
public boolean rollback(Player player, int radius, String time, String targetPlayer, String action, String block,
|
||||
String exclude, String world, String extraFilters) {
|
||||
if (!isAvailable()) {
|
||||
player.sendMessage(configManager.getPrefixedMessage(configManager.getMsgCoreProtectUnavailable()));
|
||||
return false;
|
||||
}
|
||||
|
||||
StringBuilder command = new StringBuilder("co rollback");
|
||||
appendPlayerFilter(command, targetPlayer);
|
||||
command.append(" r:").append(normalizeRadius(radius));
|
||||
command.append(" t:").append(normalizeTime(time));
|
||||
appendCommonFilters(command, targetPlayer, action, block, exclude, world, radius, time);
|
||||
appendExtraFilters(command, extraFilters);
|
||||
return Bukkit.dispatchCommand(player, command.toString());
|
||||
}
|
||||
|
||||
public boolean restore(Player player, int radius, String time, String targetPlayer, String action, String block,
|
||||
String exclude, String world, String extraFilters) {
|
||||
if (!isAvailable()) {
|
||||
player.sendMessage(configManager.getPrefixedMessage(configManager.getMsgCoreProtectUnavailable()));
|
||||
return false;
|
||||
}
|
||||
|
||||
StringBuilder command = new StringBuilder("co restore");
|
||||
appendCommonFilters(command, targetPlayer, action, block, exclude, world, radius, time);
|
||||
appendExtraFilters(command, extraFilters);
|
||||
return Bukkit.dispatchCommand(player, command.toString());
|
||||
}
|
||||
|
||||
private String sanitizeAction(String action) {
|
||||
String normalized = action.trim();
|
||||
if (normalized.matches("[a-zA-Z0-9_,:+\\-]+")) {
|
||||
return normalized;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String sanitizeBlock(String block) {
|
||||
String normalized = block.trim();
|
||||
if (normalized.matches("[a-zA-Z0-9_,:]+")) {
|
||||
return normalized;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private void appendPlayerFilter(StringBuilder command, String targetPlayer) {
|
||||
String sanitized = sanitizePlayerName(targetPlayer);
|
||||
if (!sanitized.isEmpty()) {
|
||||
@@ -61,6 +97,58 @@ public class CoreProtectIntegration {
|
||||
}
|
||||
}
|
||||
|
||||
private void appendActionFilter(StringBuilder command, String action) {
|
||||
String sanitized = sanitizeAction(action);
|
||||
if (!sanitized.isEmpty()) {
|
||||
command.append(" a:").append(sanitized);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendBlockFilter(StringBuilder command, String block) {
|
||||
String sanitized = sanitizeBlock(block);
|
||||
if (!sanitized.isEmpty()) {
|
||||
command.append(" b:").append(sanitized);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendExcludeFilter(StringBuilder command, String exclude) {
|
||||
String sanitized = sanitizeBlock(exclude);
|
||||
if (!sanitized.isEmpty()) {
|
||||
command.append(" e:").append(sanitized);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendWorldFilter(StringBuilder command, String world) {
|
||||
String sanitized = sanitizeWorld(world);
|
||||
if (!sanitized.isEmpty()) {
|
||||
command.append(" w:").append(sanitized);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendCommonFilters(StringBuilder command, String targetPlayer, String action, String block,
|
||||
String exclude, String world, int radius, String time) {
|
||||
appendPlayerFilter(command, targetPlayer);
|
||||
appendActionFilter(command, action);
|
||||
appendBlockFilter(command, block);
|
||||
appendExcludeFilter(command, exclude);
|
||||
appendWorldFilter(command, world);
|
||||
command.append(" r:").append(normalizeRadius(radius));
|
||||
command.append(" t:").append(normalizeTime(time));
|
||||
}
|
||||
|
||||
private void appendExtraFilters(StringBuilder command, String extraFilters) {
|
||||
if (extraFilters == null || extraFilters.isBlank()) {
|
||||
return;
|
||||
}
|
||||
String[] tokens = extraFilters.split(";");
|
||||
for (String token : tokens) {
|
||||
String normalized = token.trim();
|
||||
if (normalized.matches("[a-zA-Z]+:[A-Za-z0-9_.,:+\\-]+")) {
|
||||
command.append(' ').append(normalized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int normalizeRadius(int radius) {
|
||||
return Math.max(1, Math.min(100, radius));
|
||||
}
|
||||
@@ -89,4 +177,15 @@ public class CoreProtectIntegration {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String sanitizeWorld(String world) {
|
||||
if (world == null || world.isBlank()) {
|
||||
return "";
|
||||
}
|
||||
String normalized = world.trim();
|
||||
if (normalized.matches("[A-Za-z0-9_:\\-]+")) {
|
||||
return normalized;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
65
src/main/java/org/blz/adminmode/integrations/LuckPermsIntegration.java
Normal file → Executable file
65
src/main/java/org/blz/adminmode/integrations/LuckPermsIntegration.java
Normal file → Executable file
@@ -6,7 +6,6 @@ import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.node.Node;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.blz.adminmode.moderation.ModeSession;
|
||||
import org.blz.adminmode.moderation.ModeratorProfile;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
@@ -21,64 +20,54 @@ public class LuckPermsIntegration {
|
||||
}
|
||||
|
||||
public String resolveCurrentGroup(Player player) {
|
||||
if (!configManager.isUseLuckPerms()) {
|
||||
return configManager.getBaseGroup();
|
||||
}
|
||||
|
||||
if (!configManager.isUseLuckPerms()) return configManager.getBaseGroup();
|
||||
try {
|
||||
User user = resolveUser(player);
|
||||
if (user == null) {
|
||||
return configManager.getBaseGroup();
|
||||
}
|
||||
return user.getPrimaryGroup();
|
||||
} catch (IllegalStateException exception) {
|
||||
return user != null ? user.getPrimaryGroup() : configManager.getBaseGroup();
|
||||
} catch (RuntimeException e) {
|
||||
plugin.getLogger().warning("Не удалось определить текущую группу LuckPerms для " + player.getName() + ": " + e.getMessage());
|
||||
return configManager.getBaseGroup();
|
||||
}
|
||||
}
|
||||
|
||||
public void enterMode(Player player, ModeratorProfile profile) {
|
||||
public void enterMode(Player player) {
|
||||
if (!configManager.isUseLuckPerms()) {
|
||||
player.setOp(true);
|
||||
plugin.getLogger().warning("LuckPerms-интеграция отключена в конфиге. Временные группы для " + player.getName() + " не применены.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
User user = resolveUser(player);
|
||||
if (user == null) {
|
||||
return;
|
||||
if (user == null) return;
|
||||
for (String group : configManager.getLuckPermsGroups()) {
|
||||
user.data().add(groupNode(group));
|
||||
}
|
||||
|
||||
removeKnownGroups(user);
|
||||
user.data().add(groupNode(configManager.getActiveGroup(profile)));
|
||||
saveUser(user);
|
||||
} catch (IllegalStateException exception) {
|
||||
player.setOp(true);
|
||||
plugin.getLogger().warning("LuckPerms не найден, используется OP для " + player.getName());
|
||||
} catch (RuntimeException e) {
|
||||
plugin.getLogger().warning("Не удалось выдать временные группы LuckPerms для " + player.getName() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void exitMode(Player player, ModeSession session) {
|
||||
if (!configManager.isUseLuckPerms()) {
|
||||
player.setOp(false);
|
||||
plugin.getLogger().warning("LuckPerms-интеграция отключена в конфиге. Группы для " + player.getName() + " не менялись.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
User user = resolveUser(player);
|
||||
if (user == null) {
|
||||
return;
|
||||
if (user == null) return;
|
||||
if (configManager.isRemoveGroupsOnDisable()) {
|
||||
removeTemporaryGroups(user);
|
||||
}
|
||||
|
||||
removeKnownGroups(user);
|
||||
String restoreGroup = session.getPreviousGroup();
|
||||
if (restoreGroup == null || restoreGroup.isBlank() || "op".equalsIgnoreCase(restoreGroup)) {
|
||||
restoreGroup = configManager.getBaseGroup();
|
||||
}
|
||||
user.data().add(groupNode(restoreGroup));
|
||||
saveUser(user);
|
||||
} catch (IllegalStateException exception) {
|
||||
player.setOp(false);
|
||||
plugin.getLogger().warning("LuckPerms не найден, снят OP у " + player.getName());
|
||||
} catch (RuntimeException e) {
|
||||
plugin.getLogger().warning("Не удалось восстановить группы LuckPerms для " + player.getName() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void removeTemporaryGroups(User user) {
|
||||
user.data().remove(groupNode(configManager.getAdminGroup()));
|
||||
for (String group : configManager.getLuckPermsGroups()) {
|
||||
user.data().remove(groupNode(group));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,12 +80,6 @@ public class LuckPermsIntegration {
|
||||
return user;
|
||||
}
|
||||
|
||||
private void removeKnownGroups(User user) {
|
||||
user.data().remove(groupNode(configManager.getBaseGroup()));
|
||||
user.data().remove(groupNode(configManager.getSoftGroup()));
|
||||
user.data().remove(groupNode(configManager.getHardGroup()));
|
||||
}
|
||||
|
||||
private Node groupNode(String group) {
|
||||
return Node.builder("group." + group).build();
|
||||
}
|
||||
|
||||
15
src/main/java/org/blz/adminmode/listeners/AdminModeListener.java
Normal file → Executable file
15
src/main/java/org/blz/adminmode/listeners/AdminModeListener.java
Normal file → Executable file
@@ -97,21 +97,14 @@ public class AdminModeListener implements Listener {
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
|
||||
|
||||
if ((e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK)
|
||||
&& e.getItem() != null
|
||||
&& modeManager.isPanelItem(e.getItem())) {
|
||||
if (e.getAction() == Action.RIGHT_CLICK_BLOCK && e.getClickedBlock() != null
|
||||
&& e.getClickedBlock().getType() == Material.ENDER_CHEST) {
|
||||
e.setCancelled(true);
|
||||
|
||||
String panelType = modeManager.getPanelType(e.getItem());
|
||||
if (ModeManager.PANEL_CP_INSPECTOR.equals(panelType)) {
|
||||
adminModeCommand.toggleInspector(player);
|
||||
return;
|
||||
}
|
||||
|
||||
dialogService.openCurrentPanel(player);
|
||||
player.sendMessage(configManager.getPrefixedMessage("§cВ admin mode нельзя взаимодействовать с эндер-сундуком."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!configManager.isPreventItemUse()) return;
|
||||
|
||||
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
|
||||
49
src/main/java/org/blz/adminmode/listeners/GameModeChangeListener.java
Normal file → Executable file
49
src/main/java/org/blz/adminmode/listeners/GameModeChangeListener.java
Normal file → Executable file
@@ -4,8 +4,6 @@ import java.util.List;
|
||||
|
||||
import org.blz.adminmode.commands.AdminModeCommand;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.blz.adminmode.moderation.ModeratorProfile;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -26,29 +24,11 @@ public class GameModeChangeListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onGameModeChange(PlayerGameModeChangeEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModeratorProfile activeProfile = adminModeCommand.getActiveProfile(player.getUniqueId());
|
||||
boolean hardProfile = activeProfile != null && activeProfile.isHardProfile();
|
||||
|
||||
if (event.getNewGameMode() == GameMode.CREATIVE && !hardProfile) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage(configManager.getPrefixedMessage("§c✖ В режиме Soft Moder креатив запрещен!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getNewGameMode() == GameMode.CREATIVE && hardProfile) {
|
||||
return;
|
||||
}
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
|
||||
|
||||
List<String> allowedModes = configManager.getAllowedGameModes();
|
||||
|
||||
if (!allowedModes.isEmpty()) {
|
||||
String newMode = event.getNewGameMode().name();
|
||||
|
||||
if (!allowedModes.contains(newMode)) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage(configManager.getPrefixedMessage("§c✖ В админ моде можно переключаться только на разрешенные режимы!"));
|
||||
@@ -57,15 +37,18 @@ public class GameModeChangeListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
// Включаем полет после смены режима, если это разрешено
|
||||
if (event.getNewGameMode() == org.bukkit.GameMode.CREATIVE && !player.hasPermission("adminmode.chief")) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage(configManager.getPrefixedMessage("§cКреатив в admin mode доступен только главным модераторам."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (configManager.isAllowFlightInSurvival()) {
|
||||
player.getServer().getScheduler().runTaskLater(
|
||||
player.getServer().getPluginManager().getPlugin("AdminMode"),
|
||||
() -> {
|
||||
player.setAllowFlight(true);
|
||||
if (!player.isFlying()) {
|
||||
player.setFlying(true);
|
||||
}
|
||||
if (!player.isFlying()) player.setFlying(true);
|
||||
},
|
||||
1L);
|
||||
}
|
||||
@@ -74,18 +57,8 @@ public class GameModeChangeListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onToggleFlight(PlayerToggleFlightEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!configManager.isAllowFlightInSurvival()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Всегда разрешаем полет в админ моде
|
||||
if (!player.getAllowFlight()) {
|
||||
player.setAllowFlight(true);
|
||||
}
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
|
||||
if (!configManager.isAllowFlightInSurvival()) return;
|
||||
if (!player.getAllowFlight()) player.setAllowFlight(true);
|
||||
}
|
||||
}
|
||||
|
||||
0
src/main/java/org/blz/adminmode/listeners/MobTargetListener.java
Normal file → Executable file
0
src/main/java/org/blz/adminmode/listeners/MobTargetListener.java
Normal file → Executable file
2
src/main/java/org/blz/adminmode/listeners/PlayerDeathListener.java
Normal file → Executable file
2
src/main/java/org/blz/adminmode/listeners/PlayerDeathListener.java
Normal file → Executable file
@@ -15,6 +15,6 @@ public class PlayerDeathListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||
modeManager.handleHardModeDeath(event);
|
||||
modeManager.handleAdminDeath(event);
|
||||
}
|
||||
}
|
||||
|
||||
3
src/main/java/org/blz/adminmode/listeners/PlayerSessionListener.java
Normal file → Executable file
3
src/main/java/org/blz/adminmode/listeners/PlayerSessionListener.java
Normal file → Executable file
@@ -26,13 +26,14 @@ public class PlayerSessionListener implements Listener {
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
modeManager.refreshVanishFor(player);
|
||||
if (!modeManager.hasSession(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.getServer().getScheduler().runTaskLater(
|
||||
org.blz.adminmode.AdminMode.getInstance(),
|
||||
() -> adminModeCommand.recoverSession(player),
|
||||
() -> adminModeCommand.resumeMode(player),
|
||||
1L);
|
||||
}
|
||||
}
|
||||
|
||||
60
src/main/java/org/blz/adminmode/managers/BelzeBoolManager.java
Normal file → Executable file
60
src/main/java/org/blz/adminmode/managers/BelzeBoolManager.java
Normal file → Executable file
@@ -10,6 +10,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
@@ -23,6 +24,7 @@ import java.util.*;
|
||||
|
||||
public class BelzeBoolManager implements Listener {
|
||||
|
||||
private static final String SPECIAL_PERMISSION = "adminmode.special.belzebool";
|
||||
private final Plugin plugin;
|
||||
private final String BELZEBOOL_NAME = "BelzeBool";
|
||||
private final String POCKET_DIMENSION_WORLD = "pocket_dimension";
|
||||
@@ -39,6 +41,9 @@ public class BelzeBoolManager implements Listener {
|
||||
// Vanish State: UUID -> isVanished
|
||||
private final Set<UUID> vanishedPlayers = new HashSet<>();
|
||||
|
||||
// Pocket return state: player UUID -> original location before abduction
|
||||
private final Map<UUID, Location> pocketReturnLocations = new HashMap<>();
|
||||
|
||||
// Input Tracking
|
||||
private final Map<UUID, List<Long>> rightClickTimestamps = new HashMap<>();
|
||||
|
||||
@@ -49,7 +54,7 @@ public class BelzeBoolManager implements Listener {
|
||||
}
|
||||
|
||||
public boolean isBelzeBool(Player player) {
|
||||
return player.getName().equalsIgnoreCase(BELZEBOOL_NAME);
|
||||
return player.hasPermission(SPECIAL_PERMISSION) && player.getName().equalsIgnoreCase(BELZEBOOL_NAME);
|
||||
}
|
||||
|
||||
// --- Casting Mode Logic ---
|
||||
@@ -278,6 +283,9 @@ public class BelzeBoolManager implements Listener {
|
||||
target.getWorld().spawnParticle(Particle.SCULK_SOUL, target.getLocation(), 50, 0.5, 1, 0.5, 0.1);
|
||||
|
||||
Location originalLoc = target.getLocation();
|
||||
if (target instanceof Player targetPlayer) {
|
||||
pocketReturnLocations.put(targetPlayer.getUniqueId(), originalLoc.clone());
|
||||
}
|
||||
|
||||
// 2. Teleport after 5 seconds
|
||||
new BukkitRunnable() {
|
||||
@@ -320,6 +328,8 @@ public class BelzeBoolManager implements Listener {
|
||||
if (target instanceof Player targetP) {
|
||||
targetP.removePotionEffect(PotionEffectType.LEVITATION);
|
||||
targetP.removePotionEffect(PotionEffectType.DARKNESS);
|
||||
targetP.removePotionEffect(PotionEffectType.SLOWNESS);
|
||||
pocketReturnLocations.remove(targetP.getUniqueId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -410,4 +420,52 @@ public class BelzeBoolManager implements Listener {
|
||||
player.sendMessage(Component.text("You have vanished.", NamedTextColor.AQUA));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Location returnLocation = pocketReturnLocations.remove(player.getUniqueId());
|
||||
if (returnLocation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
player.teleport(returnLocation);
|
||||
player.removePotionEffect(PotionEffectType.LEVITATION);
|
||||
player.removePotionEffect(PotionEffectType.DARKNESS);
|
||||
player.removePotionEffect(PotionEffectType.SLOWNESS);
|
||||
});
|
||||
}
|
||||
|
||||
public boolean forceDisable(Player player) {
|
||||
boolean changed = false;
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
if (castingModePlayers.remove(uuid)) {
|
||||
changed = true;
|
||||
}
|
||||
rightClickTimestamps.remove(uuid);
|
||||
selectedSpellIndex.remove(uuid);
|
||||
cooldowns.remove(uuid);
|
||||
|
||||
if (vanishedPlayers.remove(uuid)) {
|
||||
for (Player online : Bukkit.getOnlinePlayers()) {
|
||||
online.showPlayer(plugin, player);
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
Location returnLocation = pocketReturnLocations.remove(uuid);
|
||||
if (returnLocation != null) {
|
||||
changed = true;
|
||||
if (player.isOnline()) {
|
||||
player.teleport(returnLocation);
|
||||
}
|
||||
player.removePotionEffect(PotionEffectType.LEVITATION);
|
||||
player.removePotionEffect(PotionEffectType.DARKNESS);
|
||||
player.removePotionEffect(PotionEffectType.SLOWNESS);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
333
src/main/java/org/blz/adminmode/moderation/ModeManager.java
Normal file → Executable file
333
src/main/java/org/blz/adminmode/moderation/ModeManager.java
Normal file → Executable file
@@ -8,7 +8,6 @@ import org.blz.adminmode.session.SessionStorage;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
@@ -16,46 +15,44 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ModeManager {
|
||||
|
||||
public static final String PANEL_SOFT = "soft";
|
||||
public static final String PANEL_HARD = "hard";
|
||||
public static final String PANEL_CP_INSPECTOR = "cp_inspector";
|
||||
|
||||
private final Plugin plugin;
|
||||
private final ConfigManager configManager;
|
||||
private final LuckPermsIntegration luckPermsIntegration;
|
||||
private final SessionStorage sessionStorage;
|
||||
private final ModeSessionLogger sessionLogger;
|
||||
private final NamespacedKey panelTypeKey;
|
||||
private final ModeratorPreferencesStore preferencesStore;
|
||||
private final Map<UUID, ModeSession> activeSessions = new HashMap<>();
|
||||
private final Set<UUID> vanishedModerators = new HashSet<>();
|
||||
|
||||
public ModeManager(
|
||||
Plugin plugin,
|
||||
ConfigManager configManager,
|
||||
LuckPermsIntegration luckPermsIntegration,
|
||||
SessionStorage sessionStorage,
|
||||
ModeSessionLogger sessionLogger) {
|
||||
ModeSessionLogger sessionLogger,
|
||||
ModeratorPreferencesStore preferencesStore) {
|
||||
this.plugin = plugin;
|
||||
this.configManager = configManager;
|
||||
this.luckPermsIntegration = luckPermsIntegration;
|
||||
this.sessionStorage = sessionStorage;
|
||||
this.sessionLogger = sessionLogger;
|
||||
this.panelTypeKey = new NamespacedKey(plugin, "panel_type");
|
||||
this.preferencesStore = preferencesStore;
|
||||
this.activeSessions.putAll(sessionStorage.loadSessions());
|
||||
}
|
||||
|
||||
@@ -71,37 +68,32 @@ public class ModeManager {
|
||||
return player == null ? null : getSession(player.getUniqueId());
|
||||
}
|
||||
|
||||
public ModeratorProfile getProfile(UUID playerId) {
|
||||
ModeSession session = getSession(playerId);
|
||||
return session == null ? null : session.getProfile();
|
||||
}
|
||||
|
||||
public List<ModeratorProfile> getAvailableProfiles(Player player) {
|
||||
return ModeratorProfile.availableFor(player);
|
||||
}
|
||||
|
||||
public Collection<ModeSession> getActiveSessions() {
|
||||
return new ArrayList<>(activeSessions.values());
|
||||
}
|
||||
|
||||
public boolean enterMode(Player player, ModeratorProfile profile) {
|
||||
if (player == null || profile == null || hasSession(player.getUniqueId())) {
|
||||
return false;
|
||||
}
|
||||
public boolean enterMode(Player player) {
|
||||
if (player == null || hasSession(player.getUniqueId())) return false;
|
||||
if (!player.hasPermission(ModeratorProfile.ADMIN.getPermission())) return false;
|
||||
|
||||
String previousGroup = luckPermsIntegration.resolveCurrentGroup(player);
|
||||
String activeGroup = configManager.getActiveGroup(profile);
|
||||
ModeSession session = ModeSession.capture(player, profile, previousGroup, activeGroup);
|
||||
activeSessions.put(player.getUniqueId(), session);
|
||||
persistSessions();
|
||||
ModeSession session = ModeSession.capture(player, ModeratorProfile.ADMIN, previousGroup, configManager.getAdminGroup());
|
||||
try {
|
||||
activeSessions.put(player.getUniqueId(), session);
|
||||
persistSessions();
|
||||
|
||||
preparePlayerForModeration(player, profile);
|
||||
luckPermsIntegration.enterMode(player, profile);
|
||||
sessionLogger.logEnter(session);
|
||||
preparePlayerForModeration(player);
|
||||
luckPermsIntegration.enterMode(player);
|
||||
sessionLogger.logEnter(session);
|
||||
|
||||
String enterMessage = profile.isHardProfile() ? configManager.getMsgEnterHard() : configManager.getMsgEnterSoft();
|
||||
player.sendMessage(configManager.getPrefixedMessage(enterMessage));
|
||||
return true;
|
||||
player.sendMessage(configManager.getPrefixedMessage(configManager.getMsgEnter()));
|
||||
return true;
|
||||
} catch (RuntimeException exception) {
|
||||
activeSessions.remove(player.getUniqueId());
|
||||
persistSessions();
|
||||
plugin.getLogger().warning("AdminMode: не удалось включить режим для " + player.getName() + ": " + exception.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean exitMode(Player player) {
|
||||
@@ -112,6 +104,19 @@ public class ModeManager {
|
||||
return finishSession(player, true);
|
||||
}
|
||||
|
||||
public boolean resumeMode(Player player) {
|
||||
if (player == null || !hasSession(player.getUniqueId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
applyResumedModerationState(player);
|
||||
luckPermsIntegration.enterMode(player);
|
||||
if (isVanished(player.getUniqueId())) {
|
||||
reapplyVanish(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void markQuit(Player player) {
|
||||
if (player != null && hasSession(player.getUniqueId())) {
|
||||
persistSessions();
|
||||
@@ -119,33 +124,48 @@ public class ModeManager {
|
||||
}
|
||||
|
||||
public boolean canUseHardActions(CommandSender sender) {
|
||||
if (sender.hasPermission("adminmode.admin")) {
|
||||
return true;
|
||||
}
|
||||
return sender.hasPermission("adminmode.admin");
|
||||
}
|
||||
|
||||
if (!(sender instanceof Player player)) {
|
||||
public boolean isVanished(UUID playerId) {
|
||||
return vanishedModerators.contains(playerId);
|
||||
}
|
||||
|
||||
public boolean toggleVanish(Player player) {
|
||||
if (player == null || !hasSession(player.getUniqueId())) {
|
||||
return false;
|
||||
}
|
||||
if (isVanished(player.getUniqueId())) {
|
||||
disableVanish(player);
|
||||
player.sendMessage(configManager.getPrefixedMessage("§7Vanish отключён."));
|
||||
return false;
|
||||
}
|
||||
enableVanish(player);
|
||||
player.sendMessage(configManager.getPrefixedMessage("§aVanish включён."));
|
||||
return true;
|
||||
}
|
||||
|
||||
ModeSession session = getSession(player);
|
||||
return session != null && session.getProfile().isHardProfile();
|
||||
public void refreshVanishFor(Player viewer) {
|
||||
if (viewer == null) {
|
||||
return;
|
||||
}
|
||||
for (UUID vanishedId : vanishedModerators) {
|
||||
Player vanishedPlayer = plugin.getServer().getPlayer(vanishedId);
|
||||
if (vanishedPlayer != null && !viewer.getUniqueId().equals(vanishedId)) {
|
||||
viewer.hidePlayer(plugin, vanishedPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean teleportToPlayer(Player moderator, Player target) {
|
||||
if (moderator == null || target == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moderator == null || target == null) return false;
|
||||
moderator.teleport(target.getLocation());
|
||||
moderator.sendMessage(configManager.getPrefixedMessage("§aТелепортация к §f" + target.getName() + "§a выполнена."));
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean teleportPlayerHere(Player moderator, Player target) {
|
||||
if (moderator == null || target == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moderator == null || target == null) return false;
|
||||
target.teleport(moderator.getLocation());
|
||||
moderator.sendMessage(configManager.getPrefixedMessage("§aИгрок §f" + target.getName() + "§a телепортирован к вам."));
|
||||
target.sendMessage(configManager.getPrefixedMessage("§eВас телепортировал модератор §f" + moderator.getName()));
|
||||
@@ -153,15 +173,11 @@ public class ModeManager {
|
||||
}
|
||||
|
||||
public boolean spectatePlayer(Player moderator, Player target) {
|
||||
if (moderator == null || target == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moderator == null || target == null) return false;
|
||||
if (moderator.equals(target)) {
|
||||
moderator.sendMessage(configManager.getPrefixedMessage("§cНельзя спектейтить самого себя."));
|
||||
return false;
|
||||
}
|
||||
|
||||
moderator.setGameMode(GameMode.SPECTATOR);
|
||||
moderator.setSpectatorTarget((Entity) target);
|
||||
moderator.sendMessage(configManager.getPrefixedMessage("§bВы наблюдаете за §f" + target.getName()));
|
||||
@@ -169,20 +185,14 @@ public class ModeManager {
|
||||
}
|
||||
|
||||
public boolean openInvsee(Player moderator, Player target) {
|
||||
if (moderator == null || target == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
moderator.openInventory(target.getInventory());
|
||||
if (moderator == null || target == null) return false;
|
||||
moderator.getServer().dispatchCommand(moderator, "invsee " + target.getName());
|
||||
moderator.sendMessage(configManager.getPrefixedMessage("§7Открыт инвентарь игрока §f" + target.getName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void applyAdminSettings(Player player, float flySpeed, float walkSpeed, boolean invulnerable) {
|
||||
if (!hasSession(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasSession(player.getUniqueId())) return;
|
||||
player.setAllowFlight(true);
|
||||
player.setFlying(true);
|
||||
player.setFlySpeed(clampSpeed(flySpeed, 0.1f));
|
||||
@@ -192,7 +202,7 @@ public class ModeManager {
|
||||
|
||||
public List<Player> listOtherOnlinePlayers(Player viewer) {
|
||||
List<Player> players = new ArrayList<>(plugin.getServer().getOnlinePlayers());
|
||||
players.removeIf(player -> viewer != null && player.getUniqueId().equals(viewer.getUniqueId()));
|
||||
players.removeIf(p -> viewer != null && p.getUniqueId().equals(viewer.getUniqueId()));
|
||||
players.sort(Comparator.comparing(Player::getName, String.CASE_INSENSITIVE_ORDER));
|
||||
return players;
|
||||
}
|
||||
@@ -200,10 +210,10 @@ public class ModeManager {
|
||||
public List<Component> buildOnlineSummary(Player viewer) {
|
||||
List<Component> lines = new ArrayList<>();
|
||||
for (Player target : listOtherOnlinePlayers(viewer)) {
|
||||
Location location = target.getLocation();
|
||||
Location loc = target.getLocation();
|
||||
lines.add(Component.text(
|
||||
target.getName() + " | " + target.getWorld().getName() + " | " +
|
||||
location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ(),
|
||||
loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ(),
|
||||
NamedTextColor.GRAY));
|
||||
}
|
||||
if (lines.isEmpty()) {
|
||||
@@ -212,12 +222,11 @@ public class ModeManager {
|
||||
return lines;
|
||||
}
|
||||
|
||||
public void handleHardModeDeath(PlayerDeathEvent event) {
|
||||
/** Keep inventory/levels and teleport back on death while in admin mode. */
|
||||
public void handleAdminDeath(PlayerDeathEvent event) {
|
||||
Player player = event.getEntity();
|
||||
ModeSession session = getSession(player);
|
||||
if (session == null || !session.getProfile().isHardProfile()) {
|
||||
return;
|
||||
}
|
||||
if (session == null) return;
|
||||
|
||||
event.setKeepInventory(true);
|
||||
event.setKeepLevel(true);
|
||||
@@ -228,45 +237,18 @@ public class ModeManager {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPanelItem(ItemStack itemStack) {
|
||||
return getPanelType(itemStack) != null;
|
||||
}
|
||||
|
||||
public String getPanelType(ItemStack itemStack) {
|
||||
if (itemStack == null || itemStack.getType() == Material.AIR || !itemStack.hasItemMeta()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
|
||||
if (!container.has(panelTypeKey, PersistentDataType.STRING)) {
|
||||
return null;
|
||||
}
|
||||
return container.get(panelTypeKey, PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
public boolean isReadOnlyViewedInventory(Player viewer, org.bukkit.inventory.Inventory inventory) {
|
||||
if (viewer == null || inventory == null || inventory.getHolder() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(inventory.getHolder() instanceof Player target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (viewer == null || inventory == null || inventory.getHolder() == null) return false;
|
||||
if (!(inventory.getHolder() instanceof Player target)) return false;
|
||||
return hasSession(viewer.getUniqueId()) && !viewer.getUniqueId().equals(target.getUniqueId());
|
||||
}
|
||||
|
||||
private boolean finishSession(Player player, boolean recovered) {
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player == null) return false;
|
||||
ModeSession session = activeSessions.remove(player.getUniqueId());
|
||||
if (session == null) {
|
||||
return false;
|
||||
}
|
||||
if (session == null) return false;
|
||||
|
||||
disableVanish(player);
|
||||
restorePlayerState(player, session);
|
||||
luckPermsIntegration.exitMode(player, session);
|
||||
persistSessions();
|
||||
@@ -281,14 +263,14 @@ public class ModeManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void preparePlayerForModeration(Player player, ModeratorProfile profile) {
|
||||
private void preparePlayerForModeration(Player player) {
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
inventory.clear();
|
||||
inventory.setArmorContents(new ItemStack[4]);
|
||||
inventory.setItemInOffHand(new ItemStack(Material.AIR));
|
||||
inventory.setItemInOffHand(ItemStack.empty());
|
||||
|
||||
player.closeInventory();
|
||||
player.setSpectatorTarget(null);
|
||||
clearSpectatorTargetIfNeeded(player);
|
||||
for (PotionEffect effect : player.getActivePotionEffects()) {
|
||||
player.removePotionEffect(effect.getType());
|
||||
}
|
||||
@@ -305,27 +287,35 @@ public class ModeManager {
|
||||
player.setFlying(true);
|
||||
player.setFlySpeed(clampSpeed(configManager.getCustomFlySpeed(), 0.1f));
|
||||
player.setWalkSpeed(clampSpeed(configManager.getCustomWalkSpeed(), 0.1f));
|
||||
player.setInvulnerable(true);
|
||||
player.setGameMode(profile.isHardProfile() ? GameMode.CREATIVE : GameMode.SPECTATOR);
|
||||
|
||||
inventory.setItem(0, createPanelItem(profile.isHardProfile() ? configManager.getHardPanelMaterial() : configManager.getSoftPanelMaterial(),
|
||||
profile.isHardProfile() ? "Hard Panel" : "Soft Panel",
|
||||
profile.isHardProfile() ? NamedTextColor.RED : NamedTextColor.AQUA,
|
||||
profile.isHardProfile() ? PANEL_HARD : PANEL_SOFT));
|
||||
|
||||
if (profile.isHardProfile()) {
|
||||
inventory.setItem(1, createPanelItem(
|
||||
configManager.getCpInspectorMaterial(),
|
||||
"CP Inspector",
|
||||
NamedTextColor.YELLOW,
|
||||
PANEL_CP_INSPECTOR));
|
||||
}
|
||||
player.setInvulnerable(configManager.isGodMode());
|
||||
player.setGameMode(resolveAdminGameMode(player));
|
||||
|
||||
if (configManager.isGivePresetBlocks()) {
|
||||
givePresetBlocks(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyResumedModerationState(Player player) {
|
||||
player.closeInventory();
|
||||
clearSpectatorTargetIfNeeded(player);
|
||||
player.setFireTicks(0);
|
||||
player.setInvulnerable(configManager.isGodMode());
|
||||
player.setFlySpeed(clampSpeed(player.getFlySpeed(), configManager.getCustomFlySpeed()));
|
||||
player.setWalkSpeed(clampSpeed(player.getWalkSpeed(), configManager.getCustomWalkSpeed()));
|
||||
|
||||
GameMode resumedMode = isAdminGameModeAllowedForPlayer(player, player.getGameMode())
|
||||
? player.getGameMode()
|
||||
: resolveAdminGameMode(player);
|
||||
player.setGameMode(resumedMode);
|
||||
|
||||
if (!player.getAllowFlight() && (resumedMode != GameMode.SURVIVAL || configManager.isAllowFlightInSurvival())) {
|
||||
player.setAllowFlight(true);
|
||||
}
|
||||
if (player.getAllowFlight() && resumedMode != GameMode.SURVIVAL) {
|
||||
player.setFlying(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void restorePlayerState(Player player, ModeSession session) {
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
inventory.clear();
|
||||
@@ -333,7 +323,7 @@ public class ModeManager {
|
||||
inventory.setArmorContents(session.getArmorContents());
|
||||
inventory.setItemInOffHand(session.getOffHandItem());
|
||||
|
||||
player.setSpectatorTarget(null);
|
||||
clearSpectatorTargetIfNeeded(player);
|
||||
player.setInvulnerable(false);
|
||||
player.setAllowFlight(false);
|
||||
player.setFlying(false);
|
||||
@@ -346,7 +336,11 @@ public class ModeManager {
|
||||
|
||||
player.setGameMode(session.getGameMode());
|
||||
if (session.getLocation() != null) {
|
||||
player.teleport(session.getLocation());
|
||||
player.teleportAsync(session.getLocation()).thenAccept(success -> {
|
||||
if (!success) {
|
||||
plugin.getLogger().warning("AdminMode: Не удалось телепортировать " + player.getName() + " обратно.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
player.setHealth(Math.min(resolveMaxHealth(player), session.getHealth()));
|
||||
@@ -377,26 +371,96 @@ public class ModeManager {
|
||||
String[] parts = blockString.split(":");
|
||||
Material material = Material.valueOf(parts[0].trim().toUpperCase());
|
||||
int amount = parts.length > 1 ? Integer.parseInt(parts[1].trim()) : 64;
|
||||
player.getInventory().addItem(new ItemStack(material, Math.max(1, amount)));
|
||||
} catch (Exception exception) {
|
||||
player.getInventory().addItem(ItemStack.of(material, Math.max(1, amount)));
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Неверный блок в preset_blocks: " + blockString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack createPanelItem(Material material, String title, NamedTextColor color, String panelType) {
|
||||
ItemStack itemStack = new ItemStack(material);
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
itemMeta.displayName(Component.text("[" + title + "]", color));
|
||||
itemMeta.getPersistentDataContainer().set(panelTypeKey, PersistentDataType.STRING, panelType);
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
private void persistSessions() {
|
||||
sessionStorage.saveSessions(activeSessions);
|
||||
}
|
||||
|
||||
private void clearSpectatorTargetIfNeeded(Player player) {
|
||||
if (player.getGameMode() == GameMode.SPECTATOR) {
|
||||
player.setSpectatorTarget(null);
|
||||
}
|
||||
}
|
||||
|
||||
private GameMode resolveAdminGameMode(Player player) {
|
||||
if (configManager.isForceSpectator()) {
|
||||
return GameMode.SPECTATOR;
|
||||
}
|
||||
|
||||
ModeratorPreferencesStore.DefaultEntryMode preferredMode = preferencesStore.get(player.getUniqueId()).defaultEntryMode();
|
||||
return switch (preferredMode) {
|
||||
case SURVIVAL -> GameMode.SURVIVAL;
|
||||
case SPECTATOR -> GameMode.SPECTATOR;
|
||||
case AUTO -> fallbackDefaultGameMode(player);
|
||||
};
|
||||
}
|
||||
|
||||
private GameMode fallbackDefaultGameMode(Player player) {
|
||||
if (canUseCreativeInAdminMode(player)) {
|
||||
return GameMode.CREATIVE;
|
||||
}
|
||||
return GameMode.SPECTATOR;
|
||||
}
|
||||
|
||||
private boolean canUseCreativeInAdminMode(Player player) {
|
||||
return player.hasPermission("adminmode.chief") && configManager.isChiefCreativeMode();
|
||||
}
|
||||
|
||||
private boolean isAdminGameModeAllowedForPlayer(Player player, GameMode gameMode) {
|
||||
if (gameMode == null) {
|
||||
return false;
|
||||
}
|
||||
if (configManager.isForceSpectator()) {
|
||||
return gameMode == GameMode.SPECTATOR;
|
||||
}
|
||||
return switch (gameMode) {
|
||||
case SURVIVAL, SPECTATOR -> true;
|
||||
case CREATIVE -> canUseCreativeInAdminMode(player);
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private void enableVanish(Player player) {
|
||||
vanishedModerators.add(player.getUniqueId());
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false, false));
|
||||
player.setSilent(true);
|
||||
for (Player online : plugin.getServer().getOnlinePlayers()) {
|
||||
if (!online.getUniqueId().equals(player.getUniqueId())) {
|
||||
online.hidePlayer(plugin, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void disableVanish(Player player) {
|
||||
if (!vanishedModerators.remove(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
player.removePotionEffect(PotionEffectType.INVISIBILITY);
|
||||
player.setSilent(false);
|
||||
for (Player online : plugin.getServer().getOnlinePlayers()) {
|
||||
if (!online.getUniqueId().equals(player.getUniqueId())) {
|
||||
online.showPlayer(plugin, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reapplyVanish(Player player) {
|
||||
vanishedModerators.add(player.getUniqueId());
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false, false));
|
||||
player.setSilent(true);
|
||||
for (Player online : plugin.getServer().getOnlinePlayers()) {
|
||||
if (!online.getUniqueId().equals(player.getUniqueId())) {
|
||||
online.hidePlayer(plugin, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double resolveMaxHealth(Player player) {
|
||||
if (player.getAttribute(Attribute.MAX_HEALTH) != null) {
|
||||
return player.getAttribute(Attribute.MAX_HEALTH).getValue();
|
||||
@@ -404,7 +468,8 @@ public class ModeManager {
|
||||
return 20.0D;
|
||||
}
|
||||
|
||||
private float clampSpeed(float value, float min) {
|
||||
return Math.max(min, Math.min(1.0f, value));
|
||||
private float clampSpeed(float value, float fallback) {
|
||||
float normalized = value <= 0.0f ? fallback : value;
|
||||
return Math.max(0.1f, Math.min(1.0f, normalized));
|
||||
}
|
||||
}
|
||||
|
||||
2
src/main/java/org/blz/adminmode/moderation/ModeSession.java
Normal file → Executable file
2
src/main/java/org/blz/adminmode/moderation/ModeSession.java
Normal file → Executable file
@@ -246,7 +246,7 @@ public final class ModeSession {
|
||||
|
||||
private static ItemStack cloneItem(ItemStack item) {
|
||||
if (item == null || item.getType() == Material.AIR) {
|
||||
return new ItemStack(Material.AIR);
|
||||
return ItemStack.empty();
|
||||
}
|
||||
return item.clone();
|
||||
}
|
||||
|
||||
2
src/main/java/org/blz/adminmode/moderation/ModeSessionLogger.java
Normal file → Executable file
2
src/main/java/org/blz/adminmode/moderation/ModeSessionLogger.java
Normal file → Executable file
@@ -60,7 +60,7 @@ public class ModeSessionLogger {
|
||||
}
|
||||
|
||||
private String modeSuffix(ModeSession session) {
|
||||
return session.getProfile().isHardProfile() ? "HARD" : "SOFT";
|
||||
return "ADMIN";
|
||||
}
|
||||
|
||||
private String formatDuration(long millis) {
|
||||
|
||||
280
src/main/java/org/blz/adminmode/moderation/ModeratorAccessManager.java
Executable file
280
src/main/java/org/blz/adminmode/moderation/ModeratorAccessManager.java
Executable file
@@ -0,0 +1,280 @@
|
||||
package org.blz.adminmode.moderation;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ModeratorAccessManager {
|
||||
|
||||
private static final long PERMANENT_EXPIRY = -1L;
|
||||
|
||||
private final Plugin plugin;
|
||||
private final File storageFile;
|
||||
private final Gson gson;
|
||||
private final Map<UUID, RestrictionEntry> restrictions = new HashMap<>();
|
||||
|
||||
public ModeratorAccessManager(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.storageFile = new File(plugin.getDataFolder(), "moderator-access.json");
|
||||
this.gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
load();
|
||||
}
|
||||
|
||||
public Optional<RestrictionEntry> getActiveRestriction(UUID playerId) {
|
||||
RestrictionEntry entry = restrictions.get(playerId);
|
||||
if (entry == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (entry.isExpired()) {
|
||||
restrictions.remove(playerId);
|
||||
save();
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(entry);
|
||||
}
|
||||
|
||||
public boolean isRestricted(UUID playerId) {
|
||||
return getActiveRestriction(playerId).isPresent();
|
||||
}
|
||||
|
||||
public RestrictionEntry restrict(OfflinePlayer target, String targetName, String actorName, Long expiresAt, String reason) {
|
||||
RestrictionEntry entry = new RestrictionEntry(
|
||||
target.getUniqueId(),
|
||||
targetName,
|
||||
actorName,
|
||||
reason == null ? "" : reason.trim(),
|
||||
System.currentTimeMillis(),
|
||||
expiresAt == null ? PERMANENT_EXPIRY : expiresAt);
|
||||
restrictions.put(target.getUniqueId(), entry);
|
||||
save();
|
||||
return entry;
|
||||
}
|
||||
|
||||
public boolean clearRestriction(UUID playerId) {
|
||||
RestrictionEntry removed = restrictions.remove(playerId);
|
||||
if (removed != null) {
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<String> getRestrictedPlayerNames() {
|
||||
List<String> names = new ArrayList<>();
|
||||
for (RestrictionEntry entry : restrictions.values()) {
|
||||
if (!entry.isExpired() && entry.getPlayerName() != null && !entry.getPlayerName().isBlank()) {
|
||||
names.add(entry.getPlayerName());
|
||||
}
|
||||
}
|
||||
names.sort(String.CASE_INSENSITIVE_ORDER);
|
||||
return names;
|
||||
}
|
||||
|
||||
public String describeRestriction(UUID playerId) {
|
||||
Optional<RestrictionEntry> optional = getActiveRestriction(playerId);
|
||||
if (optional.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
RestrictionEntry entry = optional.get();
|
||||
StringBuilder message = new StringBuilder("§cВам запрещено входить в admin mode");
|
||||
if (!entry.isPermanent()) {
|
||||
message.append(" §7(").append(formatRemaining(entry.getExpiresAt() - System.currentTimeMillis())).append("§7)");
|
||||
} else {
|
||||
message.append(" §7(навсегда)");
|
||||
}
|
||||
if (!entry.getReason().isBlank()) {
|
||||
message.append("§c. Причина: §f").append(entry.getReason());
|
||||
}
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
public static Long parseDurationToExpiry(String input) {
|
||||
if (input == null || input.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
String normalized = input.trim().toLowerCase();
|
||||
if (normalized.equals("perm") || normalized.equals("permanent") || normalized.equals("forever")
|
||||
|| normalized.equals("навсегда")) {
|
||||
return null;
|
||||
}
|
||||
if (!normalized.matches("\\d+[smhdwy]")) {
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
long amount = Long.parseLong(normalized.substring(0, normalized.length() - 1));
|
||||
char suffix = normalized.charAt(normalized.length() - 1);
|
||||
Duration duration = switch (suffix) {
|
||||
case 's' -> Duration.ofSeconds(amount);
|
||||
case 'm' -> Duration.ofMinutes(amount);
|
||||
case 'h' -> Duration.ofHours(amount);
|
||||
case 'd' -> Duration.ofDays(amount);
|
||||
case 'w' -> Duration.ofDays(amount * 7);
|
||||
case 'y' -> Duration.ofDays(amount * 365);
|
||||
default -> null;
|
||||
};
|
||||
if (duration == null || duration.isNegative() || duration.isZero()) {
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
return System.currentTimeMillis() + duration.toMillis();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
restrictions.clear();
|
||||
if (!storageFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(storageFile)) {
|
||||
JsonElement root = JsonParser.parseReader(reader);
|
||||
if (!root.isJsonArray()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (JsonElement element : root.getAsJsonArray()) {
|
||||
if (!element.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
RestrictionEntry entry = deserialize(element.getAsJsonObject());
|
||||
if (entry != null && !entry.isExpired()) {
|
||||
restrictions.put(entry.getPlayerId(), entry);
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось загрузить moderator-access.json: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
File parent = storageFile.getParentFile();
|
||||
if (parent != null && !parent.exists()) {
|
||||
parent.mkdirs();
|
||||
}
|
||||
|
||||
JsonArray array = new JsonArray();
|
||||
for (RestrictionEntry entry : restrictions.values()) {
|
||||
if (!entry.isExpired()) {
|
||||
array.add(serialize(entry));
|
||||
}
|
||||
}
|
||||
|
||||
try (FileWriter writer = new FileWriter(storageFile)) {
|
||||
writer.write(gson.toJson(array));
|
||||
} catch (IOException exception) {
|
||||
plugin.getLogger().warning("Не удалось сохранить moderator-access.json: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private JsonObject serialize(RestrictionEntry entry) {
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("playerId", entry.getPlayerId().toString());
|
||||
json.addProperty("playerName", entry.getPlayerName());
|
||||
json.addProperty("actorName", entry.getActorName());
|
||||
json.addProperty("reason", entry.getReason());
|
||||
json.addProperty("createdAt", entry.getCreatedAt());
|
||||
json.addProperty("expiresAt", entry.getExpiresAt());
|
||||
return json;
|
||||
}
|
||||
|
||||
private RestrictionEntry deserialize(JsonObject json) {
|
||||
try {
|
||||
UUID playerId = UUID.fromString(json.get("playerId").getAsString());
|
||||
String playerName = json.has("playerName") ? json.get("playerName").getAsString() : playerId.toString();
|
||||
String actorName = json.has("actorName") ? json.get("actorName").getAsString() : "unknown";
|
||||
String reason = json.has("reason") ? json.get("reason").getAsString() : "";
|
||||
long createdAt = json.has("createdAt") ? json.get("createdAt").getAsLong() : System.currentTimeMillis();
|
||||
long expiresAt = json.has("expiresAt") ? json.get("expiresAt").getAsLong() : PERMANENT_EXPIRY;
|
||||
return new RestrictionEntry(playerId, playerName, actorName, reason, createdAt, expiresAt);
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось прочитать запись ограничения admin mode: " + exception.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String formatRemaining(long millis) {
|
||||
Duration duration = Duration.ofMillis(Math.max(millis, 0L));
|
||||
long days = duration.toDays();
|
||||
long hours = duration.toHoursPart();
|
||||
long minutes = duration.toMinutesPart();
|
||||
|
||||
if (days > 0) {
|
||||
return days + "д " + hours + "ч";
|
||||
}
|
||||
if (duration.toHours() > 0) {
|
||||
return duration.toHours() + "ч " + minutes + "м";
|
||||
}
|
||||
if (duration.toMinutes() > 0) {
|
||||
return duration.toMinutes() + "м";
|
||||
}
|
||||
if (duration.toSeconds() > 0) {
|
||||
return duration.toSeconds() + "с";
|
||||
}
|
||||
return Math.max(1L, duration.toMinutes()) + "м";
|
||||
}
|
||||
|
||||
public static final class RestrictionEntry {
|
||||
private final UUID playerId;
|
||||
private final String playerName;
|
||||
private final String actorName;
|
||||
private final String reason;
|
||||
private final long createdAt;
|
||||
private final long expiresAt;
|
||||
|
||||
public RestrictionEntry(UUID playerId, String playerName, String actorName, String reason, long createdAt, long expiresAt) {
|
||||
this.playerId = playerId;
|
||||
this.playerName = playerName;
|
||||
this.actorName = actorName;
|
||||
this.reason = reason;
|
||||
this.createdAt = createdAt;
|
||||
this.expiresAt = expiresAt;
|
||||
}
|
||||
|
||||
public UUID getPlayerId() {
|
||||
return playerId;
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
public String getActorName() {
|
||||
return actorName;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public long getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public long getExpiresAt() {
|
||||
return expiresAt;
|
||||
}
|
||||
|
||||
public boolean isPermanent() {
|
||||
return expiresAt == PERMANENT_EXPIRY;
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return !isPermanent() && System.currentTimeMillis() >= expiresAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
230
src/main/java/org/blz/adminmode/moderation/ModeratorPreferencesStore.java
Executable file
230
src/main/java/org/blz/adminmode/moderation/ModeratorPreferencesStore.java
Executable file
@@ -0,0 +1,230 @@
|
||||
package org.blz.adminmode.moderation;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ModeratorPreferencesStore {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final File storageFile;
|
||||
private final Gson gson;
|
||||
private final Map<UUID, ModeratorPreferences> preferences = new LinkedHashMap<>();
|
||||
|
||||
public ModeratorPreferencesStore(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.storageFile = new File(plugin.getDataFolder(), "moderator-preferences.json");
|
||||
this.gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
load();
|
||||
}
|
||||
|
||||
public ModeratorPreferences get(UUID playerId) {
|
||||
return preferences.computeIfAbsent(playerId, ignored -> new ModeratorPreferences());
|
||||
}
|
||||
|
||||
public DefaultEntryMode cycleDefaultEntryMode(UUID playerId) {
|
||||
ModeratorPreferences preferences = get(playerId);
|
||||
DefaultEntryMode[] values = new DefaultEntryMode[]{DefaultEntryMode.AUTO, DefaultEntryMode.SURVIVAL, DefaultEntryMode.SPECTATOR};
|
||||
preferences.defaultEntryMode = cycle(values, preferences.defaultEntryMode);
|
||||
save();
|
||||
return preferences.defaultEntryMode;
|
||||
}
|
||||
|
||||
public MenuTheme cycleTheme(UUID playerId) {
|
||||
ModeratorPreferences preferences = get(playerId);
|
||||
preferences.theme = cycle(MenuTheme.values(), preferences.theme);
|
||||
save();
|
||||
return preferences.theme;
|
||||
}
|
||||
|
||||
public AccentColor cycleAccentColor(UUID playerId) {
|
||||
ModeratorPreferences preferences = get(playerId);
|
||||
preferences.accentColor = cycle(AccentColor.values(), preferences.accentColor);
|
||||
save();
|
||||
return preferences.accentColor;
|
||||
}
|
||||
|
||||
private <T> T cycle(T[] values, T current) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (values[i] == current) {
|
||||
return values[(i + 1) % values.length];
|
||||
}
|
||||
}
|
||||
return values[0];
|
||||
}
|
||||
|
||||
private void load() {
|
||||
preferences.clear();
|
||||
if (!storageFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(storageFile)) {
|
||||
JsonElement root = JsonParser.parseReader(reader);
|
||||
if (!root.isJsonObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, JsonElement> entry : root.getAsJsonObject().entrySet()) {
|
||||
if (!entry.getValue().isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
UUID uuid = UUID.fromString(entry.getKey());
|
||||
preferences.put(uuid, readPreferences(entry.getValue().getAsJsonObject()));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось загрузить moderator-preferences.json: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private ModeratorPreferences readPreferences(JsonObject json) {
|
||||
ModeratorPreferences result = new ModeratorPreferences();
|
||||
result.defaultEntryMode = DefaultEntryMode.fromName(getString(json, "defaultEntryMode"));
|
||||
result.theme = MenuTheme.fromName(getString(json, "theme"));
|
||||
result.accentColor = AccentColor.fromName(getString(json, "accentColor"));
|
||||
return result;
|
||||
}
|
||||
|
||||
private void save() {
|
||||
File parent = storageFile.getParentFile();
|
||||
if (parent != null && !parent.exists()) {
|
||||
parent.mkdirs();
|
||||
}
|
||||
|
||||
JsonObject root = new JsonObject();
|
||||
for (Map.Entry<UUID, ModeratorPreferences> entry : preferences.entrySet()) {
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("defaultEntryMode", entry.getValue().defaultEntryMode.name());
|
||||
json.addProperty("theme", entry.getValue().theme.name());
|
||||
json.addProperty("accentColor", entry.getValue().accentColor.name());
|
||||
root.add(entry.getKey().toString(), json);
|
||||
}
|
||||
|
||||
try (FileWriter writer = new FileWriter(storageFile)) {
|
||||
writer.write(gson.toJson(root));
|
||||
} catch (IOException exception) {
|
||||
plugin.getLogger().warning("Не удалось сохранить moderator-preferences.json: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String getString(JsonObject json, String key) {
|
||||
return json.has(key) && !json.get(key).isJsonNull() ? json.get(key).getAsString() : "";
|
||||
}
|
||||
|
||||
public static final class ModeratorPreferences {
|
||||
private DefaultEntryMode defaultEntryMode = DefaultEntryMode.AUTO;
|
||||
private MenuTheme theme = MenuTheme.RAINBOW;
|
||||
private AccentColor accentColor = AccentColor.AQUA;
|
||||
|
||||
public DefaultEntryMode defaultEntryMode() {
|
||||
return defaultEntryMode;
|
||||
}
|
||||
|
||||
public MenuTheme theme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
public AccentColor accentColor() {
|
||||
return accentColor;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DefaultEntryMode {
|
||||
AUTO("По серверу"),
|
||||
SURVIVAL("SURVIVAL"),
|
||||
SPECTATOR("SPECTATOR");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
DefaultEntryMode(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public static DefaultEntryMode fromName(String value) {
|
||||
for (DefaultEntryMode mode : values()) {
|
||||
if (mode.name().equalsIgnoreCase(value)) {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
return AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
public enum MenuTheme {
|
||||
RAINBOW("Радужная"),
|
||||
CLEAN_ACCENT("Светлая акцентная"),
|
||||
WHITE("Белая");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
MenuTheme(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public static MenuTheme fromName(String value) {
|
||||
for (MenuTheme theme : values()) {
|
||||
if (theme.name().equalsIgnoreCase(value)) {
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
return RAINBOW;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AccentColor {
|
||||
AQUA("Аква", NamedTextColor.AQUA),
|
||||
GOLD("Золото", NamedTextColor.GOLD),
|
||||
GREEN("Лайм", NamedTextColor.GREEN),
|
||||
YELLOW("Жёлтый", NamedTextColor.YELLOW),
|
||||
RED("Красный", NamedTextColor.RED),
|
||||
BLUE("Синий", NamedTextColor.BLUE);
|
||||
|
||||
private final String displayName;
|
||||
private final NamedTextColor textColor;
|
||||
|
||||
AccentColor(String displayName, NamedTextColor textColor) {
|
||||
this.displayName = displayName;
|
||||
this.textColor = textColor;
|
||||
}
|
||||
|
||||
public String displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public NamedTextColor textColor() {
|
||||
return textColor;
|
||||
}
|
||||
|
||||
public static AccentColor fromName(String value) {
|
||||
for (AccentColor color : values()) {
|
||||
if (color.name().equalsIgnoreCase(value)) {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
return AQUA;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/main/java/org/blz/adminmode/moderation/ModeratorProfile.java
Normal file → Executable file
54
src/main/java/org/blz/adminmode/moderation/ModeratorProfile.java
Normal file → Executable file
@@ -2,14 +2,10 @@ package org.blz.adminmode.moderation;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum ModeratorProfile {
|
||||
SOFT_MODER("soft_moder", "Soft Moder", "adminmode.profile.soft"),
|
||||
HARD_MODER("hard_moder", "Hard Moder", "adminmode.profile.hard");
|
||||
ADMIN("admin", "Admin Mode", "adminmode.use");
|
||||
|
||||
private final String configKey;
|
||||
private final String displayName;
|
||||
@@ -33,54 +29,12 @@ public enum ModeratorProfile {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public boolean isHardProfile() {
|
||||
return this == HARD_MODER;
|
||||
}
|
||||
|
||||
public boolean isAvailableFor(Player player) {
|
||||
return switch (this) {
|
||||
case SOFT_MODER -> player.hasPermission("adminmode.use")
|
||||
|| player.hasPermission(permission)
|
||||
|| player.hasPermission(HARD_MODER.permission);
|
||||
case HARD_MODER -> player.hasPermission(permission);
|
||||
};
|
||||
}
|
||||
|
||||
public static List<ModeratorProfile> availableFor(Player player) {
|
||||
List<ModeratorProfile> profiles = new ArrayList<>();
|
||||
for (ModeratorProfile profile : values()) {
|
||||
if (profile.isAvailableFor(player)) {
|
||||
profiles.add(profile);
|
||||
}
|
||||
}
|
||||
return profiles;
|
||||
return player.hasPermission(permission);
|
||||
}
|
||||
|
||||
/** Accepts any old key (soft_moder, hard_moder, admin) and returns ADMIN. */
|
||||
public static Optional<ModeratorProfile> fromConfigKey(String key) {
|
||||
if (key == null || key.isBlank()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String normalized = key.toLowerCase(Locale.ROOT);
|
||||
for (ModeratorProfile profile : values()) {
|
||||
if (profile.configKey.equals(normalized)) {
|
||||
return Optional.of(profile);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static Optional<ModeratorProfile> fromInput(String input) {
|
||||
if (input == null || input.isBlank()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String normalized = input.trim().toLowerCase(Locale.ROOT);
|
||||
return switch (normalized) {
|
||||
case "soft", "soft_moder", "soft-moder", "softmoder" -> Optional.of(SOFT_MODER);
|
||||
case "hard", "hard_moder", "hard-moder", "hardmoder" -> Optional.of(HARD_MODER);
|
||||
default -> Optional.empty();
|
||||
};
|
||||
return Optional.of(ADMIN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
package org.blz.adminmode.moderation;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ModeratorWarningStore {
|
||||
|
||||
private static final long NOT_REVOKED = -1L;
|
||||
|
||||
private final Plugin plugin;
|
||||
private final File storageFile;
|
||||
private final Gson gson;
|
||||
private final List<WarningEntry> entries = new ArrayList<>();
|
||||
|
||||
public ModeratorWarningStore(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.storageFile = new File(plugin.getDataFolder(), "warn-history.json");
|
||||
this.gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
load();
|
||||
}
|
||||
|
||||
public WarningEntry recordWarn(Player target, Player moderator, String reason, String durationToken) {
|
||||
if (target == null || moderator == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long expiresAt = PunishmentDuration.toExpiry(durationToken, now);
|
||||
WarningEntry entry = new WarningEntry(
|
||||
UUID.randomUUID(),
|
||||
target.getUniqueId(),
|
||||
target.getName(),
|
||||
moderator.getName(),
|
||||
sanitizeReason(reason),
|
||||
now,
|
||||
expiresAt,
|
||||
NOT_REVOKED,
|
||||
"",
|
||||
"");
|
||||
entries.add(entry);
|
||||
save();
|
||||
return entry;
|
||||
}
|
||||
|
||||
public List<WarningEntry> getRecentWarnings(UUID playerId, int limit) {
|
||||
return entries.stream()
|
||||
.filter(entry -> entry.playerId.equals(playerId))
|
||||
.sorted(Comparator.comparingLong(WarningEntry::createdAt).reversed())
|
||||
.limit(Math.max(0, limit))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<WarningEntry> getActiveWarnings(UUID playerId) {
|
||||
return entries.stream()
|
||||
.filter(entry -> entry.playerId.equals(playerId) && entry.status() == WarningStatus.ACTIVE)
|
||||
.sorted(Comparator.comparingLong(WarningEntry::createdAt).reversed())
|
||||
.toList();
|
||||
}
|
||||
|
||||
public Optional<WarningEntry> findWarning(UUID warningId) {
|
||||
if (warningId == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return entries.stream().filter(entry -> entry.id.equals(warningId)).findFirst();
|
||||
}
|
||||
|
||||
public boolean revokeWarning(UUID warningId, Player moderator, String reason) {
|
||||
if (warningId == null || moderator == null || reason == null || reason.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < entries.size(); index++) {
|
||||
WarningEntry current = entries.get(index);
|
||||
if (!current.id.equals(warningId) || current.status() != WarningStatus.ACTIVE) {
|
||||
continue;
|
||||
}
|
||||
entries.set(index, current.revokedBy(moderator.getName(), sanitizeReason(reason), System.currentTimeMillis()));
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String sanitizeReason(String reason) {
|
||||
if (reason == null || reason.isBlank()) {
|
||||
return "без причины";
|
||||
}
|
||||
return reason.replace('\n', ' ').replace('\r', ' ').trim();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
entries.clear();
|
||||
if (!storageFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(storageFile)) {
|
||||
JsonElement root = JsonParser.parseReader(reader);
|
||||
if (!root.isJsonArray()) {
|
||||
return;
|
||||
}
|
||||
for (JsonElement element : root.getAsJsonArray()) {
|
||||
if (!element.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
WarningEntry entry = readEntry(element.getAsJsonObject());
|
||||
if (entry != null) {
|
||||
entries.add(entry);
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось загрузить warn-history.json: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private WarningEntry readEntry(JsonObject json) {
|
||||
try {
|
||||
long createdAt = json.get("createdAt").getAsLong();
|
||||
boolean legacyActive = !json.has("active") || json.get("active").getAsBoolean();
|
||||
long revokedAt = json.has("revokedAt")
|
||||
? json.get("revokedAt").getAsLong()
|
||||
: legacyActive ? NOT_REVOKED : 0L;
|
||||
return new WarningEntry(
|
||||
json.has("id") ? UUID.fromString(json.get("id").getAsString()) : UUID.randomUUID(),
|
||||
UUID.fromString(json.get("playerId").getAsString()),
|
||||
json.get("playerName").getAsString(),
|
||||
json.get("moderatorName").getAsString(),
|
||||
json.get("reason").getAsString(),
|
||||
createdAt,
|
||||
json.has("expiresAt") ? json.get("expiresAt").getAsLong() : PunishmentDuration.PERMANENT_EXPIRY,
|
||||
revokedAt,
|
||||
readString(json, "revokedBy", legacyActive ? "" : "неизвестно"),
|
||||
readString(json, "revocationReason", legacyActive ? "" : "данные отсутствуют"));
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось загрузить запись warn: " + exception.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String readString(JsonObject json, String key, String fallback) {
|
||||
return json.has(key) && !json.get(key).isJsonNull() ? json.get(key).getAsString() : fallback;
|
||||
}
|
||||
|
||||
private void save() {
|
||||
File parent = storageFile.getParentFile();
|
||||
if (parent != null && !parent.exists()) {
|
||||
parent.mkdirs();
|
||||
}
|
||||
|
||||
JsonArray root = new JsonArray();
|
||||
for (WarningEntry entry : entries) {
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("id", entry.id.toString());
|
||||
json.addProperty("playerId", entry.playerId.toString());
|
||||
json.addProperty("playerName", entry.playerName);
|
||||
json.addProperty("moderatorName", entry.moderatorName);
|
||||
json.addProperty("reason", entry.reason);
|
||||
json.addProperty("createdAt", entry.createdAt);
|
||||
json.addProperty("expiresAt", entry.expiresAt);
|
||||
json.addProperty("revokedAt", entry.revokedAt);
|
||||
json.addProperty("revokedBy", entry.revokedBy);
|
||||
json.addProperty("revocationReason", entry.revocationReason);
|
||||
json.addProperty("active", entry.status() == WarningStatus.ACTIVE);
|
||||
root.add(json);
|
||||
}
|
||||
|
||||
try (FileWriter writer = new FileWriter(storageFile)) {
|
||||
writer.write(gson.toJson(root));
|
||||
} catch (IOException exception) {
|
||||
plugin.getLogger().warning("Не удалось сохранить warn-history.json: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public enum WarningStatus {
|
||||
ACTIVE,
|
||||
EXPIRED,
|
||||
REVOKED
|
||||
}
|
||||
|
||||
public static final class WarningEntry {
|
||||
private final UUID id;
|
||||
private final UUID playerId;
|
||||
private final String playerName;
|
||||
private final String moderatorName;
|
||||
private final String reason;
|
||||
private final long createdAt;
|
||||
private final long expiresAt;
|
||||
private final long revokedAt;
|
||||
private final String revokedBy;
|
||||
private final String revocationReason;
|
||||
|
||||
private WarningEntry(UUID id, UUID playerId, String playerName, String moderatorName, String reason,
|
||||
long createdAt, long expiresAt, long revokedAt, String revokedBy, String revocationReason) {
|
||||
this.id = id;
|
||||
this.playerId = playerId;
|
||||
this.playerName = playerName;
|
||||
this.moderatorName = moderatorName;
|
||||
this.reason = reason;
|
||||
this.createdAt = createdAt;
|
||||
this.expiresAt = expiresAt;
|
||||
this.revokedAt = revokedAt;
|
||||
this.revokedBy = revokedBy;
|
||||
this.revocationReason = revocationReason;
|
||||
}
|
||||
|
||||
private WarningEntry revokedBy(String actor, String revocationReason, long timestamp) {
|
||||
return new WarningEntry(id, playerId, playerName, moderatorName, reason, createdAt, expiresAt,
|
||||
timestamp, actor, revocationReason);
|
||||
}
|
||||
|
||||
public UUID id() { return id; }
|
||||
public UUID playerId() { return playerId; }
|
||||
public String playerName() { return playerName; }
|
||||
public String moderatorName() { return moderatorName; }
|
||||
public String reason() { return reason; }
|
||||
public long createdAt() { return createdAt; }
|
||||
public long expiresAt() { return expiresAt; }
|
||||
public long revokedAt() { return revokedAt; }
|
||||
public String revokedBy() { return revokedBy; }
|
||||
public String revocationReason() { return revocationReason; }
|
||||
|
||||
public boolean isPermanent() {
|
||||
return expiresAt == PunishmentDuration.PERMANENT_EXPIRY;
|
||||
}
|
||||
|
||||
public WarningStatus status() {
|
||||
if (revokedAt != NOT_REVOKED) {
|
||||
return WarningStatus.REVOKED;
|
||||
}
|
||||
if (!isPermanent() && System.currentTimeMillis() >= expiresAt) {
|
||||
return WarningStatus.EXPIRED;
|
||||
}
|
||||
return WarningStatus.ACTIVE;
|
||||
}
|
||||
|
||||
public boolean active() {
|
||||
return status() == WarningStatus.ACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
127
src/main/java/org/blz/adminmode/moderation/PlayerFreezeManager.java
Executable file
127
src/main/java/org/blz/adminmode/moderation/PlayerFreezeManager.java
Executable file
@@ -0,0 +1,127 @@
|
||||
package org.blz.adminmode.moderation;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerFreezeManager implements Listener {
|
||||
|
||||
private static final long NOTIFY_COOLDOWN_MS = 1500L;
|
||||
|
||||
private final Plugin plugin;
|
||||
private final Set<UUID> frozenPlayers = new HashSet<>();
|
||||
private final Map<UUID, Long> lastNotify = new HashMap<>();
|
||||
|
||||
public PlayerFreezeManager(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public boolean toggleFreeze(Player target) {
|
||||
UUID uuid = target.getUniqueId();
|
||||
if (frozenPlayers.remove(uuid)) {
|
||||
target.sendMessage(Component.text("Вы больше не заморожены.", NamedTextColor.GREEN));
|
||||
return false;
|
||||
}
|
||||
frozenPlayers.add(uuid);
|
||||
target.sendMessage(Component.text("Вы заморожены. Любые действия заблокированы.", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isFrozen(UUID playerId) {
|
||||
return frozenPlayers.contains(playerId);
|
||||
}
|
||||
|
||||
private boolean shouldBlock(Player player) {
|
||||
return frozenPlayers.contains(player.getUniqueId());
|
||||
}
|
||||
|
||||
private void notifyFrozen(Player player) {
|
||||
long now = System.currentTimeMillis();
|
||||
long previous = lastNotify.getOrDefault(player.getUniqueId(), 0L);
|
||||
if (now - previous < NOTIFY_COOLDOWN_MS) {
|
||||
return;
|
||||
}
|
||||
lastNotify.put(player.getUniqueId(), now);
|
||||
player.sendActionBar(Component.text("Вы заморожены модератором.", NamedTextColor.RED));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onMove(PlayerMoveEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (!shouldBlock(player) || event.getTo() == null) return;
|
||||
if (event.getFrom().distanceSquared(event.getTo()) > 0.0D) {
|
||||
event.setTo(event.getFrom());
|
||||
notifyFrozen(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
if (!shouldBlock(event.getPlayer())) return;
|
||||
event.setCancelled(true);
|
||||
notifyFrozen(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onDrop(PlayerDropItemEvent event) {
|
||||
if (!shouldBlock(event.getPlayer())) return;
|
||||
event.setCancelled(true);
|
||||
notifyFrozen(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPickup(EntityPickupItemEvent event) {
|
||||
if (!(event.getEntity() instanceof Player player)) return;
|
||||
if (!shouldBlock(player)) return;
|
||||
event.setCancelled(true);
|
||||
notifyFrozen(player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (!(event.getWhoClicked() instanceof Player player)) return;
|
||||
if (!shouldBlock(player)) return;
|
||||
event.setCancelled(true);
|
||||
notifyFrozen(player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onCommand(PlayerCommandPreprocessEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (!shouldBlock(player)) return;
|
||||
event.setCancelled(true);
|
||||
notifyFrozen(player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
if (!shouldBlock(event.getPlayer())) return;
|
||||
event.setCancelled(true);
|
||||
notifyFrozen(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
if (!shouldBlock(event.getPlayer())) return;
|
||||
event.setCancelled(true);
|
||||
notifyFrozen(event.getPlayer());
|
||||
}
|
||||
}
|
||||
3
src/main/java/org/blz/adminmode/moderation/PlayerListAction.java
Normal file → Executable file
3
src/main/java/org/blz/adminmode/moderation/PlayerListAction.java
Normal file → Executable file
@@ -3,5 +3,6 @@ package org.blz.adminmode.moderation;
|
||||
public enum PlayerListAction {
|
||||
SPECTATE,
|
||||
TELEPORT,
|
||||
INVSEE
|
||||
INVSEE,
|
||||
MANAGE
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.blz.adminmode.moderation;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Locale;
|
||||
|
||||
public final class PunishmentDuration {
|
||||
|
||||
public static final long PERMANENT_EXPIRY = -1L;
|
||||
|
||||
private PunishmentDuration() {
|
||||
}
|
||||
|
||||
public static String normalizeToken(String input) {
|
||||
if (input == null || input.isBlank()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String normalized = input.trim().toLowerCase(Locale.ROOT);
|
||||
if (normalized.equals("perm") || normalized.equals("permanent") || normalized.equals("permanently")) {
|
||||
return "permanent";
|
||||
}
|
||||
if (!normalized.matches("[1-9]\\d*[smhdwy]")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
toDuration(normalized);
|
||||
return normalized;
|
||||
} catch (ArithmeticException | IllegalArgumentException exception) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static long toExpiry(String token, long now) {
|
||||
String normalized = normalizeToken(token);
|
||||
if (normalized.isEmpty()) {
|
||||
throw new IllegalArgumentException("Unsupported punishment duration: " + token);
|
||||
}
|
||||
if (normalized.equals("permanent")) {
|
||||
return PERMANENT_EXPIRY;
|
||||
}
|
||||
return Math.addExact(now, toDuration(normalized).toMillis());
|
||||
}
|
||||
|
||||
private static Duration toDuration(String normalized) {
|
||||
long amount = Long.parseLong(normalized.substring(0, normalized.length() - 1));
|
||||
return switch (normalized.charAt(normalized.length() - 1)) {
|
||||
case 's' -> Duration.ofSeconds(amount);
|
||||
case 'm' -> Duration.ofMinutes(amount);
|
||||
case 'h' -> Duration.ofHours(amount);
|
||||
case 'd' -> Duration.ofDays(amount);
|
||||
case 'w' -> Duration.ofDays(Math.multiplyExact(amount, 7L));
|
||||
case 'y' -> Duration.ofDays(Math.multiplyExact(amount, 365L));
|
||||
default -> throw new IllegalArgumentException("Unsupported punishment duration: " + normalized);
|
||||
};
|
||||
}
|
||||
}
|
||||
90
src/main/java/org/blz/adminmode/session/SessionStorage.java
Normal file → Executable file
90
src/main/java/org/blz/adminmode/session/SessionStorage.java
Normal file → Executable file
@@ -8,29 +8,22 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.blz.adminmode.moderation.ModeSession;
|
||||
import org.blz.adminmode.moderation.ModeratorProfile;
|
||||
import org.blz.adminmode.utils.ItemStackCodec;
|
||||
import org.blz.adminmode.utils.PotionEffectCodec;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
import org.bukkit.util.io.BukkitObjectOutputStream;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -128,7 +121,7 @@ public class SessionStorage {
|
||||
UUID playerId = UUID.fromString(json.get("playerId").getAsString());
|
||||
String playerName = json.get("playerName").getAsString();
|
||||
ModeratorProfile profile = ModeratorProfile.fromConfigKey(json.get("profile").getAsString())
|
||||
.orElse(ModeratorProfile.SOFT_MODER);
|
||||
.orElse(ModeratorProfile.ADMIN);
|
||||
long startTimestamp = json.get("startTimestamp").getAsLong();
|
||||
String previousGroup = getString(json, "previousGroup");
|
||||
String activeGroup = getString(json, "activeGroup");
|
||||
@@ -224,14 +217,7 @@ public class SessionStorage {
|
||||
|
||||
private String serializeItemArray(ItemStack[] items) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream)) {
|
||||
dataOutput.writeInt(items.length);
|
||||
for (ItemStack item : items) {
|
||||
dataOutput.writeObject(item);
|
||||
}
|
||||
}
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
return ItemStackCodec.serializeItems(items);
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось сериализовать item array: " + exception.getMessage());
|
||||
return "";
|
||||
@@ -244,15 +230,7 @@ public class SessionStorage {
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(data));
|
||||
try (BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream)) {
|
||||
int length = dataInput.readInt();
|
||||
ItemStack[] items = new ItemStack[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
items[i] = (ItemStack) dataInput.readObject();
|
||||
}
|
||||
return items;
|
||||
}
|
||||
return ItemStackCodec.deserializeItems(data);
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось десериализовать item array: " + exception.getMessage());
|
||||
return new ItemStack[0];
|
||||
@@ -261,11 +239,7 @@ public class SessionStorage {
|
||||
|
||||
private String serializeItem(ItemStack item) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream)) {
|
||||
dataOutput.writeObject(item);
|
||||
}
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
return ItemStackCodec.serializeItem(item);
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось сериализовать item: " + exception.getMessage());
|
||||
return "";
|
||||
@@ -274,62 +248,24 @@ public class SessionStorage {
|
||||
|
||||
private ItemStack deserializeItem(String data) {
|
||||
if (data == null || data.isEmpty()) {
|
||||
return new ItemStack(Material.AIR);
|
||||
return ItemStack.empty();
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(data));
|
||||
try (BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream)) {
|
||||
return (ItemStack) dataInput.readObject();
|
||||
}
|
||||
return ItemStackCodec.deserializeItem(data);
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось десериализовать item: " + exception.getMessage());
|
||||
return new ItemStack(Material.AIR);
|
||||
return ItemStack.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private String serializePotionEffects(Collection<PotionEffect> effects) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (PotionEffect effect : effects) {
|
||||
builder.append(effect.getType().getName()).append(':')
|
||||
.append(effect.getDuration()).append(':')
|
||||
.append(effect.getAmplifier()).append(':')
|
||||
.append(effect.isAmbient()).append(':')
|
||||
.append(effect.hasParticles()).append(':')
|
||||
.append(effect.hasIcon()).append(';');
|
||||
}
|
||||
return builder.toString();
|
||||
return PotionEffectCodec.serialize(effects);
|
||||
}
|
||||
|
||||
private Collection<PotionEffect> deserializePotionEffects(String data) {
|
||||
List<PotionEffect> effects = new ArrayList<>();
|
||||
if (data == null || data.isEmpty()) {
|
||||
return effects;
|
||||
}
|
||||
|
||||
String[] effectStrings = data.split(";");
|
||||
for (String effectString : effectStrings) {
|
||||
if (effectString.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
String[] parts = effectString.split(":");
|
||||
PotionEffectType type = PotionEffectType.getByName(parts[0]);
|
||||
if (type == null) {
|
||||
continue;
|
||||
}
|
||||
effects.add(new PotionEffect(
|
||||
type,
|
||||
Integer.parseInt(parts[1]),
|
||||
Integer.parseInt(parts[2]),
|
||||
Boolean.parseBoolean(parts[3]),
|
||||
Boolean.parseBoolean(parts[4]),
|
||||
Boolean.parseBoolean(parts[5])));
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось десериализовать potion effect: " + effectString);
|
||||
}
|
||||
}
|
||||
return effects;
|
||||
return PotionEffectCodec.deserialize(data,
|
||||
encodedEffect -> plugin.getLogger().warning(
|
||||
"Не удалось десериализовать potion effect: " + encodedEffect));
|
||||
}
|
||||
}
|
||||
|
||||
85
src/main/java/org/blz/adminmode/utils/ItemStackCodec.java
Normal file
85
src/main/java/org/blz/adminmode/utils/ItemStackCodec.java
Normal file
@@ -0,0 +1,85 @@
|
||||
package org.blz.adminmode.utils;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* Stores item stacks using Paper's data-version-aware NBT format while retaining
|
||||
* read compatibility with sessions written by older AdminMode releases.
|
||||
*/
|
||||
public final class ItemStackCodec {
|
||||
|
||||
private static final String ITEM_FORMAT_PREFIX = "nbt-item-v1:";
|
||||
private static final String ITEMS_FORMAT_PREFIX = "nbt-items-v1:";
|
||||
|
||||
private ItemStackCodec() {
|
||||
}
|
||||
|
||||
public static String serializeItems(ItemStack[] items) {
|
||||
ItemStack[] safeItems = items == null ? new ItemStack[0] : items;
|
||||
return ITEMS_FORMAT_PREFIX
|
||||
+ Base64.getEncoder().encodeToString(ItemStack.serializeItemsAsBytes(safeItems));
|
||||
}
|
||||
|
||||
public static ItemStack[] deserializeItems(String data) throws IOException, ClassNotFoundException {
|
||||
if (data == null || data.isEmpty()) {
|
||||
return new ItemStack[0];
|
||||
}
|
||||
if (data.startsWith(ITEMS_FORMAT_PREFIX)) {
|
||||
byte[] bytes = decode(data.substring(ITEMS_FORMAT_PREFIX.length()));
|
||||
return ItemStack.deserializeItemsFromBytes(bytes);
|
||||
}
|
||||
return deserializeLegacyItems(data);
|
||||
}
|
||||
|
||||
public static String serializeItem(ItemStack item) {
|
||||
ItemStack safeItem = item == null ? ItemStack.empty() : item;
|
||||
return ITEM_FORMAT_PREFIX
|
||||
+ Base64.getEncoder().encodeToString(safeItem.serializeAsBytes());
|
||||
}
|
||||
|
||||
public static ItemStack deserializeItem(String data) throws IOException, ClassNotFoundException {
|
||||
if (data == null || data.isEmpty()) {
|
||||
return ItemStack.empty();
|
||||
}
|
||||
if (data.startsWith(ITEM_FORMAT_PREFIX)) {
|
||||
byte[] bytes = decode(data.substring(ITEM_FORMAT_PREFIX.length()));
|
||||
return ItemStack.deserializeBytes(bytes);
|
||||
}
|
||||
return deserializeLegacyItem(data);
|
||||
}
|
||||
|
||||
private static byte[] decode(String data) throws IOException {
|
||||
try {
|
||||
return Base64.getDecoder().decode(data);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
throw new IOException("Invalid Base64 item data", exception);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static ItemStack[] deserializeLegacyItems(String data) throws IOException, ClassNotFoundException {
|
||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(decode(data));
|
||||
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream)) {
|
||||
int length = dataInput.readInt();
|
||||
ItemStack[] items = new ItemStack[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
items[i] = (ItemStack) dataInput.readObject();
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static ItemStack deserializeLegacyItem(String data) throws IOException, ClassNotFoundException {
|
||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(decode(data));
|
||||
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream)) {
|
||||
ItemStack item = (ItemStack) dataInput.readObject();
|
||||
return item == null ? ItemStack.empty() : item;
|
||||
}
|
||||
}
|
||||
}
|
||||
86
src/main/java/org/blz/adminmode/utils/PotionEffectCodec.java
Normal file
86
src/main/java/org/blz/adminmode/utils/PotionEffectCodec.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package org.blz.adminmode.utils;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/** Encodes potion effects with registry keys and reads the legacy enum-name format. */
|
||||
public final class PotionEffectCodec {
|
||||
|
||||
private static final String FORMAT_PREFIX = "potion-v2:";
|
||||
|
||||
private PotionEffectCodec() {
|
||||
}
|
||||
|
||||
public static String serialize(Collection<PotionEffect> effects) {
|
||||
StringBuilder builder = new StringBuilder(FORMAT_PREFIX);
|
||||
if (effects == null) {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
for (PotionEffect effect : effects) {
|
||||
NamespacedKey key = Registry.MOB_EFFECT.getKey(effect.getType());
|
||||
builder.append(key).append('|')
|
||||
.append(effect.getDuration()).append('|')
|
||||
.append(effect.getAmplifier()).append('|')
|
||||
.append(effect.isAmbient()).append('|')
|
||||
.append(effect.hasParticles()).append('|')
|
||||
.append(effect.hasIcon()).append(';');
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static Collection<PotionEffect> deserialize(String data, Consumer<String> warningSink) {
|
||||
List<PotionEffect> effects = new ArrayList<>();
|
||||
if (data == null || data.isEmpty()) {
|
||||
return effects;
|
||||
}
|
||||
|
||||
boolean currentFormat = data.startsWith(FORMAT_PREFIX);
|
||||
String payload = currentFormat ? data.substring(FORMAT_PREFIX.length()) : data;
|
||||
for (String encodedEffect : payload.split(";")) {
|
||||
if (encodedEffect.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
String[] parts = currentFormat
|
||||
? encodedEffect.split("\\|", -1)
|
||||
: encodedEffect.split(":", -1);
|
||||
if (parts.length != 6) {
|
||||
throw new IllegalArgumentException("Expected 6 fields");
|
||||
}
|
||||
|
||||
PotionEffectType type = resolveType(parts[0], currentFormat);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Unknown effect " + parts[0]);
|
||||
}
|
||||
|
||||
effects.add(new PotionEffect(
|
||||
type,
|
||||
Integer.parseInt(parts[1]),
|
||||
Integer.parseInt(parts[2]),
|
||||
Boolean.parseBoolean(parts[3]),
|
||||
Boolean.parseBoolean(parts[4]),
|
||||
Boolean.parseBoolean(parts[5])));
|
||||
} catch (RuntimeException exception) {
|
||||
warningSink.accept(encodedEffect);
|
||||
}
|
||||
}
|
||||
return effects;
|
||||
}
|
||||
|
||||
private static PotionEffectType resolveType(String identifier, boolean currentFormat) {
|
||||
NamespacedKey key = currentFormat
|
||||
? NamespacedKey.fromString(identifier)
|
||||
: NamespacedKey.minecraft(identifier.toLowerCase(Locale.ROOT));
|
||||
return key == null ? null : Registry.MOB_EFFECT.get(key);
|
||||
}
|
||||
}
|
||||
0
src/main/java/org/blz/adminmode/utils/ScreenEffects.java
Normal file → Executable file
0
src/main/java/org/blz/adminmode/utils/ScreenEffects.java
Normal file → Executable file
59
src/main/java/org/blz/adminmode/utils/WorldLoader.java
Normal file → Executable file
59
src/main/java/org/blz/adminmode/utils/WorldLoader.java
Normal file → Executable file
@@ -38,6 +38,7 @@ public class WorldLoader {
|
||||
return;
|
||||
}
|
||||
}
|
||||
cleanupSkippedFiles(worldFolder);
|
||||
|
||||
plugin.getLogger().info("Загрузка мира " + worldName + "...");
|
||||
WorldCreator creator = new WorldCreator(worldName);
|
||||
@@ -64,8 +65,18 @@ public class WorldLoader {
|
||||
|
||||
try (ZipInputStream zipIn = new ZipInputStream(in)) {
|
||||
ZipEntry entry = zipIn.getNextEntry();
|
||||
String destinationPath = destination.getCanonicalPath() + File.separator;
|
||||
while (entry != null) {
|
||||
if (shouldSkipEntry(entry.getName())) {
|
||||
zipIn.closeEntry();
|
||||
entry = zipIn.getNextEntry();
|
||||
continue;
|
||||
}
|
||||
File file = new File(destination, entry.getName());
|
||||
String filePath = file.getCanonicalPath();
|
||||
if (!filePath.startsWith(destinationPath)) {
|
||||
throw new IOException("Blocked unsafe zip entry: " + entry.getName());
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
file.mkdirs();
|
||||
} else {
|
||||
@@ -91,4 +102,52 @@ public class WorldLoader {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldSkipEntry(String entryName) {
|
||||
String normalized = entryName.replace('\\', '/');
|
||||
return normalized.equals("level.dat")
|
||||
|| normalized.equals("level.dat_old")
|
||||
|| normalized.equals("session.lock")
|
||||
|| normalized.equals("icon.png")
|
||||
|| normalized.equals("xaeromap.txt")
|
||||
|| normalized.startsWith("serverconfig/")
|
||||
|| normalized.startsWith("playerdata/")
|
||||
|| normalized.startsWith("stats/")
|
||||
|| normalized.startsWith("advancements/");
|
||||
}
|
||||
|
||||
private void cleanupSkippedFiles(File destination) {
|
||||
deleteIfExists(new File(destination, "level.dat"));
|
||||
deleteIfExists(new File(destination, "level.dat_old"));
|
||||
deleteIfExists(new File(destination, "session.lock"));
|
||||
deleteIfExists(new File(destination, "icon.png"));
|
||||
deleteIfExists(new File(destination, "xaeromap.txt"));
|
||||
deleteRecursively(new File(destination, "serverconfig"));
|
||||
deleteRecursively(new File(destination, "playerdata"));
|
||||
deleteRecursively(new File(destination, "stats"));
|
||||
deleteRecursively(new File(destination, "advancements"));
|
||||
}
|
||||
|
||||
private void deleteIfExists(File file) {
|
||||
if (file.exists() && !file.delete()) {
|
||||
plugin.getLogger().warning("Не удалось удалить файл " + file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteRecursively(File file) {
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
File[] children = file.listFiles();
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
deleteRecursively(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!file.delete()) {
|
||||
plugin.getLogger().warning("Не удалось удалить " + file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user