first commit

This commit is contained in:
2026-03-26 11:24:40 +07:00
commit b439a42134
57 changed files with 3271 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
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.listeners.AdminModeListener;
import org.blz.adminmode.listeners.GameModeChangeListener;
import org.blz.adminmode.listeners.MobTargetListener;
import org.bukkit.plugin.java.JavaPlugin;
public class AdminMode extends JavaPlugin {
private static AdminMode instance;
private ConfigManager configManager;
private AdminModeCommand adminModeCommand;
private AdminDialogService dialogService;
@Override
public void onEnable() {
instance = this;
saveDefaultConfig();
configManager = new ConfigManager(this);
adminModeCommand = new AdminModeCommand(this, configManager);
dialogService = new AdminDialogService(this, configManager, adminModeCommand);
adminModeCommand.setDialogService(dialogService);
getCommand("adminmode").setExecutor(adminModeCommand);
getCommand("admfix").setExecutor(new org.blz.adminmode.commands.AdminFixCommand(adminModeCommand));
getServer().getPluginManager().registerEvents(new AdminModeListener(this, adminModeCommand, configManager),
this);
getServer().getPluginManager().registerEvents(new MobTargetListener(adminModeCommand, configManager), this);
getServer().getPluginManager().registerEvents(new GameModeChangeListener(adminModeCommand, configManager),
this);
// Load Pocket Dimension World
new org.blz.adminmode.utils.WorldLoader(this, "pocket_dimension").loadWorld();
// Register Abilities
belzeManager = new org.blz.adminmode.managers.BelzeBoolManager(this);
getLogger().info("AdminMode успешно включен!");
}
private org.blz.adminmode.managers.BelzeBoolManager belzeManager; // Field to store manager
@Override
public void onDisable() {
getLogger().info("AdminMode отключен!");
}
public static AdminMode getInstance() {
return instance;
}
public ConfigManager getConfigManager() {
return configManager;
}
public AdminModeCommand getAdminModeCommand() {
return adminModeCommand;
}
}

View File

@@ -0,0 +1,43 @@
package org.blz.adminmode.commands;
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.entity.Player;
public class AdminFixCommand implements CommandExecutor {
private final AdminModeCommand adminModeCommand;
public AdminFixCommand(AdminModeCommand adminModeCommand) {
this.adminModeCommand = adminModeCommand;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("adminmode.admin")) {
sender.sendMessage(ChatColor.RED + "У вас нет прав для использования этой команды!");
return true;
}
if (args.length < 1) {
sender.sendMessage(ChatColor.RED + "Использование: /admfix <игрок>");
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
sender.sendMessage(ChatColor.RED + "Игрок не найден!");
return true;
}
adminModeCommand.forceDisableAbilities(target);
sender.sendMessage(ChatColor.GREEN + "Все способности отключены для игрока " + target.getName());
target.sendMessage(ChatColor.YELLOW + "⚠ Ваши способности были сброшены администратором");
return true;
}
}

View File

