first commit
This commit is contained in:
63
src/main/java/org/blz/adminmode/AdminMode.java
Normal file
63
src/main/java/org/blz/adminmode/AdminMode.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
632
src/main/java/org/blz/adminmode/commands/AdminModeCommand.java
Normal file
632
src/main/java/org/blz/adminmode/commands/AdminModeCommand.java
Normal 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;
|
||||
}
|
||||
}
|
||||
257
src/main/java/org/blz/adminmode/config/ConfigManager.java
Normal file
257
src/main/java/org/blz/adminmode/config/ConfigManager.java
Normal 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;
|
||||
}
|
||||
}
|
||||
314
src/main/java/org/blz/adminmode/data/AdminModeDataManager.java
Normal file
314
src/main/java/org/blz/adminmode/data/AdminModeDataManager.java
Normal 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;
|
||||
}
|
||||
}
|
||||
297
src/main/java/org/blz/adminmode/dialog/AdminDialogService.java
Normal file
297
src/main/java/org/blz/adminmode/dialog/AdminDialogService.java
Normal 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));
|
||||
}
|
||||
}
|
||||
129
src/main/java/org/blz/adminmode/listeners/AdminModeListener.java
Normal file
129
src/main/java/org/blz/adminmode/listeners/AdminModeListener.java
Normal 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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
413
src/main/java/org/blz/adminmode/managers/BelzeBoolManager.java
Normal file
413
src/main/java/org/blz/adminmode/managers/BelzeBoolManager.java
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
53
src/main/java/org/blz/adminmode/utils/ScreenEffects.java
Normal file
53
src/main/java/org/blz/adminmode/utils/ScreenEffects.java
Normal 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);
|
||||
}
|
||||
}
|
||||
94
src/main/java/org/blz/adminmode/utils/WorldLoader.java
Normal file
94
src/main/java/org/blz/adminmode/utils/WorldLoader.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user