From c7ca8aad200e7a184c9105f888dcecf1f0e60bdf Mon Sep 17 00:00:00 2001 From: hdvt Date: Fri, 28 Nov 2025 03:55:57 +0300 Subject: [PATCH 1/2] huge changes, rewrite from 0.5 idk --- .idea/.name | 1 + .idea/discord.xml | 14 + .idea/modules/BlockAndSeek.test.iml | 13 + .../hdvtdev/blockAndSeek/BlockAndSeek.java | 84 ------ .../hdvtdev/blockAndSeek/CommandListener.java | 280 ------------------ .../java/hdvtdev/blockAndSeek/Config.java | 41 --- .../hdvtdev/blockAndSeek/Localization.java | 109 ------- .../eventListeners/DefaultEventListener.java | 279 ----------------- .../blockAndSeek/managers/ConfigManager.java | 134 --------- .../blockAndSeek/managers/GuiManager.java | 115 ------- .../blockAndSeek/managers/MapsManager.java | 53 ---- .../blockAndSeek/managers/PropManager.java | 159 ---------- .../hdvtdev/blockandseek/BlockAndSeek.java | 182 ++++++++++++ .../hdvtdev/blockandseek/BlocksGenerator.java | 113 +++++++ .../hdvtdev/blockandseek/CommandBuilder.java | 58 ++++ .../hdvtdev/blockandseek/CommandListener.java | 21 ++ .../java/hdvtdev/blockandseek/Config.java | 80 +++++ .../java/hdvtdev/blockandseek/GuiHolder.java | 12 + .../{blockAndSeek => blockandseek}/Keys.java | 4 + .../hdvtdev/blockandseek/Localization.java | 83 ++++++ .../{blockAndSeek => blockandseek}/Utils.java | 22 +- .../eventListeners/EventListener.java | 0 .../ForceControlEventListener.java | 11 + .../eventListeners/RequiredEventListener.java | 98 ++++++ .../managers/GamesManager.java | 13 +- .../managers/ItemManager.java | 23 +- .../blockandseek/managers/MapsManager.java | 54 ++++ .../blockandseek/managers/PropManager.java | 76 +++++ .../blockandseek/managers/StateManager.java | 57 ++++ .../managers/WorldManager.java | 2 + .../hdvtdev/blockandseek/menus/GamesMenu.java | 38 +++ .../objects/BlockAndSeekGame.java | 43 +++ .../blockandseek/objects/BlockAndSeekMap.java | 17 ++ .../blockandseek/objects/GamePhase.java | 4 + .../blockandseek/objects/PropBlock.java | 9 + .../hdvtdev/blockandseek/objects/Rarity.java | 23 ++ .../roulette/RouletteCreator.java | 8 +- .../roulette/RouletteGenerator.java | 5 +- .../roulette/RouletteList.java | 4 +- src/main/resources/config.yml | 19 -- src/main/resources/languages/en_US.yml | 0 src/main/resources/localization.yml | 40 --- src/main/resources/maps.yml | 1 - 43 files changed, 1048 insertions(+), 1354 deletions(-) create mode 100644 .idea/.name create mode 100644 .idea/discord.xml create mode 100644 .idea/modules/BlockAndSeek.test.iml delete mode 100644 src/main/java/hdvtdev/blockAndSeek/BlockAndSeek.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/CommandListener.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/Config.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/Localization.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/eventListeners/DefaultEventListener.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/managers/ConfigManager.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/managers/GuiManager.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/managers/MapsManager.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/managers/PropManager.java create mode 100644 src/main/java/hdvtdev/blockandseek/BlockAndSeek.java create mode 100644 src/main/java/hdvtdev/blockandseek/BlocksGenerator.java create mode 100644 src/main/java/hdvtdev/blockandseek/CommandBuilder.java create mode 100644 src/main/java/hdvtdev/blockandseek/CommandListener.java create mode 100644 src/main/java/hdvtdev/blockandseek/Config.java create mode 100644 src/main/java/hdvtdev/blockandseek/GuiHolder.java rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/Keys.java (93%) create mode 100644 src/main/java/hdvtdev/blockandseek/Localization.java rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/Utils.java (73%) rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/eventListeners/EventListener.java (100%) rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/eventListeners/ForceControlEventListener.java (87%) create mode 100644 src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/managers/GamesManager.java (68%) rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/managers/ItemManager.java (87%) create mode 100644 src/main/java/hdvtdev/blockandseek/managers/MapsManager.java create mode 100644 src/main/java/hdvtdev/blockandseek/managers/PropManager.java create mode 100644 src/main/java/hdvtdev/blockandseek/managers/StateManager.java rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/managers/WorldManager.java (99%) create mode 100644 src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java create mode 100644 src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java create mode 100644 src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java create mode 100644 src/main/java/hdvtdev/blockandseek/objects/GamePhase.java create mode 100644 src/main/java/hdvtdev/blockandseek/objects/PropBlock.java create mode 100644 src/main/java/hdvtdev/blockandseek/objects/Rarity.java rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/roulette/RouletteCreator.java (97%) rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/roulette/RouletteGenerator.java (94%) rename src/main/java/hdvtdev/{blockAndSeek => blockandseek}/roulette/RouletteList.java (85%) delete mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/languages/en_US.yml delete mode 100644 src/main/resources/localization.yml delete mode 100644 src/main/resources/maps.yml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..936d500 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +BlockAndSeek \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..baf5572 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules/BlockAndSeek.test.iml b/.idea/modules/BlockAndSeek.test.iml new file mode 100644 index 0000000..a376b96 --- /dev/null +++ b/.idea/modules/BlockAndSeek.test.iml @@ -0,0 +1,13 @@ + + + + + + + ADVENTURE + + 1 + + + + \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeek.java b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeek.java deleted file mode 100644 index 01e97ac..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeek.java +++ /dev/null @@ -1,84 +0,0 @@ -package hdvtdev.blockAndSeek; - -import hdvtdev.blockAndSeek.eventListeners.DefaultEventListener; -import hdvtdev.blockAndSeek.eventListeners.EventListener; -import hdvtdev.blockAndSeek.eventListeners.ForceControlEventListener; -import hdvtdev.blockAndSeek.managers.ConfigManager; -import me.libraryaddict.disguise.LibsDisguises; -import org.bukkit.Bukkit; -import org.bukkit.command.PluginCommand; -import org.bukkit.configuration.serialization.ConfigurationSerialization; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; -import java.util.logging.Logger; - -public class BlockAndSeek extends JavaPlugin { - - private static JavaPlugin javaPlugin; - - public static Plugin getInstance() { - return javaPlugin; - } - - public static File getPluginDataFolder() { - return javaPlugin.getDataFolder(); - } - - public static File getServerDataFolder() { - return javaPlugin.getServer().getPluginsFolder().getParentFile(); - } - - public static InputStream getPluginResource(String resource) { - return javaPlugin.getResource(resource); - } - - public static void saveResource(String file) { - javaPlugin.saveResource(file, false); - } - - public static Logger getPluginLogger() { - return javaPlugin.getLogger(); - } - - @Override - public void onEnable() { - - javaPlugin = this; - - ConfigurationSerialization.registerClass(BlockAndSeekMap.class, "BlockAndSeekMap"); - ConfigurationSerialization.registerClass(Config.class, "BlockAndSeekConfig"); - - - LibsDisguises libsDisguises = (LibsDisguises) Bukkit.getPluginManager().getPlugin("LibsDisguises"); - if (libsDisguises == null) { - getLogger().severe("LibsDisguises not found! It's required for the plugin to work!"); - super.onDisable(); - } - - try { - ConfigManager.loadAll(); - } catch (IOException e) { - getLogger().severe("Failed to save some .yml configs!"); - } - - PluginCommand command = Objects.requireNonNull(getCommand("blockandseek")); - command.setExecutor(new CommandListener()); - - PluginManager manager = getServer().getPluginManager(); - manager.registerEvents(ConfigManager.getConfig().forceControl() ? new ForceControlEventListener() : new EventListener(), this); - manager.registerEvents(new DefaultEventListener(), this); - - - } - - @Override - public void onDisable() { - } - -} diff --git a/src/main/java/hdvtdev/blockAndSeek/CommandListener.java b/src/main/java/hdvtdev/blockAndSeek/CommandListener.java deleted file mode 100644 index 82c565f..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/CommandListener.java +++ /dev/null @@ -1,280 +0,0 @@ -package hdvtdev.blockAndSeek; - -//import com.mojang.brigadier.arguments.StringArgumentType; -//import com.mojang.brigadier.builder.LiteralArgumentBuilder; -//import com.mojang.brigadier.builder.RequiredArgumentBuilder; - -import hdvtdev.blockAndSeek.managers.*; -import hdvtdev.blockAndSeek.roulette.RouletteCreator; -import me.libraryaddict.disguise.DisguiseAPI; -import me.libraryaddict.disguise.disguisetypes.DisguiseType; -import me.libraryaddict.disguise.disguisetypes.MiscDisguise; -import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.attribute.Attribute; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.util.*; - -public class CommandListener implements TabExecutor { - - private static final MiniMessage miniMessage = MiniMessage.miniMessage(); - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - - - int argsLen = args.length; - - if (argsLen == 0) { - sender.sendMessage(Localization.get("bs-usage")); - return true; - } - - - switch (args[0]) { - case "test" -> { - if (sender instanceof Player player) { - GamesManager.createGame("dust2"); - GamesManager.get("dust2").addPlayer(player); - } - - - } - case "locale" -> { - if (sender instanceof Player player) { - player.sendMessage(player.locale().toLanguageTag()); - player.sendMessage("eq: " + player.locale().toLanguageTag().equals("en-US")); - } - } - case "menu" -> { - if (sender instanceof Player player) { - GuiManager.Menu.open(player); - } - } - - - case "morph" -> { - if (sender instanceof Player player && args.length == 2) { - Material material = Material.valueOf(args[1].toUpperCase()); - - PropManager.addPlayerDisguise(player, material.createBlockData()); - DisguiseAPI.disguiseToAll(player, new MiscDisguise(DisguiseType.FALLING_BLOCK, new ItemStack(material))); - } - } - - case "damage" -> { - if (sender instanceof Player player && args.length == 2) { - player.damage(Double.parseDouble(args[1])); - } - } - - case "health" -> { - if (sender instanceof Player player && args.length == 2) { - player.setHealth(Double.parseDouble(args[1])); - } - } - - case "new" -> { - if (sender instanceof Player player) { - new RouletteCreator(player, List.of( - new BlockAndSeekMap.Block(new ItemStack(Material.STONE), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.DIRT), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.LANTERN), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.TARGET), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.SCULK_SHRIEKER), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.FLOWER_POT), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.AZALEA_LEAVES), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.PUMPKIN), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.MELON), 10), - new BlockAndSeekMap.Block(new ItemStack(Material.DIAMOND_BLOCK), 10) - )); - } - } - case "foo" -> { - if (sender instanceof Player player) { - ItemStack foo = new ItemStack(Material.BROWN_DYE); - ItemMeta fooMeta = foo.getItemMeta(); - fooMeta.displayName(MiniMessage.miniMessage().deserialize("SoundMaker3000")); - fooMeta.getPersistentDataContainer().set(Keys.SOUND_ITEM, PersistentDataType.BOOLEAN, true); - foo.setItemMeta(fooMeta); - player.getInventory().addItem(foo); - } - } - case "bbb" -> { - if (sender instanceof Player player) { - PropManager.changePropDirection(player); - } - } - case "container" -> { - if (sender instanceof Player player) { - var container = player.getPersistentDataContainer(); - player.sendMessage("containers: " + container.getKeys()); - - } - } - case "def" -> { - if (sender instanceof Player player) { - player.setVisibleByDefault(true); - player.setInvisible(false); - player.setInvulnerable(false); - player.setGameMode(GameMode.SURVIVAL); - player.setGlowing(false); - player.clearActivePotionEffects(); - player.setHealth(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getDefaultValue()); - player.setFoodLevel(20); - Utils.setLevelWithBar(player, 0); - DisguiseAPI.undisguiseToAll(player); - PersistentDataContainer dataContainer = player.getPersistentDataContainer(); - for (var key : dataContainer.getKeys()) { - dataContainer.remove(key); - } - } - } - case "map" -> { - if (sender.hasPermission("blockandseek.manage")) { - if (argsLen > 1) { - switch (args[1]) { - case "list" -> { - StringBuilder buffer = new StringBuilder(Localization.get("maps-available")); - String listElement = Localization.get("maps-available-element"); - Set readyMaps = null; //TODO ConfigManager.getReadyMaps(); - for (String map : ConfigManager.getAllMaps()) { - buffer.append("\n").append(listElement.replace("{map}", map).replace("{color-status}", - readyMaps.contains(map) ? "" : "")); - } - sender.sendMessage(miniMessage.deserialize(buffer.toString())); - } - default -> { - if (ConfigManager.getAllMaps().contains(args[1])) { - if (argsLen > 3) { - switch (args[2]) { - case "setduration" -> { - try { - int duration = Integer.parseInt(args[3]); - if (duration > 0) { - sender.sendMessage(args[1]); - var map = MapsManager.getMap(args[1]); - map.setDuration(duration); - MapsManager.saveMap(args[1], map); - sender.sendMessage("duration set"); - } else sender.sendMessage("idk"); - - } catch (NumberFormatException | IOException e) { - sender.sendMessage("idk"); - } - } - } - } - } - } - } - } else - sender.sendMessage(Localization.getComponent("not-enough-arguments", "{command}", "/blockandseek map", "{help}", "[MAP NAME | COMMANDS]")); - - } else sender.sendMessage(Localization.getComponent("not-enough-permissions")); - } - case "reload" -> { - if (sender.hasPermission("blockandseek.manage")) { - if (argsLen > 1) { - switch (args[1]) { - case "localization" -> { - try { - - ConfigManager.load("localization.yml"); - sender.sendMessage(Localization.getComponentWithPrefix("successful-reload", "{config}", "localization.yml")); - } catch (IOException e) { - sender.sendMessage(Localization.getComponentWithPrefix("failed-reload", "{config}", "localization.yml", "{e}", e.getMessage())); - } - - } - case "maps" -> { - try { - ConfigManager.load(null); - } catch (IOException e) { - throw new RuntimeException(e); - } - sender.sendMessage(Localization.get("maps-reload")); - } - } - } else - sender.sendMessage(Localization.get("not-enough-arguments", "{usage}", "/blockandseek reload [messages | maps]")); - - } else sender.sendMessage(Localization.get("not-enough-permissions")); - } - - } - - - return true; - } - - - @Override - public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - return !sender.hasPermission("blockandseek.manage") ? List.of() : switch (args.length) { - case 1 -> List.of("info", "map", "reload"); - case 2 -> switch (args[0]) { - case "reload" -> List.of("localization", "config"); - case "map" -> { - List mapCommands = new ArrayList<>(MapsManager.getAllMaps()); - mapCommands.add("create"); - mapCommands.add("list"); - yield mapCommands; - } - default -> List.of(); - }; - case 3 -> { - if (MapsManager.getAllMaps().contains(args[1])) { - yield List.of("status", "setspawn", "setlobby", "setduration", "setminplayers", "setmaxplayers", "addblock", "deleteblock"); - } - yield List.of(); - } - case 4 -> switch (args[2]) { - case "setspawn", "setlobby" -> { - if (sender instanceof Player player) { - Location location = player.getLocation().toCenterLocation(); - yield List.of(String.format("%s %s %s", location.getX(), location.getY(), location.getZ())); - } else yield List.of(); - } - case "setduration" -> List.of("[]"); - case "setminplayers", "setmaxplayers" -> List.of("[]"); - case "addblock", "removeblock" -> - Arrays.stream(Material.values()).map(Objects::toString).map(String::toLowerCase).toList(); - default -> List.of(); - }; - case 5 -> args[2].equalsIgnoreCase("addblock") ? List.of("[]") : List.of(); - - default -> List.of(); - }; - } - - /* TODO - public static void registerCompletions(Commodore commodore, PluginCommand command) { - commodore.register(command, LiteralArgumentBuilder.literal("blockandseek") - .then(RequiredArgumentBuilder.argument("idk", StringArgumentType.greedyString()).suggests((a, b) -> { - b.suggest("sometextidk"); - - return b.buildFuture(); - }).executes(o -> { - System.out.println(23238923); - return 1; - }))); - } - - */ - - -} diff --git a/src/main/java/hdvtdev/blockAndSeek/Config.java b/src/main/java/hdvtdev/blockAndSeek/Config.java deleted file mode 100644 index 40dfd1e..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/Config.java +++ /dev/null @@ -1,41 +0,0 @@ -package hdvtdev.blockAndSeek; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.WorldCreator; -import org.bukkit.configuration.serialization.ConfigurationSerializable; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public record Config(@NotNull Location defaultSpawn, boolean forceControl) implements ConfigurationSerializable { - - @Override - public @NotNull Map serialize() { - Map map = new HashMap<>(); - map.put("default-spawn", defaultSpawn.serialize()); - map.put("force-control", Boolean.valueOf(forceControl)); - return map; - } - - @NotNull - @SuppressWarnings("unchecked") - public static Config deserialize(@NotNull Map args) { - Map location = (Map) args.get("default-spawn"); - List cords = location == null || location.isEmpty() ? List.of() : (List) location.get("location"); - World world = location == null || location.isEmpty() ? null : Bukkit.getWorld((String) location.get("world")); - if (world == null) { - world = Bukkit.createWorld(new WorldCreator("world")); - } - if (cords.isEmpty() || cords.size() < 3) { - Location spawn = world.getSpawnLocation(); - cords = List.of((int) spawn.getX(), (int) spawn.getY(), (int) spawn.getZ()); - } - return new Config(new Location(world, cords.getFirst(), cords.get(1), cords.get(2)), (Boolean) args.get("force-control")); - } - - -} \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockAndSeek/Localization.java b/src/main/java/hdvtdev/blockAndSeek/Localization.java deleted file mode 100644 index 5e3a6f3..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/Localization.java +++ /dev/null @@ -1,109 +0,0 @@ -package hdvtdev.blockAndSeek; - -import hdvtdev.blockAndSeek.managers.ConfigManager; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import net.kyori.adventure.title.Title; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.Map; - - -public class Localization { - - private static volatile Map> localization = Collections.unmodifiableMap(ConfigManager.getLocalization()); - - private static final MiniMessage miniMessage = MiniMessage.miniMessage(); - private static final PlainTextComponentSerializer plainText = PlainTextComponentSerializer.plainText(); - private static final Component prefix = miniMessage.deserialize("[BlockAndSeek] "); - private static final Component empty = Component.empty(); - - public static void update() { - localization = Collections.unmodifiableMap(ConfigManager.getLocalization()); - } - - public static ItemStack translateItem(@NotNull Player player, @NotNull ItemStack itemStack, @NotNull String... replacements) { - ItemStack translatedItem = itemStack.clone(); - ItemMeta itemMeta = translatedItem.getItemMeta(); - String key = plainText.serialize(itemMeta.displayName()); - itemMeta.displayName(getComponent(player.locale().toLanguageTag(), key, replacements)); - translatedItem.setItemMeta(itemMeta); - return translatedItem; - } - - public static void sendMessage(@NotNull Iterable players, boolean addPrefix, @NotNull String key, @NotNull String... replacements) { - for (Player player : players) { - sendMessage(player, addPrefix, key, replacements); - } - } - - public static void sendMessage(@NotNull Player player, boolean addPrefix, @NotNull String key, @NotNull String... replacements) { - Component component = getComponent(player.locale().toLanguageTag(), key, replacements); - player.sendMessage(addPrefix ? prefix.append(component) : component); - } - - public static void sendActionBar(@NotNull Iterable players, boolean addPrefix, @NotNull String key, @NotNull String... replacements) { - for (Player player : players) { - sendActionBar(player, addPrefix, key, replacements); - } - } - - @Deprecated - public static String get(String a) { - return ""; - } - - @Deprecated - public static Component getComponent(String a) { - return empty; - } - - @Deprecated - public static Component getComponentWithPrefix(String... a) { - return empty; - } - - - public static void sendActionBar(@NotNull Player player, boolean addPrefix, @NotNull String key, @NotNull String... replacements) { - Component component = getComponent(player.locale().toLanguageTag(), key, replacements); - player.sendActionBar(addPrefix ? prefix.append(component) : component); - } - - public static void sendTitle(@NotNull Iterable players, boolean addPrefix, @NotNull String key, @NotNull String... replacements) { - for (Player player : players) { - sendTitle(player, addPrefix, key, replacements); - } - } - - public static void sendTitle(@NotNull Player player, boolean addPrefix, @NotNull String key, @NotNull String... replacements) { - Component component = getComponent(player.locale().toLanguageTag(), key, replacements); - player.showTitle(Title.title(addPrefix ? prefix.append(component) : component, empty)); - } - - public static @NotNull Component getComponent(@NotNull Player p, @NotNull String key, @NotNull String... replacements) { - return getComponent(p.locale().toLanguageTag(), key, replacements); - } - - public static @NotNull Component getComponent(@NotNull String lang, @NotNull String key, @NotNull String... replacements) { - return miniMessage.deserialize(get(lang, key, replacements)); - } - - public static @NotNull String get(@NotNull String lang, @NotNull String key, @NotNull String... replacements) { - - String s = localization.getOrDefault(lang, localization.get("en-US")).get(key); - if (s != null) { - for (int i = 0; i < replacements.length; i += 2) { - s = s.replace(replacements[i], replacements[i + 1]); - } - } else return "Unknown localization: " + key; - - - return s; - } - -} diff --git a/src/main/java/hdvtdev/blockAndSeek/eventListeners/DefaultEventListener.java b/src/main/java/hdvtdev/blockAndSeek/eventListeners/DefaultEventListener.java deleted file mode 100644 index 4ee9152..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/eventListeners/DefaultEventListener.java +++ /dev/null @@ -1,279 +0,0 @@ -package hdvtdev.blockAndSeek.eventListeners; - -import hdvtdev.blockAndSeek.BlockAndSeek; -import hdvtdev.blockAndSeek.Keys; -import hdvtdev.blockAndSeek.Utils; -import hdvtdev.blockAndSeek.managers.GamesManager; -import hdvtdev.blockAndSeek.managers.GuiManager; -import hdvtdev.blockAndSeek.managers.PropManager; -import hdvtdev.blockAndSeek.roulette.RouletteCreator; -import org.bukkit.Bukkit; -import org.bukkit.entity.ArmorStand; -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.block.BlockDamageEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDismountEvent; -import org.bukkit.event.entity.EntityRegainHealthEvent; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import static hdvtdev.blockAndSeek.Utils.isInOneTeam; -import static hdvtdev.blockAndSeek.Utils.playerInGame; - -public class DefaultEventListener implements Listener { - - private static final BukkitScheduler scheduler = Bukkit.getScheduler(); - private static final Set coolDown = ConcurrentHashMap.newKeySet(); - - @Deprecated(forRemoval = true) - private static final ConcurrentHashMap tasks = new ConcurrentHashMap<>(); - - @Deprecated(forRemoval = true) - public static void createTask(Player player, BukkitTask bukkitTask) { - tasks.put(player, bukkitTask); - } - - @Deprecated(forRemoval = true) - public static void stopTask(Player player) { - BukkitTask task = tasks.remove(player); - task.cancel(); - } - - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - if (player.getVehicle() instanceof ArmorStand armorStand) { - PersistentDataContainer armorStandContainer = armorStand.getPersistentDataContainer(); - if (armorStandContainer.has(Keys.FROZEN_PLAYER)) { - armorStandContainer.remove(Keys.FROZEN_PLAYER); - armorStand.remove(); - } - } - } - - @EventHandler - public void onBlockDamage(BlockDamageEvent event) { - Player player = event.getPlayer(); - if (player.getPersistentDataContainer().has(Keys.SEEKER)) { - if (PropManager.unfreeze(event.getBlock().getBlockData())) { - event.setCancelled(true); - } else { - player.damage(2); - Utils.setLevelWithBar(player, (int) Math.round(player.getHealth() * 5)); - } - } - } - - @EventHandler - public void onRightClick(PlayerInteractEvent event) { - if (event.getHand() != EquipmentSlot.HAND) return; - Action action = event.getAction(); - Player player = event.getPlayer(); - if (action.isRightClick() && !coolDown.contains(player)) { - - - ItemStack itemInHand = player.getInventory().getItemInMainHand(); - ItemMeta meta = itemInHand.getItemMeta(); - - if (meta != null) { - PersistentDataContainer itemData = meta.getPersistentDataContainer(); - if (itemData.has(Keys.FREEZE_ITEM) && playerInGame(player)) { - coolDown.add(player); - scheduler.runTaskLater(BlockAndSeek.getInstance(), () -> coolDown.remove(player), 3L); - PropManager.freeze(player); - event.setCancelled(true); - } else if (itemData.has(Keys.MENU_ITEM)) { - GuiManager.Menu.open(player); - event.setCancelled(true); - } else if (itemData.has(Keys.LEAVE_ITEM)) { - String game = player.getPersistentDataContainer().get(Keys.GAME, PersistentDataType.STRING); - GamesManager.get(game).removePlayer(player); - event.setCancelled(true); - } else if (itemData.has(Keys.FACE_CHANGING_ITEM)) { - PropManager.changePropDirection(player); - event.setCancelled(true); - } - } - - - } - - } - - @EventHandler - public void onEntityDismount(EntityDismountEvent event) { - Player player = (Player) event.getEntity(); - if (event.getDismounted() instanceof ArmorStand armorStand && armorStand.getPersistentDataContainer().has(Keys.FROZEN_PLAYER)) { - PropManager.freeze(player); - } - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - PersistentDataContainer container = player.getPersistentDataContainer(); - - String arena = container.get(Keys.GAME, PersistentDataType.STRING); - if (arena != null) { - GamesManager.get(arena).removePlayer(player); - PropManager.removePlayerDisguise(player); - } - } - - @EventHandler - public void onPlayerDeath(PlayerDeathEvent event) { - Player player = event.getPlayer(); - String game = player.getPersistentDataContainer().get(Keys.GAME, PersistentDataType.STRING); - if (game != null) { - event.deathMessage(null); - event.setDroppedExp(0); - event.getDrops().clear(); - scheduler.runTask(BlockAndSeek.getInstance(), () -> GamesManager.get(game).setSpectator(player, player.getKiller())); - //without scheduler strange things are happening idk - } - } - - @EventHandler - public void onInventoryClose(InventoryCloseEvent event) { - - Player player = (Player) event.getPlayer(); - InventoryHolder holder = event.getInventory().getHolder(); - - - if (holder instanceof RouletteCreator rouletteCreator) { - - Boolean isClosedByPlayer = rouletteCreator.isClosedByPlayer(); - - if (isClosedByPlayer != null) { - RouletteCreator.Task task = rouletteCreator.getTask(); - if (isClosedByPlayer) { - if (!task.rouletteTask().isCancelled()) { - Utils.firstDisguise(player, rouletteCreator.randomPropItem()); - } else Utils.firstDisguise(player, rouletteCreator.randomMidPropItem()); - task.cancelBoth(); - } else Utils.firstDisguise(player, rouletteCreator.randomMidPropItem()); - } - - - } - - - } - - @EventHandler - public void onInventoryClick(InventoryClickEvent event) { - Player player = (Player) event.getWhoClicked(); - Inventory inventory = event.getClickedInventory(); - - - if (inventory != null) { - - InventoryHolder holder = inventory.getHolder(); - int slot = event.getSlot(); - ItemStack item = inventory.getItem(slot); - - if (holder instanceof RouletteCreator rouletteCreator) { - RouletteCreator.Task task = rouletteCreator.getTask(); - - if (task.rouletteTask().isCancelled()) { - if (slot == 21 || slot == 23 || slot == 25) { - task.autoCloseTask().cancel(); - Utils.firstDisguise(player, inventory.getItem(slot)); - rouletteCreator.closeInventory(); - } - event.setCancelled(true); - return; - } else { - if (slot == 36) { - task.cancelBoth(); - Utils.firstDisguise(player, rouletteCreator.randomPropItem()); - rouletteCreator.closeInventory(); - event.setCancelled(true); - return; - } - } - - - } - - - if (item != null) { - ItemMeta meta = item.getItemMeta(); - if (meta != null) { - PersistentDataContainer itemData = meta.getPersistentDataContainer(); - - if (itemData.has(Keys.GAME_PAGE)) { - GuiManager.Menu.Games.open(player); - event.setCancelled(true); - } else if (itemData.has(Keys.GAME)) { - String game = itemData.get(Keys.GAME, PersistentDataType.STRING); - if (game != null) { - GamesManager.get(game).addPlayer(player); - event.setCancelled(true); - } - } - } - } - - } - - //TODO MOVE TO EVENT LISTENER - if (player.getPersistentDataContainer().has(Keys.GAME)) { - event.setCancelled(true); - } - - - } - - @EventHandler - public void onRegainHealth(EntityRegainHealthEvent event) { - if (event.getEntity() instanceof Player player) { - PersistentDataContainer container = player.getPersistentDataContainer(); - if (container.has(Keys.SEEKER)) { - event.setCancelled(true); - } else if (container.has(Keys.HIDER)) { - if (!PropManager.isPlayerDisguised(player)) event.setCancelled(true); - } - } - } - - @EventHandler - public void onPlayerDamage(EntityDamageByEntityEvent event) { - if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) { - if (isInOneTeam(damager, victim)) { - event.setCancelled(true); - } else if (victim.getPersistentDataContainer().has(Keys.SEEKER)) { - event.setDamage(0); - } else if (damager.getPersistentDataContainer().has(Keys.SEEKER)) { - double maxHealth = 20.0; - double currentHealth = damager.getHealth(); - if (currentHealth < maxHealth) { - double newHealth = Math.min(currentHealth + event.getDamage(), maxHealth); - damager.setHealth(newHealth); - Utils.setLevelWithBar(damager, (int) Math.round(damager.getHealth() * 5)); - } - } - } - } - -} diff --git a/src/main/java/hdvtdev/blockAndSeek/managers/ConfigManager.java b/src/main/java/hdvtdev/blockAndSeek/managers/ConfigManager.java deleted file mode 100644 index 5d29775..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/managers/ConfigManager.java +++ /dev/null @@ -1,134 +0,0 @@ -package hdvtdev.blockAndSeek.managers; - -import hdvtdev.blockAndSeek.BlockAndSeek; -import hdvtdev.blockAndSeek.BlockAndSeekMap; -import hdvtdev.blockAndSeek.Config; -import hdvtdev.blockAndSeek.Localization; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -public class ConfigManager { - - private static volatile Map> localization; - private static volatile Config config; - private static Map maps = new ConcurrentHashMap<>(); - - private static final File mapsFile = new File(BlockAndSeek.getPluginDataFolder(), "maps.yml"); - - public static Config getConfig() { - return config; - } - - - public static Set getAllMaps() { - return YamlConfiguration.loadConfiguration(mapsFile).getKeys(false); - } - - public static void loadAll() throws IOException { - load("config.yml"); - load("localization.yml"); - load("maps.yml"); - } - - public static void load(String file) throws IOException { - - File conf = new File(BlockAndSeek.getPluginDataFolder(), file); - - YamlConfiguration defaultConfiguration = YamlConfiguration.loadConfiguration( - new InputStreamReader(BlockAndSeek.getPluginResource(file))); - - if (!conf.exists()) { - BlockAndSeek.saveResource(file); - - - /* - switch (file) { - case "config.yml" -> config = defaultConfiguration.getSerializable("config", Config.class); - case "localization.yml" -> { - Map> confMap = new HashMap<>(); - Map lang = new HashMap<>(); - for (String key : defaultConfiguration.getConfigurationSection("en-US").getKeys(false)) { - lang.put(key, defaultConfiguration.getString(key, "NULL")); - } - confMap.put("en-US", lang); - localization = confMap; - Localization.update(); - } - } - - */ - - - } - - switch (file) { - case "config.yml" -> loadConfig(conf, defaultConfiguration); - case "localization.yml" -> loadLocalization(conf, defaultConfiguration); - case "maps.yml" -> MapsManager.loadMaps(); - } - - - } - - - private static void loadConfig(File configurationFile, YamlConfiguration defaultConfiguration) { - YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile); - configuration.setDefaults(defaultConfiguration); - - config = configuration.getSerializable("config", Config.class); - } - - private static void loadLocalization(File configurationFile, YamlConfiguration defaultConfiguration) throws IOException { - - Map> confMap = new HashMap<>(); - YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configurationFile); - - ConfigurationSection defaultSection = defaultConfiguration.getConfigurationSection("en-US"); - - for (String langKey : configuration.getKeys(false)) { - ConfigurationSection configSection = configuration.getConfigurationSection(langKey); - Map langMap = new HashMap<>(); - - if (configSection != null) { - for (String key : defaultSection.getKeys(false)) { - if (configSection.contains(key)) { - langMap.put(key, configSection.getString(key, defaultSection.getString(key, "NULL"))); - } else { - String value = defaultSection.getString(key, "NULL"); - configSection.set(key, value); - langMap.put(key, value); - } - - } - } else { - BlockAndSeek.getPluginLogger().warning("No any language found in the configuration! Using default en-US."); - for (String key : defaultSection.getKeys(false)) { - langMap.put(key, defaultSection.getString(key, "NULL")); - } - } - - confMap.put(langKey, langMap); - } - - - configuration.save(configurationFile); - - localization = confMap; - Localization.update(); - } - - - public static Map> getLocalization() { - return localization; - } - - -} diff --git a/src/main/java/hdvtdev/blockAndSeek/managers/GuiManager.java b/src/main/java/hdvtdev/blockAndSeek/managers/GuiManager.java deleted file mode 100644 index a6ad179..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/managers/GuiManager.java +++ /dev/null @@ -1,115 +0,0 @@ -package hdvtdev.blockAndSeek.managers; - -import hdvtdev.blockAndSeek.BlockAndSeekGame; -import hdvtdev.blockAndSeek.Keys; -import hdvtdev.blockAndSeek.Localization; -import net.kyori.adventure.text.Component; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.persistence.PersistentDataType; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -public class GuiManager { - - private static final ItemStack filler1 = new ItemStack(Material.ORANGE_STAINED_GLASS_PANE); - private static final ItemStack filler2 = new ItemStack(Material.BLUE_STAINED_GLASS_PANE); - private static final ItemStack filler3 = new ItemStack(Material.GREEN_STAINED_GLASS_PANE); - - private GuiManager() { - } - - public static void fill(Inventory inventory) { - int size = inventory.getSize(); - for (int i = 0; i < size; i++) { - inventory.setItem(i, i % 2 == 0 ? filler1 : filler2); - } - } - - public static void fillAlt(Inventory inventory) { - int size = inventory.getSize(); - for (int i = 0; i < size; i++) { - inventory.setItem(i, i % 2 == 0 ? filler3 : filler2); - } - } - - - public static class Menu implements InventoryHolder { - - public static final Menu instance = new Menu(); - - - private Menu() { - } - - public static void open(Player player) { - - Inventory inventory = Bukkit.createInventory(instance, 27, Localization.getComponent(player, "menu-item")); - inventory.setItem(13, Localization.translateItem(player, ItemManager.getGamesPageItem())); - - player.openInventory(inventory); - } - - - @Override - public @NotNull Inventory getInventory() { - return Bukkit.createInventory(instance, 27, Component.text("raw")); - } - - public static class Games implements InventoryHolder { - - private static final ItemStack defaultGameItem = new ItemStack(Material.CLOCK); - - private Games() { - } - - public static void open(Player player) { - - Inventory gamesMenu = Bukkit.createInventory(new Games(), 45, Localization.getComponent(player, "games-page-item")); - for (String game : GamesManager.getAvailableGames()) { - BlockAndSeekGame blockAndSeekGame = GamesManager.get(game); - ItemStack gameItem = defaultGameItem.clone(); - ItemMeta meta = gameItem.getItemMeta(); - meta.getPersistentDataContainer().set(Keys.GAME, PersistentDataType.STRING, game); - meta.displayName(Component.text("game-name")); - meta.lore(List.of(Localization.getComponent( - player, - "game-player-count", - "{players}", String.valueOf(blockAndSeekGame.playerCount()), - "{max-players}", String.valueOf(blockAndSeekGame.maxPlayers()) - ))); - gameItem.setItemMeta(meta); - gamesMenu.addItem(Localization.translateItem(player, gameItem, "{name}", game)); - } - - - if (player.hasPermission("blockandseek.manage")) { - gamesMenu.setItem(44, ItemManager.getCreateGameButton()); - } - - player.openInventory(gamesMenu); - } - - @Override - public @NotNull Inventory getInventory() { - return Bukkit.createInventory(null, 9); - } - - - public static abstract class Maps implements InventoryHolder { - - } - - } - - - } - - -} diff --git a/src/main/java/hdvtdev/blockAndSeek/managers/MapsManager.java b/src/main/java/hdvtdev/blockAndSeek/managers/MapsManager.java deleted file mode 100644 index 3c42cb5..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/managers/MapsManager.java +++ /dev/null @@ -1,53 +0,0 @@ -package hdvtdev.blockAndSeek.managers; - -import hdvtdev.blockAndSeek.BlockAndSeek; -import hdvtdev.blockAndSeek.BlockAndSeekMap; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.io.File; -import java.io.IOException; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -public class MapsManager { - - private static volatile Map allMaps = new ConcurrentHashMap<>(); - private static final Map readyMaps = new ConcurrentHashMap<>(); - - private static final File mapsFile = new File(BlockAndSeek.getPluginDataFolder(), "maps.yml"); - - public static Set getAllMaps() { - return allMaps.keySet(); - } - - public static BlockAndSeekMap getMap(String name) { - return allMaps.get(name); - } - - public static void saveMap(String name, BlockAndSeekMap map) throws IOException { - var conf = YamlConfiguration.loadConfiguration(mapsFile); - if (conf.contains(name)) conf.set(name, null); - conf.set(name, map); - conf.save(mapsFile); - } - - public static void loadMaps() { - Map confMap = new ConcurrentHashMap<>(); - YamlConfiguration configuration = YamlConfiguration.loadConfiguration(mapsFile); - - for (String map : configuration.getKeys(false)) { - - - BlockAndSeekMap blockAndSeekMap = configuration.getSerializable(map, BlockAndSeekMap.class, BlockAndSeekMap.defaultMap()); - if (blockAndSeekMap.isReady()) readyMaps.put(map, blockAndSeekMap); - confMap.put(map, blockAndSeekMap); - } - - allMaps = confMap; - } - - -} - - diff --git a/src/main/java/hdvtdev/blockAndSeek/managers/PropManager.java b/src/main/java/hdvtdev/blockAndSeek/managers/PropManager.java deleted file mode 100644 index 165a781..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/managers/PropManager.java +++ /dev/null @@ -1,159 +0,0 @@ -package hdvtdev.blockAndSeek.managers; - -import hdvtdev.blockAndSeek.Keys; -import me.libraryaddict.disguise.DisguiseAPI; -import me.libraryaddict.disguise.disguisetypes.Disguise; -import me.libraryaddict.disguise.disguisetypes.DisguiseType; -import me.libraryaddict.disguise.disguisetypes.MiscDisguise; -import org.bukkit.Location; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Directional; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Player; -import org.bukkit.persistence.PersistentDataType; -import org.bukkit.util.Vector; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class PropManager { - - private static final Map frozenPlayers = new ConcurrentHashMap<>(); - private static final Map playerDisguise = new ConcurrentHashMap<>(); - private static final Map disguisePlayer = new ConcurrentHashMap<>(); - - private static final Disguise hideDisguise = new MiscDisguise(DisguiseType.LLAMA_SPIT); - private static final Vector zeroVelocity = new Vector(0, 0, 0); - - public static boolean isPlayerDisguised(Player player) { - return frozenPlayers.containsKey(player); - } - - public static void addPlayerDisguise(Player player, BlockData blockData) { - disguisePlayer.put(blockData, player); - playerDisguise.put(player, blockData); - } - - public static void removePlayerDisguise(Player player) { - disguisePlayer.remove(playerDisguise.remove(player)); - } - - public static void changePropDirection(Player player) { - - if (frozenPlayers.containsKey(player)) { - Block block = player.getLocation().getBlock(); - BlockData blockData = block.getBlockData(); - if (blockData instanceof Directional directional) { - - BlockFace face = switch (directional.getFacing()) { - case NORTH -> BlockFace.EAST; - case EAST -> BlockFace.SOUTH; - case SOUTH -> BlockFace.WEST; - case WEST -> directional.getFaces().contains(BlockFace.UP) ? BlockFace.UP : BlockFace.NORTH; - case UP -> BlockFace.DOWN; - case DOWN -> BlockFace.NORTH; - default -> null; - }; - if (face != null && directional.getFaces().contains(face)) { - directional.setFacing(face); - block.setBlockData(blockData); - } - } - } - } - - public static void unfreezeIfFrozen(Player player) { - Location location = player.getLocation(); - FreezeData data = frozenPlayers.remove(player); - if (data != null) { - unfreeze(player, location, data); - } - } - - public static boolean unfreeze(BlockData blockData) { - Player player = disguisePlayer.get(blockData); - if (player != null) { - freeze(player); - return true; - } else return false; - } - - private static void unfreeze(Player player, Location location, FreezeData data) { - - Location blockLocation = location.getBlock().getLocation(); - location.getWorld().setBlockData(blockLocation, data.blockData); - player.getPersistentDataContainer().remove(Keys.FROZEN_PLAYER); - - player.setFreezeTicks(0); - data.armorStand.remove(); - player.setInvulnerable(false); - - Keys.NO_COLLIDE_TEAM.removeEntry(player.getName()); - - if (data.disguise != null) DisguiseAPI.disguiseToAll(player, data.disguise); - - } - - public static boolean freeze(Player player) { - Location location = player.getLocation(); - FreezeData data = frozenPlayers.remove(player); - if (data != null) { - unfreeze(player, location, data); - } else { - - Block block = location.getBlock(); - BlockData blockData = block.getBlockData(); - Location blockLocation = block.getLocation(); - Location centerLocation = blockLocation.toCenterLocation(); - Location upperBlockLocation = centerLocation.clone(); - upperBlockLocation.setY(upperBlockLocation.getY() + 0.25); - - if (!upperBlockLocation.getBlock().isSolid() && !blockLocation.getBlock().isSolid()) { - - - location.getWorld().setBlockData(blockLocation, playerDisguise.get(player)); - - centerLocation.setY(centerLocation.getY() - 0.85); - - player.setVelocity(zeroVelocity); - player.setInvulnerable(true); - player.getPersistentDataContainer().set(Keys.FROZEN_PLAYER, PersistentDataType.BOOLEAN, true); - Keys.NO_COLLIDE_TEAM.addEntry(player.getName()); - - - ArmorStand armorStand = location.getWorld().spawn(centerLocation, ArmorStand.class, stand -> { - stand.setVisible(false); - stand.setVisible(false); - stand.setCollidable(false); - stand.setGravity(true); - stand.setSmall(true); - stand.setCanMove(false); - stand.addPassenger(player); - stand.getPersistentDataContainer().set(Keys.FROZEN_PLAYER, PersistentDataType.BOOLEAN, true); - stand.setInvulnerable(true); - }); - - - Disguise disguise = DisguiseAPI.getDisguise(player); - - DisguiseAPI.disguiseToAll(player, hideDisguise); - - player.setFreezeTicks(40); - - - frozenPlayers.put(player, new FreezeData(armorStand, blockData, disguise)); - } else return false; - - - } - return true; - } - - - private record FreezeData(ArmorStand armorStand, BlockData blockData, Disguise disguise) { - } - - -} diff --git a/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java b/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java new file mode 100644 index 0000000..12d32df --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java @@ -0,0 +1,182 @@ +package hdvtdev.blockAndSeek; + + +import hdvtdev.blockAndSeek.eventListeners.RequiredEventListener; +import hdvtdev.blockAndSeek.eventListeners.EventListener; +import hdvtdev.blockAndSeek.eventListeners.ForceControlEventListener; + +import me.libraryaddict.disguise.LibsDisguises; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + +import org.incendo.cloud.Command; +import org.incendo.cloud.bukkit.CloudBukkitCapabilities; +import org.incendo.cloud.bukkit.parser.PlayerParser; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.paper.LegacyPaperCommandManager; +import org.incendo.cloud.parser.standard.IntegerParser; +import org.incendo.cloud.parser.standard.StringParser; + +import java.io.File; +import java.util.Objects; +import java.util.logging.Logger; + +public class BlockAndSeek extends JavaPlugin { + + private static JavaPlugin javaPlugin; + private static LegacyPaperCommandManager commandManager; + private static final String perm = "blockandseek.manage"; + + public static Plugin getInstance() { + return javaPlugin; + } + + public static File getPluginDataFolder() { + return javaPlugin.getDataFolder(); + } + + public static File getServerDataFolder() { + return javaPlugin.getServer().getPluginsFolder().getParentFile(); + } + + public static void saveResource(String file) { + javaPlugin.saveResource(file, false); + } + + public static Logger getPluginLogger() { + return javaPlugin.getLogger(); + } + + + @Override + public void onEnable() { + javaPlugin = this; + + LibsDisguises libsDisguises = (LibsDisguises) Bukkit.getPluginManager().getPlugin("LibsDisguises"); + if (libsDisguises == null) { + getLogger().severe("LibsDisguises not found! It's required for the plugin to work!"); + super.onDisable(); + } + + this.init(); + + if (!Config.loadConfig()) getPluginLogger().warning("Failed to load BlockAndSeek config.toml! Using default config..."); + + + PluginCommand command = Objects.requireNonNull(getCommand("blockandseek")); + + + PluginManager manager = getServer().getPluginManager(); + manager.registerEvents(Config.forceControl() ? new ForceControlEventListener() : new EventListener(), this); + manager.registerEvents(new RequiredEventListener(), this); + + + } + + + private void init() { + try { + + File dataFolder = getDataFolder(); + + if (!dataFolder.exists()) { + dataFolder.mkdirs(); + } + + File mapsFolder = new File(dataFolder, "maps"); + if (!mapsFolder.exists()) { + mapsFolder.mkdirs(); + } + + File langsFolder = new File(dataFolder, "languages"); + if (!langsFolder.exists()) { + langsFolder.mkdirs(); + } + + File defaultLangFile = new File(langsFolder, "en_US.yml"); + + if (!defaultLangFile.exists()) { + saveResource("languages/en_US.yml", false); + } + + commandManager = LegacyPaperCommandManager.createNative( + this, + ExecutionCoordinator.simpleCoordinator() + ); + + + if (commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { + try { + commandManager.registerBrigadier(); + } catch (IllegalStateException ignored) { + + } + } + + this.registerCommands(); + + } catch (Exception e) { + getLogger().severe("Cloud err: " + e.getMessage()); + e.printStackTrace(); + } + + + + } + + private void registerCommands() { + + Command.Builder root = commandManager.commandBuilder("blockandseek"); + + + commandManager.command(root + .literal("reload") + .permission(perm) + .handler(context -> { + + }) + ); + + + + commandManager.command(root + .literal("inttest") + .required("text", IntegerParser.integerParser(0, 64)) + + .handler(context -> { + String text = context.get("text"); + context.sender().sendMessage(text); + }) + ); + + + commandManager.command(root + .literal("map") + .permission(perm) + .required("map", StringParser.stringParser()) + .required("action", StringParser.stringParser()) + .handler(context -> { + Player target = context.get("target"); + int amount = context.getOrDefault("amount", 1); + + + }) + ); + + + + + + + + + + } + +} diff --git a/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java b/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java new file mode 100644 index 0000000..8b42902 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java @@ -0,0 +1,113 @@ +package hdvtdev.blockAndSeek; + +import org.bukkit.*; +import org.bukkit.block.data.AnaloguePowerable; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Openable; +import org.bukkit.block.data.Powerable; +import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +@ApiStatus.Experimental +public class BlocksGenerator { + + private static boolean isSupported(Material type, BlockData data) { + + if (type.isAir() || type.hasGravity() || !type.isSolid()) { + return false; + } + + if (data instanceof Powerable + || data instanceof Openable + || data instanceof AnaloguePowerable) { + return false; + } + + return switch (type) { + case CACTUS, FARMLAND, + TNT, DISPENSER, DROPPER, HOPPER, + PISTON, STICKY_PISTON, OBSERVER, + COMMAND_BLOCK, REPEATING_COMMAND_BLOCK, + CHAIN_COMMAND_BLOCK, + SCULK_SENSOR, SCULK_SHRIEKER, + DAYLIGHT_DETECTOR, JUKEBOX, + TURTLE_EGG, DRAGON_EGG, + BAMBOO, BAMBOO_SAPLING, + CAKE, LECTERN, COMPOSTER, + CAMPFIRE, SOUL_CAMPFIRE, + BEEHIVE, BEE_NEST + -> false; + default -> true; + }; + } + + public static void getSortedBlockStats(Location center, int chunkRadius, Consumer>> callback) { + World world = center.getWorld(); + if (world == null) return; + + + List snapshots = new ArrayList<>(); + + int centerX = center.getBlockX() >> 4; + int centerZ = center.getBlockZ() >> 4; + + + for (int x = centerX - chunkRadius; x <= centerX + chunkRadius; x++) { + for (int z = centerZ - chunkRadius; z <= centerZ + chunkRadius; z++) { + if (world.isChunkLoaded(x, z)) { + Chunk chunk = world.getChunkAt(x, z); + snapshots.add(chunk.getChunkSnapshot(false, false, false)); + } + } + } + + + new BukkitRunnable() { + @Override + public void run() { + Map counts = new HashMap<>(); + + int minH = world.getMinHeight(); + int maxH = world.getMaxHeight(); + + for (ChunkSnapshot snap : snapshots) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = minH; y < maxH; y++) { + + + BlockData data = snap.getBlockData(x, y, z); + Material type = data.getMaterial(); + + if (isSupported(type, data)) { + counts.put(type, counts.getOrDefault(type, 0L) + 1); + } + } + } + } + } + + + List> sortedList = new ArrayList<>(counts.entrySet()); + sortedList.sort(Map.Entry.comparingByValue()); + + + + new BukkitRunnable() { + @Override + public void run() { + callback.accept(sortedList); + } + }.runTask(BlockAndSeek.getInstance()); + } + }.runTaskAsynchronously(BlockAndSeek.getInstance()); + } + + +} diff --git a/src/main/java/hdvtdev/blockandseek/CommandBuilder.java b/src/main/java/hdvtdev/blockandseek/CommandBuilder.java new file mode 100644 index 0000000..faddced --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/CommandBuilder.java @@ -0,0 +1,58 @@ +package hdvtdev.blockAndSeek; + +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class CommandBuilder { + + private final List forest = new ArrayList<>(); + + public Node addNode(String name) { + Node node = new Node(name); + forest.add(node); + return node; + } + + @Nullable + public String tryGet(String fullPath) { + return null; + } + + + public static void printTree(Node node, String indent) { + System.out.println(indent + "- " + node.getName()); + for (Node child : node.getChildren()) { + printTree(child, indent + " "); + } + } + + + public static class Node { + private final String name; + private final List children; + + public Node(String name) { + this.name = name; + this.children = new ArrayList<>(); + } + + public void addChild(Node child) { + this.children.add(child); + } + + public List getChildren() { + return children; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } + } +} \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockandseek/CommandListener.java b/src/main/java/hdvtdev/blockandseek/CommandListener.java new file mode 100644 index 0000000..b705253 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/CommandListener.java @@ -0,0 +1,21 @@ +package hdvtdev.blockAndSeek; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class CommandListener implements TabExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + return false; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + return List.of(); + } +} diff --git a/src/main/java/hdvtdev/blockandseek/Config.java b/src/main/java/hdvtdev/blockandseek/Config.java new file mode 100644 index 0000000..c2ad2f6 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/Config.java @@ -0,0 +1,80 @@ +package hdvtdev.blockAndSeek; + +import eu.okaeri.configs.ConfigManager; +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.annotation.Comment; +import eu.okaeri.configs.annotation.Exclude; +import eu.okaeri.configs.serdes.commons.SerdesCommons; +import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer; +import eu.okaeri.configs.yaml.bukkit.serdes.SerdesBukkit; + + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.WorldCreator; + +import java.io.File; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +public class Config extends OkaeriConfig { + + @Exclude + private static final AtomicReference config = new AtomicReference<>(new Config()); + + @Comment("Server options.") + private Server server = new Server(false); + @Comment("Spawn location. Useless if the Server.forceControl is false.") + private Location spawn = Objects.requireNonNull(Bukkit.createWorld(new WorldCreator("world"))).getSpawnLocation(); + @Comment("Show hidden BlockAndSeek commands.") + private boolean enableDebugCommands = false; + + + public static boolean debugEnabled() { + return config.get().enableDebugCommands; + } + + public static boolean forceControl() { + return config.get().server.forceControl; + } + + public static Location spawn() { + return config.get().spawn; + } + + + public static boolean loadConfig() { + try { + Config conf = ConfigManager.create(Config.class, (it) -> { + it.withConfigurer( + new YamlBukkitConfigurer(), + new SerdesBukkit(), + new SerdesCommons() + ); + it.withBindFile(new File(BlockAndSeek.getPluginDataFolder(), "config.yml")); + it.withLogger(BlockAndSeek.getPluginLogger()); + it.saveDefaults(); + }); + + config.setRelease(conf); + } catch (Exception e) { + BlockAndSeek.getPluginLogger().severe("Failed to load config.yml: " + e.getMessage()); + return false; + } + return true; + } + + private static class Server { + + private boolean forceControl = false; + + public Server(boolean forceControl) { + this.forceControl = forceControl; + } + + public boolean isForceControl() { + return forceControl; + } + } + +} diff --git a/src/main/java/hdvtdev/blockandseek/GuiHolder.java b/src/main/java/hdvtdev/blockandseek/GuiHolder.java new file mode 100644 index 0000000..0ed8a59 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/GuiHolder.java @@ -0,0 +1,12 @@ +package hdvtdev.blockAndSeek; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.InventoryHolder; + +public interface GuiHolder extends InventoryHolder { + void onClick(InventoryClickEvent event); + default void showInventory(Player player) { + player.openInventory(getInventory()); + } +} diff --git a/src/main/java/hdvtdev/blockAndSeek/Keys.java b/src/main/java/hdvtdev/blockandseek/Keys.java similarity index 93% rename from src/main/java/hdvtdev/blockAndSeek/Keys.java rename to src/main/java/hdvtdev/blockandseek/Keys.java index 2803800..32748a7 100644 --- a/src/main/java/hdvtdev/blockAndSeek/Keys.java +++ b/src/main/java/hdvtdev/blockandseek/Keys.java @@ -20,6 +20,10 @@ public class Keys { public static final NamespacedKey HIDER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekHider"); public static final NamespacedKey SEEKER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekSeeker"); + public static final NamespacedKey LANG_KEY = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekLangKey"); + + + public static final Team NO_COLLIDE_TEAM; static { diff --git a/src/main/java/hdvtdev/blockandseek/Localization.java b/src/main/java/hdvtdev/blockandseek/Localization.java new file mode 100644 index 0000000..b4a9b84 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/Localization.java @@ -0,0 +1,83 @@ +package hdvtdev.blockAndSeek; + + + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +public final class Localization { + + private Localization() {} + + private static final String defaultLanguage = "en_US"; + private static final MiniMessage mm = MiniMessage.miniMessage(); + + private static final AtomicReference>> translations = new AtomicReference<>(); + + public static Component get(Player player, String key, String... placeholders) { + return get(player.locale().toString(), key, placeholders); + } + + public static Component get(String lang, String key, String... placeholders) { + String raw = translations.get().get(lang).getOrDefault(key, "?" + key + "?"); + if (placeholders.length % 2 == 0) { + for (int i = 0; i < placeholders.length; i++) { + raw = raw.replace(placeholders[i], placeholders[++i]); + } + } else BlockAndSeek.getPluginLogger().warning("Wrong amount of placeholders for key: " + key); + + return mm.deserialize(raw); + } + + public static ItemStack translateItem(Player player, ItemStack itemStack, String key) { + ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.displayName(get(player, key)); + itemStack.setItemMeta(itemMeta); + return itemStack; + } + + public static boolean loadTranslations() { + /* + Path path = BlockAndSeek.getPluginDataFolder().toPath().resolve("translations"); + if (Files.notExists(path)) { + try { + Files.createDirectories(path); + } catch (IOException e) { + BlockAndSeek.getPluginLogger().severe("Failed to create \"translations\" dir: " + e); + return false; + } + } + + File[] files = path.toFile().listFiles(); + if (files != null) { + for (File file : files) { + String lang = file.getName().split(".toml")[0]; + Map translation = new HashMap<>(); + for (Map.Entry entry : new Toml().read(file).entrySet()) { + translation.put(entry.getKey(), entry.getValue().toString()); + } + translations.get().put(lang, translation); + } + } else { + BlockAndSeek.getPluginLogger().severe("Failed to load translations! " + path + " returned null."); + } + + + */ + + return true; + } + +} diff --git a/src/main/java/hdvtdev/blockAndSeek/Utils.java b/src/main/java/hdvtdev/blockandseek/Utils.java similarity index 73% rename from src/main/java/hdvtdev/blockAndSeek/Utils.java rename to src/main/java/hdvtdev/blockandseek/Utils.java index 1e84563..88996a1 100644 --- a/src/main/java/hdvtdev/blockAndSeek/Utils.java +++ b/src/main/java/hdvtdev/blockandseek/Utils.java @@ -1,12 +1,20 @@ package hdvtdev.blockAndSeek; -import hdvtdev.blockAndSeek.managers.PropManager; + import me.libraryaddict.disguise.DisguiseAPI; +import me.libraryaddict.disguise.disguisetypes.Disguise; import me.libraryaddict.disguise.disguisetypes.DisguiseType; import me.libraryaddict.disguise.disguisetypes.MiscDisguise; + +import me.libraryaddict.disguise.disguisetypes.watchers.FallingBlockWatcher; +import org.bukkit.Bukkit; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.Nullable; + +import java.io.File; public final class Utils { @@ -28,15 +36,17 @@ public final class Utils { return player.getPersistentDataContainer().has(Keys.GAME); } - public static void firstDisguise(Player player, ItemStack prop) { - DisguiseAPI.disguiseToAll(player, new MiscDisguise(DisguiseType.FALLING_BLOCK, prop)); - PropManager.addPlayerDisguise(player, prop.getType().createBlockData()); - } - public static boolean hasPermsToDamage(Player p1, Player p2) { PersistentDataContainer c1 = p1.getPersistentDataContainer(); PersistentDataContainer c2 = p2.getPersistentDataContainer(); return (c1.has(Keys.SEEKER) || c1.has(Keys.HIDER)) && (c2.has(Keys.SEEKER) || c2.has(Keys.HIDER)); } + public static void clearPlayer(Player p) { + PersistentDataContainer container = p.getPersistentDataContainer(); + container.remove(Keys.SEEKER); + container.remove(Keys.HIDER); + + } + } diff --git a/src/main/java/hdvtdev/blockAndSeek/eventListeners/EventListener.java b/src/main/java/hdvtdev/blockandseek/eventListeners/EventListener.java similarity index 100% rename from src/main/java/hdvtdev/blockAndSeek/eventListeners/EventListener.java rename to src/main/java/hdvtdev/blockandseek/eventListeners/EventListener.java diff --git a/src/main/java/hdvtdev/blockAndSeek/eventListeners/ForceControlEventListener.java b/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java similarity index 87% rename from src/main/java/hdvtdev/blockAndSeek/eventListeners/ForceControlEventListener.java rename to src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java index bce174d..ef550df 100644 --- a/src/main/java/hdvtdev/blockAndSeek/eventListeners/ForceControlEventListener.java +++ b/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java @@ -8,6 +8,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerJoinEvent; @@ -58,6 +59,7 @@ public class ForceControlEventListener implements Listener { @EventHandler public void onPlayerDamage(EntityDamageByEntityEvent event) { + if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) { if (!Utils.hasPermsToDamage(damager, victim)) { event.setCancelled(true); @@ -65,5 +67,14 @@ public class ForceControlEventListener implements Listener { } } + @EventHandler + public void onFallDamage(EntityDamageEvent e) { + if (e.getEntity() instanceof Player) { + if (e.getCause() == EntityDamageEvent.DamageCause.FALL) { + e.setCancelled(true); + } + } + } + } diff --git a/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java b/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java new file mode 100644 index 0000000..7c36a9b --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java @@ -0,0 +1,98 @@ +package hdvtdev.blockAndSeek.eventListeners; + +import hdvtdev.blockAndSeek.Keys; +import hdvtdev.blockAndSeek.Utils; +import hdvtdev.blockAndSeek.GuiHolder; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDismountEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.EquipmentSlot; + + +import static hdvtdev.blockAndSeek.Utils.isInOneTeam; + +public class RequiredEventListener implements Listener { + + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + + } + + @EventHandler + public void onBlockDamage(BlockDamageEvent event) { + + } + + @EventHandler + public void onRightClick(PlayerInteractEvent event) { + if (event.getHand() != EquipmentSlot.HAND) return; + + } + + @EventHandler + public void onEntityDismount(EntityDismountEvent event) { + + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + + } + + @EventHandler + public void onPlayerDeath(PlayerDeathEvent event) { + + } + + @EventHandler + public void onInventoryClose(InventoryCloseEvent event) { + + + + + } + + @EventHandler + public void onInventoryClick(InventoryClickEvent e) { + if (e.getInventory().getHolder() instanceof GuiHolder gui) { + e.setCancelled(true); + gui.onClick(e); + } + } + + @EventHandler + public void onRegainHealth(EntityRegainHealthEvent event) { + + } + + @EventHandler + public void onPlayerDamage(EntityDamageByEntityEvent event) { + if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) { + if (isInOneTeam(damager, victim)) { + event.setCancelled(true); + } else if (victim.getPersistentDataContainer().has(Keys.SEEKER)) { + event.setDamage(0); + } else if (damager.getPersistentDataContainer().has(Keys.SEEKER)) { + double maxHealth = 20.0; + double currentHealth = damager.getHealth(); + if (currentHealth < maxHealth) { + double newHealth = Math.min(currentHealth + event.getDamage(), maxHealth); + damager.setHealth(newHealth); + Utils.setLevelWithBar(damager, (int) Math.round(damager.getHealth() * 5)); + } + } + } + } + +} diff --git a/src/main/java/hdvtdev/blockAndSeek/managers/GamesManager.java b/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java similarity index 68% rename from src/main/java/hdvtdev/blockAndSeek/managers/GamesManager.java rename to src/main/java/hdvtdev/blockandseek/managers/GamesManager.java index 970f6fd..fa700e8 100644 --- a/src/main/java/hdvtdev/blockAndSeek/managers/GamesManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java @@ -1,8 +1,6 @@ package hdvtdev.blockAndSeek.managers; -import hdvtdev.blockAndSeek.BlockAndSeek; -import hdvtdev.blockAndSeek.BlockAndSeekGame; -import hdvtdev.blockAndSeek.BlockAndSeekMap; +import hdvtdev.blockAndSeek.objects.BlockAndSeekGame; import org.bukkit.Bukkit; import org.bukkit.WorldCreator; import org.bukkit.entity.Player; @@ -32,16 +30,7 @@ public class GamesManager { public static @Nullable String createGame(String name) { if (games.containsKey(name)) return name; //TODO use copy or create copy - if (Bukkit.getWorld(name) == null) { - if (new File(BlockAndSeek.getServerDataFolder(), name).exists()) { - Bukkit.createWorld(new WorldCreator(name)); - } else return null; - } - BlockAndSeekMap map = MapsManager.getMap(name); - BlockAndSeekGame game = new BlockAndSeekGame(name, map); - - games.put(name, game); return null; } diff --git a/src/main/java/hdvtdev/blockAndSeek/managers/ItemManager.java b/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java similarity index 87% rename from src/main/java/hdvtdev/blockAndSeek/managers/ItemManager.java rename to src/main/java/hdvtdev/blockandseek/managers/ItemManager.java index 375433c..734177f 100644 --- a/src/main/java/hdvtdev/blockAndSeek/managers/ItemManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java @@ -34,41 +34,34 @@ public class ItemManager { static { ItemMeta freezeMeta = freezeItem.getItemMeta(); - freezeMeta.displayName(Component.text("freeze-item")); freezeMeta.getPersistentDataContainer().set(Keys.FREEZE_ITEM, PersistentDataType.BOOLEAN, true); freezeItem.setItemMeta(freezeMeta); ItemMeta faceChangingMeta = faceChangingItem.getItemMeta(); - faceChangingMeta.displayName(Component.text("face-changing-item")); faceChangingMeta.getPersistentDataContainer().set(Keys.FACE_CHANGING_ITEM, PersistentDataType.BOOLEAN, true); faceChangingItem.setItemMeta(faceChangingMeta); ItemMeta swordMeta = seekerSword.getItemMeta(); - swordMeta.displayName(Component.text("seeker-sword")); swordMeta.addEnchant(Enchantment.DAMAGE_ALL, 2, false); swordMeta.setUnbreakable(true); swordMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES); seekerSword.setItemMeta(swordMeta); ItemMeta menuMeta = menuItem.getItemMeta(); - menuMeta.displayName(Component.text("menu-item")); menuMeta.getPersistentDataContainer().set(Keys.MENU_ITEM, PersistentDataType.BOOLEAN, true); menuMeta.addEnchant(Enchantment.ARROW_INFINITE, 1, true); menuMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); menuItem.setItemMeta(menuMeta); ItemMeta gamesMeta = games.getItemMeta(); - gamesMeta.displayName(Component.text("games-page-item")); gamesMeta.getPersistentDataContainer().set(Keys.GAME_PAGE, PersistentDataType.BOOLEAN, true); games.setItemMeta(gamesMeta); ItemMeta leaveMeta = leaveItem.getItemMeta(); - leaveMeta.displayName(Component.text("leave-item")); leaveMeta.getPersistentDataContainer().set(Keys.LEAVE_ITEM, PersistentDataType.BOOLEAN, true); leaveItem.setItemMeta(leaveMeta); ItemMeta createGameButtonMeta = createGameButton.getItemMeta(); - createGameButtonMeta.displayName(Component.text("create-game-item")); createGameButton.setItemMeta(createGameButtonMeta); @@ -82,12 +75,12 @@ public class ItemManager { public static void setSeekerSet(Player seeker) { PlayerInventory inventory = seeker.getInventory(); inventory.clear(); - inventory.addItem(Localization.translateItem(seeker, seekerSword)); + inventory.addItem(Localization.translateItem(seeker, seekerSword, "seeker_sword")); ItemStack[] armor = new ItemStack[]{ - Localization.translateItem(seeker, seekerBoots), - Localization.translateItem(seeker, seekerLeggings), - Localization.translateItem(seeker, seekerChestplate), - Localization.translateItem(seeker, seekerHelmet) + Localization.translateItem(seeker, seekerBoots, "seeker_boots"), + Localization.translateItem(seeker, seekerLeggings, "seeker_leggings"), + Localization.translateItem(seeker, seekerChestplate, "seeker_chestplate"), + Localization.translateItem(seeker, seekerHelmet, "seeker_helmet") }; inventory.setArmorContents(armor); @@ -109,11 +102,11 @@ public class ItemManager { public static void defaultInventory(Player player) { PlayerInventory inventory = player.getInventory(); inventory.clear(); - inventory.addItem(Localization.translateItem(player, menuItem)); + inventory.addItem(Localization.translateItem(player, menuItem, "menu_item")); } - public static ItemStack getFaceChangingItem() { - return faceChangingItem; + public static void giveFaceChangingItem(Player player) { + player.getInventory().addItem(Localization.translateItem(player, faceChangingItem, "face_changing_item")); } public static ItemStack getLeaveItem() { diff --git a/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java b/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java new file mode 100644 index 0000000..fb3bc4f --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java @@ -0,0 +1,54 @@ +package hdvtdev.blockAndSeek.managers; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; + +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public final class MapsManager { + + private MapsManager() { + } + + public static SuggestionProvider worldSuggestions = (context, input) -> + CompletableFuture.supplyAsync(() -> { + List suggestions = new ArrayList<>(); + + File container = Bukkit.getWorldContainer(); + + File[] files = container.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory() && new File(file, "level.dat").exists()) { + suggestions.add(Suggestion.suggestion(file.getName())); + } + } + } + return suggestions; + }); + + public static SuggestionProvider mapSuggestions = (context, input) -> + CompletableFuture.supplyAsync(() -> { + List suggestions = new ArrayList<>(); + + File container = new File(Bukkit.getPluginsFolder(), "maps"); + + File[] files = container.listFiles(); + if (files != null) { + for (File file : files) { + String name = file.getName(); + if (file.isFile() && name.endsWith(".toml")) { + suggestions.add(Suggestion.suggestion(name.replace(".toml", ""))); //baddd + } + } + } + + return suggestions; + }); +} diff --git a/src/main/java/hdvtdev/blockandseek/managers/PropManager.java b/src/main/java/hdvtdev/blockandseek/managers/PropManager.java new file mode 100644 index 0000000..dd3ac35 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/managers/PropManager.java @@ -0,0 +1,76 @@ +package hdvtdev.blockAndSeek.managers; + +import hdvtdev.blockAndSeek.BlockAndSeek; +import me.libraryaddict.disguise.DisguiseAPI; +import me.libraryaddict.disguise.disguisetypes.Disguise; +import me.libraryaddict.disguise.disguisetypes.DisguiseType; +import me.libraryaddict.disguise.disguisetypes.MiscDisguise; +import me.libraryaddict.disguise.disguisetypes.watchers.FallingBlockWatcher; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public final class PropManager { + + private final Map players = new HashMap<>(); + + public PropState freezeOrUnfreeze(Player player) { + UUID uuid = player.getUniqueId(); + PropData propData = players.remove(uuid); + Location location = player.getLocation(); + + Block originalBlock = location.getBlock(); + + if (propData != null) { + + originalBlock.setBlockData(propData.blockData); + + } else { + + BlockData originalBlockData = originalBlock.getBlockData(); + BlockData disguiseBlockData = getPlayerDisguiseData(player); + + + players.put(uuid, new PropData(null, originalBlockData, null)); + + } + + + + return PropState.FAILED; + } + + @Nullable + private static BlockData getPlayerDisguiseData(Player player) { + Disguise disguise = DisguiseAPI.getDisguise(player); + if (disguise instanceof MiscDisguise miscDisguise && miscDisguise.getType() == DisguiseType.FALLING_BLOCK) { + FallingBlockWatcher watcher = (FallingBlockWatcher) miscDisguise.getWatcher(); + return watcher.getBlockData(); + } + return null; + } + + + public enum PropState { + FROZEN, + UNFROZEN, + FAILED + } + + private record PropData(ArmorStand armorStand, BlockData blockData, Disguise disguise) { + + } + + +} diff --git a/src/main/java/hdvtdev/blockandseek/managers/StateManager.java b/src/main/java/hdvtdev/blockandseek/managers/StateManager.java new file mode 100644 index 0000000..7334176 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/managers/StateManager.java @@ -0,0 +1,57 @@ +package hdvtdev.blockAndSeek.managers; + +import hdvtdev.blockAndSeek.objects.BlockAndSeekGame; + +import java.util.*; + +public class StateManager { + + private final Map playerToState = new HashMap<>(); + private final Map> stateToPlayers = new HashMap<>(); + + + public void setPlayerState(UUID uuid, BlockAndSeekGame.PlayerType newState) { + + BlockAndSeekGame.PlayerType oldState = playerToState.get(uuid); + if (oldState != null && oldState.equals(newState)) { + return; + } + + if (oldState != null) { + removeUuidFromStateSet(oldState, uuid); + } + + playerToState.put(uuid, newState); + + stateToPlayers.computeIfAbsent(newState, k -> new HashSet<>()).add(uuid); + } + + public int playerCount() { + return playerToState.size(); + } + + public BlockAndSeekGame.PlayerType getState(UUID uuid) { + return playerToState.get(uuid); + } + + public Set getPlayersInState(BlockAndSeekGame.PlayerType state) { + return Collections.unmodifiableSet(stateToPlayers.getOrDefault(state, Collections.emptySet())); + } + + public void removePlayer(UUID uuid) { + BlockAndSeekGame.PlayerType oldState = playerToState.remove(uuid); + if (oldState != null) { + removeUuidFromStateSet(oldState, uuid); + } + } + + private void removeUuidFromStateSet(BlockAndSeekGame.PlayerType state, UUID uuid) { + Set uuids = stateToPlayers.get(state); + if (uuids != null) { + uuids.remove(uuid); + if (uuids.isEmpty()) { + stateToPlayers.remove(state); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockAndSeek/managers/WorldManager.java b/src/main/java/hdvtdev/blockandseek/managers/WorldManager.java similarity index 99% rename from src/main/java/hdvtdev/blockAndSeek/managers/WorldManager.java rename to src/main/java/hdvtdev/blockandseek/managers/WorldManager.java index 5194145..4b72748 100644 --- a/src/main/java/hdvtdev/blockAndSeek/managers/WorldManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/WorldManager.java @@ -2,7 +2,9 @@ package hdvtdev.blockAndSeek.managers; import hdvtdev.blockAndSeek.BlockAndSeek; + import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; + import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.WorldCreator; diff --git a/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java b/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java new file mode 100644 index 0000000..a2d08a6 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java @@ -0,0 +1,38 @@ +package hdvtdev.blockAndSeek.menus; + +import hdvtdev.blockAndSeek.Localization; +import hdvtdev.blockAndSeek.GuiHolder; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.jetbrains.annotations.NotNull; + +public class GamesMenu implements GuiHolder { + + + private final Inventory inventory; + + public GamesMenu(Player player) { + Component title = Localization.get(player, "games_menu"); + this.inventory = Bukkit.createInventory(this, 54, title); + initInventory(); + } + + private void initInventory() { + + } + + @Override + public void onClick(InventoryClickEvent event) { + + } + + @Override + public @NotNull Inventory getInventory() { + return inventory; + } + + +} diff --git a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java new file mode 100644 index 0000000..7a76057 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java @@ -0,0 +1,43 @@ +package hdvtdev.blockAndSeek.objects; + +import hdvtdev.blockAndSeek.managers.StateManager; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import java.util.*; + +public class BlockAndSeekGame { + + private final BlockAndSeekMap map; + private final World world; + private final StateManager stateManager = new StateManager(); + + public BlockAndSeekGame(BlockAndSeekMap blockAndSeekMap) { + this.map = blockAndSeekMap; + this.world = Objects.requireNonNull(Bukkit.getWorld(blockAndSeekMap.world())); + } + + public boolean addPlayer(Player player) { + if (stateManager.playerCount() < map.maxPlayers()) { + stateManager.setPlayerState(player.getUniqueId(), PlayerType.NONE); + return true; + } + return false; + } + + public void removePlayer(Player player) { + stateManager.removePlayer(player.getUniqueId()); + } + + public enum PlayerType { + NONE, + PROP, + SEEKER, + SPECTATOR + } + + + + +} diff --git a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java new file mode 100644 index 0000000..e2b7fbd --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java @@ -0,0 +1,17 @@ +package hdvtdev.blockAndSeek.objects; + +import org.bukkit.Bukkit; +import org.bukkit.World; + +public record BlockAndSeekMap(String world, Cords spawn, Cords lobby, + int minPlayers, int maxPlayers, int duration, int seekerSpawnDelay, int delayBeforeEnd) { + + public static void prepareWorld(World world) { + if (Integer.parseInt(Bukkit.getMinecraftVersion().replaceAll("[^0-9]", "")) >= 1215) { + String cmd = "execute in " + world.getKey() + " run gamerule locatorBar true"; + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd); + } + } + + +} diff --git a/src/main/java/hdvtdev/blockandseek/objects/GamePhase.java b/src/main/java/hdvtdev/blockandseek/objects/GamePhase.java new file mode 100644 index 0000000..eeb1ead --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/objects/GamePhase.java @@ -0,0 +1,4 @@ +package hdvtdev.blockandseek.objects; + +public interface GamePhase { +} diff --git a/src/main/java/hdvtdev/blockandseek/objects/PropBlock.java b/src/main/java/hdvtdev/blockandseek/objects/PropBlock.java new file mode 100644 index 0000000..ac8cdd9 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/objects/PropBlock.java @@ -0,0 +1,9 @@ +package hdvtdev.blockAndSeek.objects; + +import org.bukkit.inventory.ItemStack; + +public record PropBlock(ItemStack block, int chance) { + public PropBlock(ItemStack block, Rarity rarity) { + this(block, rarity.toChance()); + } +} diff --git a/src/main/java/hdvtdev/blockandseek/objects/Rarity.java b/src/main/java/hdvtdev/blockandseek/objects/Rarity.java new file mode 100644 index 0000000..98655fd --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/objects/Rarity.java @@ -0,0 +1,23 @@ +package hdvtdev.blockAndSeek.objects; + +public enum Rarity { + + COMMON,// 38% + UNCOMMON,// 27% + RARE,// 19% + EPIC,// 10% + MYTHIC,// 4% + LEGENDARY; // 2% + + public int toChance() { + return switch (this.ordinal()) { + case 1 -> 27; + case 2 -> 19; + case 3 -> 10; + case 4 -> 4; + case 5 -> 2; + default -> 38; + }; + } + +} diff --git a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteCreator.java b/src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java similarity index 97% rename from src/main/java/hdvtdev/blockAndSeek/roulette/RouletteCreator.java rename to src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java index f8fa4d6..fc24209 100644 --- a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteCreator.java +++ b/src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java @@ -1,8 +1,5 @@ package hdvtdev.blockAndSeek.roulette; -import hdvtdev.blockAndSeek.BlockAndSeek; -import hdvtdev.blockAndSeek.BlockAndSeekMap; -import hdvtdev.blockAndSeek.Localization; import org.bukkit.Bukkit; import org.bukkit.Sound; import org.bukkit.entity.Player; @@ -18,7 +15,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Random; - +/* public final class RouletteCreator implements InventoryHolder { @@ -167,3 +164,6 @@ public final class RouletteCreator implements InventoryHolder { } + + + */ \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteGenerator.java b/src/main/java/hdvtdev/blockandseek/roulette/RouletteGenerator.java similarity index 94% rename from src/main/java/hdvtdev/blockAndSeek/roulette/RouletteGenerator.java rename to src/main/java/hdvtdev/blockandseek/roulette/RouletteGenerator.java index 75e0b74..6504d6e 100644 --- a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteGenerator.java +++ b/src/main/java/hdvtdev/blockandseek/roulette/RouletteGenerator.java @@ -1,12 +1,11 @@ package hdvtdev.blockAndSeek.roulette; import com.lewdev.probabilitylib.ProbabilityCollection; -import hdvtdev.blockAndSeek.BlockAndSeekMap; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.List; - +/* public class RouletteGenerator { private final ProbabilityCollection probabilityCollection = new ProbabilityCollection<>(); @@ -25,3 +24,5 @@ public class RouletteGenerator { } + + */ diff --git a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteList.java b/src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java similarity index 85% rename from src/main/java/hdvtdev/blockAndSeek/roulette/RouletteList.java rename to src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java index d1e3524..7aee9e8 100644 --- a/src/main/java/hdvtdev/blockAndSeek/roulette/RouletteList.java +++ b/src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java @@ -1,5 +1,7 @@ package hdvtdev.blockAndSeek.roulette; +import org.jetbrains.annotations.NotNull; + import java.util.List; import java.util.Objects; @@ -7,7 +9,7 @@ public class RouletteList { private final List items; private int currentIndex; - public RouletteList(List items) { + public RouletteList(@NotNull List items) { this.items = Objects.requireNonNull(items); this.currentIndex = 0; if (items.isEmpty()) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml deleted file mode 100644 index 0f88007..0000000 --- a/src/main/resources/config.yml +++ /dev/null @@ -1,19 +0,0 @@ -config: - ==: hdvtdev.blockAndSeek.Config # <-- DO NOT CHANGE THIS FIELD!!! - # A place to teleport players to after the game is over - # Example: - # default-spawn: - # - world: "your world" - # location: - # - 0 #x - # - 60 #y - # - 0 #z - default-spawn: { } - - # If force-control set to true plugin will control typical aspects such as - # disabling breaking blocks, disabling damage in lobbies, etc. - # WARN: DO NOT USE THIS WITH OTHER PLUGINS THAT PROVIDE SIMILAR FUNCTIONALITY - force-control: false - - # planned - # auto-update: false \ No newline at end of file diff --git a/src/main/resources/languages/en_US.yml b/src/main/resources/languages/en_US.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/localization.yml b/src/main/resources/localization.yml deleted file mode 100644 index c175e11..0000000 --- a/src/main/resources/localization.yml +++ /dev/null @@ -1,40 +0,0 @@ -en-US: - #Maps - maps-available: "Available maps: " - maps-available-element: "- {color-status}{map}" - map-lobby-sidebar: "{map}" - - not-enough-permissions: "You do not have permission to run this command." - not-enough-arguments: "Too few arguments to run command {command}. Arguments example: {help}" - - successful-reload: "Successfully reloaded {config}." - failed-reload: "Failed to reload {config}. Error: {e}" - - seekers-won: "Seekers won!" - hiders-won: "Hiders won!" - hiders-solo-win: "{hider} won this game!" - hider-was-found: "{hider} was found by {seeker}" - hider-died: "{hider} somehow died xd" - - game-time-left: "Time left: {time}s" - game-players-count: "{players} of {max-players}" - player-join: "{player} joined. {players}" - player-leave: "{player} leaved. {players}" - game-title: "{title}" - - wait-time-left: "Game starts in: {time}s" - - #items - freeze-item: "Freeze" - seeker-armor: "Seeker armor" - - menu-item: "BlockAndSeek Menu" - games-page-item: "Games" - - create-game-item: "Create new game" - game-name: "{name}" - game-player-count: "{players} of {max-players} players" - leave-item: "Leave game" - - roulette-title: "Props Roulette" - diff --git a/src/main/resources/maps.yml b/src/main/resources/maps.yml deleted file mode 100644 index 10855ad..0000000 --- a/src/main/resources/maps.yml +++ /dev/null @@ -1 +0,0 @@ -# DO NOT edit this file manually! Use plugin commands to edit maps instead. \ No newline at end of file From 5a989ad05373111fd6c218b544e2a6c5bc904148 Mon Sep 17 00:00:00 2001 From: hdvt Date: Sat, 29 Nov 2025 19:22:04 +0300 Subject: [PATCH 2/2] it works. commands are broken. --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .idea/compiler.xml | 11 +- .idea/misc.xml | 2 +- .idea/modules.xml | 1 + .idea/modules/BlockAndSeek.main.iml | 5 + build.gradle | 108 ++++- gradle.properties | 7 + .../blockAndSeek/BlockAndSeekGame.java | 315 ------------- .../hdvtdev/blockAndSeek/BlockAndSeekMap.java | 173 ------- .../hdvtdev/blockandseek/BlockAndSeek.java | 258 ++++++++-- .../hdvtdev/blockandseek/BlocksGenerator.java | 231 +++++++-- .../hdvtdev/blockandseek/CommandBuilder.java | 2 +- .../hdvtdev/blockandseek/CommandListener.java | 21 - .../java/hdvtdev/blockandseek/Config.java | 70 ++- .../java/hdvtdev/blockandseek/GuiHolder.java | 2 +- src/main/java/hdvtdev/blockandseek/Keys.java | 16 +- .../hdvtdev/blockandseek/Localization.java | 83 ---- src/main/java/hdvtdev/blockandseek/Utils.java | 62 +-- .../eventListeners/EventListener.java | 17 +- .../ForceControlEventListener.java | 31 +- .../eventListeners/RequiredEventListener.java | 67 ++- .../blockandseek/managers/GamesManager.java | 33 +- .../blockandseek/managers/ItemManager.java | 77 +-- .../blockandseek/managers/MapsManager.java | 149 ++++-- .../blockandseek/managers/PropManager.java | 100 +++- .../blockandseek/managers/StateManager.java | 12 +- .../managers/TranslationManager.java | 94 ++++ .../blockandseek/managers/WorldManager.java | 4 +- .../hdvtdev/blockandseek/menus/GamesMenu.java | 52 +- .../hdvtdev/blockandseek/menus/MapsMenu.java | 66 +++ .../objects/BlockAndSeekGame.java | 443 +++++++++++++++++- .../blockandseek/objects/BlockAndSeekMap.java | 64 ++- .../blockandseek/objects/GamePhase.java | 16 +- .../blockandseek/objects/PropBlock.java | 24 +- .../hdvtdev/blockandseek/objects/Rarity.java | 31 +- .../blockandseek/objects/Translation.java | 17 + .../blockandseek/objects/TranslationKey.java | 40 ++ .../roulette/RouletteCreator.java | 172 +++---- .../roulette/RouletteGenerator.java | 17 +- .../blockandseek/roulette/RouletteList.java | 2 +- src/main/resources/languages/README.txt | 2 + src/main/resources/languages/en_US.yml | 26 + src/main/resources/languages/ru_RU.yml | 23 + src/main/resources/plugin.yml | 8 +- 44 files changed, 1890 insertions(+), 1064 deletions(-) delete mode 100644 src/main/java/hdvtdev/blockAndSeek/BlockAndSeekGame.java delete mode 100644 src/main/java/hdvtdev/blockAndSeek/BlockAndSeekMap.java delete mode 100644 src/main/java/hdvtdev/blockandseek/CommandListener.java delete mode 100644 src/main/java/hdvtdev/blockandseek/Localization.java create mode 100644 src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java create mode 100644 src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java create mode 100644 src/main/java/hdvtdev/blockandseek/objects/Translation.java create mode 100644 src/main/java/hdvtdev/blockandseek/objects/TranslationKey.java create mode 100644 src/main/resources/languages/README.txt create mode 100644 src/main/resources/languages/ru_RU.yml diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index b4911b7cea05239fff644153733695f1d185bd69..34130c3d404f5a44467a2ac6047b4a492ee1163d 100644 GIT binary patch literal 17 VcmZQhY`Gk`{>!NV1~4#K0RTKB1)=}| literal 17 VcmZQhY`Gk`{>!NV1~AY#0RTKR1-bwL diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b86273d..bc52ee8 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,15 @@ - + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 5cd9a10..87a20fc 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 1b7e58d..ae6737f 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -4,6 +4,7 @@ + \ No newline at end of file diff --git a/.idea/modules/BlockAndSeek.main.iml b/.idea/modules/BlockAndSeek.main.iml index bbeeb3e..d329813 100644 --- a/.idea/modules/BlockAndSeek.main.iml +++ b/.idea/modules/BlockAndSeek.main.iml @@ -1,5 +1,10 @@ + + + + + diff --git a/build.gradle b/build.gradle index 7af82b3..090d6fd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,9 @@ +import java.nio.ByteBuffer +import java.nio.ByteOrder + plugins { id 'java' - id("xyz.jpenilla.run-paper") version "2.3.1" + id "com.gradleup.shadow" version "9.2.2" } group = 'hdvtdev' @@ -8,6 +11,7 @@ version = '0.0.1-a' repositories { mavenCentral() + maven { url 'https://storehouse.okaeri.eu/repository/maven-releases/'} maven { url 'https://repo.md-5.net/content/groups/public/' } maven { url 'https://jitpack.io' } maven { @@ -21,15 +25,24 @@ repositories { maven { url 'https://libraries.minecraft.net/' } } +def okaeriConfigsVersion = '5.0.13' + dependencies { compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT") - implementation group: 'me.libraryaddict.disguises', name: 'libsdisguises', version: '11.0.6' - //TODO implementation 'me.lucko:commodore:2.2' + compileOnly group: 'me.libraryaddict.disguises', name: 'libsdisguises', version: '11.0.6' + compileOnly 'org.projectlombok:lombok:1.18.42' + annotationProcessor 'org.projectlombok:lombok:1.18.42' + implementation "eu.okaeri:okaeri-configs-validator-okaeri:$okaeriConfigsVersion" + implementation "eu.okaeri:okaeri-configs-yaml-bukkit:$okaeriConfigsVersion" + implementation "eu.okaeri:okaeri-configs-serdes-bukkit:$okaeriConfigsVersion" + implementation "eu.okaeri:okaeri-configs-serdes-commons:$okaeriConfigsVersion" + + implementation "org.incendo:cloud-paper:2.0.0-beta.13" } -def targetJavaVersion = 21 +def targetJavaVersion = 17 java { def javaVersion = JavaVersion.toVersion(targetJavaVersion) sourceCompatibility = javaVersion @@ -56,14 +69,83 @@ processResources { } } -jar { - //destinationDirectory.set(file("/home/hadvart/Documents/Minecraft/Pufferfish 1.20.4/plugins")) - from sourceSets.main.output - from { - configurations.runtimeClasspath.findAll { - it.name.startsWith('Java-Probability-Collection') || it.name.startsWith('commodore') || it.name.startsWith('brigadier') - }.collect { zipTree(it) } - } - duplicatesStrategy = DuplicatesStrategy.EXCLUDE +tasks.shadowJar { + archiveClassifier.set("") + relocate("eu.okaeri", "hdvtdev.blockandseek.libs.okaeri") + relocate("org.incendo", "hdvtdev.blockandseek.libs.cloud") } +tasks.build { + dependsOn(tasks.shadowJar) +} + +tasks.register('deploy') { + dependsOn build + + + doLast { + def targetDir = project.property('server.plugins.dir') + def rconHost = project.property('rcon.host') + def rconPort = project.property('rcon.port') as int + def rconPass = project.property('rcon.password') + + + def jarFile = tasks.jar.archiveFile.get().asFile + + if (!file(targetDir).exists()) { + println "Err folder not found : $targetDir" + return + } + + copy { + from jarFile + into targetDir + } + + try { + sendRconCommand(rconHost, rconPort, rconPass, "plugman reload BlockAndSeek") + sendRconCommand(rconHost, rconPort, rconPass, "reload") + println "Plugin reloaded" + } catch (Exception e) { + println "RCON: ${e.message}" + } + } +} + +def sendRconCommand(String host, int port, String password, String command) { + new Socket(host, port).withCloseable { socket -> + def out = socket.outputStream + def inp = socket.inputStream + + def sendPacket = { int id, int type, String body -> + byte[] bodyBytes = body.getBytes("UTF-8") + int length = 4 + 4 + bodyBytes.length + 2 // id + type + body + 2 nulls + ByteBuffer buffer = ByteBuffer.allocate(4 + length) + buffer.order(ByteOrder.LITTLE_ENDIAN) + + buffer.putInt(length) + buffer.putInt(id) + buffer.putInt(type) + buffer.put(bodyBytes) + buffer.put((byte) 0) + buffer.put((byte) 0) + + out.write(buffer.array()) + out.flush() + } + + + sendPacket(1, 3, password) + + inp.read(new byte[4096]) + + sendPacket(2, 2, command) + + byte[] buffer = new byte[4096] + int read = inp.read(buffer) + if (read > 12) { + String response = new String(buffer, 12, read - 12 - 2, "UTF-8") + println "Server response: $response" + } + } +} diff --git a/gradle.properties b/gradle.properties index e69de29..07be753 100644 --- a/gradle.properties +++ b/gradle.properties @@ -0,0 +1,7 @@ +plugin.name=MySuperPlugin + +server.plugins.dir=/home/hadvart/Documents/minecraft/Pufferfish/1.21.8/plugins + +rcon.host=127.0.0.1 +rcon.port=25575 +rcon.password=14881488 \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekGame.java b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekGame.java deleted file mode 100644 index 071e9c9..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekGame.java +++ /dev/null @@ -1,315 +0,0 @@ -package hdvtdev.blockAndSeek; - -import hdvtdev.blockAndSeek.managers.ConfigManager; -import hdvtdev.blockAndSeek.managers.GamesManager; -import hdvtdev.blockAndSeek.managers.ItemManager; -import hdvtdev.blockAndSeek.managers.PropManager; -import hdvtdev.blockAndSeek.roulette.RouletteCreator; -import me.libraryaddict.disguise.DisguiseAPI; -import org.bukkit.*; -import org.bukkit.entity.Player; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; -import org.bukkit.scheduler.BukkitRunnable; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public class BlockAndSeekGame { - - private final Map players = new ConcurrentHashMap<>(); - private final Map hiderRoulette = new HashMap<>(); - - private volatile boolean started = false; - private final BlockAndSeekMap map; - private final Location lobby; - private final Location spawn; - private final String name; - - public BlockAndSeekGame(String name, BlockAndSeekMap map) { - this.map = map; - World world = Bukkit.getWorld(name); - world.setTime(1000); - world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); - world.setStorm(false); - world.setGameRule(GameRule.DO_WEATHER_CYCLE, false); - this.name = name; - this.lobby = map.getLobbyLocation(world); - this.spawn = map.getSpawnLocation(world); - this.startBukkitTask(); - } - - public int playerCount() { - return players.size(); - } - - public boolean isStarted() { - return started; - } - - public int maxPlayers() { - return map.getMaxPlayers(); - } - - public boolean addPlayer(Player player) { - if (!started) { - players.put(player, PlayerType.HIDER); - player.getPersistentDataContainer().set(Keys.GAME, PersistentDataType.STRING, name); - player.teleport(lobby); - PlayerInventory inventory = player.getInventory(); - inventory.clear(); - inventory.setItem(8, Localization.translateItem(player, ItemManager.getLeaveItem())); - player.setGameMode(GameMode.SURVIVAL); - player.setInvulnerable(true); - player.setHealth(20.0); - player.setFoodLevel(20); - Localization.sendMessage( - players.keySet(), - true, - "player-join", - "{player}", player.getName(), - "{players}", players.size() + "/" + map.getMaxPlayers() - ); - return true; - } else return false; - } - - public void removePlayer(Player player) { - players.remove(player); - DisguiseAPI.undisguiseToAll(player); - player.getInventory().clear(); - player.setGameMode(GameMode.SURVIVAL); - player.getPersistentDataContainer().remove(Keys.GAME); - Config config = ConfigManager.getConfig(); - if (config.forceControl()) ItemManager.defaultInventory(player); - player.teleport(config.defaultSpawn()); - - - Localization.sendMessage( - players.keySet(), - true, - "player-leave", - "{player}", player.getName(), - "{players}", started ? "" : players.size() + "/" + map.getMaxPlayers() - ); - } - - public void setSpectator(Player hider, @Nullable Player seeker) { - hider.spigot().respawn(); - hider.teleport(hider.getLastDeathLocation()); - players.put(hider, PlayerType.SPECTATOR); - hider.setGameMode(GameMode.SPECTATOR); - Localization.sendMessage( - players.keySet(), - true, - seeker == null ? "hider-died" : "hider-was-found", - "{hider}", hider.getName(), - "{seeker}", seeker == null ? "" : seeker.getName() - ); - } - - private long getHidersCount() { - return players.values().stream().filter(type -> type == PlayerType.HIDER).count(); - } - - private long getSeekersCount() { - return players.values().stream().filter(type -> type == PlayerType.SEEKER).count(); - } - - private List getSeekers() { - return players.entrySet().stream().filter(entry -> entry.getValue() == PlayerType.SEEKER).map(Map.Entry::getKey).toList(); - } - - private List getHiders() { - return players.entrySet().stream().filter(entry -> entry.getValue() == PlayerType.HIDER).map(Map.Entry::getKey).toList(); - } - - private Player getLastHider() { - return players.keySet().iterator().next(); - } - - private void start() { - started = true; - selectRandomSeekers((int) Math.round(players.size() * 0.25)); - List hiders = getHiders(); - for (Player hider : hiders) { - hider.getPersistentDataContainer().set(Keys.HIDER, PersistentDataType.BOOLEAN, true); - hider.teleport(spawn); - hider.setInvulnerable(false); - PlayerInventory inventory = hider.getInventory(); - inventory.clear(); - inventory.addItem(Localization.translateItem(hider, ItemManager.getFreezeItem())); - inventory.addItem(Localization.translateItem(hider, ItemManager.getFaceChangingItem())); - hiderRoulette.put(hider, new RouletteCreator(hider, map.getBlocks())); - } - } - - private void end(boolean force) { - GamesManager.remove(name); - if (!force) { - Config config = ConfigManager.getConfig(); - Location serverLobby = config.defaultSpawn(); - boolean defaultInventory = config.forceControl(); - for (Player player : players.keySet()) { - - - DisguiseAPI.undisguiseToAll(player); - if (defaultInventory) ItemManager.defaultInventory(player); - player.setGlowing(false); - player.setInvulnerable(false); - Utils.setLevelWithBar(player, 0); - player.setVisibleByDefault(true); - player.setHealth(20); - player.setGameMode(GameMode.SURVIVAL); - player.teleport(serverLobby); - - } - } - } - - private void preEnd() { - for (Player player : players.keySet()) { - PersistentDataContainer container = player.getPersistentDataContainer(); - player.setInvulnerable(true); - container.remove(Keys.HIDER); - container.remove(Keys.SEEKER); - container.remove(Keys.GAME); - } - for (Player hider : getHiders()) { - hider.getInventory().clear(); - PropManager.unfreezeIfFrozen(hider); - hider.setGlowing(true); - RouletteCreator rouletteCreator = hiderRoulette.get(hider); - rouletteCreator.getTask().cancelBoth(); - rouletteCreator.closeInventory(); - } - } - - private void selectRandomSeekers(int count) { - ArrayList rawSeekers = new ArrayList<>(); - Set playerSet = players.keySet(); - for (Player player : playerSet) { - if (!GamesManager.triggerSeekerImmune(player)) rawSeekers.add(player); - } - Collections.shuffle(rawSeekers); - - for (Player seeker : rawSeekers.subList(0, Math.min(count, playerSet.size()))) { - players.put(seeker, PlayerType.SEEKER); - ItemManager.setSeekerSet(seeker); - Utils.setLevelWithBar(seeker, 100); - seeker.setInvulnerable(false); - seeker.getPersistentDataContainer().set(Keys.SEEKER, PersistentDataType.BOOLEAN, true); - GamesManager.addSeekerImmune(seeker); - } - - } - - private void startBukkitTask() { - new BukkitRunnable() { - - int waitTime = 30; - final int defaultWaitTime = waitTime; - int duration = map.getDuration(); - final int seekerDeploy = duration - 15; - - - @Override - public void run() { - if (waitTime != 0) { - int playerSize = players.size(); - if (playerSize >= map.getMinPlayers()) { - if (waitTime % 5 == 0 || waitTime <= 5) { - Localization.sendMessage( - players.keySet(), - true, - "wait-time-left", - "{time}", String.valueOf(waitTime) - ); - } - waitTime--; - } else if (playerSize == 0) { - end(true); - this.cancel(); - } else if (waitTime != defaultWaitTime) { - waitTime = defaultWaitTime; - } - } else { - if (!started) { - start(); - } else { - - if (players.isEmpty()) { - end(false); - this.cancel(); - return; - } - - if (duration > 0 && getHidersCount() == 0) { - Localization.sendTitle( - players.keySet(), - false, - "seekers-won" - ); - preEnd(); - duration = -1; - } - - if (duration == seekerDeploy) { - for (Player seeker : getSeekers()) { - seeker.teleport(spawn); - } - } - - if (duration > 0 && getSeekersCount() == 0) duration = 0; - - if (duration == 0) { - - preEnd(); - if (getHidersCount() == 1) { - Localization.sendTitle( - players.keySet(), - false, - "hiders-solo-win", - "{hider}", getLastHider().getName() - ); - } else { - Localization.sendTitle( - players.keySet(), - false, - "hiders-won" - ); - } - duration--; // уменьшаем только один раз - } else if (duration > 0) { - Localization.sendActionBar( - players.keySet(), - false, - "game-time-left", - "{time}", String.valueOf(duration) - ); - duration--; - } else if (duration == -10) { - end(false); - this.cancel(); - } else { - duration--; - } - } - } - } - - - }.runTaskTimer(BlockAndSeek.getInstance(), 0L, 20L); - } - - - private enum PlayerType { - SEEKER, - HIDER, - SPECTATOR - } - - -} diff --git a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekMap.java b/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekMap.java deleted file mode 100644 index a8bbfb7..0000000 --- a/src/main/java/hdvtdev/blockAndSeek/BlockAndSeekMap.java +++ /dev/null @@ -1,173 +0,0 @@ -package hdvtdev.blockAndSeek; - - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.configuration.serialization.ConfigurationSerializable; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class BlockAndSeekMap implements ConfigurationSerializable { - - private List spawn; - private List lobby; - private int duration; - private int minPlayers; - private int maxPlayers; - private List blocks; - - public BlockAndSeekMap() { - - } - - public BlockAndSeekMap(List spawn, List lobby, int duration, int minPlayers, int maxPlayers, - List blocks) { - this.spawn = spawn; - this.lobby = lobby; - this.duration = duration; - this.minPlayers = minPlayers; - this.maxPlayers = maxPlayers; - this.blocks = blocks; - } - - public List getSpawn() { - return spawn; - } - - public Location getSpawnLocation(@Nullable World world) { - return new Location(world, spawn.getFirst(), spawn.get(1), spawn.get(2)); - } - - public void setSpawn(List spawn) { - this.spawn = spawn; - } - - public List getLobby() { - return lobby; - } - - public Location getLobbyLocation(@Nullable World world) { - return new Location(world, lobby.getFirst(), lobby.get(1), lobby.get(2)); - } - - public void setLobby(List lobby) { - this.lobby = lobby; - } - - public int getDuration() { - return duration; - } - - public void setDuration(int duration) { - this.duration = duration; - } - - public int getMinPlayers() { - return minPlayers; - } - - public void setMinPlayers(int minPlayers) { - this.minPlayers = minPlayers; - } - - public int getMaxPlayers() { - return maxPlayers; - } - - public void setMaxPlayers(int maxPlayers) { - this.maxPlayers = maxPlayers; - } - - public List getBlocks() { - return blocks; - } - - public void setBlocks(List blocks) { - this.blocks = blocks; - } - - public boolean isReady() { - return !spawn.isEmpty() && !lobby.isEmpty() && duration > 0 && !blocks.isEmpty() && minPlayers > 0 && maxPlayers > 0; - } - - public static BlockAndSeekMap defaultMap() { - return new BlockAndSeekMap(List.of(), List.of(), 0, 0, 0, List.of()); - } - - public Set check() { - Set status = new HashSet<>(); - if (spawn.isEmpty()) status.add(MapStatus.SPAWN_REQUIRED); - if (lobby.isEmpty()) status.add(MapStatus.LOBBY_REQUIRED); - if (duration <= 0) status.add(MapStatus.DURATION_REQUIRED); - if (minPlayers <= 0) status.add(MapStatus.MIN_PLAYERS_REQUIRED); - if (maxPlayers <= 0) status.add(MapStatus.MAX_PLAYERS_REQUIRED); - if (blocks.isEmpty()) status.add(MapStatus.BLOCKS_REQUIRED); - return status; - } - - @Override - public @NotNull Map serialize() { - - Map map = new HashMap<>(); - map.put("spawn", spawn); - map.put("lobby", lobby); - map.put("duration", duration); - map.put("min-players", minPlayers); - map.put("max-players", maxPlayers); - List> serBlocks = new ArrayList<>(); - for (Block block : blocks) { - serBlocks.add(block.toMap()); - } - map.put("blocks", serBlocks); - - - return map; - } - - @NotNull - @SuppressWarnings("unchecked") - public static BlockAndSeekMap deserialize(@NotNull Map args) { - - BlockAndSeekMap map = new BlockAndSeekMap(); - map.setSpawn((List) args.get("spawn")); - map.setLobby((List) args.get("lobby")); - map.setDuration((int) args.get("duration")); - map.setMinPlayers((int) args.get("min-players")); - map.setMaxPlayers((int) args.get("max-players")); - map.setBlocks(((List>) args.get("blocks")).stream().map(Block::fromMap).toList()); - - return map; - } - - @Override - public String toString() { - return String.format("BlockAndSeekMap[spawn=%s, lobby=%s, duration=%s, minPlayers=%s, maxPlayers=%s, blocks=%s]", spawn, lobby, duration, minPlayers, maxPlayers, blocks); - } - - public enum MapStatus { - SPAWN_REQUIRED, - LOBBY_REQUIRED, - DURATION_REQUIRED, - BLOCKS_REQUIRED, - MIN_PLAYERS_REQUIRED, - MAX_PLAYERS_REQUIRED - } - - public record Block(@NotNull ItemStack block, int chance) { - public Map toMap() { - Map map = new HashMap<>(); - map.put("block", block.getType().name()); - map.put("chance", chance); - return map; - } - - public static Block fromMap(Map map) { - return new Block(new ItemStack(Material.valueOf(((String) map.get("block")).toUpperCase())), (int) map.get("chance")); - } - } - -} diff --git a/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java b/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java index 12d32df..6d7bf5b 100644 --- a/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java +++ b/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java @@ -1,31 +1,39 @@ -package hdvtdev.blockAndSeek; +package hdvtdev.blockandseek; -import hdvtdev.blockAndSeek.eventListeners.RequiredEventListener; -import hdvtdev.blockAndSeek.eventListeners.EventListener; -import hdvtdev.blockAndSeek.eventListeners.ForceControlEventListener; +import hdvtdev.blockandseek.eventListeners.RequiredEventListener; +import hdvtdev.blockandseek.eventListeners.EventListener; +import hdvtdev.blockandseek.eventListeners.ForceControlEventListener; +import hdvtdev.blockandseek.managers.*; +import hdvtdev.blockandseek.objects.*; +import hdvtdev.blockandseek.roulette.RouletteCreator; import me.libraryaddict.disguise.LibsDisguises; -import org.bukkit.Bukkit; +import net.kyori.adventure.text.minimessage.MiniMessage; + +import org.bukkit.*; import org.bukkit.command.CommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; -import org.incendo.cloud.Command; import org.incendo.cloud.bukkit.CloudBukkitCapabilities; -import org.incendo.cloud.bukkit.parser.PlayerParser; +import org.incendo.cloud.bukkit.parser.location.LocationParser; import org.incendo.cloud.execution.ExecutionCoordinator; import org.incendo.cloud.paper.LegacyPaperCommandManager; -import org.incendo.cloud.parser.standard.IntegerParser; import org.incendo.cloud.parser.standard.StringParser; import java.io.File; -import java.util.Objects; +import java.util.*; import java.util.logging.Logger; +import java.util.stream.Collectors; public class BlockAndSeek extends JavaPlugin { @@ -66,17 +74,13 @@ public class BlockAndSeek extends JavaPlugin { this.init(); - if (!Config.loadConfig()) getPluginLogger().warning("Failed to load BlockAndSeek config.toml! Using default config..."); - - PluginCommand command = Objects.requireNonNull(getCommand("blockandseek")); - PluginManager manager = getServer().getPluginManager(); - manager.registerEvents(Config.forceControl() ? new ForceControlEventListener() : new EventListener(), this); + boolean forceControl = Config.forceControl(); + if (forceControl) getLogger().info("Using force control"); + manager.registerEvents(forceControl ? new ForceControlEventListener() : new EventListener(), this); manager.registerEvents(new RequiredEventListener(), this); - - } @@ -105,6 +109,9 @@ public class BlockAndSeek extends JavaPlugin { saveResource("languages/en_US.yml", false); } + MapsManager.loadMaps(); + TranslationManager.loadLanguages(); + commandManager = LegacyPaperCommandManager.createNative( this, ExecutionCoordinator.simpleCoordinator() @@ -130,53 +137,226 @@ public class BlockAndSeek extends JavaPlugin { } + private final PropManager propManager = new PropManager(); + private void registerCommands() { - Command.Builder root = commandManager.commandBuilder("blockandseek"); + var root = commandManager.commandBuilder("blockandseek"); + + var editBase = root + .literal("editMap") + .required("map_name", StringParser.stringParser(), MapsManager.mapSuggestions); + + //edit commands + + + commandManager.command( + editBase.literal("setLobby") // Это наш как литерал + .required("location", LocationParser.locationParser()) + .handler(ctx -> { + + }) + ); + + commandManager.command( + editBase.literal("setLocation") + .required("location", LocationParser.locationParser()) // Это + .handler(ctx -> { + String configName = ctx.get("config_name"); + Location location = ctx.get("location"); + + ctx.sender().sendMessage("В конфиге " + configName + " точка установлена: " + location.toString()); + }) + ); + + commandManager.command(root + .literal("maps") + .handler(ctx -> { + ctx.sender().sendMessage(MapsManager.getMaps().stream().map(BlockAndSeekMap::getWorld).collect(Collectors.joining(", "))); + }) + ); + + commandManager.command(root + .literal("testMessage") + .handler(ctx -> { + ctx.sender().sendMessage(MiniMessage.miniMessage().deserialize(" System » Ваш игровой режим изменен.\n")); + }) + ); + + commandManager.command(root + .literal("menuTest") + .handler(ctx -> { + if (ctx.sender() instanceof Player player) { + player.getInventory().addItem(ItemManager.getMenuItem()); + } + }) + ); commandManager.command(root - .literal("reload") + .literal("localeTest") + .handler(ctx -> { + if (ctx.sender() instanceof Player player) { + player.sendMessage("Locale is: " + player.locale()); + player.sendMessage(TranslationManager.get(player, TranslationKey.FREEZE_ITEM)); + } + }) + ); + + + commandManager.command(root + .literal("createGame") .permission(perm) + .required("map_name", StringParser.stringParser(), MapsManager.mapSuggestions) .handler(context -> { - + String name = context.get("map_name"); + GamesManager.createGame(name); + if (context.sender() instanceof Player player) { + GamesManager.get(name).addPlayer(player); + } }) ); - - commandManager.command(root - .literal("inttest") - .required("text", IntegerParser.integerParser(0, 64)) - - .handler(context -> { - String text = context.get("text"); - context.sender().sendMessage(text); - }) - ); - - - commandManager.command(root - .literal("map") + .literal("createMap") .permission(perm) - .required("map", StringParser.stringParser()) - .required("action", StringParser.stringParser()) + .required("map_name", StringParser.stringParser(), MapsManager.worldSuggestions) .handler(context -> { - Player target = context.get("target"); - int amount = context.getOrDefault("amount", 1); - - + String name = context.get("map_name"); + MapsManager.createMap(name); + context.sender().sendMessage("Map probably created"); }) ); + commandManager.command(root + .literal("joinGame") + .permission(perm) + .required("name", StringParser.stringParser()) + .handler(context -> { + String name = context.get("name"); + if (context.sender() instanceof Player player) { + BlockAndSeekGame game = GamesManager.get(name); + if (game != null) game.addPlayer(player); + } + }) + ); + + commandManager.command( + editBase.literal("generateBlocks") + .handler(ctx -> { + if (ctx.sender() instanceof Player player) { + + String mapName = ctx.get("map_name"); + BlockAndSeekMap map = MapsManager.getMap(mapName); + + var cached = BlocksGenerator.get(map.getSpawn().getWorld().getName()); + + if (cached != null) { + new RouletteCreator(player, cached); + } else { + BlocksGenerator.getSortedBlockStats(player.getLocation(), 32, (var list) -> { + + List> selectedBlocks = new ArrayList<>(list); + + // 2. Перемешиваем и берем 30 случайных (или меньше, если всего блоков меньше 30) + Collections.shuffle(selectedBlocks); + if (selectedBlocks.size() > 30) { + selectedBlocks = selectedBlocks.subList(0, 30); + } + + selectedBlocks.sort((a, b) -> Long.compare(b.getValue(), a.getValue())); + + List> result = new ArrayList<>(); + + // 4. Считаем общий вес редкостей (100 + 50 + 25 + ...) = 189 + int totalWeight = Arrays.stream(Rarity.values()).mapToInt(Rarity::getChance).sum(); + + // Шаг веса на один блок. + // Представь длинную полоску длиной 189 единиц. Мы режем её на 30 равных частей. + // Куда попадает разрез — такая и редкость. + double weightStep = (double) totalWeight / selectedBlocks.size(); + + double currentWeightPosition = 0; // Текущая позиция на шкале весов + + // Идем по отсортированному списку (от самых частых к самым редким) + for (Map.Entry entry : selectedBlocks) { + + // Определяем, в какой диапазон редкости попадает текущий блок + Rarity assignedRarity = Rarity.COMMON; // Дефолт + + int weightCursor = 0; + for (Rarity r : Rarity.values()) { + weightCursor += r.getChance(); + // Если текущая позиция веса меньше границы этой редкости — мы нашли её + // (Добавляем половину шага, чтобы брать "центр" диапазона блока для точности) + if ((currentWeightPosition + weightStep / 2) <= weightCursor) { + assignedRarity = r; + break; + } + } + + result.add(new AbstractMap.SimpleEntry<>(entry.getKey(), assignedRarity)); + + // Сдвигаемся дальше по шкале + currentWeightPosition += weightStep; + } + var r = result.stream().map(e -> new PropBlock(new ItemStack(e.getKey()), e.getValue())).toList(); + map.setBlocks(r); + + map.save(); + BlocksGenerator.addCache(player.getLocation().getWorld().getName(), r); + + + + }); + } + + + } + + }) + ); + } + + private void spawnSmokeCloud(Location center) { + + new BukkitRunnable() { + int ticksPassed = 0; + + final int maxIterations = (10 * 20) / 5; + + @Override + public void run() { + if (ticksPassed >= maxIterations) { + this.cancel(); + return; + } + + World world = center.getWorld(); + if (world == null) return; + + + world.spawnParticle(Particle.EXPLOSION_HUGE, center, 15, 1.2, 1.2, 1.2, 0.05); + + + + for (var entity : world.getNearbyEntities(center, 2.5, 2.5, 2.5)) { + if (entity instanceof Player player && player.getLocation().distanceSquared(center) <= 9) { + player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 40, 1)); + } + } + + ticksPassed++; + } + }.runTaskTimer(this, 0L, 5L); } } diff --git a/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java b/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java index 8b42902..f943831 100644 --- a/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java +++ b/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java @@ -1,50 +1,191 @@ -package hdvtdev.blockAndSeek; +package hdvtdev.blockandseek; +import hdvtdev.blockandseek.objects.PropBlock; import org.bukkit.*; -import org.bukkit.block.data.AnaloguePowerable; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Openable; -import org.bukkit.block.data.Powerable; +import org.bukkit.block.Banner; +import org.bukkit.block.Comparator; +import org.bukkit.block.data.*; +import org.bukkit.block.data.type.Observer; +import org.bukkit.block.data.type.Piston; +import org.bukkit.block.data.type.RedstoneWire; import org.bukkit.scheduler.BukkitRunnable; -import org.jetbrains.annotations.ApiStatus; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; @ApiStatus.Experimental public class BlocksGenerator { - private static boolean isSupported(Material type, BlockData data) { + private static final Set BLACKLIST = EnumSet.noneOf(Material.class); + private static final Map> cached = new HashMap<>(); - if (type.isAir() || type.hasGravity() || !type.isSolid()) { + static { + // --- 1. ГРАВИТАЦИЯ (Сыпучие) --- + BLACKLIST.add(Material.SAND); + BLACKLIST.add(Material.RED_SAND); + BLACKLIST.add(Material.GRAVEL); + BLACKLIST.add(Material.DRAGON_EGG); + BLACKLIST.add(Material.ANVIL); + BLACKLIST.add(Material.CHIPPED_ANVIL); + BLACKLIST.add(Material.DAMAGED_ANVIL); + BLACKLIST.add(Material.POINTED_DRIPSTONE); // Сталактит (может упасть) + BLACKLIST.add(Material.SCAFFOLDING); // Строительные леса + + // --- 2. РЕДСТОУН И МЕХАНИЗМЫ --- + BLACKLIST.addAll(Tag.BUTTONS.getValues()); // Все кнопки + BLACKLIST.addAll(Tag.PRESSURE_PLATES.getValues()); // Все нажимные плиты + BLACKLIST.addAll(Tag.DOORS.getValues()); // Двери + BLACKLIST.addAll(Tag.TRAPDOORS.getValues()); // Люки + BLACKLIST.addAll(Tag.FENCE_GATES.getValues()); // Калитки + BLACKLIST.addAll(Tag.RAILS.getValues()); // Рельсы + + BLACKLIST.add(Material.REDSTONE_WIRE); + BLACKLIST.add(Material.REDSTONE_TORCH); + BLACKLIST.add(Material.REDSTONE_BLOCK); // Если не нужен блок редстоуна + BLACKLIST.add(Material.REPEATER); + BLACKLIST.add(Material.COMPARATOR); + BLACKLIST.add(Material.OBSERVER); + BLACKLIST.add(Material.PISTON); + BLACKLIST.add(Material.STICKY_PISTON); + BLACKLIST.add(Material.PISTON_HEAD); + BLACKLIST.add(Material.MOVING_PISTON); + BLACKLIST.add(Material.DISPENSER); + BLACKLIST.add(Material.DROPPER); + BLACKLIST.add(Material.HOPPER); + BLACKLIST.add(Material.DAYLIGHT_DETECTOR); + BLACKLIST.add(Material.TRIPWIRE); + BLACKLIST.add(Material.TRIPWIRE_HOOK); + BLACKLIST.add(Material.LEVER); + BLACKLIST.add(Material.TNT); + BLACKLIST.add(Material.NOTE_BLOCK); + BLACKLIST.add(Material.JUKEBOX); + BLACKLIST.add(Material.SCULK_SENSOR); + BLACKLIST.add(Material.SCULK_SHRIEKER); + BLACKLIST.add(Material.SCULK_CATALYST); + BLACKLIST.add(Material.COMMAND_BLOCK); + BLACKLIST.add(Material.REPEATING_COMMAND_BLOCK); + BLACKLIST.add(Material.CHAIN_COMMAND_BLOCK); + BLACKLIST.add(Material.LIGHTNING_ROD); + BLACKLIST.add(Material.BELL); // Колокол + + // --- 3. ХРУПКИЕ / ЗАВИСЯЩИЕ ОТ ОПОРЫ (Растения, декор) --- + BLACKLIST.addAll(Tag.SAPLINGS.getValues()); // Саженцы + BLACKLIST.addAll(Tag.FLOWERS.getValues()); // Цветы + BLACKLIST.addAll(Tag.CROPS.getValues()); // Пшеница, картошка и т.д. + BLACKLIST.addAll(Tag.BANNERS.getValues()); // Флаги (стоячие и настенные) + BLACKLIST.addAll(Tag.SIGNS.getValues()); // Таблички + BLACKLIST.addAll(Tag.BEDS.getValues()); // Кровати + BLACKLIST.addAll(Tag.CANDLES.getValues()); // Свечи + BLACKLIST.addAll(Tag.CAMPFIRES.getValues()); // Костры + BLACKLIST.addAll(Tag.CAULDRONS.getValues()); // Котлы + BLACKLIST.addAll(Tag.WOOL_CARPETS.getValues()); // Ковры + BLACKLIST.addAll(Tag.FLOWER_POTS.getValues()); // Горшки + + BLACKLIST.add(Material.BROWN_MUSHROOM); + BLACKLIST.add(Material.RED_MUSHROOM); + BLACKLIST.add(Material.CRIMSON_FUNGUS); + BLACKLIST.add(Material.WARPED_FUNGUS); + BLACKLIST.add(Material.SUGAR_CANE); + BLACKLIST.add(Material.BAMBOO); + BLACKLIST.add(Material.BAMBOO_SAPLING); + BLACKLIST.add(Material.CACTUS); + BLACKLIST.add(Material.DEAD_BUSH); + BLACKLIST.add(Material.SWEET_BERRY_BUSH); + BLACKLIST.add(Material.PUMPKIN_STEM); + BLACKLIST.add(Material.MELON_STEM); + BLACKLIST.add(Material.NETHER_WART); + BLACKLIST.add(Material.CHORUS_PLANT); + BLACKLIST.add(Material.CHORUS_FLOWER); + BLACKLIST.add(Material.KELP); + BLACKLIST.add(Material.KELP_PLANT); + BLACKLIST.add(Material.SEAGRASS); + BLACKLIST.add(Material.TALL_SEAGRASS); + BLACKLIST.add(Material.VINE); + BLACKLIST.add(Material.WEEPING_VINES); + BLACKLIST.add(Material.TWISTING_VINES); + BLACKLIST.add(Material.LILY_PAD); + BLACKLIST.add(Material.SMALL_DRIPLEAF); + BLACKLIST.add(Material.BIG_DRIPLEAF); + BLACKLIST.add(Material.SPORE_BLOSSOM); + BLACKLIST.add(Material.HANGING_ROOTS); + BLACKLIST.add(Material.GLOW_LICHEN); + BLACKLIST.add(Material.AMETHYST_CLUSTER); + BLACKLIST.add(Material.SMALL_AMETHYST_BUD); + BLACKLIST.add(Material.MEDIUM_AMETHYST_BUD); + BLACKLIST.add(Material.LARGE_AMETHYST_BUD); + BLACKLIST.add(Material.POINTED_DRIPSTONE); + BLACKLIST.add(Material.COCOA); + + BLACKLIST.add(Material.TORCH); + BLACKLIST.add(Material.SOUL_TORCH); + BLACKLIST.add(Material.LANTERN); + BLACKLIST.add(Material.SOUL_LANTERN); + BLACKLIST.add(Material.CHAIN); + BLACKLIST.add(Material.END_ROD); + BLACKLIST.add(Material.IRON_BARS); // Обычно некрасиво в топах + BLACKLIST.add(Material.LADDER); + BLACKLIST.add(Material.SNOW); // Снежный покров (тонкий) + BLACKLIST.add(Material.TURTLE_EGG); + BLACKLIST.add(Material.CAKE); + + // --- 4. КОНТЕЙНЕРЫ (Если не хочешь, чтобы выпадали сундуки) --- + BLACKLIST.add(Material.CHEST); + BLACKLIST.add(Material.TRAPPED_CHEST); + BLACKLIST.add(Material.ENDER_CHEST); + BLACKLIST.add(Material.BARREL); + BLACKLIST.add(Material.FURNACE); + BLACKLIST.add(Material.BLAST_FURNACE); + BLACKLIST.add(Material.SMOKER); + BLACKLIST.add(Material.BREWING_STAND); + BLACKLIST.add(Material.LECTERN); + BLACKLIST.add(Material.COMPOSTER); + BLACKLIST.add(Material.BEEHIVE); + BLACKLIST.add(Material.BEE_NEST); + + // --- 5. ТЕХНИЧЕСКИЕ И ПРОЗРАЧНЫЕ --- + BLACKLIST.add(Material.BARRIER); + BLACKLIST.add(Material.STRUCTURE_VOID); + BLACKLIST.add(Material.STRUCTURE_BLOCK); + BLACKLIST.add(Material.JIGSAW); + BLACKLIST.add(Material.LIGHT); + BLACKLIST.add(Material.SPAWNER); + BLACKLIST.add(Material.COBWEB); + BLACKLIST.add(Material.SLIME_BLOCK); // Спорно, но липкий + BLACKLIST.add(Material.HONEY_BLOCK); + + // --- 6. ЗАЧИСТКА ПО ИМЕНАМ (На всякий случай) --- + // Добавляем все, что мы могли забыть, но что имеет общие корни + for (Material m : Material.values()) { + String name = m.name(); + if (name.contains("POTTED") || // Горшки с цветами + name.contains("WALL_") || // Настенные варианты (факелы, знаки) + name.contains("HEAD") || // Головы + name.contains("SKULL") || // Черепа + name.contains("BANNER") || // Флаги (дублируем для надежности) + name.contains("CORAL") // Кораллы (дохнут без воды) + ) { + BLACKLIST.add(m); + } + } + } + + // Твой метод проверки стал очень простым + private static boolean isSupported(Material type) { + // 1. Воздух + if (type.isAir()) return false; + + // 2. Черный список (самая надежная проверка) + if (BLACKLIST.contains(type)) { return false; } - if (data instanceof Powerable - || data instanceof Openable - || data instanceof AnaloguePowerable) { - return false; - } - - return switch (type) { - case CACTUS, FARMLAND, - TNT, DISPENSER, DROPPER, HOPPER, - PISTON, STICKY_PISTON, OBSERVER, - COMMAND_BLOCK, REPEATING_COMMAND_BLOCK, - CHAIN_COMMAND_BLOCK, - SCULK_SENSOR, SCULK_SHRIEKER, - DAYLIGHT_DETECTOR, JUKEBOX, - TURTLE_EGG, DRAGON_EGG, - BAMBOO, BAMBOO_SAPLING, - CAKE, LECTERN, COMPOSTER, - CAMPFIRE, SOUL_CAMPFIRE, - BEEHIVE, BEE_NEST - -> false; - default -> true; - }; + // 3. Дополнительная защита: блок должен быть твердым + // (Это отсечет то, что мы могли случайно забыть в списке, типа нитки/String) + return type.isSolid(); } public static void getSortedBlockStats(Location center, int chunkRadius, Consumer>> callback) { @@ -81,11 +222,10 @@ public class BlocksGenerator { for (int z = 0; z < 16; z++) { for (int y = minH; y < maxH; y++) { - BlockData data = snap.getBlockData(x, y, z); Material type = data.getMaterial(); - if (isSupported(type, data)) { + if (isSupported(type)) { counts.put(type, counts.getOrDefault(type, 0L) + 1); } } @@ -93,12 +233,9 @@ public class BlocksGenerator { } } - List> sortedList = new ArrayList<>(counts.entrySet()); sortedList.sort(Map.Entry.comparingByValue()); - - new BukkitRunnable() { @Override public void run() { @@ -109,5 +246,21 @@ public class BlocksGenerator { }.runTaskAsynchronously(BlockAndSeek.getInstance()); } + public static void addCache(String key, List propBlocks) { + cached.put(key, propBlocks); + } + + @Nullable + public static List get(String key) { + return cached.get(key); + } + + private static final ThreadLocalRandom random = ThreadLocalRandom.current(); + + @Nullable + public static PropBlock getRandom(String key) { + List propBlocks = get(key); + return propBlocks == null ? null : propBlocks.get(random.nextInt(0, propBlocks.size())); + } } diff --git a/src/main/java/hdvtdev/blockandseek/CommandBuilder.java b/src/main/java/hdvtdev/blockandseek/CommandBuilder.java index faddced..47eb8ba 100644 --- a/src/main/java/hdvtdev/blockandseek/CommandBuilder.java +++ b/src/main/java/hdvtdev/blockandseek/CommandBuilder.java @@ -1,4 +1,4 @@ -package hdvtdev.blockAndSeek; +package hdvtdev.blockandseek; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/hdvtdev/blockandseek/CommandListener.java b/src/main/java/hdvtdev/blockandseek/CommandListener.java deleted file mode 100644 index b705253..0000000 --- a/src/main/java/hdvtdev/blockandseek/CommandListener.java +++ /dev/null @@ -1,21 +0,0 @@ -package hdvtdev.blockAndSeek; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public class CommandListener implements TabExecutor { - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - return false; - } - - @Override - public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - return List.of(); - } -} diff --git a/src/main/java/hdvtdev/blockandseek/Config.java b/src/main/java/hdvtdev/blockandseek/Config.java index c2ad2f6..95f6790 100644 --- a/src/main/java/hdvtdev/blockandseek/Config.java +++ b/src/main/java/hdvtdev/blockandseek/Config.java @@ -1,4 +1,4 @@ -package hdvtdev.blockAndSeek; +package hdvtdev.blockandseek; import eu.okaeri.configs.ConfigManager; import eu.okaeri.configs.OkaeriConfig; @@ -8,22 +8,43 @@ import eu.okaeri.configs.serdes.commons.SerdesCommons; import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer; import eu.okaeri.configs.yaml.bukkit.serdes.SerdesBukkit; - import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.WorldCreator; import java.io.File; import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; public class Config extends OkaeriConfig { @Exclude - private static final AtomicReference config = new AtomicReference<>(new Config()); + private static Config config; + + static { + try { + File configFile = new File(BlockAndSeek.getPluginDataFolder(), "config.yml"); + if (!configFile.exists()) configFile.createNewFile(); + config = ConfigManager.create(Config.class, (it) -> { + it.withConfigurer( + new YamlBukkitConfigurer(), + new SerdesBukkit(), + new SerdesCommons() + ); + it.withBindFile(configFile); + it.withLogger(BlockAndSeek.getPluginLogger()); + it.saveDefaults(); + }); + + config.load(); + config.save(); + } catch (Exception e) { + BlockAndSeek.getPluginLogger().severe("Failed to load config.yml: " + e.getMessage()); + e.printStackTrace(); + } + } @Comment("Server options.") - private Server server = new Server(false); + private ServerSettings serverSettings = new ServerSettings(); @Comment("Spawn location. Useless if the Server.forceControl is false.") private Location spawn = Objects.requireNonNull(Bukkit.createWorld(new WorldCreator("world"))).getSpawnLocation(); @Comment("Show hidden BlockAndSeek commands.") @@ -31,50 +52,23 @@ public class Config extends OkaeriConfig { public static boolean debugEnabled() { - return config.get().enableDebugCommands; + return config.enableDebugCommands; } public static boolean forceControl() { - return config.get().server.forceControl; + return config.serverSettings.forceControl; } public static Location spawn() { - return config.get().spawn; + return config.spawn; } - - public static boolean loadConfig() { - try { - Config conf = ConfigManager.create(Config.class, (it) -> { - it.withConfigurer( - new YamlBukkitConfigurer(), - new SerdesBukkit(), - new SerdesCommons() - ); - it.withBindFile(new File(BlockAndSeek.getPluginDataFolder(), "config.yml")); - it.withLogger(BlockAndSeek.getPluginLogger()); - it.saveDefaults(); - }); - - config.setRelease(conf); - } catch (Exception e) { - BlockAndSeek.getPluginLogger().severe("Failed to load config.yml: " + e.getMessage()); - return false; - } - return true; + public static String toStaticString() { + return String.format("BlockAndSeekConfig[forceControl = %s, spawn = %s, enableDebugCommands = %s]", forceControl(), spawn(), debugEnabled()); } - private static class Server { - + private static class ServerSettings extends OkaeriConfig { private boolean forceControl = false; - - public Server(boolean forceControl) { - this.forceControl = forceControl; - } - - public boolean isForceControl() { - return forceControl; - } } } diff --git a/src/main/java/hdvtdev/blockandseek/GuiHolder.java b/src/main/java/hdvtdev/blockandseek/GuiHolder.java index 0ed8a59..a8d3ca8 100644 --- a/src/main/java/hdvtdev/blockandseek/GuiHolder.java +++ b/src/main/java/hdvtdev/blockandseek/GuiHolder.java @@ -1,4 +1,4 @@ -package hdvtdev.blockAndSeek; +package hdvtdev.blockandseek; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; diff --git a/src/main/java/hdvtdev/blockandseek/Keys.java b/src/main/java/hdvtdev/blockandseek/Keys.java index 32748a7..ad60870 100644 --- a/src/main/java/hdvtdev/blockandseek/Keys.java +++ b/src/main/java/hdvtdev/blockandseek/Keys.java @@ -1,4 +1,4 @@ -package hdvtdev.blockAndSeek; +package hdvtdev.blockandseek; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; @@ -8,21 +8,11 @@ import org.bukkit.scoreboard.Team; public class Keys { public static final NamespacedKey SOUND_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekSoundItem"); + public static final NamespacedKey DASH_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekDashItem"); public static final NamespacedKey FREEZE_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFreezeItem"); public static final NamespacedKey FACE_CHANGING_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFaceChangingItem"); public static final NamespacedKey MENU_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekMenuItem"); public static final NamespacedKey LEAVE_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekLeaveItem"); - public static final NamespacedKey GAME_PAGE = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekGamePage"); - - public static final NamespacedKey FROZEN_PLAYER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFrozenPlayer"); - public static final NamespacedKey GAME = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekGame"); - - public static final NamespacedKey HIDER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekHider"); - public static final NamespacedKey SEEKER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekSeeker"); - - public static final NamespacedKey LANG_KEY = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekLangKey"); - - public static final Team NO_COLLIDE_TEAM; @@ -32,7 +22,5 @@ public class Keys { if (team == null) team = scoreboard.registerNewTeam("BlockAndSeekNoCollide"); team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER); NO_COLLIDE_TEAM = team; - - } } diff --git a/src/main/java/hdvtdev/blockandseek/Localization.java b/src/main/java/hdvtdev/blockandseek/Localization.java deleted file mode 100644 index b4a9b84..0000000 --- a/src/main/java/hdvtdev/blockandseek/Localization.java +++ /dev/null @@ -1,83 +0,0 @@ -package hdvtdev.blockAndSeek; - - - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; - -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -public final class Localization { - - private Localization() {} - - private static final String defaultLanguage = "en_US"; - private static final MiniMessage mm = MiniMessage.miniMessage(); - - private static final AtomicReference>> translations = new AtomicReference<>(); - - public static Component get(Player player, String key, String... placeholders) { - return get(player.locale().toString(), key, placeholders); - } - - public static Component get(String lang, String key, String... placeholders) { - String raw = translations.get().get(lang).getOrDefault(key, "?" + key + "?"); - if (placeholders.length % 2 == 0) { - for (int i = 0; i < placeholders.length; i++) { - raw = raw.replace(placeholders[i], placeholders[++i]); - } - } else BlockAndSeek.getPluginLogger().warning("Wrong amount of placeholders for key: " + key); - - return mm.deserialize(raw); - } - - public static ItemStack translateItem(Player player, ItemStack itemStack, String key) { - ItemMeta itemMeta = itemStack.getItemMeta(); - itemMeta.displayName(get(player, key)); - itemStack.setItemMeta(itemMeta); - return itemStack; - } - - public static boolean loadTranslations() { - /* - Path path = BlockAndSeek.getPluginDataFolder().toPath().resolve("translations"); - if (Files.notExists(path)) { - try { - Files.createDirectories(path); - } catch (IOException e) { - BlockAndSeek.getPluginLogger().severe("Failed to create \"translations\" dir: " + e); - return false; - } - } - - File[] files = path.toFile().listFiles(); - if (files != null) { - for (File file : files) { - String lang = file.getName().split(".toml")[0]; - Map translation = new HashMap<>(); - for (Map.Entry entry : new Toml().read(file).entrySet()) { - translation.put(entry.getKey(), entry.getValue().toString()); - } - translations.get().put(lang, translation); - } - } else { - BlockAndSeek.getPluginLogger().severe("Failed to load translations! " + path + " returned null."); - } - - - */ - - return true; - } - -} diff --git a/src/main/java/hdvtdev/blockandseek/Utils.java b/src/main/java/hdvtdev/blockandseek/Utils.java index 88996a1..0073fad 100644 --- a/src/main/java/hdvtdev/blockandseek/Utils.java +++ b/src/main/java/hdvtdev/blockandseek/Utils.java @@ -1,20 +1,12 @@ -package hdvtdev.blockAndSeek; +package hdvtdev.blockandseek; import me.libraryaddict.disguise.DisguiseAPI; -import me.libraryaddict.disguise.disguisetypes.Disguise; -import me.libraryaddict.disguise.disguisetypes.DisguiseType; -import me.libraryaddict.disguise.disguisetypes.MiscDisguise; - -import me.libraryaddict.disguise.disguisetypes.watchers.FallingBlockWatcher; -import org.bukkit.Bukkit; -import org.bukkit.block.data.BlockData; +import org.bukkit.GameMode; +import org.bukkit.attribute.Attribute; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; -import org.jetbrains.annotations.Nullable; - -import java.io.File; +import org.bukkit.potion.PotionEffect; public final class Utils { @@ -26,26 +18,38 @@ public final class Utils { p.setExp(0.9998f * ((float) level / 100)); } - public static boolean isInOneTeam(Player p1, Player p2) { - var c1 = p1.getPersistentDataContainer(); - var c2 = p2.getPersistentDataContainer(); - return (c1.has(Keys.HIDER) && c2.has(Keys.HIDER)) || (c1.has(Keys.SEEKER) && c2.has(Keys.SEEKER)); - } + public static void clearPlayer(Player player) { - public static boolean playerInGame(Player player) { - return player.getPersistentDataContainer().has(Keys.GAME); - } + DisguiseAPI.undisguiseToAll(player); - public static boolean hasPermsToDamage(Player p1, Player p2) { - PersistentDataContainer c1 = p1.getPersistentDataContainer(); - PersistentDataContainer c2 = p2.getPersistentDataContainer(); - return (c1.has(Keys.SEEKER) || c1.has(Keys.HIDER)) && (c2.has(Keys.SEEKER) || c2.has(Keys.HIDER)); - } + player.getInventory().clear(); + player.getInventory().setArmorContents(null); + player.getInventory().setExtraContents(null); + + + player.setGameMode(GameMode.SURVIVAL); + + if (player.getAttribute(Attribute.GENERIC_MAX_HEALTH) != null) { + player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(20.0); + } + player.setHealth(20.0); + + player.setFoodLevel(20); + player.setSaturation(5.0f); + player.setExhaustion(0f); + player.setInvulnerable(false); + player.setLevel(0); + player.setExp(0f); + player.setFireTicks(0); + player.setFallDistance(0f); + player.setWalkSpeed(0.2f); + player.setFlySpeed(0.1f); + player.setAllowFlight(false); + player.setFlying(false); + player.setGliding(false); + player.setGlowing(false); + player.closeInventory(); - public static void clearPlayer(Player p) { - PersistentDataContainer container = p.getPersistentDataContainer(); - container.remove(Keys.SEEKER); - container.remove(Keys.HIDER); } diff --git a/src/main/java/hdvtdev/blockandseek/eventListeners/EventListener.java b/src/main/java/hdvtdev/blockandseek/eventListeners/EventListener.java index 3040b8c..04bab96 100644 --- a/src/main/java/hdvtdev/blockandseek/eventListeners/EventListener.java +++ b/src/main/java/hdvtdev/blockandseek/eventListeners/EventListener.java @@ -1,7 +1,7 @@ -package hdvtdev.blockAndSeek.eventListeners; +package hdvtdev.blockandseek.eventListeners; -import hdvtdev.blockAndSeek.Keys; -import hdvtdev.blockAndSeek.Utils; +import hdvtdev.blockandseek.Keys; +import hdvtdev.blockandseek.Utils; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -14,25 +14,22 @@ public class EventListener implements Listener { @EventHandler public void onDrop(PlayerDropItemEvent event) { - if (event.getPlayer().getPersistentDataContainer().has(Keys.GAME)) event.setCancelled(true); + } @EventHandler public void onFoodLevelChange(FoodLevelChangeEvent event) { - if (event.getEntity() instanceof Player player && Utils.playerInGame(player)) { - event.setCancelled(true); - event.getEntity().setFoodLevel(20); - } + } @EventHandler public void onBlockPlacement(BlockPlaceEvent event) { - if (event.getPlayer().getPersistentDataContainer().has(Keys.GAME)) event.setCancelled(true); + } @EventHandler public void onBlockBreak(BlockBreakEvent event) { - if (event.getPlayer().getPersistentDataContainer().has(Keys.GAME)) event.setCancelled(true); + } diff --git a/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java b/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java index ef550df..0eb6c8f 100644 --- a/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java +++ b/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java @@ -1,9 +1,11 @@ -package hdvtdev.blockAndSeek.eventListeners; +package hdvtdev.blockandseek.eventListeners; -import hdvtdev.blockAndSeek.Utils; -import hdvtdev.blockAndSeek.managers.ItemManager; +import hdvtdev.blockandseek.Config; +import hdvtdev.blockandseek.Utils; +import hdvtdev.blockandseek.managers.ItemManager; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; @@ -21,6 +23,9 @@ public class ForceControlEventListener implements Listener { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); + player.teleport(Config.spawn()); + Utils.clearPlayer(player); + player.setInvulnerable(true); ItemManager.defaultInventory(player); } @@ -34,17 +39,17 @@ public class ForceControlEventListener implements Listener { if (event.getSkipReason() != TimeSkipEvent.SkipReason.COMMAND) event.setCancelled(true); } - @EventHandler + @EventHandler(ignoreCancelled = true) public void onBlockPlacement(BlockPlaceEvent event) { event.setCancelled(true); } - @EventHandler + @EventHandler(ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent event) { event.setCancelled(true); } - @EventHandler + @EventHandler(ignoreCancelled = true) public void onFoodLevelChange(FoodLevelChangeEvent event) { if (event.getEntity() instanceof Player player) { event.setCancelled(true); @@ -52,22 +57,12 @@ public class ForceControlEventListener implements Listener { } } - @EventHandler + @EventHandler(ignoreCancelled = true) public void onDrop(PlayerDropItemEvent event) { event.setCancelled(true); } - @EventHandler - public void onPlayerDamage(EntityDamageByEntityEvent event) { - - if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) { - if (!Utils.hasPermsToDamage(damager, victim)) { - event.setCancelled(true); - } - } - } - - @EventHandler + @EventHandler(ignoreCancelled = true) public void onFallDamage(EntityDamageEvent e) { if (e.getEntity() instanceof Player) { if (e.getCause() == EntityDamageEvent.DamageCause.FALL) { diff --git a/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java b/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java index 7c36a9b..c8218f7 100644 --- a/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java +++ b/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java @@ -1,8 +1,15 @@ -package hdvtdev.blockAndSeek.eventListeners; +package hdvtdev.blockandseek.eventListeners; -import hdvtdev.blockAndSeek.Keys; -import hdvtdev.blockAndSeek.Utils; -import hdvtdev.blockAndSeek.GuiHolder; +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.Keys; +import hdvtdev.blockandseek.Utils; +import hdvtdev.blockandseek.GuiHolder; +import hdvtdev.blockandseek.managers.PropManager; + +import hdvtdev.blockandseek.menus.GamesMenu; +import net.kyori.adventure.text.Component; + +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -16,10 +23,17 @@ import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.ServerLoadEvent; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.scheduler.BukkitRunnable; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; -import static hdvtdev.blockAndSeek.Utils.isInOneTeam; public class RequiredEventListener implements Listener { @@ -34,9 +48,36 @@ public class RequiredEventListener implements Listener { } + //todo remove + private final PropManager propManager = new PropManager(); + private final Set coolDown = new HashSet<>(); + @EventHandler public void onRightClick(PlayerInteractEvent event) { if (event.getHand() != EquipmentSlot.HAND) return; + if (event.getAction().isLeftClick()) return; + + Player player = event.getPlayer(); + UUID uuid = player.getUniqueId(); + + ItemStack item = event.getItem(); + if (item != null) { + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + PersistentDataContainer dataContainer = meta.getPersistentDataContainer(); + if (dataContainer.has(Keys.MENU_ITEM)) { + new GamesMenu(player); + event.setCancelled(true); + } + + } + + } + + + + + } @@ -78,21 +119,7 @@ public class RequiredEventListener implements Listener { @EventHandler public void onPlayerDamage(EntityDamageByEntityEvent event) { - if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) { - if (isInOneTeam(damager, victim)) { - event.setCancelled(true); - } else if (victim.getPersistentDataContainer().has(Keys.SEEKER)) { - event.setDamage(0); - } else if (damager.getPersistentDataContainer().has(Keys.SEEKER)) { - double maxHealth = 20.0; - double currentHealth = damager.getHealth(); - if (currentHealth < maxHealth) { - double newHealth = Math.min(currentHealth + event.getDamage(), maxHealth); - damager.setHealth(newHealth); - Utils.setLevelWithBar(damager, (int) Math.round(damager.getHealth() * 5)); - } - } - } + } } diff --git a/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java b/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java index fa700e8..301597d 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java @@ -1,35 +1,40 @@ -package hdvtdev.blockAndSeek.managers; +package hdvtdev.blockandseek.managers; -import hdvtdev.blockAndSeek.objects.BlockAndSeekGame; -import org.bukkit.Bukkit; -import org.bukkit.WorldCreator; +import hdvtdev.blockandseek.objects.BlockAndSeekGame; + +import hdvtdev.blockandseek.objects.BlockAndSeekMap; import org.bukkit.entity.Player; + import org.jetbrains.annotations.Nullable; -import java.io.File; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import java.util.*; + public class GamesManager { - private static final ConcurrentHashMap games = new ConcurrentHashMap<>(); - private static final Set seekerImmune = ConcurrentHashMap.newKeySet(); + private static final Map games = new HashMap<>(); + private static final Set seekerImmune = new HashSet<>(); - public static boolean triggerSeekerImmune(Player player) { - return seekerImmune.remove(player); + public static boolean triggerSeekerImmune(UUID uuid) { + return seekerImmune.remove(uuid); } public static void addSeekerImmune(Player player) { - seekerImmune.add(player); + seekerImmune.add(player.getUniqueId()); } public static Set getAvailableGames() { return games.keySet(); } - public static @Nullable String createGame(String name) { - if (games.containsKey(name)) return name; //TODO use copy or create copy + public static @Nullable BlockAndSeekGame createGame(String name) { + BlockAndSeekMap map = MapsManager.getMap(name); + if (map != null) { + BlockAndSeekGame game = new BlockAndSeekGame(name, map); + games.put(name, game); + return game; + } return null; } diff --git a/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java b/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java index 734177f..9b34aba 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java @@ -1,7 +1,8 @@ -package hdvtdev.blockAndSeek.managers; +package hdvtdev.blockandseek.managers; -import hdvtdev.blockAndSeek.Keys; -import hdvtdev.blockAndSeek.Localization; +import hdvtdev.blockandseek.Keys; +import hdvtdev.blockandseek.objects.TranslationKey; +import lombok.Getter; import net.kyori.adventure.text.Component; import org.bukkit.Color; import org.bukkit.Material; @@ -14,10 +15,19 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; import org.bukkit.persistence.PersistentDataType; +import static hdvtdev.blockandseek.objects.TranslationKey.*; + public class ItemManager { + @Getter private static final ItemStack freezeItem = new ItemStack(Material.HEART_OF_THE_SEA); + @Getter private static final ItemStack faceChangingItem = new ItemStack(Material.NETHER_STAR); + @Getter + private static final ItemStack dashItem = new ItemStack(Material.LAPIS_LAZULI); + @Getter + private static final ItemStack soundItem = new ItemStack(Material.BROWN_DYE); + private static final ItemStack seekerSword = new ItemStack(Material.WOODEN_SWORD); private static final ItemStack seekerHelmet = new ItemStack(Material.LEATHER_HELMET); @@ -25,9 +35,13 @@ public class ItemManager { private static final ItemStack seekerLeggings = new ItemStack(Material.LEATHER_LEGGINGS); private static final ItemStack seekerBoots = new ItemStack(Material.LEATHER_BOOTS); + @Getter private static final ItemStack menuItem = new ItemStack(Material.COMPASS); + @Getter private static final ItemStack games = new ItemStack(Material.BOOKSHELF); + @Getter private static final ItemStack createGameButton = new ItemStack(Material.SLIME_BALL); + @Getter private static final ItemStack leaveItem = new ItemStack(Material.RED_DYE); @@ -53,8 +67,19 @@ public class ItemManager { menuMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); menuItem.setItemMeta(menuMeta); + ItemMeta dashMeta = dashItem.getItemMeta(); + dashMeta.getPersistentDataContainer().set(Keys.DASH_ITEM, PersistentDataType.BOOLEAN, true); + dashMeta.addEnchant(Enchantment.ARROW_INFINITE, 1, true); + dashMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + dashItem.setItemMeta(dashMeta); + + ItemMeta soundMeta = soundItem.getItemMeta(); + soundMeta.getPersistentDataContainer().set(Keys.SOUND_ITEM, PersistentDataType.BOOLEAN, true); + soundMeta.addEnchant(Enchantment.ARROW_INFINITE, 1, true); + soundMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + soundItem.setItemMeta(soundMeta); + ItemMeta gamesMeta = games.getItemMeta(); - gamesMeta.getPersistentDataContainer().set(Keys.GAME_PAGE, PersistentDataType.BOOLEAN, true); games.setItemMeta(gamesMeta); ItemMeta leaveMeta = leaveItem.getItemMeta(); @@ -75,12 +100,12 @@ public class ItemManager { public static void setSeekerSet(Player seeker) { PlayerInventory inventory = seeker.getInventory(); inventory.clear(); - inventory.addItem(Localization.translateItem(seeker, seekerSword, "seeker_sword")); + inventory.addItem(TranslationManager.translateItem(seeker, seekerSword, TranslationKey.SEEKER_TEMPLATE)); ItemStack[] armor = new ItemStack[]{ - Localization.translateItem(seeker, seekerBoots, "seeker_boots"), - Localization.translateItem(seeker, seekerLeggings, "seeker_leggings"), - Localization.translateItem(seeker, seekerChestplate, "seeker_chestplate"), - Localization.translateItem(seeker, seekerHelmet, "seeker_helmet") + TranslationManager.translateItem(seeker, seekerBoots, TranslationKey.SEEKER_TEMPLATE), + TranslationManager.translateItem(seeker, seekerLeggings, TranslationKey.SEEKER_TEMPLATE), + TranslationManager.translateItem(seeker, seekerChestplate, TranslationKey.SEEKER_TEMPLATE), + TranslationManager.translateItem(seeker, seekerHelmet, TranslationKey.SEEKER_TEMPLATE) }; inventory.setArmorContents(armor); @@ -94,7 +119,6 @@ public class ItemManager { meta.setUnbreakable(true); meta.addEnchant(Enchantment.PROTECTION_ENVIRONMENTAL, 10, true); meta.addEnchant(Enchantment.THORNS, 3, true); - meta.displayName(Component.text("seeker-armor")); return meta; } @@ -102,32 +126,25 @@ public class ItemManager { public static void defaultInventory(Player player) { PlayerInventory inventory = player.getInventory(); inventory.clear(); - inventory.addItem(Localization.translateItem(player, menuItem, "menu_item")); + inventory.addItem(TranslationManager.translateItem(player, menuItem, TranslationKey.MENU)); + } + + public static void hiderInventory(Player player) { + PlayerInventory playerInventory = player.getInventory(); + playerInventory.clear(); + playerInventory.addItem( + TranslationManager.translateItem(player, freezeItem, FREEZE_ITEM), + TranslationManager.translateItem(player, faceChangingItem, FACE_CHANGING_ITEM), + TranslationManager.translateItem(player, soundItem, SOUND_ITEM), + TranslationManager.translateItem(player, dashItem, DASH_ITEM) + ); } public static void giveFaceChangingItem(Player player) { - player.getInventory().addItem(Localization.translateItem(player, faceChangingItem, "face_changing_item")); + player.getInventory().addItem(TranslationManager.translateItem(player, faceChangingItem, TranslationKey.SEEKER_TEMPLATE)); } - public static ItemStack getLeaveItem() { - return leaveItem; - } - public static ItemStack getCreateGameButton() { - return createGameButton; - } - - public static ItemStack getGamesPageItem() { - return games; - } - - public static ItemStack getMenuItem() { - return menuItem; - } - - public static ItemStack getFreezeItem() { - return freezeItem; - } } diff --git a/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java b/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java index fb3bc4f..8b2dd98 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java @@ -1,54 +1,135 @@ -package hdvtdev.blockAndSeek.managers; +package hdvtdev.blockandseek.managers; +import eu.okaeri.configs.ConfigManager; +import eu.okaeri.configs.serdes.commons.SerdesCommons; +import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer; +import eu.okaeri.configs.yaml.bukkit.serdes.SerdesBukkit; +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.objects.BlockAndSeekMap; import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.WorldCreator; import org.bukkit.command.CommandSender; - import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; import java.io.File; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; public final class MapsManager { - private MapsManager() { + private static final Map maps = new HashMap<>(); + private static final File MAPS_DIR = new File(BlockAndSeek.getPluginDataFolder(), "maps"); + + private MapsManager() {} + + public static void loadMaps() { + if (!MAPS_DIR.exists()) { + MAPS_DIR.mkdirs(); + } + + File[] files = MAPS_DIR.listFiles((dir, name) -> name.endsWith(".yml")); + if (files == null) return; + + for (File file : files) { + String name = file.getName().replace(".yml", ""); + try { + BlockAndSeekMap map = loadConfig(file); + maps.put(name, map); + } catch (Exception e) { + BlockAndSeek.getPluginLogger().severe("Error loading map " + name + ": " + e.getMessage()); + e.printStackTrace(); + } + } + BlockAndSeek.getPluginLogger().info("Loaded " + maps.size() + " maps."); } + public static BlockAndSeekMap getMap(String name) { + return maps.get(name); + } + + public static Collection getMaps() { + return maps.values(); + } + + public static void createMap(String name) { + File mapFile = new File(MAPS_DIR, name + ".yml"); + if (mapFile.exists()) { + throw new IllegalArgumentException("Map already exists!"); + } + + BlockAndSeekMap map = loadConfig(mapFile); + + map.setWorld(name); + + if (Bukkit.getWorld(name) != null) { + Location spawn = Bukkit.getWorld(name).getSpawnLocation(); + map.setLobby(spawn); + map.setSpawn(spawn); + } + + map.save(); + maps.put(name, map); + } + + private static BlockAndSeekMap loadConfig(File file) { + var map = ConfigManager.create(BlockAndSeekMap.class, (it) -> { + it.withConfigurer( + new YamlBukkitConfigurer(), + new SerdesBukkit(), + new SerdesCommons() + ); + it.withBindFile(file); + it.withLogger(BlockAndSeek.getPluginLogger()); + it.load(true); + }); + + String worldName = map.getWorld(); + if (worldName == null) { + BlockAndSeek.getPluginLogger().warning("Map " + file.getName() + " has no world defined!"); + return map; + } + + World world = Bukkit.getWorld(worldName); + + if (world == null) { + File worldFolder = new File(Bukkit.getWorldContainer(), worldName); + if (worldFolder.exists() && worldFolder.isDirectory()) { + BlockAndSeek.getPluginLogger().info("World '" + worldName + "' is not loaded. Loading now..."); + world = Bukkit.createWorld(new WorldCreator(worldName)); + } + } + + map.getLobby().setWorld(world); + map.getSpawn().setWorld(world); + + map.save(); + + return map; + } + + // --- Suggestions --- + public static SuggestionProvider worldSuggestions = (context, input) -> CompletableFuture.supplyAsync(() -> { - List suggestions = new ArrayList<>(); - + // Лучше брать загруженные миры Bukkit, если карта должна быть в активном мире + // Если нужны папки миров: File container = Bukkit.getWorldContainer(); + File[] files = container.listFiles((dir, name) -> new File(dir, name + "/level.dat").exists()); - File[] files = container.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory() && new File(file, "level.dat").exists()) { - suggestions.add(Suggestion.suggestion(file.getName())); - } - } - } - return suggestions; + if (files == null) return Collections.emptyList(); + + return Arrays.stream(files) + .map(File::getName) + .map(Suggestion::suggestion) + .collect(Collectors.toList()); }); public static SuggestionProvider mapSuggestions = (context, input) -> - CompletableFuture.supplyAsync(() -> { - List suggestions = new ArrayList<>(); - - File container = new File(Bukkit.getPluginsFolder(), "maps"); - - File[] files = container.listFiles(); - if (files != null) { - for (File file : files) { - String name = file.getName(); - if (file.isFile() && name.endsWith(".toml")) { - suggestions.add(Suggestion.suggestion(name.replace(".toml", ""))); //baddd - } - } - } - - return suggestions; - }); -} + CompletableFuture.supplyAsync(() -> maps.keySet().stream() + .map(Suggestion::suggestion) + .collect(Collectors.toList())); +} \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockandseek/managers/PropManager.java b/src/main/java/hdvtdev/blockandseek/managers/PropManager.java index dd3ac35..22fdc05 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/PropManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/PropManager.java @@ -1,20 +1,23 @@ -package hdvtdev.blockAndSeek.managers; +package hdvtdev.blockandseek.managers; -import hdvtdev.blockAndSeek.BlockAndSeek; +import hdvtdev.blockandseek.BlockAndSeek; import me.libraryaddict.disguise.DisguiseAPI; import me.libraryaddict.disguise.disguisetypes.Disguise; import me.libraryaddict.disguise.disguisetypes.DisguiseType; import me.libraryaddict.disguise.disguisetypes.MiscDisguise; import me.libraryaddict.disguise.disguisetypes.watchers.FallingBlockWatcher; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Openable; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.EntityType; -import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -24,30 +27,105 @@ import java.util.UUID; public final class PropManager { private final Map players = new HashMap<>(); + private final Map props = new HashMap<>(); + public void removePlayer(Player player) { + + } + + public boolean isProped(UUID uuid) { + return props.containsValue(uuid); + } + + public void forceUnfreeze(Player player) { + if (players.containsKey(player.getUniqueId())) { + freezeOrUnfreeze(player); + } + } + + public void forceUnfreeze(UUID uuid) { + if (players.containsKey(uuid)) { + freezeOrUnfreeze(Bukkit.getPlayer(uuid)); + } + } + + @Nullable + public UUID getProp(Location location) { + return props.remove(location); + } + + + //fixme: replace body with freezeOrUnfreeze(Player player) body + /* + public PropState freezeOrUnfreeze(UUID uuid) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + return freezeOrUnfreeze(player); + } + return PropState.FAILED; + } + + */ + + //i dont know how dis works xd public PropState freezeOrUnfreeze(Player player) { UUID uuid = player.getUniqueId(); PropData propData = players.remove(uuid); - Location location = player.getLocation(); - - Block originalBlock = location.getBlock(); + Location location = player.getLocation().toCenterLocation(); if (propData != null) { + ArmorStand armorStand = propData.armorStand; + location.getWorld().setBlockData(location, propData.blockData); + location.setY(Math.floor(location.getY())); + player.setInvulnerable(false); + armorStand.removePassenger(player); + armorStand.remove(); - originalBlock.setBlockData(propData.blockData); + return PropState.UNFROZEN; } else { - BlockData originalBlockData = originalBlock.getBlockData(); - BlockData disguiseBlockData = getPlayerDisguiseData(player); + Block block = location.getBlock(); + BlockData blockData = block.getBlockData(); + + Location blockLocation = block.getLocation(); + Location centerLocation = blockLocation.toCenterLocation(); + Location upperBlockLocation = centerLocation.clone(); + upperBlockLocation.setY(upperBlockLocation.getY() + 1); + + if (!upperBlockLocation.getBlock().isSolid() && !blockLocation.getBlock().isSolid()) { + props.put(blockLocation, uuid); + + BlockData disguiseBlockData = getPlayerDisguiseData(player); + location.getWorld().setBlockData(blockLocation, disguiseBlockData == null ? Material.TARGET.createBlockData() : disguiseBlockData); + centerLocation.setY(centerLocation.getY() - 0.85); + + player.setInvulnerable(true); + player.setFreezeTicks(40); + + ArmorStand armorStand = location.getWorld().spawn(centerLocation, ArmorStand.class, stand -> { + stand.setVisible(false); + stand.setVisible(false); + stand.setCollidable(false); + stand.setGravity(true); + stand.setSmall(true); + stand.setCanMove(false); + stand.addPassenger(player); + stand.setInvulnerable(true); + }); + + players.put(uuid, new PropData(armorStand, blockData)); + return PropState.FROZEN; + } - players.put(uuid, new PropData(null, originalBlockData, null)); } + + return PropState.FAILED; } @@ -68,7 +146,7 @@ public final class PropManager { FAILED } - private record PropData(ArmorStand armorStand, BlockData blockData, Disguise disguise) { + private record PropData(ArmorStand armorStand, BlockData blockData) { } diff --git a/src/main/java/hdvtdev/blockandseek/managers/StateManager.java b/src/main/java/hdvtdev/blockandseek/managers/StateManager.java index 7334176..ee0917a 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/StateManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/StateManager.java @@ -1,6 +1,6 @@ -package hdvtdev.blockAndSeek.managers; +package hdvtdev.blockandseek.managers; -import hdvtdev.blockAndSeek.objects.BlockAndSeekGame; +import hdvtdev.blockandseek.objects.BlockAndSeekGame; import java.util.*; @@ -26,6 +26,14 @@ public class StateManager { stateToPlayers.computeIfAbsent(newState, k -> new HashSet<>()).add(uuid); } + public Set getPlayers() { + return playerToState.keySet(); + } + + public boolean hasPlayer(UUID uuid) { + return playerToState.containsKey(uuid); + } + public int playerCount() { return playerToState.size(); } diff --git a/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java b/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java new file mode 100644 index 0000000..b71dfc4 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java @@ -0,0 +1,94 @@ +package hdvtdev.blockandseek.managers; + + + +import eu.okaeri.configs.ConfigManager; +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.annotation.Exclude; +import eu.okaeri.configs.serdes.commons.SerdesCommons; +import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer; +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.objects.Translation; +import hdvtdev.blockandseek.objects.TranslationKey; +import lombok.Getter; +import lombok.Setter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; + +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.io.File; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +public final class TranslationManager { + + private TranslationManager() {} + + public static final String defaultLanguage = "en_US"; + public static final MiniMessage mm = MiniMessage.miniMessage(); + public static final PlainTextComponentSerializer plaintText = PlainTextComponentSerializer.plainText(); + + public static final String prefix = "BlockAndSeek »"; + public static final String bracedPrefix = "[BlockAndSeek]"; + + private static final Map> translations = new HashMap<>(); + + public static Component get(Player player, TranslationKey key, String... placeholders) { + return get(player.locale().toString(), key, placeholders); + } + + public static Component get(String lang, TranslationKey key, String... placeholders) { + String raw = translations.getOrDefault(lang, translations.get(defaultLanguage)).getOrDefault(key, "?" + key.toString() + "?"); + if (placeholders.length % 2 == 0) { + for (int i = 0; i < placeholders.length; i++) { + raw = raw.replace(placeholders[i], placeholders[++i]); + } + } else BlockAndSeek.getPluginLogger().warning("Wrong amount of placeholders for key: " + key); + return mm.deserialize(raw); + } + + public static ItemStack translateItem(Player player, ItemStack itemStack, TranslationKey key, String... placeholders) { + ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.displayName(get(player, key, placeholders)); + itemStack.setItemMeta(itemMeta); + return itemStack; + } + + public static void loadLanguages() { + File langDir = new File(BlockAndSeek.getPluginDataFolder(), "languages"); + if (!langDir.exists()) langDir.mkdirs(); + + if (!new File(langDir, "en_US.yml").exists()) BlockAndSeek.saveResource("languages/en_US.yml"); + if (!new File(langDir, "ru_RU.yml").exists()) BlockAndSeek.saveResource("languages/ru_RU.yml"); + BlockAndSeek.getInstance().saveResource("languages/README.txt", true); + + for (File lang : langDir.listFiles()) { + String name = lang.getName(); + if (!name.endsWith(".yml")) continue; + + Translation config = ConfigManager.create(Translation.class, (it) -> { + it.withConfigurer(new YamlBukkitConfigurer(), new SerdesCommons()); + it.withBindFile(new File(langDir, name)); + it.load(true); + }); + + EnumMap enumMap = new EnumMap<>(TranslationKey.class); + enumMap.putAll(config.getMessages()); + + translations.put(name.replace(".yml", ""), enumMap); + + BlockAndSeek.getPluginLogger().info("Loaded " + name + " translation"); + } + } + + + + + + +} diff --git a/src/main/java/hdvtdev/blockandseek/managers/WorldManager.java b/src/main/java/hdvtdev/blockandseek/managers/WorldManager.java index 4b72748..35c3586 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/WorldManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/WorldManager.java @@ -1,7 +1,7 @@ -package hdvtdev.blockAndSeek.managers; +package hdvtdev.blockandseek.managers; -import hdvtdev.blockAndSeek.BlockAndSeek; +import hdvtdev.blockandseek.BlockAndSeek; import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; diff --git a/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java b/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java index a2d08a6..98d4546 100644 --- a/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java +++ b/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java @@ -1,31 +1,73 @@ -package hdvtdev.blockAndSeek.menus; +package hdvtdev.blockandseek.menus; -import hdvtdev.blockAndSeek.Localization; -import hdvtdev.blockAndSeek.GuiHolder; +import hdvtdev.blockandseek.managers.TranslationManager; +import hdvtdev.blockandseek.GuiHolder; +import hdvtdev.blockandseek.managers.GamesManager; +import hdvtdev.blockandseek.managers.ItemManager; +import hdvtdev.blockandseek.objects.TranslationKey; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; +import java.util.List; + public class GamesMenu implements GuiHolder { private final Inventory inventory; public GamesMenu(Player player) { - Component title = Localization.get(player, "games_menu"); + Component title = TranslationManager.get(player, TranslationKey.GAMES_MENU); this.inventory = Bukkit.createInventory(this, 54, title); initInventory(); + showInventory(player); } private void initInventory() { - + inventory.setItem(53, ItemManager.getCreateGameButton()); + for (String gameName : GamesManager.getAvailableGames()) { + ItemStack gameItem = new ItemStack(Material.AMETHYST_BLOCK); + ItemMeta itemMeta = gameItem.getItemMeta(); + itemMeta.displayName(TranslationManager.get(TranslationManager.defaultLanguage, TranslationKey.GAME, "%name%", gameName)); + var game = GamesManager.get(gameName); + itemMeta.lore(List.of(Component.text(game.players()))); + gameItem.setItemMeta(itemMeta); + inventory.addItem(gameItem); + } } @Override public void onClick(InventoryClickEvent event) { + int slot = event.getSlot(); + Player player = (Player) event.getWhoClicked(); + + event.setCancelled(true); + + if (slot == 53) { + new MapsMenu(player); + } else { + ItemStack item = event.getCurrentItem(); + if (item != null) { + String gameName = TranslationManager.plaintText.serialize(item.displayName()).replaceAll("[\\[\\]]", ""); + var game = GamesManager.get(gameName); + if (game != null) { + if (!game.addPlayer(player)) { + player.sendMessage(TranslationManager.get(player, TranslationKey.GAME_IS_FULL, "%game%", gameName)); + } + } + event.getInventory().close(); + } + } + + + } diff --git a/src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java b/src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java new file mode 100644 index 0000000..4e2cd84 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java @@ -0,0 +1,66 @@ +package hdvtdev.blockandseek.menus; + +import hdvtdev.blockandseek.GuiHolder; +import hdvtdev.blockandseek.managers.GamesManager; +import hdvtdev.blockandseek.managers.ItemManager; +import hdvtdev.blockandseek.managers.MapsManager; +import hdvtdev.blockandseek.managers.TranslationManager; +import hdvtdev.blockandseek.objects.BlockAndSeekMap; +import hdvtdev.blockandseek.objects.TranslationKey; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Collectors; + +import static hdvtdev.blockandseek.objects.TranslationKey.UNKNOWN_MAP; + +public class MapsMenu implements GuiHolder { + + private final Inventory inventory; + + public MapsMenu(Player player) { + Component title = TranslationManager.get(player, TranslationKey.GAMES_MENU); + this.inventory = Bukkit.createInventory(this, 54, title); + init(); + showInventory(player); + } + + private void init() { + for (BlockAndSeekMap map : MapsManager.getMaps()) { + ItemStack gameItem = new ItemStack(Material.MAP); + ItemMeta itemMeta = gameItem.getItemMeta(); + itemMeta.displayName(TranslationManager.get(TranslationManager.defaultLanguage, TranslationKey.MAP, "%name%", map.getWorld())); + gameItem.setItemMeta(itemMeta); + inventory.addItem(gameItem); + } + } + + @Override + public void onClick(InventoryClickEvent event) { + ItemStack item = event.getCurrentItem(); + event.setCancelled(true); + if (item != null) { + Player player = (Player) event.getWhoClicked(); + String mapName = TranslationManager.plaintText.serialize(item.displayName()).replaceAll("[\\[\\]]", ""); + var map = MapsManager.getMap(mapName); + if (map != null) { + GamesManager.createGame(mapName).addPlayer(player); + } else { + player.sendMessage(TranslationManager.get(player, UNKNOWN_MAP, "%map%", mapName, "%maps%", MapsManager.getMaps().stream().map(BlockAndSeekMap::getWorld).collect(Collectors.joining(", ")))); + } + player.closeInventory(); + } + } + + @Override + public @NotNull Inventory getInventory() { + return inventory; + } +} diff --git a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java index 7a76057..00bfee5 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java +++ b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java @@ -1,33 +1,121 @@ -package hdvtdev.blockAndSeek.objects; +package hdvtdev.blockandseek.objects; + +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.Config; +import hdvtdev.blockandseek.Keys; +import hdvtdev.blockandseek.managers.TranslationManager; +import hdvtdev.blockandseek.Utils; +import hdvtdev.blockandseek.managers.GamesManager; +import hdvtdev.blockandseek.managers.ItemManager; +import hdvtdev.blockandseek.managers.PropManager; +import hdvtdev.blockandseek.managers.StateManager; + +import hdvtdev.blockandseek.menus.GamesMenu; +import hdvtdev.blockandseek.roulette.RouletteCreator; +import me.libraryaddict.disguise.DisguiseAPI; +import me.libraryaddict.disguise.disguisetypes.DisguiseType; +import me.libraryaddict.disguise.disguisetypes.MiscDisguise; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; -import hdvtdev.blockAndSeek.managers.StateManager; import org.bukkit.Bukkit; -import org.bukkit.World; +import org.bukkit.GameMode; +import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.*; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; import java.util.*; public class BlockAndSeekGame { private final BlockAndSeekMap map; - private final World world; private final StateManager stateManager = new StateManager(); + private final PropManager propManager = new PropManager(); + private final String name; - public BlockAndSeekGame(BlockAndSeekMap blockAndSeekMap) { + private GamePhase phase; + + public BlockAndSeekGame(String name, BlockAndSeekMap blockAndSeekMap) { + this.name = name; this.map = blockAndSeekMap; - this.world = Objects.requireNonNull(Bukkit.getWorld(blockAndSeekMap.world())); + start(); } public boolean addPlayer(Player player) { - if (stateManager.playerCount() < map.maxPlayers()) { + if (phase instanceof LobbyPhase && stateManager.playerCount() < map.getMaxPlayers()) { stateManager.setPlayerState(player.getUniqueId(), PlayerType.NONE); + player.teleport(map.getLobby()); + player.setInvulnerable(true); return true; } return false; } - public void removePlayer(Player player) { - stateManager.removePlayer(player.getUniqueId()); + public String players() { + return stateManager.getPlayers().size() + "/" + map.getMaxPlayers(); + } + + private void start() { + phase = new LobbyPhase(); + phase.onEnable(); + new BukkitRunnable() { + @Override + public void run() { + if (phase != null) { + phase.tick(); + } else this.cancel(); + } + }.runTaskTimer(BlockAndSeek.getInstance(), 0, 20); + } + + private void endGame() { + phase = null; + GamesManager.remove(name); + } + + private void sendToAll(TranslationKey key, String... placeholders) { + for (UUID uuid : stateManager.getPlayers()) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + player.sendMessage(TranslationManager.get(player, key, placeholders)); + } + } + } + + private void broadcastToAll(TranslationKey key, String... placeholders) { + for (UUID uuid : stateManager.getPlayers()) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + player.showTitle(Title.title(TranslationManager.get(player, key, placeholders), Component.empty())); + } + } + } + + private void actionBarToAll(TranslationKey key, String... placeholders) { + for (UUID uuid : stateManager.getPlayers()) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + player.sendActionBar(TranslationManager.get(player, key, placeholders)); + } + } } public enum PlayerType { @@ -37,6 +125,343 @@ public class BlockAndSeekGame { SPECTATOR } + //fixme: player leave event: count == 0 -> phase = null -> delete game + private class LobbyPhase extends GamePhase { + + private static final int WAIT_TIME = 30; + + @Override + public void onTick() { + + if (map.getMinPlayers() > stateManager.playerCount()) { + super.tick = 0; + } else { + int timeLeft = WAIT_TIME - tick; + + if (timeLeft <= 0) { + this.onDisable(); + } + + if (timeLeft == 30 || timeLeft == 15 || timeLeft == 10 || timeLeft <= 5) { + sendToAll(TranslationKey.TIME_TO_START, "%time%", String.valueOf(timeLeft)); + } + } + } + + @Override + public void onEnable() { + sendToAll(TranslationKey.WAITING_FOR_PLAYERS); + } + + @Override + public void onDisable() { + phase = new StartedGamePhase(); + phase.onEnable(); + } + + } + + + + private class StartedGamePhase extends GamePhase implements Listener { + + private long gameDuration = map.getGameDuration().toSeconds(); + + @Override + public void onTick() { + if (stateManager.getPlayersInState(PlayerType.SEEKER).isEmpty() || gameDuration == 0) { + var props = stateManager.getPlayersInState(PlayerType.PROP); + if (props.size() == 1) { + Player player = Bukkit.getPlayer(props.iterator().next()); + if (player != null) { + broadcastToAll(TranslationKey.HIDER_SOLO_WIN, "%player%", player.getName()); + } else broadcastToAll(TranslationKey.HIDERS_WIN); + } else broadcastToAll(TranslationKey.HIDERS_WIN); + this.onDisable(); + } else if (stateManager.getPlayersInState(PlayerType.PROP).isEmpty()) { + broadcastToAll(TranslationKey.SEEKERS_WIN); + this.onDisable(); + } else { + actionBarToAll(TranslationKey.TIME_LEFT, "%time%", String.valueOf(gameDuration)); + } + gameDuration--; + } + + @Override + public void onEnable() { + Plugin instance = BlockAndSeek.getInstance(); + instance.getServer().getPluginManager().registerEvents(this, instance); + selectSeekers(1 + (stateManager.playerCount() / 7)); + for (UUID uuid : stateManager.getPlayersInState(PlayerType.NONE)) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + stateManager.setPlayerState(uuid, PlayerType.PROP); + ItemManager.hiderInventory(player); + player.teleport(map.getSpawn()); + new RouletteCreator(player, map.getBlocks()); + player.setInvulnerable(false); + } else BlockAndSeek.getPluginLogger().warning("Player is null. "); + } + } + + private void selectSeekers(int count) { + ArrayList rawSeekers = new ArrayList<>(); + Set playerSet = stateManager.getPlayers(); + for (UUID uuid : playerSet) { + if (!GamesManager.triggerSeekerImmune(uuid)) rawSeekers.add(uuid); + } + Collections.shuffle(rawSeekers); + + var seekers = rawSeekers.subList(0, Math.min(count, playerSet.size())); + + for (UUID seeker : seekers) { + Player player = Bukkit.getPlayer(seeker); + if (player != null) { + stateManager.setPlayerState(seeker, PlayerType.SEEKER); + ItemManager.setSeekerSet(player); + Utils.setLevelWithBar(player, 100); + GamesManager.addSeekerImmune(player); + } + } + + new BukkitRunnable() { + @Override + public void run() { + for (UUID seeker : seekers) { + Player player = Bukkit.getPlayer(seeker); + if (player != null) { + player.teleport(map.getSpawn()); + player.setInvulnerable(false); + } + } + } + }.runTaskLater(BlockAndSeek.getInstance(), map.getSeekerSpawnDelay().toSeconds() * 20); + } + + @Override + public void onDisable() { + HandlerList.unregisterAll(this); + phase = new EndedGamePhase(); + phase.onEnable(); + } + + @EventHandler + private void onPlayerLeaveEvent(PlayerQuitEvent event) { + Player player = event.getPlayer(); + UUID uuid = player.getUniqueId(); + if (stateManager.hasPlayer(uuid)) { + stateManager.removePlayer(uuid); + Utils.clearPlayer(player); + } + } + + @EventHandler + private void onItemDrop(PlayerDropItemEvent event) { + if (stateManager.hasPlayer(event.getPlayer().getUniqueId())) { + event.setCancelled(true); + } + } + + @EventHandler + private void onPlayerDamage(EntityDamageEvent event) { + if (event.getEntity() instanceof Player player) { + if (stateManager.hasPlayer(player.getUniqueId())) { + if (event.getCause() == EntityDamageEvent.DamageCause.FALL) { + event.setCancelled(true); + } + } + } + } + + @EventHandler + private void onPlayerDeath(PlayerDeathEvent event) { + Player player = event.getPlayer(); + UUID uuid = player.getUniqueId(); + if (stateManager.hasPlayer(uuid)) { + stateManager.setPlayerState(uuid, PlayerType.SPECTATOR); + player.setGameMode(GameMode.SPECTATOR); + event.setCancelled(true); + } + } + + @EventHandler + private void onBlockBreak(BlockBreakEvent event) { + Player player = event.getPlayer(); + if (stateManager.hasPlayer(player.getUniqueId())) { + event.setCancelled(true); + } + } + + @EventHandler + public void onRegainHealth(EntityRegainHealthEvent event) { + if (event.getEntity() instanceof Player player) { + UUID uuid = player.getUniqueId(); + PlayerType playerType = stateManager.getState(uuid); + + if (playerType == PlayerType.SEEKER) { + event.setCancelled(true); + } else if (playerType == PlayerType.PROP) { + if (!propManager.isProped(uuid)) { + event.setCancelled(true); + } + } + } + } + + @EventHandler + public void onEntityDismount(EntityDismountEvent event) { + if (event.getEntity() instanceof Player player && event.getDismounted() instanceof ArmorStand) { + if (stateManager.hasPlayer(player.getUniqueId())) { + propManager.forceUnfreeze(player); + } + } + } + + + @EventHandler + private void onBlockPlace(BlockPlaceEvent event) { + Player player = event.getPlayer(); + if (stateManager.hasPlayer(player.getUniqueId())) { + event.setCancelled(true); + } + } + + @EventHandler + private void onPlayerDamageByPlayer(EntityDamageByEntityEvent event) { + if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) { + PlayerType damagerType = stateManager.getState(damager.getUniqueId()); + PlayerType victimType = stateManager.getState(victim.getUniqueId()); + if (damagerType == victimType) { + event.setCancelled(true); + } else { + if (damagerType == PlayerType.SEEKER) { + double currentHealth = damager.getHealth(); + if (currentHealth < 20) { + double newHealth = Math.min(currentHealth + event.getDamage(), 20); + damager.setHealth(newHealth); + Utils.setLevelWithBar(damager, (int) Math.round(damager.getHealth() * 5)); + } + } + } + } + } + + @EventHandler + private void onInventoryClose(InventoryCloseEvent event) { + Inventory inventory = event.getInventory(); + if (inventory.getHolder() instanceof RouletteCreator rouletteCreator && event.getReason() != InventoryCloseEvent.Reason.PLUGIN) { + Player player = (Player) event.getPlayer(); + DisguiseAPI.disguiseToAll(player, new MiscDisguise(DisguiseType.FALLING_BLOCK, rouletteCreator.randomPropItem())); + DisguiseAPI.setActionBarShown(player, false); + } + } + + @EventHandler + public void onBlockDamage(BlockDamageEvent event) { + + Player player = event.getPlayer(); + UUID uuid = player.getUniqueId(); + if (PlayerType.SEEKER.equals(stateManager.getState(uuid))) { + UUID prop = propManager.getProp(event.getBlock().getLocation()); + if (prop != null) { + propManager.forceUnfreeze(prop); + } else { + player.damage(2); + Utils.setLevelWithBar(player, (int) Math.round(player.getHealth() * 5)); + } + } + } + + @EventHandler + private void onInventoryClick(InventoryClickEvent event) { + Inventory inventory = event.getInventory(); + if (inventory.getHolder() instanceof RouletteCreator) { + ItemStack itemStack = event.getCurrentItem(); + int slot = event.getSlot(); + if (itemStack != null && (slot == 21 || slot == 23 || slot == 25)) { + Player player = (Player) event.getWhoClicked(); + player.closeInventory(InventoryCloseEvent.Reason.PLUGIN); + DisguiseAPI.disguiseToAll(player, new MiscDisguise(DisguiseType.FALLING_BLOCK, itemStack)); + DisguiseAPI.setActionBarShown(player, false); + } + event.setCancelled(true); + } + } + + private final Set coolDown = new HashSet<>(); + + @EventHandler + public void onRightClick(PlayerInteractEvent event) { + if (event.getHand() != EquipmentSlot.HAND) return; + if (event.getAction().isLeftClick()) return; + + Player player = event.getPlayer(); + UUID uuid = player.getUniqueId(); + + ItemStack item = event.getItem(); + if (item != null) { + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + PersistentDataContainer dataContainer = meta.getPersistentDataContainer(); + if (dataContainer.has(Keys.FREEZE_ITEM)) { + if (!coolDown.contains(uuid)) { + player.sendActionBar(Component.text(propManager.freezeOrUnfreeze(event.getPlayer()).toString())); + coolDown.add(uuid); + new BukkitRunnable() { + @Override + public void run() { + coolDown.remove(uuid); + } + }.runTaskLater(BlockAndSeek.getInstance(), 2); + } + } + } + } + } + + + + } + + private class EndedGamePhase extends GamePhase { + + private final long endTick = map.getDelayBeforeGameEnd().toSeconds(); + + @Override + public void onTick() { + if (super.tick == endTick) { + this.onDisable(); + } + } + + @Override + public void onEnable() { + for (UUID uuid : stateManager.getPlayers()) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + propManager.forceUnfreeze(player); + player.setInvulnerable(true); + player.setGlowing(true); + } + } + } + + @Override + public void onDisable() { + for (UUID uuid : stateManager.getPlayers()) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + //propManager.removePlayer(player); + Utils.clearPlayer(player); + player.setInvulnerable(true); + ItemManager.defaultInventory(player); + player.teleport(Config.spawn()); + } + } + endGame(); + } + + } diff --git a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java index e2b7fbd..f26f684 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java +++ b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java @@ -1,17 +1,59 @@ -package hdvtdev.blockAndSeek.objects; +package hdvtdev.blockandseek.objects; -import org.bukkit.Bukkit; -import org.bukkit.World; +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.annotation.Comment; +import eu.okaeri.configs.annotation.CustomKey; +import eu.okaeri.validator.annotation.Min; -public record BlockAndSeekMap(String world, Cords spawn, Cords lobby, - int minPlayers, int maxPlayers, int duration, int seekerSpawnDelay, int delayBeforeEnd) { +import lombok.Getter; +import lombok.Setter; - public static void prepareWorld(World world) { - if (Integer.parseInt(Bukkit.getMinecraftVersion().replaceAll("[^0-9]", "")) >= 1215) { - String cmd = "execute in " + world.getKey() + " run gamerule locatorBar true"; - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd); - } - } +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class BlockAndSeekMap extends OkaeriConfig { + + @Comment("The name of the world where the game takes place") + private String world; + + @Comment("The main spawn point inside the arena") + private Location spawn; + + @Comment("The waiting lobby location where players join before the match") + private Location lobby; + + @Comment("Minimum number of players required to start the game") + @Min(2) + @CustomKey("min-players") + private int minPlayers = 2; + + @Comment("Maximum number of players allowed in the game") + @CustomKey("max-players") + private int maxPlayers = 12; + + @Comment("Total duration of the match. Format examples: 10m, 300s, 1h") + @CustomKey("game-duration") + private Duration gameDuration = Duration.ofMinutes(10); + + @Comment("How long seekers must wait before they are released") + @CustomKey("seeker-spawn-delay") + private Duration seekerSpawnDelay = Duration.ofSeconds(30); + + @Comment("Time to stay in the arena after the game ends (Post-game phase)") + @Comment("Allows players to look around, check positions and chat before being sent to lobby") + @CustomKey("delay-before-game-end") + private Duration delayBeforeGameEnd = Duration.ofSeconds(10); + + @Comment("Available blocks for hiders") + private List blocks = new ArrayList<>(List.of(new PropBlock(new ItemStack(Material.TARGET), Rarity.LEGENDARY))); } + + diff --git a/src/main/java/hdvtdev/blockandseek/objects/GamePhase.java b/src/main/java/hdvtdev/blockandseek/objects/GamePhase.java index eeb1ead..d83fac7 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/GamePhase.java +++ b/src/main/java/hdvtdev/blockandseek/objects/GamePhase.java @@ -1,4 +1,18 @@ package hdvtdev.blockandseek.objects; -public interface GamePhase { +import org.jetbrains.annotations.Nullable; + +public abstract class GamePhase { + + protected int tick = 0; + + public final void tick() { + onTick(); + tick++; + } + + protected abstract void onTick(); + protected abstract void onEnable(); + protected abstract void onDisable(); + } diff --git a/src/main/java/hdvtdev/blockandseek/objects/PropBlock.java b/src/main/java/hdvtdev/blockandseek/objects/PropBlock.java index ac8cdd9..59b93c3 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/PropBlock.java +++ b/src/main/java/hdvtdev/blockandseek/objects/PropBlock.java @@ -1,9 +1,25 @@ -package hdvtdev.blockAndSeek.objects; +package hdvtdev.blockandseek.objects; +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.annotation.Comment; import org.bukkit.inventory.ItemStack; -public record PropBlock(ItemStack block, int chance) { - public PropBlock(ItemStack block, Rarity rarity) { - this(block, rarity.toChance()); +public class PropBlock extends OkaeriConfig { + + private ItemStack block; + private Rarity rarity = Rarity.COMMON; + + public ItemStack getBlock() { + return block; } + + public Rarity getRarity() { + return rarity; + } + + public PropBlock(ItemStack itemStack, Rarity rarity) { + this.block = itemStack; + this.rarity = rarity; + } + } diff --git a/src/main/java/hdvtdev/blockandseek/objects/Rarity.java b/src/main/java/hdvtdev/blockandseek/objects/Rarity.java index 98655fd..837db2a 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/Rarity.java +++ b/src/main/java/hdvtdev/blockandseek/objects/Rarity.java @@ -1,23 +1,20 @@ -package hdvtdev.blockAndSeek.objects; +package hdvtdev.blockandseek.objects; public enum Rarity { + COMMON(100), // Очень часто (как грязь) + UNCOMMON(50), // Часто (половина от обычного) + RARE(25), // Редко + EPIC(10), // Очень редко + MYTHIC(3), // Почти невозможно + LEGENDARY(1); // Чудо - COMMON,// 38% - UNCOMMON,// 27% - RARE,// 19% - EPIC,// 10% - MYTHIC,// 4% - LEGENDARY; // 2% + private final int weight; - public int toChance() { - return switch (this.ordinal()) { - case 1 -> 27; - case 2 -> 19; - case 3 -> 10; - case 4 -> 4; - case 5 -> 2; - default -> 38; - }; + Rarity(int weight) { + this.weight = weight; } -} + public int getChance() { + return weight; + } +} \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockandseek/objects/Translation.java b/src/main/java/hdvtdev/blockandseek/objects/Translation.java new file mode 100644 index 0000000..66ac95b --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/objects/Translation.java @@ -0,0 +1,17 @@ +package hdvtdev.blockandseek.objects; + +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.annotation.Header; + +import lombok.Getter; + +import java.util.EnumMap; +import java.util.Map; + +@Header("Translations lives here") +@Getter +public class Translation extends OkaeriConfig { + + private Map messages = new EnumMap<>(TranslationKey.class); + +} \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockandseek/objects/TranslationKey.java b/src/main/java/hdvtdev/blockandseek/objects/TranslationKey.java new file mode 100644 index 0000000..efe63c9 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/objects/TranslationKey.java @@ -0,0 +1,40 @@ +package hdvtdev.blockandseek.objects; + +public enum TranslationKey { + // Misc + UNKNOWN_COMMAND, + SEEKER_TEMPLATE, + + // Maps management + UNKNOWN_MAP, + SUCCESSFUL_MAP_CREATION, + + // Menus + MENU, + GAMES_MENU, + MAPS_MENU, + + // Menus buttons + GAME, + CREATE_GAME, + MAP, + + // Game + TIME_LEFT, + TIME_TO_START, + PLAYER_JOINED, + PLAYER_LEFT, + SEEKERS_WIN, + HIDERS_WIN, + HIDER_SOLO_WIN, + ROULETTE, + GAME_IS_FULL, + WAITING_FOR_PLAYERS, + + // Items + FREEZE_ITEM, + FACE_CHANGING_ITEM, + SOUND_ITEM, + LEAVE_ITEM, + DASH_ITEM; +} \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java b/src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java index fc24209..7c92c56 100644 --- a/src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java +++ b/src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java @@ -1,4 +1,11 @@ -package hdvtdev.blockAndSeek.roulette; +package hdvtdev.blockandseek.roulette; + + +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.managers.TranslationManager; +import hdvtdev.blockandseek.objects.PropBlock; + +import hdvtdev.blockandseek.objects.TranslationKey; import org.bukkit.Bukkit; import org.bukkit.Sound; @@ -7,15 +14,14 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scheduler.BukkitTask; + import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Random; -/* + public final class RouletteCreator implements InventoryHolder { @@ -24,146 +30,116 @@ public final class RouletteCreator implements InventoryHolder { private static final Random random = new Random(); private final Inventory roulette; - private Task task; - private volatile Boolean closedByPlayer = true; + private boolean isRunning = true; - public RouletteCreator(@NotNull Player player, List blocks) { - roulette = Bukkit.createInventory(this, 45, Localization.getComponent(player, "roulette-title")); - this.createUnoptimizedRoulette(roulette, player, blocks); + public RouletteCreator(@NotNull Player player, @NotNull List blocks) { + roulette = Bukkit.createInventory(this, 45, TranslationManager.get(player, TranslationKey.ROULETTE)); + this.createSmoothRoulette(roulette, player, blocks); } - public @NotNull Task getTask() { - return task; - } - - public @Nullable Boolean isClosedByPlayer() { - return closedByPlayer; - } @Override public @NotNull Inventory getInventory() { return roulette; } - public void closeInventoryBySystem() { - closedByPlayer = false; - roulette.close(); - } - - public void closeInventory() { - closedByPlayer = null; - roulette.close(); - } public ItemStack randomPropItem() { - return roulette.getItem(slots[random.nextInt(0, 15)]); - } - - public ItemStack randomMidPropItem() { - return roulette.getItem(midSlots[random.nextInt(0, 3)]); + return isRunning ? roulette.getItem(slots[random.nextInt(0, 15)]) : roulette.getItem(midSlots[random.nextInt(0, 3)]); } @ApiStatus.Experimental - private void createUnoptimizedRoulette(Inventory gui, Player player, List blocks) { - - BukkitTask rouletteTask = new BukkitRunnable() { + private void createSmoothRoulette(Inventory gui, Player player, List blocks) { + player.openInventory(gui); + new BukkitRunnable() { final RouletteGenerator rouletteGenerator = new RouletteGenerator(blocks); - final List> rows = List.of( + final List> sources = List.of( new RouletteList<>(rouletteGenerator.getRandomRow(15)), new RouletteList<>(rouletteGenerator.getRandomRow(15)), new RouletteList<>(rouletteGenerator.getRandomRow(15)) ); - - final List items; - + final List columns = new ArrayList<>(); { - List rawItems = new ArrayList<>(); - for (int j = 0; j < 3; j++) { - ItemStack[] itemStacks = new ItemStack[5]; - for (int l = 0; l < 5; l++) { - itemStacks[l] = rows.get(j).next(); + for (int i = 0; i < 3; i++) { + ItemStack[] col = new ItemStack[5]; + for (int row = 0; row < 5; row++) { + col[row] = sources.get(i).next(); } - rawItems.add(j, itemStacks); + columns.add(col); } - items = rawItems; } - final long startTime = System.currentTimeMillis(); - double currentSpeed = 0; - int i = 0; + final int[] colStartIndices = {3, 5, 7}; + int ticksAlive = 0; // Общее время работы анимации + int ticksUntilNextMove = 0; // Обратный отсчет до следующего кадра @Override public void run() { - - long now = System.currentTimeMillis(); - double elapsed = (now - startTime) / 1000.0; - - if (elapsed >= 5) { + // Безопасность + if (!player.isOnline() || !player.getOpenInventory().getTopInventory().equals(gui)) { this.cancel(); + return; } - double speed; - if (elapsed < 2) speed = 1.0; - else if (elapsed < 2.2) speed = 0.8; - else if (elapsed < 2.4) speed = 0.6; - else if (elapsed < 2.6) speed = 0.5; - else if (elapsed < 2.8) speed = 0.4; - else if (elapsed < 3) speed = 0.33; - else if (elapsed < 3.2) speed = 0.28; - else if (elapsed < 3.5) speed = 0.22; - else if (elapsed < 3.8) speed = 0.15; - else speed = 0.1; + // Увеличиваем общий счетчик жизни таймера + ticksAlive++; - task(speed); + // Если время ожидания еще не вышло — ждем + if (ticksUntilNextMove > 0) { + ticksUntilNextMove--; + return; + } - i++; + updateRoulette(); + + if (ticksAlive < 30) { // 0 - 1.5 сек: + ticksUntilNextMove = 1; // Каждые 2 тика (быстро, но не мыло) + } else if (ticksAlive < 50) { // 1.5 - 2.5 сек: + ticksUntilNextMove = 2; // Чуть медленнее (каждые 3 тика) + } else if (ticksAlive < 65) { // 2.5 - 3.2 сек: + ticksUntilNextMove = 3; // Еще медленнее (каждые 4 тика) + } else if (ticksAlive < 75) { // 3.2 - 3.7 сек: + ticksUntilNextMove = 5; // Заметное торможение + } else if (ticksAlive < 85) { // 3.7 - 4.2 сек: + ticksUntilNextMove = 8; // Почти конец + } else if (ticksAlive < 95) { // Последние вздохи + ticksUntilNextMove = 12; + } else if (ticksAlive < 110) { + ticksUntilNextMove = 20; // Финальный медленный шаг + } else { + // КОНЕЦ + isRunning = false; + player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1f, 2f); + this.cancel(); + } } - private void task(double speed) { - if (currentSpeed >= 1) { - currentSpeed = 0; - for (int j = 0; j < 5; j++) { - gui.setItem(3 + j * 9, items.getFirst()[j]); - gui.setItem(5 + j * 9, items.get(1)[j]); - gui.setItem(7 + j * 9, items.get(2)[j]); + private void updateRoulette() { + player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 1f); + + for (int colIndex = 0; colIndex < 3; colIndex++) { + ItemStack[] colItems = columns.get(colIndex); + + for (int row = 0; row < 5; row++) { + int slot = colStartIndices[colIndex] + (row * 9); + gui.setItem(slot, colItems[row]); } - player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 2f); - - for (int j = 4; j >= 1; j--) { - items.getFirst()[j] = items.getFirst()[j - 1]; - items.get(1)[j] = items.get(1)[j - 1]; - items.get(2)[j] = items.get(2)[j - 1]; - } - - items.getFirst()[0] = rows.getFirst().next(); - items.get(1)[0] = rows.get(1).next(); - items.get(2)[0] = rows.get(2).next(); - } else currentSpeed += speed; - + System.arraycopy(colItems, 0, colItems, 1, 4); + colItems[0] = sources.get(colIndex).next(); + } } - }.runTaskTimer(BlockAndSeek.getInstance(), 0, 1); - - - task = new Task(rouletteTask, Bukkit.getScheduler().runTaskLater(BlockAndSeek.getInstance(), this::closeInventoryBySystem, 300)); - - player.openInventory(gui); + }.runTaskTimer(BlockAndSeek.getInstance(), 0L, 1L); } - public record Task(BukkitTask rouletteTask, BukkitTask autoCloseTask) { - public void cancelBoth() { - rouletteTask.cancel(); - autoCloseTask.cancel(); - } } -} - */ \ No newline at end of file + diff --git a/src/main/java/hdvtdev/blockandseek/roulette/RouletteGenerator.java b/src/main/java/hdvtdev/blockandseek/roulette/RouletteGenerator.java index 6504d6e..80532b5 100644 --- a/src/main/java/hdvtdev/blockandseek/roulette/RouletteGenerator.java +++ b/src/main/java/hdvtdev/blockandseek/roulette/RouletteGenerator.java @@ -1,18 +1,22 @@ -package hdvtdev.blockAndSeek.roulette; +package hdvtdev.blockandseek.roulette; + import com.lewdev.probabilitylib.ProbabilityCollection; + +import hdvtdev.blockandseek.objects.PropBlock; + import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.List; -/* + public class RouletteGenerator { private final ProbabilityCollection probabilityCollection = new ProbabilityCollection<>(); - public RouletteGenerator(List blocks) { - for (BlockAndSeekMap.Block block : blocks) { - probabilityCollection.add(block.block(), block.chance()); + public RouletteGenerator(List blocks) { + for (PropBlock block : blocks) { + probabilityCollection.add(block.getBlock(), block.getRarity().getChance()); } } @@ -22,7 +26,6 @@ public class RouletteGenerator { return items; } - } - */ + diff --git a/src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java b/src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java index 7aee9e8..7901e6b 100644 --- a/src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java +++ b/src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java @@ -1,4 +1,4 @@ -package hdvtdev.blockAndSeek.roulette; +package hdvtdev.blockandseek.roulette; import org.jetbrains.annotations.NotNull; diff --git a/src/main/resources/languages/README.txt b/src/main/resources/languages/README.txt new file mode 100644 index 0000000..0bcfc0e --- /dev/null +++ b/src/main/resources/languages/README.txt @@ -0,0 +1,2 @@ +Place your translations in language folder. Translation file name must be a language tag and file extension must be .yml. +Use en_US.yml as example. \ No newline at end of file diff --git a/src/main/resources/languages/en_US.yml b/src/main/resources/languages/en_US.yml index e69de29..7835ed0 100644 --- a/src/main/resources/languages/en_US.yml +++ b/src/main/resources/languages/en_US.yml @@ -0,0 +1,26 @@ +messages: + UNKNOWN_COMMAND: "Unknown command: %command%." + SEEKER_TEMPLATE: "%template%" + UNKNOWN_MAP: "Unknown map: %map%. Available maps: %maps%" + SUCCESSFUL_MAP_CREATION: "Map %map% was successfully created. Use /blockandseek map %map% to edit" + MENU: menu + GAMES_MENU: "games" + MAPS_MENU: "maps" + GAME: "%name%" + CREATE_GAME: "Create game" + MAP: "%name%" + TIME_LEFT: "Time left %time%" + PLAYER_JOINED: "%player% joined. %count%/%max%" + PLAYER_LEFT: "%player% left. %count%/%max%" + SEEKERS_WIN: "Seekers won this game!" + HIDERS_WIN: "Hiders won this game!" + HIDER_SOLO_WIN: "%player% won this game!" + FREEZE_ITEM: "Freezer 3000" + SOUND_ITEM: "Sounder 3000" + LEAVE_ITEM: "Leave" + DASH_ITEM: "Dash" + ROULETTE: "Blocks roulette" + TIME_TO_START: "Game starts in %time%" + GAME_IS_FULL: "failed> to join %game%. Game is full." + FACE_CHANGING_ITEM: "FACE_CHANGING_ITEM: todo" + WAITING_FOR_PLAYERS: "Waiting for players" \ No newline at end of file diff --git a/src/main/resources/languages/ru_RU.yml b/src/main/resources/languages/ru_RU.yml new file mode 100644 index 0000000..4946811 --- /dev/null +++ b/src/main/resources/languages/ru_RU.yml @@ -0,0 +1,23 @@ +messages: + UNKNOWN_COMMAND: "Неизвестная команда: %command%." + SEEKER_TEMPLATE: %template% + UNKNOWN_MAP: "Неизвестная карта: %map%. Доступные карты: %maps%" + SUCCESSFUL_MAP_CREATION: Карта %map% была успешно создана. Используйте /blockandseek map %map%, чтобы редактировать + MENU: меню + GAMES_MENU: игры + MAPS_MENU: карты + GAME: %name% + CREATE_GAME: Создать игру + MAP: %name% + TIME_LEFT: "Осталось времени: %time%" + PLAYER_JOINED: %player% присоединился. %count%/%max% + PLAYER_LEFT: %player% вышел. %count%/%max% + SEEKERS_WIN: Искатели победили! + HIDERS_WIN: Прячущиеся победили! + HIDER_SOLO_WIN: %player% победил! + FREEZE_ITEM: Замораживатель 3000 + SOUND_ITEM: Шумелка 3000 + LEAVE_ITEM: Выйти + DASH_ITEM: Рывок + ROULETTE: Рулетка блоков + TIME_TO_START: Игра начнется через %time% \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 6e9a625..c268846 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,11 @@ name: BlockAndSeek version: '0.0.1-a' -main: hdvtdev.blockAndSeek.BlockAndSeek +main: hdvtdev.blockandseek.BlockAndSeek api-version: '1.20' +load: POSTWORLD + +depend: + - LibsDisguises permissions: blockandseek.manage: @@ -12,4 +16,4 @@ commands: blockandseek: aliases: - bs - usage: "Usage: /blockandseek [subcommand]" \ No newline at end of file + usage: "Usage: /blockandseek [subcommand]"