@@ -0,0 +1,632 @@
package org.blz.adminmode.commands;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.model.user.User;
import net.luckperms.api.node.Node;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffect;
import org.blz.adminmode.dialog.AdminDialogService;
import org.blz.adminmode.config.ConfigManager;
import org.blz.adminmode.data.AdminModeDataManager;
import org.blz.adminmode.data.AdminModeDataManager.PlayerStateData;
import org.blz.adminmode.moderation.ModeratorProfile;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class AdminModeCommand implements CommandExecutor {
private final Plugin plugin;
private final ConfigManager configManager;
private final Map<UUID, PlayerState> savedStates = new HashMap<>();
private final Map<UUID, ModeratorProfile> activeProfiles = new HashMap<>();
private final AdminModeDataManager dataManager;
private AdminDialogService dialogService;
public AdminModeCommand(Plugin plugin, ConfigManager configManager) {
this.plugin = plugin;
this.configManager = configManager;
this.dataManager = new AdminModeDataManager(plugin);
loadAllStates();
}
public void setDialogService(AdminDialogService dialogService) {
this.dialogService = dialogService;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length > 0 && args[0].equalsIgnoreCase("reload")) {
if (!sender.hasPermission("adminmode.reload")) {
sender.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
return true;
}
configManager.loadConfig();
sender.sendMessage(ChatColor.GREEN + configManager.getMsgReloaded());
return true;
}
// Команда disable <игрок> - принудительно отключить способности
if (args.length > 0 && args[0].equalsIgnoreCase("disable")) {
if (!canUseHardActions(sender)) {
sender.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
return true;
}
if (args.length < 2) {
sender.sendMessage(ChatColor.RED + "Использование: /adminmode disable <игрок>");
return true;
}
forceDisableTarget(sender, args[1]);
return true;
}
if (!(sender instanceof Player)) {
sender.sendMessage(ChatColor.RED + "Эта команда доступна только игрокам!");
return true;
}
Player player = (Player) sender;
if (!configManager.isEnabled()) {
player.sendMessage(ChatColor.RED + "Режим администратора отключен!");
return true;
}
if (args.length > 0 && args[0].equalsIgnoreCase("dialog")) {
if (!openRelevantDialog(player)) {
player.sendMessage(ChatColor.YELLOW + "Dialog-панель недоступна. Используйте /adminmode enable <soft|hard>.");
}
return true;
}
if (args.length > 0 && (args[0].equalsIgnoreCase("enable") || args[0].equalsIgnoreCase("profile"))) {
if (args.length < 2) {
if (!openRelevantDialog(player)) {
player.sendMessage(ChatColor.YELLOW + "Использование: /adminmode enable <soft|hard>");
}
return true;
}
ModeratorProfile profile = ModeratorProfile.fromInput(args[1]).orElse(null);
if (profile == null) {
player.sendMessage(ChatColor.RED + "Неизвестный профиль. Доступно: soft, hard.");
return true;
}
toggleAdminMode(player, profile);
return true;
}
if (!isInAdminMode(player.getUniqueId()) && getAvailableProfiles(player).isEmpty()) {
player.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
return true;
}
toggleAdminMode(player);
return true;
}
public void toggleAdminMode(Player player) {
if (isInAdminMode(player.getUniqueId())) {
disableAdminMode(player);
return;
}
List<ModeratorProfile> availableProfiles = getAvailableProfiles(player);
if (availableProfiles.isEmpty()) {
player.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
return;
}
if (availableProfiles.size() == 1) {
enableAdminMode(player, availableProfiles.get(0));
return;
}
if (!openRelevantDialog(player)) {
player.sendMessage(ChatColor.YELLOW + "Доступно несколько профилей. Используйте /adminmode enable <soft|hard>.");
}
}
public void toggleAdminMode(Player player, ModeratorProfile profile) {
if (profile == null) {
toggleAdminMode(player);
return;
}
if (isInAdminMode(player.getUniqueId())) {
ModeratorProfile activeProfile = getActiveProfile(player.getUniqueId());
if (activeProfile == profile) {
disableAdminMode(player);
} else {
player.sendMessage(ChatColor.YELLOW + "Сначала выключите текущий режим модерации, затем включите новый профиль.");
}
return;
}
if (!profile.isAvailableFor(player)) {
player.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
return;
}
enableAdminMode(player, profile);
}
public List<ModeratorProfile> getAvailableProfiles(Player player) {
return ModeratorProfile.availableFor(player);
}
public ModeratorProfile getActiveProfile(UUID playerId) {
return activeProfiles.get(playerId);
}
public void applyAdminSettings(Player player, float flySpeed, float walkSpeed, boolean godMode) {
if (!isInAdminMode(player.getUniqueId())) {
return;
}
player.setAllowFlight(true);
player.setFlying(true);
player.setFlySpeed(clampSpeed(flySpeed, 0.1f));
player.setWalkSpeed(clampSpeed(walkSpeed, 0.1f));
player.setInvulnerable(godMode);
player.sendMessage(ChatColor.GREEN + "✓ Настройки admin mode обновлены.");
}
public boolean teleportToPlayer(Player moderator, String targetName) {
if (!validateHardActionPlayer(moderator)) {
return false;
}
Player target = resolveOnlinePlayer(targetName, moderator);
if (target == null) {
return false;
}
moderator.teleport(target.getLocation());
moderator.sendMessage(ChatColor.GREEN + "✓ Вы телепортированы к игроку " + target.getName());
return true;
}
public boolean teleportPlayerHere(Player moderator, String targetName) {
if (!validateHardActionPlayer(moderator)) {
return false;
}
Player target = resolveOnlinePlayer(targetName, moderator);
if (target == null) {
return false;
}
target.teleport(moderator.getLocation());
moderator.sendMessage(ChatColor.GREEN + "✓ Игрок " + target.getName() + " телепортирован к вам.");
target.sendMessage(ChatColor.YELLOW + "Вас телепортировал модератор " + moderator.getName());
return true;
}
public boolean forceDisableTarget(CommandSender sender, String targetName) {
if (!canUseHardActions(sender)) {
sender.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
return false;
}
Player target = resolveOnlinePlayer(targetName, sender);
if (target == null) {
return false;
}
forceDisableAbilities(target);
sender.sendMessage(ChatColor.GREEN + "Все способности отключены для игрока " + target.getName());
target.sendMessage(ChatColor.YELLOW + "⚠ Ваши способности были сброшены модератором");
return true;
}
private boolean openRelevantDialog(Player player) {
if (dialogService == null || !configManager.isDialogsEnabled()) {
return false;
}
if (isInAdminMode(player.getUniqueId())) {
return dialogService.openModerationPanel(player);
}
return dialogService.openProfileSelectionDialog(player);
}
private void enableAdminMode(Player player, ModeratorProfile profile) {
savePlayerState(player, profile);
activeProfiles.put(player.getUniqueId(), profile);
clearPlayerState(player);
givePresetBlocks(player);
setAdminGameMode(player);
savePlayerStateToFile(player);
grantLuckPermsPermissions(player, profile);
player.sendMessage(ChatColor.AQUA + configManager.getMsgEnabled());
player.sendMessage(ChatColor.GRAY + configManager.getMsgEnabledSubtitle());
player.sendMessage(ChatColor.YELLOW + configManager.getMsgPermissionsGranted());
player.sendMessage(ChatColor.GRAY + "Профиль: " + profile.getDisplayName());
}
private void disableAdminMode(Player player) {
UUID playerId = player.getUniqueId();
ModeratorProfile profile = activeProfiles.getOrDefault(playerId, ModeratorProfile.SOFT_MODER);
removeLuckPermsPermissions(player, profile);
restorePlayerState(player);
dataManager.deletePlayerState(playerId);
player.sendMessage(ChatColor.GREEN + configManager.getMsgDisabled());
player.sendMessage(ChatColor.GRAY + configManager.getMsgDisabledSubtitle());
}
private void savePlayerState(Player player, ModeratorProfile profile) {
PlayerState state = new PlayerState();
state.inventory = player.getInventory().getContents().clone();
state.armorContents = player.getInventory().getArmorContents().clone();
state.offHand = player.getInventory().getItemInOffHand().clone();
state.location = player.getLocation().clone();
state.health = player.getHealth();
state.foodLevel = player.getFoodLevel();
state.saturation = player.getSaturation();
state.exhaustion = player.getExhaustion();
state.exp = player.getExp();
state.level = player.getLevel();
state.totalExperience = player.getTotalExperience();
state.gameMode = player.getGameMode();
state.allowFlight = player.getAllowFlight();
state.flying = player.isFlying();
state.flySpeed = player.getFlySpeed();
state.walkSpeed = player.getWalkSpeed();
state.potionEffects = player.getActivePotionEffects();
state.fireTicks = player.getFireTicks();
state.profile = profile;
savedStates.put(player.getUniqueId(), state);
}
private void clearPlayerState(Player player) {
player.getInventory().clear();
player.getInventory().setArmorContents(new ItemStack[4]);
player.getInventory().setItemInOffHand(new ItemStack(Material.AIR));
player.setHealth(20.0);
player.setFoodLevel(20);
player.setSaturation(5.0f);
player.setExhaustion(0.0f);
player.setExp(0);
player.setLevel(0);
player.setTotalExperience(0);
for (PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
player.setFireTicks(0);
}
private void givePresetBlocks(Player player) {
if (!configManager.isGivePresetBlocks())
return;
List<String> presetBlocks = configManager.getPresetBlocks();
for (String blockStr : presetBlocks) {
try {
String[] parts = blockStr.split(":");
Material material = Material.valueOf(parts[0].toUpperCase());
int amount = parts.length > 1 ? Integer.parseInt(parts[1]) : 64;
ItemStack item = new ItemStack(material, amount);
player.getInventory().addItem(item);
} catch (Exception e) {
plugin.getLogger().warning("Неверный блок в preset_blocks: " + blockStr);
}
}
}
private void setAdminGameMode(Player player) {
if (configManager.isForceSpectator()) {
player.setGameMode(GameMode.SPECTATOR);
} else {
// ВАЖНО: Не используем CREATIVE для модеров, только SURVIVAL!
player.setGameMode(GameMode.SURVIVAL);
}
// Всегда разрешаем полет в админ моде (даже в выживании)
player.setAllowFlight(true);
player.setFlying(true);
// Дополнительные возможности
if (configManager.isGodMode()) {
player.setInvulnerable(true);
}
if (configManager.getCustomFlySpeed() > 0) {
player.setFlySpeed(configManager.getCustomFlySpeed());
}
if (configManager.getCustomWalkSpeed() > 0) {
player.setWalkSpeed(configManager.getCustomWalkSpeed());
}
}
private void savePlayerStateToFile(Player player) {
UUID playerId = player.getUniqueId();
PlayerState state = savedStates.get(playerId);
if (state == null)
return;
PlayerStateData data = new PlayerStateData();
data.inventory = state.inventory;
data.armorContents = state.armorContents;
data.offHand = state.offHand;
data.location = state.location;
data.health = state.health;
data.foodLevel = state.foodLevel;
data.saturation = state.saturation;
data.exhaustion = state.exhaustion;
data.exp = state.exp;
data.level = state.level;
data.totalExperience = state.totalExperience;
data.gameMode = state.gameMode;
data.allowFlight = state.allowFlight;
data.flying = state.flying;
data.flySpeed = state.flySpeed;
data.walkSpeed = state.walkSpeed;
data.potionEffects = state.potionEffects;
data.fireTicks = state.fireTicks;
data.profileKey = state.profile == null ? null : state.profile.getConfigKey();
dataManager.savePlayerState(playerId, data);
}
private void loadAllStates() {
for (UUID playerId : dataManager.getAllSavedStates()) {
PlayerStateData data = dataManager.loadPlayerState(playerId);
if (data == null)
continue;
PlayerState state = new PlayerState();
state.inventory = data.inventory;
state.armorContents = data.armorContents;
state.offHand = data.offHand;
state.location = data.location;
state.health = data.health;
state.foodLevel = data.foodLevel;
state.saturation = data.saturation;
state.exhaustion = data.exhaustion;
state.exp = data.exp;
state.level = data.level;
state.totalExperience = data.totalExperience;
state.gameMode = data.gameMode;
state.allowFlight = data.allowFlight;
state.flying = data.flying;
state.flySpeed = data.flySpeed;
state.walkSpeed = data.walkSpeed;
state.potionEffects = data.potionEffects;
state.fireTicks = data.fireTicks;
state.profile = ModeratorProfile.fromConfigKey(data.profileKey).orElse(ModeratorProfile.SOFT_MODER);
savedStates.put(playerId, state);
activeProfiles.put(playerId, state.profile);
plugin.getLogger().info("Загружено состояние админ мода для: " + playerId);
}
}
private void restorePlayerState(Player player) {
UUID playerId = player.getUniqueId();
PlayerState state = savedStates.get(playerId);
if (state == null)
return;
// КРИТИЧНО: Удаляем из savedStates ДО восстановления режима!
// Это предотвратит срабатывание GameModeChangeListener, который мог бы снова
// включить полет
savedStates.remove(playerId);
activeProfiles.remove(playerId);
// Восстанавливаем инвентарь
player.getInventory().setContents(state.inventory);
player.getInventory().setArmorContents(state.armorContents);
player.getInventory().setItemInOffHand(state.offHand);
if (state.location != null) {
player.teleport(state.location);
}
player.setHealth(state.health);
player.setFoodLevel(state.foodLevel);
player.setSaturation(state.saturation);
player.setExhaustion(state.exhaustion);
player.setExp(state.exp);
player.setLevel(state.level);
player.setTotalExperience(state.totalExperience);
// ВАЖНО: Сначала восстанавливаем gameMode
player.setGameMode(state.gameMode);
// КРИТИЧНО: ПОТОМ применяем железную очистку способностей!
// Это гарантирует, что даже в SPECTATOR режиме у игрока не будет полета
forceDisableAbilities(player);
for (PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
for (PotionEffect effect : state.potionEffects) {
player.addPotionEffect(effect);
}
player.setFireTicks(state.fireTicks);
}
/**
* Железное отключение всех админ способностей
* Используется при выходе из режима и в команде /admfix
*/
public void forceDisableAbilities(Player player) {
player.setInvulnerable(false); // Убираем бессмертие
player.setFlying(false); // Принудительно отключаем полет
player.setAllowFlight(false); // Запрещаем полет
player.setFlySpeed(0.1f); // Сброс скорости полета на дефолт
player.setWalkSpeed(0.2f); // Сброс скорости ходьбы на дефолт
}
public boolean isInAdminMode(UUID playerId) {
return savedStates.containsKey(playerId);
}
private boolean canUseHardActions(CommandSender sender) {
if (sender.hasPermission("adminmode.admin")) {
return true;
}
if (!(sender instanceof Player player)) {
return false;
}
return isInAdminMode(player.getUniqueId()) && getActiveProfile(player.getUniqueId()) == ModeratorProfile.HARD_MODER;
}
private boolean validateHardActionPlayer(Player moderator) {
if (!canUseHardActions(moderator)) {
moderator.sendMessage(ChatColor.RED + "Для этого действия нужен активный профиль Hard Moder.");
return false;
}
return true;
}
private Player resolveOnlinePlayer(String targetName, CommandSender sender) {
if (targetName == null || targetName.isBlank()) {
sender.sendMessage(ChatColor.RED + "Укажите ник игрока.");
return null;
}
Player target = Bukkit.getPlayerExact(targetName.trim());
if (target == null) {
target = Bukkit.getPlayer(targetName.trim());
}
if (target == null) {
sender.sendMessage(ChatColor.RED + "Игрок не найден!");
return null;
}
return target;
}
private float clampSpeed(float value, float min) {
return Math.max(min, Math.min(1.0f, value));
}
private void grantLuckPermsPermissions(Player player, ModeratorProfile profile) {
if (!configManager.isUseLuckPerms()) {
player.setOp(true);
return;
}
try {
LuckPerms luckPerms = LuckPermsProvider.get();
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) {
player.sendMessage(ChatColor.RED + "Не удалось получить данные LuckPerms!");
return;
}
List<String> groups = configManager.getLuckPermsGroups(profile);
for (String group : groups) {
Node groupNode = Node.builder("group." + group).build();
user.data().add(groupNode);
}
luckPerms.getUserManager().saveUser(user);
player.sendMessage(ChatColor.GREEN + "✓ Права администратора выданы!");
} catch (IllegalStateException e) {
player.setOp(true);
player.sendMessage(ChatColor.YELLOW + "⚠ LuckPerms не найден, используется стандартный OP");
}
}
private void removeLuckPermsPermissions(Player player, ModeratorProfile profile) {
if (!configManager.isUseLuckPerms()) {
player.setOp(false);
return;
}
if (!configManager.isRemoveGroupsOnDisable()) {
return;
}
try {
LuckPerms luckPerms = LuckPermsProvider.get();
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) {
player.sendMessage(ChatColor.RED + "Не удалось получить данные LuckPerms!");
return;
}
List<String> groups = configManager.getLuckPermsGroups(profile);
for (String group : groups) {
Node groupNode = Node.builder("group." + group).build();
user.data().remove(groupNode);
}
luckPerms.getUserManager().saveUser(user);
player.sendMessage(ChatColor.GREEN + configManager.getMsgPermissionsRemoved());
} catch (IllegalStateException e) {
player.setOp(false);
player.sendMessage(ChatColor.YELLOW + "⚠ LuckPerms не найден, убран стандартный OP");
}
}
private static class PlayerState {
ItemStack[] inventory;
ItemStack[] armorContents;
ItemStack offHand;
Location location;
double health;
int foodLevel;
float saturation;
float exhaustion;
float exp;
int level;
int totalExperience;
GameMode gameMode;
boolean allowFlight;
boolean flying;
float flySpeed;
float walkSpeed;
Collection<PotionEffect> potionEffects;
int fireTicks;
ModeratorProfile profile;
}
}

View File

@@ -0,0 +1,257 @@
package org.blz.adminmode.config;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import org.blz.adminmode.moderation.ModeratorProfile;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.Plugin;
public class ConfigManager {
private final Plugin plugin;
private FileConfiguration config;
private boolean enabled;
private boolean useLuckPerms;
private Map<ModeratorProfile, List<String>> luckPermsGroups;
private boolean removeGroupsOnDisable;
private boolean dialogsEnabled;
private boolean preventItemDrop;
private boolean preventItemPickup;
private boolean preventContainerTransfer;
private boolean preventItemUse;
private boolean allowOwnInventory;
private List<String> allowedBlocks;
private List<String> allowedPlaceBlocks;
private boolean givePresetBlocks;
private List<String> presetBlocks;
private boolean forceSpectator;
private boolean mobsIgnorePlayer;
private boolean allowFlightInSurvival;
private boolean godMode;
private float customFlySpeed;
private float customWalkSpeed;
private List<String> allowedGameModes;
private String msgEnabled;
private String msgEnabledSubtitle;
private String msgPermissionsGranted;
private String msgDisabled;
private String msgDisabledSubtitle;
private String msgPermissionsRemoved;
private String msgNoPermission;
private String msgItemDropDenied;
private String msgContainerTransferDenied;
private String msgItemUseDenied;
private String msgBlockPlaceDenied;
private String msgReloaded;
public ConfigManager(Plugin plugin) {
this.plugin = plugin;
loadConfig();
}
public void loadConfig() {
plugin.reloadConfig();
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);
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()) {
softGroups = new ArrayList<>(legacyGroups);
}
if (hardGroups.isEmpty()) {
hardGroups = legacyGroups.isEmpty() ? new ArrayList<>(softGroups) : new ArrayList<>(legacyGroups);
}
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);
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);
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);
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);
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");
msgEnabled = config.getString("admin_mode.messages.enabled", "✓ Режим администратора активирован!");
msgEnabledSubtitle = config.getString("admin_mode.messages.enabled_subtitle", "Ваше состояние сохранено.");
msgPermissionsGranted = config.getString("admin_mode.messages.permissions_granted",
"⚠ Вам выданы временные права администратора!");
msgDisabled = config.getString("admin_mode.messages.disabled", "✓ Режим администратора отключен!");
msgDisabledSubtitle = config.getString("admin_mode.messages.disabled_subtitle",
"Ваше состояние восстановлено.");
msgPermissionsRemoved = config.getString("admin_mode.messages.permissions_removed",
"✓ Права администратора отозваны!");
msgNoPermission = config.getString("admin_mode.messages.no_permission",
"У вас нет прав для использования этой команды!");
msgItemDropDenied = config.getString("admin_mode.messages.item_drop_denied",
"В режиме администратора нельзя выбрасывать предметы!");
msgContainerTransferDenied = config.getString("admin_mode.messages.container_transfer_denied",
"В режиме администратора нельзя перемещать предметы в контейнеры!");
msgItemUseDenied = config.getString("admin_mode.messages.item_use_denied",
"В режиме администратора нельзя использовать предметы!");
msgBlockPlaceDenied = config.getString("admin_mode.messages.block_place_denied",
"✖ Вы можете ставить только разрешенные блоки!");
msgReloaded = config.getString("admin_mode.messages.reloaded", "✓ Конфигурация AdminMode перезагружена!");
}
public boolean isEnabled() {
return enabled;
}
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 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;
}
}

View File

@@ -0,0 +1,314 @@
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.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;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class AdminModeDataManager {
private final Plugin plugin;
private final File dataFolder;
private final Gson gson;
public AdminModeDataManager(Plugin plugin) {
this.plugin = plugin;
this.dataFolder = new File(plugin.getDataFolder(), "adminmode");
this.gson = new GsonBuilder().setPrettyPrinting().create();
if (!dataFolder.exists()) {
dataFolder.mkdirs();
}
}
public void savePlayerState(UUID playerId, PlayerStateData state) {
File playerFile = new File(dataFolder, playerId.toString() + ".json");
try (FileWriter writer = new FileWriter(playerFile)) {
JsonObject json = new JsonObject();
json.addProperty("inventory", serializeItemArray(state.inventory));
json.addProperty("armorContents", serializeItemArray(state.armorContents));
json.addProperty("offHand", serializeItem(state.offHand));
JsonObject locationJson = new JsonObject();
locationJson.addProperty("world", state.location.getWorld().getName());
locationJson.addProperty("x", state.location.getX());
locationJson.addProperty("y", state.location.getY());
locationJson.addProperty("z", state.location.getZ());
locationJson.addProperty("yaw", state.location.getYaw());
locationJson.addProperty("pitch", state.location.getPitch());
json.add("location", locationJson);
json.addProperty("health", state.health);
json.addProperty("foodLevel", state.foodLevel);
json.addProperty("saturation", state.saturation);
json.addProperty("exhaustion", state.exhaustion);
json.addProperty("exp", state.exp);
json.addProperty("level", state.level);
json.addProperty("totalExperience", state.totalExperience);
json.addProperty("gameMode", state.gameMode.name());
json.addProperty("allowFlight", state.allowFlight);
json.addProperty("flying", state.flying);
json.addProperty("flySpeed", state.flySpeed);
json.addProperty("walkSpeed", state.walkSpeed);
json.addProperty("potionEffects", serializePotionEffects(state.potionEffects));
json.addProperty("fireTicks", state.fireTicks);
json.addProperty("profileKey", state.profileKey);
writer.write(gson.toJson(json));
plugin.getLogger().info("Сохранено состояние игрока: " + playerId);
} catch (IOException e) {
plugin.getLogger().severe("Не удалось сохранить состояние игрока " + playerId);
e.printStackTrace();
}
}
public PlayerStateData loadPlayerState(UUID playerId) {
File playerFile = new File(dataFolder, playerId.toString() + ".json");
if (!playerFile.exists()) {
return null;
}
try (FileReader reader = new FileReader(playerFile)) {
JsonObject json = JsonParser.parseReader(reader).getAsJsonObject();
PlayerStateData state = new PlayerStateData();
state.inventory = deserializeItemArray(json.get("inventory").getAsString());
state.armorContents = deserializeItemArray(json.get("armorContents").getAsString());
state.offHand = deserializeItem(json.get("offHand").getAsString());
JsonObject locationJson = json.getAsJsonObject("location");
World world = Bukkit.getWorld(locationJson.get("world").getAsString());
if (world != null) {
state.location = new Location(
world,
locationJson.get("x").getAsDouble(),
locationJson.get("y").getAsDouble(),
locationJson.get("z").getAsDouble(),
locationJson.get("yaw").getAsFloat(),
locationJson.get("pitch").getAsFloat()
);
}
state.health = json.get("health").getAsDouble();
state.foodLevel = json.get("foodLevel").getAsInt();
state.saturation = json.get("saturation").getAsFloat();
state.exhaustion = json.get("exhaustion").getAsFloat();
state.exp = json.get("exp").getAsFloat();
state.level = json.get("level").getAsInt();
state.totalExperience = json.get("totalExperience").getAsInt();
state.gameMode = GameMode.valueOf(json.get("gameMode").getAsString());
state.allowFlight = json.get("allowFlight").getAsBoolean();
state.flying = json.get("flying").getAsBoolean();
state.flySpeed = json.get("flySpeed").getAsFloat();
state.walkSpeed = json.get("walkSpeed").getAsFloat();
state.potionEffects = deserializePotionEffects(json.get("potionEffects").getAsString());
state.fireTicks = json.get("fireTicks").getAsInt();
if (json.has("profileKey") && !json.get("profileKey").isJsonNull()) {
state.profileKey = json.get("profileKey").getAsString();
}
plugin.getLogger().info("Загружено состояние игрока: " + playerId);
return state;
} catch (Exception e) {
plugin.getLogger().severe("Не удалось загрузить состояние игрока " + playerId);
e.printStackTrace();
return null;
}
}
public void deletePlayerState(UUID playerId) {
File playerFile = new File(dataFolder, playerId.toString() + ".json");
if (playerFile.exists()) {
if (playerFile.delete()) {
plugin.getLogger().info("Удалено состояние игрока: " + playerId);
} else {
plugin.getLogger().warning("Не удалось удалить файл состояния: " + playerId);
}
}
}
public boolean hasPlayerState(UUID playerId) {
File playerFile = new File(dataFolder, playerId.toString() + ".json");
return playerFile.exists();
}
public Set<UUID> getAllSavedStates() {
Set<UUID> states = new HashSet<>();
File[] files = dataFolder.listFiles((dir, name) -> name.endsWith(".json"));
if (files != null) {
for (File file : files) {
try {
String uuidStr = file.getName().replace(".json", "");
states.add(UUID.fromString(uuidStr));
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Некорректный файл состояния: " + file.getName());
}
}
}
return states;
}
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());
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
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;
} catch (Exception e) {
e.printStackTrace();
return new ItemStack[0];
}
}
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());
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
private ItemStack deserializeItem(String data) {
try {
if (data.isEmpty()) {
return new ItemStack(Material.AIR);
}
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(data));
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
ItemStack item = (ItemStack) dataInput.readObject();
dataInput.close();
return item;
} catch (Exception e) {
e.printStackTrace();
return new ItemStack(Material.AIR);
}
}
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();
}
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;
}
public static class PlayerStateData {
public ItemStack[] inventory;
public ItemStack[] armorContents;
public ItemStack offHand;
public Location location;
public double health;
public int foodLevel;
public float saturation;
public float exhaustion;
public float exp;
public int level;
public int totalExperience;
public GameMode gameMode;
public boolean allowFlight;
public boolean flying;
public float flySpeed;
public float walkSpeed;
public Collection<PotionEffect> potionEffects;
public int fireTicks;
public String profileKey;
}
}

View File

@@ -0,0 +1,297 @@
package org.blz.adminmode.dialog;
import io.papermc.paper.dialog.Dialog;
import io.papermc.paper.registry.data.dialog.ActionButton;
import io.papermc.paper.registry.data.dialog.DialogBase;
import io.papermc.paper.registry.data.dialog.action.DialogAction;
import io.papermc.paper.registry.data.dialog.action.DialogActionCallback;
import io.papermc.paper.registry.data.dialog.body.DialogBody;
import io.papermc.paper.registry.data.dialog.input.DialogInput;
import io.papermc.paper.registry.data.dialog.type.DialogType;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickCallback;
import org.blz.adminmode.commands.AdminModeCommand;
import org.blz.adminmode.config.ConfigManager;
import org.blz.adminmode.moderation.ModeratorProfile;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class AdminDialogService {
private static final ClickCallback.Options CALLBACK_OPTIONS = ClickCallback.Options.builder()
.uses(1)
.lifetime(Duration.ofMinutes(5))
.build();
private final Plugin plugin;
private final ConfigManager configManager;
private final AdminModeCommand adminModeCommand;
public AdminDialogService(Plugin plugin, ConfigManager configManager, AdminModeCommand adminModeCommand) {
this.plugin = plugin;
this.configManager = configManager;
this.adminModeCommand = adminModeCommand;
}
public boolean openProfileSelectionDialog(Player player) {
if (!configManager.isDialogsEnabled()) {
return false;
}
List<ModeratorProfile> profiles = adminModeCommand.getAvailableProfiles(player);
if (profiles.isEmpty()) {
player.sendMessage(configManager.getMsgNoPermission());
return false;
}
if (profiles.size() == 1) {
adminModeCommand.toggleAdminMode(player, profiles.get(0));
return true;
}
try {
List<ActionButton> buttons = new ArrayList<>();
for (ModeratorProfile profile : profiles) {
buttons.add(actionButton(
profile.getDisplayName(),
profile.isHardProfile()
? "Полный режим модерации с сильными действиями"
: "Базовый режим модерации для повседневной работы",
(response, audience) -> withPlayer(audience, moderator -> {
adminModeCommand.toggleAdminMode(moderator, profile);
plugin.getServer().getScheduler().runTask(plugin, () -> {
if (adminModeCommand.isInAdminMode(moderator.getUniqueId())) {
openModerationPanel(moderator);
}
});
})));
}
DialogBase base = DialogBase.builder(Component.text("Выбор профиля модерации"))
.canCloseWithEscape(true)
.pause(false)
.afterAction(DialogBase.DialogAfterAction.CLOSE)
.body(List.of(DialogBody.plainMessage(Component.text(
"Выберите профиль, с которым хотите войти в admin mode. Soft — для обычной модерации, Hard — для телепортов и сильных действий."),
360)))
.inputs(List.of())
.build();
showDialog(player, base, DialogType.multiAction(buttons, closeButton(), 2));
return true;
} catch (Exception exception) {
plugin.getLogger().warning("Не удалось открыть dialog выбора профиля: " + exception.getMessage());
return false;
}
}
public boolean openModerationPanel(Player player) {
if (!configManager.isDialogsEnabled()) {
return false;
}
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
return false;
}
try {
UUID playerId = player.getUniqueId();
ModeratorProfile profile = adminModeCommand.getActiveProfile(playerId);
boolean hardProfile = profile != null && profile.isHardProfile();
List<ActionButton> buttons = new ArrayList<>();
buttons.add(actionButton(
"Скорости и режим",
"Открыть слайдеры скорости и переключатель бессмертия",
(response, audience) -> withPlayer(audience, moderator -> schedule(() -> openSpeedPanel(moderator)))));
buttons.add(actionButton(
"Выключить admin mode",
"Восстановить сохраненное состояние и снять временные права",
(response, audience) -> withPlayer(audience, adminModeCommand::toggleAdminMode)));
if (hardProfile) {
buttons.add(actionButton(
"Телепорт к игроку",
"Телепортировать себя к цели из поля ниже",
(response, audience) -> withPlayer(audience, moderator -> {
String targetName = normalizeTarget(response.getText("target_player"));
adminModeCommand.teleportToPlayer(moderator, targetName);
})));
buttons.add(actionButton(
"Игрок ко мне",
"Телепортировать цель к себе",
(response, audience) -> withPlayer(audience, moderator -> {
String targetName = normalizeTarget(response.getText("target_player"));
adminModeCommand.teleportPlayerHere(moderator, targetName);
})));
buttons.add(actionButton(
"Сбросить способности",
"Отключить полет, бессмертие и скорости у цели",
(response, audience) -> withPlayer(audience, moderator -> {
String targetName = normalizeTarget(response.getText("target_player"));
adminModeCommand.forceDisableTarget(moderator, targetName);
})));
}
List<Component> lines = new ArrayList<>();
lines.add(Component.text("Активный профиль: " + (profile == null ? "unknown" : profile.getDisplayName())));
lines.add(Component.text(hardProfile
? "Hard профиль открывает телепорты и сильные действия."
: "Soft профиль оставляет только безопасные действия и настройку режима."));
lines.add(Component.text("Для действий по цели используйте поле с ником игрока."));
DialogBase base = DialogBase.builder(Component.text("Панель модератора"))
.canCloseWithEscape(true)
.pause(false)
.afterAction(DialogBase.DialogAfterAction.CLOSE)
.body(List.of(DialogBody.plainMessage(joinLines(lines), 360)))
.inputs(List.of(DialogInput.text(
"target_player",
320,
Component.text("Ник цели"),
true,
"",
16,
null)))
.build();
showDialog(player, base, DialogType.multiAction(buttons, closeButton(), 2));
return true;
} catch (Exception exception) {
plugin.getLogger().warning("Не удалось открыть moderation dialog: " + exception.getMessage());
return false;
}
}
public boolean openSpeedPanel(Player player) {
if (!configManager.isDialogsEnabled()) {
return false;
}
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
return false;
}
try {
float currentFly = clamp(player.getFlySpeed(), 0.1f, 1.0f);
float currentWalk = clamp(player.getWalkSpeed(), 0.1f, 1.0f);
ActionButton applyButton = actionButton(
"Применить",
"Сохранить выбранные значения скорости и бессмертия",
(response, audience) -> withPlayer(audience, moderator -> {
Float flySpeed = response.getFloat("fly_speed");
Float walkSpeed = response.getFloat("walk_speed");
Boolean godMode = response.getBoolean("god_mode");
adminModeCommand.applyAdminSettings(
moderator,
flySpeed == null ? currentFly : flySpeed,
walkSpeed == null ? currentWalk : walkSpeed,
godMode != null && godMode);
schedule(() -> openModerationPanel(moderator));
}));
ActionButton backButton = actionButton(
"Назад",
"Вернуться в основную панель модератора",
(response, audience) -> withPlayer(audience, moderator -> schedule(() -> openModerationPanel(moderator))));
DialogBase base = DialogBase.builder(Component.text("Настройка admin mode"))
.canCloseWithEscape(true)
.pause(false)
.afterAction(DialogBase.DialogAfterAction.CLOSE)
.body(List.of(DialogBody.plainMessage(Component.text(
"Настройте полет, скорость передвижения и режим бессмертия через новые элементы dialog API."),
360)))
.inputs(List.of(
DialogInput.numberRange(
"fly_speed",
320,
Component.text("Скорость полета"),
"%s: %s",
0.1f,
1.0f,
currentFly,
0.05f),
DialogInput.numberRange(
"walk_speed",
320,
Component.text("Скорость ходьбы"),
"%s: %s",
0.1f,
1.0f,
currentWalk,
0.05f),
DialogInput.bool(
"god_mode",
Component.text("Бессмертие"),
player.isInvulnerable(),
"true",
"false")))
.build();
showDialog(player, base, DialogType.multiAction(List.of(applyButton), backButton, 1));
return true;
} catch (Exception exception) {
plugin.getLogger().warning("Не удалось открыть dialog настройки скоростей: " + exception.getMessage());
return false;
}
}
private void showDialog(Player player, DialogBase base, io.papermc.paper.registry.data.dialog.type.DialogType type) {
Dialog dialog = Dialog.create(factory -> {
var builder = factory.empty();
builder.base(base);
builder.type(type);
});
player.showDialog(dialog);
}
private ActionButton actionButton(String label, String tooltip, DialogActionCallback callback) {
return ActionButton.builder(Component.text(label))
.tooltip(Component.text(tooltip))
.width(170)
.action(DialogAction.customClick(callback, CALLBACK_OPTIONS))
.build();
}
private ActionButton closeButton() {
return ActionButton.builder(Component.text("Закрыть"))
.width(140)
.build();
}
private void withPlayer(net.kyori.adventure.audience.Audience audience, java.util.function.Consumer<Player> consumer) {
if (audience instanceof Player player) {
consumer.accept(player);
}
}
private Component joinLines(List<Component> lines) {
Component result = Component.empty();
for (int i = 0; i < lines.size(); i++) {
if (i > 0) {
result = result.append(Component.newline());
}
result = result.append(lines.get(i));
}
return result;
}
private void schedule(Runnable runnable) {
plugin.getServer().getScheduler().runTask(plugin, runnable);
}
private String normalizeTarget(String targetName) {
return targetName == null ? "" : targetName.trim();
}
private float clamp(float value, float min, float max) {
return Math.max(min, Math.min(max, value));
}
}

View File

@@ -0,0 +1,129 @@
package org.blz.adminmode.listeners;
import org.blz.adminmode.commands.AdminModeCommand;
import org.blz.adminmode.config.ConfigManager;
import org.bukkit.ChatColor;
import org.bukkit.Material;
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.BlockPlaceEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.plugin.Plugin;
import java.util.List;
public class AdminModeListener implements Listener {
private final Plugin plugin;
private final AdminModeCommand adminModeCommand;
private final ConfigManager configManager;
public AdminModeListener(Plugin plugin, AdminModeCommand adminModeCommand, ConfigManager configManager) {
this.plugin = plugin;
this.adminModeCommand = adminModeCommand;
this.configManager = configManager;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onItemDrop(PlayerDropItemEvent e) {
Player player = e.getPlayer();
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
if (!configManager.isPreventItemDrop()) return;
e.setCancelled(true);
player.sendMessage(ChatColor.RED + configManager.getMsgItemDropDenied());
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onItemPickup(EntityPickupItemEvent e) {
if (!(e.getEntity() instanceof Player)) return;
Player player = (Player) e.getEntity();
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
if (!configManager.isPreventItemPickup()) return;
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryClick(InventoryClickEvent e) {
if (!(e.getWhoClicked() instanceof Player)) return;
Player player = (Player) e.getWhoClicked();
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
if (!configManager.isPreventContainerTransfer()) return;
if (e.getClickedInventory() != null) {
if (e.getClickedInventory().getHolder() != null &&
!e.getClickedInventory().getHolder().equals(player)) {
e.setCancelled(true);
player.sendMessage(ChatColor.RED + configManager.getMsgContainerTransferDenied());
return;
}
}
if (e.isShiftClick()) {
if (e.getView().getTopInventory().getHolder() != null &&
!e.getView().getTopInventory().getHolder().equals(player)) {
e.setCancelled(true);
player.sendMessage(ChatColor.RED + configManager.getMsgContainerTransferDenied());
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerInteract(PlayerInteractEvent e) {
Player player = e.getPlayer();
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
if (!configManager.isPreventItemUse()) return;
if (e.getAction() == org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK) {
if (e.getClickedBlock() != null) {
Material blockType = e.getClickedBlock().getType();
List<String> allowedBlocks = configManager.getAllowedBlocks();
for (String allowed : allowedBlocks) {
if (blockType.name().contains(allowed.toUpperCase())) {
return;
}
}
}
}
if (e.getItem() != null && e.getItem().getType() != Material.AIR) {
e.setCancelled(true);
player.sendMessage(ChatColor.RED + configManager.getMsgItemUseDenied());
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onBlockPlace(BlockPlaceEvent e) {
Player player = e.getPlayer();
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
List<String> allowedPlaceBlocks = configManager.getAllowedPlaceBlocks();
if (allowedPlaceBlocks.isEmpty()) return;
Material blockType = e.getBlock().getType();
for (String allowed : allowedPlaceBlocks) {
if (blockType.name().equalsIgnoreCase(allowed)) {
return;
}
}
e.setCancelled(true);
player.sendMessage(ChatColor.RED + configManager.getMsgBlockPlaceDenied());
}
}

View File

@@ -0,0 +1,86 @@
package org.blz.adminmode.listeners;
import org.blz.adminmode.commands.AdminModeCommand;
import org.blz.adminmode.config.ConfigManager;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerGameModeChangeEvent;
import org.bukkit.event.player.PlayerToggleFlightEvent;
import java.util.List;
public class GameModeChangeListener implements Listener {
private final AdminModeCommand adminModeCommand;
private final ConfigManager configManager;
public GameModeChangeListener(AdminModeCommand adminModeCommand, ConfigManager configManager) {
this.adminModeCommand = adminModeCommand;
this.configManager = configManager;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onGameModeChange(PlayerGameModeChangeEvent event) {
Player player = event.getPlayer();
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
return;
}
// КРИТИЧНО: Блокируем CREATIVE для всех в админ моде!
if (event.getNewGameMode() == GameMode.CREATIVE) {
event.setCancelled(true);
player.sendMessage(ChatColor.RED + "В режиме модератора КРЕАТИВ запрещен!");
player.sendMessage(ChatColor.GRAY + "Доступные режимы: SURVIVAL, SPECTATOR");
return;
}
List<String> allowedModes = configManager.getAllowedGameModes();
if (!allowedModes.isEmpty()) {
String newMode = event.getNewGameMode().name();
if (!allowedModes.contains(newMode)) {
event.setCancelled(true);
player.sendMessage(ChatColor.RED + "В админ моде можно переключаться только на разрешенные режимы!");
player.sendMessage(ChatColor.GRAY + "Разрешенные режимы: " + String.join(", ", allowedModes));
return;
}
}
// Включаем полет после смены режима, если это разрешено
if (configManager.isAllowFlightInSurvival()) {
player.getServer().getScheduler().runTaskLater(
player.getServer().getPluginManager().getPlugin("AdminMode"),
() -> {
player.setAllowFlight(true);
if (!player.isFlying()) {
player.setFlying(true);
}
},
1L);
}
}
@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);
}
}
}

View File

@@ -0,0 +1,33 @@
package org.blz.adminmode.listeners;
import org.blz.adminmode.commands.AdminModeCommand;
import org.blz.adminmode.config.ConfigManager;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityTargetEvent;
public class MobTargetListener implements Listener {
private final AdminModeCommand adminModeCommand;
private final ConfigManager configManager;
public MobTargetListener(AdminModeCommand adminModeCommand, ConfigManager configManager) {
this.adminModeCommand = adminModeCommand;
this.configManager = configManager;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onMobTarget(EntityTargetEvent e) {
if (!configManager.isMobsIgnorePlayer()) return;
if (e.getTarget() instanceof Player) {
Player player = (Player) e.getTarget();
if (adminModeCommand.isInAdminMode(player.getUniqueId())) {
e.setCancelled(true);
}
}
}
}

View File

@@ -0,0 +1,413 @@
package org.blz.adminmode.managers;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.blz.adminmode.utils.ScreenEffects;
import org.bukkit.*;
import org.bukkit.entity.Entity;
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.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
public class BelzeBoolManager implements Listener {
private final Plugin plugin;
private final String BELZEBOOL_NAME = "BelzeBool";
private final String POCKET_DIMENSION_WORLD = "pocket_dimension";
private final long COOLDOWN_MS = 16000; // 16 seconds
// Casting Mode State
private final Set<UUID> castingModePlayers = new HashSet<>();
private final Map<UUID, Integer> selectedSpellIndex = new HashMap<>();
private final List<String> spells = Arrays.asList("POCKET DIMENSION", "DEADLY KISS", "VANISH");
// Cooldowns: UUID -> SpellName -> Timestamp
private final Map<UUID, Map<String, Long>> cooldowns = new HashMap<>();
// Vanish State: UUID -> isVanished
private final Set<UUID> vanishedPlayers = new HashSet<>();
// Input Tracking
private final Map<UUID, List<Long>> rightClickTimestamps = new HashMap<>();
public BelzeBoolManager(Plugin plugin) {
this.plugin = plugin;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
startActionBarTask();
}
public boolean isBelzeBool(Player player) {
return player.getName().equalsIgnoreCase(BELZEBOOL_NAME);
}
// --- Casting Mode Logic ---
@EventHandler
public void onInteract(PlayerInteractEvent event) {
if (!isBelzeBool(event.getPlayer()))
return;
Player player = event.getPlayer();
// Casting Mode Toggle: Shift + Right Click x5 (only with empty hands)
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
if (player.isSneaking() && event.getHand() == EquipmentSlot.HAND) {
// Only allow if hands are empty
ItemStack mainHand = player.getInventory().getItemInMainHand();
ItemStack offHand = player.getInventory().getItemInOffHand();
if ((mainHand == null || mainHand.getType() == Material.AIR) &&
(offHand == null || offHand.getType() == Material.AIR)) {
trackRightClick(player);
}
}
}
if (!castingModePlayers.contains(player.getUniqueId()))
return;
// Spell Cycle: Left Click (In Casting Mode)
if (event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) {
if (event.getHand() == EquipmentSlot.HAND) { // Prevent double firing
event.setCancelled(true);
cycleSpell(player);
}
}
// Cast Spell: Right Click (In Casting Mode)
// If spell is VANISH, we can cast it on Air/Block too
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
if (event.getHand() == EquipmentSlot.HAND) {
String spell = getSelectedSpell(player);
if (spell.equals("VANISH")) {
event.setCancelled(true);
castVanish(player);
}
}
}
}
@EventHandler
public void onEntityInteract(PlayerInteractEntityEvent event) {
if (!isBelzeBool(event.getPlayer()))
return;
if (event.getHand() != EquipmentSlot.HAND)
return;
Player player = event.getPlayer();
Entity target = event.getRightClicked();
if (castingModePlayers.contains(player.getUniqueId())) {
event.setCancelled(true);
castSpell(player, target);
}
}
private void trackRightClick(Player player) {
UUID uuid = player.getUniqueId();
List<Long> clicks = rightClickTimestamps.getOrDefault(uuid, new ArrayList<>());
long now = System.currentTimeMillis();
// Remove old clicks (>2s ago)
clicks.removeIf(time -> now - time > 2000);
clicks.add(now);
if (clicks.size() >= 5) {
toggleCastingMode(player);
clicks.clear();
}
rightClickTimestamps.put(uuid, clicks);
}
private void toggleCastingMode(Player player) {
UUID uuid = player.getUniqueId();
if (castingModePlayers.contains(uuid)) {
castingModePlayers.remove(uuid);
player.sendActionBar(Component.text("Casting Mode Deactivated", NamedTextColor.RED));
} else {
castingModePlayers.add(uuid);
selectedSpellIndex.putIfAbsent(uuid, 0);
player.sendActionBar(Component.text("Casting Mode Activated", NamedTextColor.GREEN));
}
player.playSound(player.getLocation(), Sound.BLOCK_BEACON_ACTIVATE, 1f, 2f);
}
public void cycleSpell(Player player) {
UUID uuid = player.getUniqueId();
int index = selectedSpellIndex.getOrDefault(uuid, 0);
index = (index + 1) % spells.size();
selectedSpellIndex.put(uuid, index);
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 1f);
}
public void castCurrentSpell(Player player) {
if (!castingModePlayers.contains(player.getUniqueId())) {
// Optional: Auto-activate casting mode if key pressed?
// Or just ignore. User logic says key is for "ability".
// Logic in onInteract checks castingModePlayers.
// I will adhere to that.
return;
}
String spell = getSelectedSpell(player);
if (spell.equals("VANISH")) {
castVanish(player);
return;
}
// RayTrace for target
Entity target = rayTraceEntity(player, 20); // 20 blocks range
if (target != null) {
castSpell(player, target);
} else {
player.sendMessage(Component.text("No target found!", NamedTextColor.RED));
}
}
private Entity rayTraceEntity(Player player, double range) {
// Simple RayTrace
org.bukkit.util.RayTraceResult result = player.getWorld().rayTraceEntities(
player.getEyeLocation(),
player.getEyeLocation().getDirection(),
range,
entity -> entity != player && entity instanceof org.bukkit.entity.LivingEntity);
return result != null ? result.getHitEntity() : null;
}
private String getSelectedSpell(Player player) {
int index = selectedSpellIndex.getOrDefault(player.getUniqueId(), 0);
return spells.get(index);
}
private void startActionBarTask() {
new BukkitRunnable() {
@Override
public void run() {
for (UUID uuid : castingModePlayers) {
Player player = Bukkit.getPlayer(uuid);
if (player != null && player.isOnline()) {
String spell = getSelectedSpell(player);
long cooldown = getCooldownRemaining(uuid, spell);
Component text;
if (cooldown > 0) {
text = Component.text("< " + spell + " (" + (cooldown / 1000) + "s) >", NamedTextColor.RED,
TextDecoration.BOLD);
} else {
if (spell.equals("VANISH") && vanishedPlayers.contains(uuid)) {
text = Component.text("< " + spell + " (ACTIVE) >", NamedTextColor.AQUA,
TextDecoration.BOLD);
} else {
text = Component.text("< " + spell + " >", NamedTextColor.GOLD, TextDecoration.BOLD);
}
}
player.sendActionBar(text);
}
}
}
}.runTaskTimer(plugin, 0L, 5L);
}
private long getCooldownRemaining(UUID uuid, String spell) {
if (!cooldowns.containsKey(uuid))
return 0;
Long timestamp = cooldowns.get(uuid).get(spell);
if (timestamp == null)
return 0;
long remaining = (timestamp + COOLDOWN_MS) - System.currentTimeMillis();
return Math.max(0, remaining);
}
private void setCooldown(UUID uuid, String spell) {
cooldowns.computeIfAbsent(uuid, k -> new HashMap<>()).put(spell, System.currentTimeMillis());
}
private void castSpell(Player player, Entity target) {
String spell = getSelectedSpell(player);
// Vanish is self-targeted, but we allow clicking on entity to trigger it too if
// selected
if (spell.equals("VANISH")) {
castVanish(player);
return;
}
if (getCooldownRemaining(player.getUniqueId(), spell) > 0) {
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 0.5f);
return;
}
setCooldown(player.getUniqueId(), spell);
switch (spell) {
case "POCKET DIMENSION" -> castPocketDimension(player, target);
case "DEADLY KISS" -> castDeadlyKiss(player, target);
}
}
// --- Ability: Pocket Dimension ---
private void castPocketDimension(Player player, Entity target) {
World pocketWorld = Bukkit.getWorld(POCKET_DIMENSION_WORLD);
if (pocketWorld == null) {
player.sendMessage(Component.text("Error: Pocket Dimension world not loaded!", NamedTextColor.RED));
return;
}
// 1. Abduction Sequence (Visuals)
if (target instanceof Player targetP) {
targetP.addPotionEffect(new PotionEffect(PotionEffectType.DARKNESS, 140, 0));
targetP.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, 140, 4));
}
target.getWorld().playSound(target.getLocation(), Sound.ENTITY_WARDEN_HEARTBEAT, 1f, 0.5f);
target.getWorld().spawnParticle(Particle.SCULK_SOUL, target.getLocation(), 50, 0.5, 1, 0.5, 0.1);
Location originalLoc = target.getLocation();
// 2. Teleport after 5 seconds
new BukkitRunnable() {
@Override
public void run() {
if (!target.isValid())
return;
// Coordinates: 9 -56 17
Location dimLoc = new Location(pocketWorld, 9.5, -56, 17.5);
dimLoc.setYaw(originalLoc.getYaw());
dimLoc.setPitch(originalLoc.getPitch());
target.teleport(dimLoc);
target.getWorld().playSound(target.getLocation(), Sound.AMBIENT_BASALT_DELTAS_LOOP, 1f, 0.5f);
// 3. Return Sequence (Total 60s in Dimension)
// At 55s (1100 ticks from now), start ascension effects
new BukkitRunnable() {
@Override
public void run() {
if (!target.isValid())
return;
if (target instanceof Player targetP) {
targetP.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, 100, 4)); // Fast up
targetP.playSound(targetP.getLocation(), Sound.ITEM_ELYTRA_FLYING, 1f, 0.5f);
}
}
}.runTaskLater(plugin, 1100L); // 55 seconds
// At 60s (1200 ticks), teleport back
new BukkitRunnable() {
@Override
public void run() {
if (target.isValid()) {
target.teleport(originalLoc);
target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
// Remove effects
if (target instanceof Player targetP) {
targetP.removePotionEffect(PotionEffectType.LEVITATION);
targetP.removePotionEffect(PotionEffectType.DARKNESS);
}
}
}
}.runTaskLater(plugin, 1200L); // 60 seconds
}
}.runTaskLater(plugin, 100L); // 5 seconds delay
}
// --- Ability: Deadly Kiss ---
private void castDeadlyKiss(Player player, Entity target) {
player.playSound(player.getLocation(), Sound.ENTITY_GHAST_SCREAM, 1f, 0.5f);
if (target instanceof Player targetP) {
ScreenEffects.shake(plugin, targetP, 2.0f, 100);
}
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 1f, 0.5f);
target.getWorld().spawnParticle(Particle.SMOKE, target.getLocation(), 20, 0.5, 0.5, 0.5, 0.1);
Location originalLoc = target.getLocation();
// Slow Drag Down (10 blocks over 5 seconds)
new BukkitRunnable() {
int ticks = 0;
final int totalTicks = 100; // 5 seconds
final double distance = 10.0;
final double blocksPerTick = distance / totalTicks;
@Override
public void run() {
if (!target.isValid() || ticks >= totalTicks) {
this.cancel();
return;
}
Location currentLoc = target.getLocation();
// Ensure we don't drag them into void damage if world doesn't support it
if (currentLoc.getY() > -63) {
Location newLoc = currentLoc.subtract(0, blocksPerTick, 0);
target.teleport(newLoc);
}
if (ticks % 5 == 0) {
target.getWorld().spawnParticle(Particle.SMOKE, target.getLocation(), 2, 0.2, 0.5, 0.2, 0);
}
ticks++;
}
}.runTaskTimer(plugin, 0L, 1L);
}
// --- Ability: Vanish ---
private void castVanish(Player player) {
UUID uuid = player.getUniqueId();
if (vanishedPlayers.contains(uuid)) {
// Deactivate
vanishedPlayers.remove(uuid);
for (Player p : Bukkit.getOnlinePlayers()) {
p.showPlayer(plugin, player);
}
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
player.getWorld().spawnParticle(Particle.WITCH, player.getLocation(), 50, 0.5, 1, 0.5, 0.1);
player.sendMessage(Component.text("You are now visible.", NamedTextColor.GREEN));
// COOLDOWN STARTS NOW
setCooldown(uuid, "VANISH");
} else {
// Activate
if (getCooldownRemaining(uuid, "VANISH") > 0) {
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 0.5f);
return;
}
vanishedPlayers.add(uuid);
for (Player p : Bukkit.getOnlinePlayers()) {
p.hidePlayer(plugin, player);
}
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_GENERIC_EXTINGUISH_FIRE, 1f, 1f);
player.getWorld().spawnParticle(Particle.CLOUD, player.getLocation(), 50, 0.5, 1, 0.5, 0.1);
player.sendMessage(Component.text("You have vanished.", NamedTextColor.AQUA));
}
}
}

View File

@@ -0,0 +1,86 @@
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");
private final String configKey;
private final String displayName;
private final String permission;
ModeratorProfile(String configKey, String displayName, String permission) {
this.configKey = configKey;
this.displayName = displayName;
this.permission = permission;
}
public String getConfigKey() {
return configKey;
}
public String getDisplayName() {
return displayName;
}
public String getPermission() {
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;
}
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();
};
}
}

View File

@@ -0,0 +1,53 @@
package org.blz.adminmode.utils;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Random;
public class ScreenEffects {
private static final Random random = new Random();
/**
* Shakes the player's screen by jittering their view direction.
*
* @param plugin Plugin instance
* @param player Player to shake
* @param intensity Intensity of shake (1-15)
* @param durationTicks Duration in ticks
*/
public static void shake(Plugin plugin, Player player, float intensity, int durationTicks) {
final float originalYaw = player.getLocation().getYaw();
final float originalPitch = player.getLocation().getPitch();
final float maxShake = Math.min(intensity, 15f);
new BukkitRunnable() {
int ticksElapsed = 0;
@Override
public void run() {
if (ticksElapsed >= durationTicks || !player.isOnline()) {
Location loc = player.getLocation();
loc.setYaw(originalYaw);
loc.setPitch(originalPitch);
player.teleport(loc);
cancel();
return;
}
float shakeYaw = (random.nextFloat() - 0.5f) * 2 * maxShake;
float shakePitch = (random.nextFloat() - 0.5f) * 2 * maxShake;
Location loc = player.getLocation();
loc.setYaw(originalYaw + shakeYaw);
loc.setPitch(originalPitch + shakePitch);
player.teleport(loc);
ticksElapsed++;
}
}.runTaskTimer(plugin, 0L, 1L);
}
}

View File

@@ -0,0 +1,94 @@
package org.blz.adminmode.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.plugin.Plugin;
public class WorldLoader {
private final Plugin plugin;
private final String worldName;
public WorldLoader(Plugin plugin, String worldName) {
this.plugin = plugin;
this.worldName = worldName;
}
public void loadWorld() {
if (Bukkit.getWorld(worldName) != null) {
plugin.getLogger().info("Мир " + worldName + " уже загружен.");
return;
}
File worldFolder = new File(Bukkit.getWorldContainer(), worldName);
if (!worldFolder.exists()) {
plugin.getLogger().info("Мир " + worldName + " не найден. Распаковка из ресурсов...");
if (extractWorld(worldFolder)) {
plugin.getLogger().info("Мир успешно распакован.");
} else {
plugin.getLogger().severe("Не удалось распаковать мир " + worldName);
return;
}
}
plugin.getLogger().info("Загрузка мира " + worldName + "...");
WorldCreator creator = new WorldCreator(worldName);
creator.environment(World.Environment.NORMAL); // Or whatever environment it should be
World world = creator.createWorld();
if (world != null) {
// Apply specific rules for the pocket dimension
world.setGameRule(org.bukkit.GameRules.ADVANCE_TIME, false);
world.setGameRule(org.bukkit.GameRules.SPAWN_MOBS, false);
world.setTime(18000); // Midnight
plugin.getLogger().info("Мир " + worldName + " успешно загружен!");
} else {
plugin.getLogger().severe("Не удалось создать/загрузить мир " + worldName);
}
}
private boolean extractWorld(File destination) {
try (InputStream in = plugin.getResource("pocket_dimension.zip")) {
if (in == null) {
plugin.getLogger().severe("Resource pocket_dimension.zip not found in plugin JAR!");
return false;
}
try (ZipInputStream zipIn = new ZipInputStream(in)) {
ZipEntry entry = zipIn.getNextEntry();
while (entry != null) {
File file = new File(destination, entry.getName());
if (entry.isDirectory()) {
file.mkdirs();
} else {
// Ensure parent directories exist
if (file.getParentFile() != null) {
file.getParentFile().mkdirs();
}
try (FileOutputStream out = new FileOutputStream(file)) {
byte[] buffer = new byte[1024];
int len;
while ((len = zipIn.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
}
zipIn.closeEntry();
entry = zipIn.getNextEntry();
}
}
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}