From a135134b55fa35ea033553d8f32574d4eae78ca8 Mon Sep 17 00:00:00 2001 From: hdvt Date: Mon, 8 Dec 2025 20:17:05 +0300 Subject: [PATCH] some fixes. last dirty commit --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .idea/workspace.xml | 60 ++-- .../hdvtdev/blockandseek/BlockAndSeek.java | 314 ++---------------- .../hdvtdev/blockandseek/BlocksGenerator.java | 76 ++--- .../java/hdvtdev/blockandseek/Config.java | 5 + src/main/java/hdvtdev/blockandseek/Utils.java | 28 +- .../ForceControlEventListener.java | 21 +- .../eventListeners/RequiredEventListener.java | 74 +---- .../hdvtdev/blockandseek/items/DashItem.java | 2 +- .../hdvtdev/blockandseek/items/Grenade.java | 13 +- .../hdvtdev/blockandseek/items/Pistol.java | 7 +- .../items/special/AntiGravity.java | 60 ++++ .../blockandseek/items/special/Chorus.java | 99 ++++++ .../blockandseek/items/special/DeathBelt.java | 52 +++ .../blockandseek/items/special/Decoy.java | 72 ++++ .../items/{ => special}/MorphItem.java | 16 +- .../blockandseek/managers/CommandManager.java | 143 ++++++++ .../blockandseek/managers/GamesManager.java | 4 + .../blockandseek/managers/ItemManager.java | 27 +- .../blockandseek/managers/PartyManager.java | 127 +++++++ .../blockandseek/managers/PropManager.java | 7 +- .../managers/TranslationManager.java | 58 +++- .../hdvtdev/blockandseek/menus/GamesMenu.java | 24 +- .../hdvtdev/blockandseek/menus/MapsMenu.java | 31 +- .../objects/BlockAndSeekGame.java | 95 +++++- .../objects/BlockAndSeekItem.java | 50 ++- .../blockandseek/objects/BlockAndSeekMap.java | 15 +- .../hdvtdev/blockandseek/objects/Items.java | 2 +- .../blockandseek/objects/LazyLocation.java | 15 +- .../hdvtdev/blockandseek/objects/Party.java | 33 ++ .../blockandseek/objects/TranslationKey.java | 30 +- 31 files changed, 1044 insertions(+), 516 deletions(-) create mode 100644 src/main/java/hdvtdev/blockandseek/items/special/AntiGravity.java create mode 100644 src/main/java/hdvtdev/blockandseek/items/special/Chorus.java create mode 100644 src/main/java/hdvtdev/blockandseek/items/special/DeathBelt.java create mode 100644 src/main/java/hdvtdev/blockandseek/items/special/Decoy.java rename src/main/java/hdvtdev/blockandseek/items/{ => special}/MorphItem.java (83%) create mode 100644 src/main/java/hdvtdev/blockandseek/managers/CommandManager.java create mode 100644 src/main/java/hdvtdev/blockandseek/managers/PartyManager.java create mode 100644 src/main/java/hdvtdev/blockandseek/objects/Party.java diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 5b9d51b98c8e1ced143023941ebe539aeed06546..9c88872ee31a944d656d40a23a7d409c7644664e 100644 GIT binary patch literal 17 UcmZS9U$0WQyF*@v0Ss7-046d6D*ylh literal 17 VcmZS9U$0WQyF*@v0SuU?0{|wI1C9Uy diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 44ea41b..9e03481 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,58 +5,37 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - + + - + + + + + - - + + + + - - @@ -121,7 +101,7 @@ "RunOnceActivity.git.unshallow": "true", "SHARE_PROJECT_CONFIGURATION_FILES": "true", "SHELLCHECK.PATH": "/home/hadvart/.local/share/JetBrains/IdeaIC2025.2/Shell Script/shellcheck", - "git-widget-placeholder": "dev/1.20.6", + "git-widget-placeholder": "dev-1.20.6", "kotlin-language-version-configured": "true", "last_opened_file_path": "/home/hadvart/IdeaProjects/blockandseek/BlockAndSeekPack/assets/minecraft/textures/misc", "settings.editor.selected.configurable": "preferences.lookFeel" diff --git a/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java b/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java index 09c906f..98693df 100644 --- a/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java +++ b/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java @@ -7,12 +7,21 @@ import hdvtdev.blockandseek.items.Pistol; import hdvtdev.blockandseek.managers.*; import hdvtdev.blockandseek.objects.*; import hdvtdev.blockandseek.roulette.RouletteCreator; + import java.io.File; import java.time.Duration; import java.util.*; import java.util.logging.Logger; import java.util.stream.Collectors; + +import me.libraryaddict.disguise.DisguiseAPI; import me.libraryaddict.disguise.LibsDisguises; +import me.libraryaddict.disguise.disguisetypes.DisguiseType; +import me.libraryaddict.disguise.disguisetypes.MiscDisguise; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.*; import org.bukkit.attribute.Attribute; @@ -33,15 +42,17 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.RayTraceResult; 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.StringParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; public class BlockAndSeek extends JavaPlugin { private static JavaPlugin javaPlugin; - private static LegacyPaperCommandManager commandManager; private static final String perm = "blockandseek.manage"; public static Plugin getInstance() { @@ -69,12 +80,12 @@ public class BlockAndSeek extends JavaPlugin { javaPlugin = this; LibsDisguises libsDisguises = - (LibsDisguises) Bukkit.getPluginManager().getPlugin( - "LibsDisguises" - ); + (LibsDisguises) Bukkit.getPluginManager().getPlugin( + "LibsDisguises" + ); if (libsDisguises == null) { getLogger().severe( - "LibsDisguises not found! It's required for the plugin to work!" + "LibsDisguises not found! It's required for the plugin to work!" ); super.onDisable(); } @@ -82,17 +93,17 @@ public class BlockAndSeek extends JavaPlugin { this.init(); PluginCommand command = Objects.requireNonNull( - getCommand("blockandseek") + getCommand("blockandseek") ); PluginManager manager = getServer().getPluginManager(); boolean forceControl = Config.forceControl(); if (forceControl) getLogger().info("Using force control"); manager.registerEvents( - forceControl - ? new ForceControlEventListener() - : new EventListener(), - this + forceControl + ? new ForceControlEventListener() + : new EventListener(), + this ); manager.registerEvents(new RequiredEventListener(), this); } @@ -125,294 +136,15 @@ public class BlockAndSeek extends JavaPlugin { TranslationManager.loadLanguages(); MapsManager.loadMaps(); - commandManager = LegacyPaperCommandManager.createNative( - this, - ExecutionCoordinator.simpleCoordinator() - ); - if ( - commandManager.hasCapability( - CloudBukkitCapabilities.NATIVE_BRIGADIER - ) - ) { - try { - commandManager.registerBrigadier(); - } catch (IllegalStateException ignored) {} - } - this.registerCommands(); + CommandManager.registerCommands("blockandseek"); + CommandManager.registerCommands("bs"); } catch (Exception e) { getLogger().severe("Cloud err: " + e.getMessage()); e.printStackTrace(); } } - private static final UUID ZOOM_UUID = UUID.randomUUID(); - private void registerCommands() { - 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("testMessage") - .handler(ctx -> { - ctx - .sender() - .sendMessage( - MiniMessage.miniMessage().deserialize( - " System » Ваш игровой режим изменен.\n" - ) - ); - }) - ); - - commandManager.command( - root - .literal("testGlow") - .handler(ctx -> { - if (ctx.sender() instanceof Player player) { - RayTraceResult result = player.rayTraceBlocks(128); - if (result != null) { - Block block = result.getHitBlock(); - if (block != null) { - GlowUtil.highlightBlock(player, block.getLocation().toBlockLocation()); - } - } - } - }) - ); - - commandManager.command( - root - .literal("menuTest") - .handler(ctx -> { - if (ctx.sender() instanceof Player player) { - player - .getInventory() - .addItem(ItemManager.getItem(Items.MENU).getTranslated(player)); - } - }) - ); - - commandManager.command( - root - .literal("morphItem") - .handler(ctx -> { - if (ctx.sender() instanceof Player player) { - player - .getInventory() - .addItem(ItemManager.getItem(Items.MORPH).getTranslated(player)); - } - }) - ); - - commandManager.command( - root - .literal("pistolGet") - .handler(ctx -> { - if (ctx.sender() instanceof Player player) { - player - .getInventory() - .addItem(ItemManager.getItem(Items.PISTOL).getTranslated(player)); - } - }) - ); - - commandManager.command( - root - .literal("clear") - .handler(ctx -> { - if (ctx.sender() instanceof Player player) { - AttributeInstance attribute = player.getAttribute( - Attribute.GENERIC_MOVEMENT_SPEED - ); - - if ( - attribute != null && - attribute.getModifier(ZOOM_UUID) != null - ) { - attribute.removeModifier(ZOOM_UUID); - } - } - }) - ); - - commandManager.command( - root - .literal("pistolTest") - .handler(ctx -> { - if (ctx.sender() instanceof Player player) { - player.getInventory().addItem(ItemManager.getItem(Items.MORPH).getTranslated(player)); - } - }) - ); - - commandManager.command( - root - .literal("grenadeTest") - .handler(ctx -> { - if (ctx.sender() instanceof Player player) { - player.getInventory().addItem(ItemManager.getItem(Items.GRENADE).getTranslated(player)); - } - }) - ); - - commandManager.command( - root - .literal("reload") - .handler(ctx -> { - var sender = ctx.sender(); - if (Config.loadConfig()) { - MapsManager.loadMaps(); - TranslationManager.loadLanguages(); - sender.sendMessage("Configs were reloaded!"); - } else sender.sendMessage("Failed to reload configs! Check server logs."); - }) - ); - - commandManager.command( - root - .literal("configTest") - .handler(ctx -> ctx.sender().sendMessage(Config.toStaticString())) - ); - - commandManager.command( - root - .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("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); - } - }) - ); - - - } - - 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, - 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 f943831..e48cba5 100644 --- a/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java +++ b/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java @@ -24,7 +24,7 @@ public class BlocksGenerator { private static final Map> cached = new HashMap<>(); static { - // --- 1. ГРАВИТАЦИЯ (Сыпучие) --- + BLACKLIST.add(Material.SAND); BLACKLIST.add(Material.RED_SAND); BLACKLIST.add(Material.GRAVEL); @@ -32,20 +32,19 @@ public class BlocksGenerator { BLACKLIST.add(Material.ANVIL); BLACKLIST.add(Material.CHIPPED_ANVIL); BLACKLIST.add(Material.DAMAGED_ANVIL); - BLACKLIST.add(Material.POINTED_DRIPSTONE); // Сталактит (может упасть) - BLACKLIST.add(Material.SCAFFOLDING); // Строительные леса + 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.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.REDSTONE_BLOCK); BLACKLIST.add(Material.REPEATER); BLACKLIST.add(Material.COMPARATOR); BLACKLIST.add(Material.OBSERVER); @@ -70,20 +69,19 @@ public class BlocksGenerator { BLACKLIST.add(Material.REPEATING_COMMAND_BLOCK); BLACKLIST.add(Material.CHAIN_COMMAND_BLOCK); BLACKLIST.add(Material.LIGHTNING_ROD); - BLACKLIST.add(Material.BELL); // Колокол + 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.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); @@ -126,13 +124,12 @@ public class BlocksGenerator { BLACKLIST.add(Material.SOUL_LANTERN); BLACKLIST.add(Material.CHAIN); BLACKLIST.add(Material.END_ROD); - BLACKLIST.add(Material.IRON_BARS); // Обычно некрасиво в топах + BLACKLIST.add(Material.IRON_BARS); BLACKLIST.add(Material.LADDER); - BLACKLIST.add(Material.SNOW); // Снежный покров (тонкий) + 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); @@ -146,7 +143,6 @@ public class BlocksGenerator { BLACKLIST.add(Material.BEEHIVE); BLACKLIST.add(Material.BEE_NEST); - // --- 5. ТЕХНИЧЕСКИЕ И ПРОЗРАЧНЫЕ --- BLACKLIST.add(Material.BARRIER); BLACKLIST.add(Material.STRUCTURE_VOID); BLACKLIST.add(Material.STRUCTURE_BLOCK); @@ -154,40 +150,34 @@ public class BlocksGenerator { BLACKLIST.add(Material.LIGHT); BLACKLIST.add(Material.SPAWNER); BLACKLIST.add(Material.COBWEB); - BLACKLIST.add(Material.SLIME_BLOCK); // Спорно, но липкий + 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") // Кораллы (дохнут без воды) + 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. Воздух + public static boolean isSupported(Material type) { if (type.isAir()) return false; - // 2. Черный список (самая надежная проверка) if (BLACKLIST.contains(type)) { return false; } - // 3. Дополнительная защита: блок должен быть твердым - // (Это отсечет то, что мы могли случайно забыть в списке, типа нитки/String) return type.isSolid(); } + @ApiStatus.Experimental public static void getSortedBlockStats(Location center, int chunkRadius, Consumer>> callback) { World world = center.getWorld(); if (world == null) return; diff --git a/src/main/java/hdvtdev/blockandseek/Config.java b/src/main/java/hdvtdev/blockandseek/Config.java index 7b538d3..0e4def8 100644 --- a/src/main/java/hdvtdev/blockandseek/Config.java +++ b/src/main/java/hdvtdev/blockandseek/Config.java @@ -13,6 +13,7 @@ import hdvtdev.blockandseek.objects.LazyLocation; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.WorldCreator; +import org.bukkit.entity.Player; import java.io.File; import java.io.IOException; @@ -69,6 +70,10 @@ public class Config extends OkaeriConfig { return config.spawn.getLocation(); } + public static void teleportToSpawn(Player player) { + config.spawn.teleport(player); + } + public static String toStaticString() { return String.format("BlockAndSeekConfig[forceControl = %s, spawn = %s, enableDebugCommands = %s]", forceControl(), spawn(), debugEnabled()); } diff --git a/src/main/java/hdvtdev/blockandseek/Utils.java b/src/main/java/hdvtdev/blockandseek/Utils.java index f3b176a..3ce8a9a 100644 --- a/src/main/java/hdvtdev/blockandseek/Utils.java +++ b/src/main/java/hdvtdev/blockandseek/Utils.java @@ -2,6 +2,7 @@ package hdvtdev.blockandseek; import hdvtdev.blockandseek.managers.PropManager; +import hdvtdev.blockandseek.objects.BlockAndSeekItem; import me.libraryaddict.disguise.DisguiseAPI; import org.bukkit.GameMode; import org.bukkit.attribute.Attribute; @@ -40,6 +41,7 @@ public final class Utils { player.getInventory().setArmorContents(null); player.getInventory().setExtraContents(null); PropManager.removePlayer(player); + BlockAndSeekItem.removeCooldownImune(player.getUniqueId()); player.setGameMode(GameMode.SURVIVAL); @@ -47,7 +49,7 @@ public final class Utils { player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(20.0); } player.setHealth(20.0); - + player.clearActivePotionEffects(); player.setFoodLevel(20); player.setSaturation(5.0f); player.setExhaustion(0f); @@ -69,4 +71,28 @@ public final class Utils { } + private static final String serverVersion = org.bukkit.Bukkit.getBukkitVersion().split("-")[0]; + + public static boolean isVersionAtLeast(String ver) { + + String[] serverParts = serverVersion.split("\\."); + String[] targetParts = ver.split("\\."); + + boolean isHighEnough = true; + + int length = Math.max(serverParts.length, targetParts.length); + + for (int i = 0; i < length; i++) { + + int sPart = i < serverParts.length ? Integer.parseInt(serverParts[i]) : 0; + int tPart = i < targetParts.length ? Integer.parseInt(targetParts[i]) : 0; + + if (sPart != tPart) { + isHighEnough = sPart > tPart; + break; + } + } + return isHighEnough; + } + } diff --git a/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java b/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java index 0eb6c8f..5bf831d 100644 --- a/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java +++ b/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java @@ -3,15 +3,14 @@ package hdvtdev.blockandseek.eventListeners; import hdvtdev.blockandseek.Config; import hdvtdev.blockandseek.Utils; import hdvtdev.blockandseek.managers.ItemManager; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.entity.*; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.weather.WeatherChangeEvent; @@ -19,7 +18,6 @@ import org.bukkit.event.world.TimeSkipEvent; public class ForceControlEventListener implements Listener { - @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); @@ -29,6 +27,12 @@ public class ForceControlEventListener implements Listener { ItemManager.defaultInventory(player); } + @EventHandler(ignoreCancelled = true) + public void onPlayerDeath(PlayerDeathEvent event) { + event.setCancelled(true); + Config.teleportToSpawn(event.getPlayer()); + } + @EventHandler public void onWeatherChange(WeatherChangeEvent event) { if (event.getCause() != WeatherChangeEvent.Cause.COMMAND) event.setCancelled(true); @@ -71,5 +75,14 @@ public class ForceControlEventListener implements Listener { } } + private static final String worldName = Config.spawn().getWorld().getName(); + + @EventHandler + private void onEntityDamage(EntityDamageByEntityEvent event) { + if (event.getDamager().getWorld().getName().equals(worldName)) { + event.setCancelled(true); + } + } + } diff --git a/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java b/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java index 468772c..634e6e5 100644 --- a/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java +++ b/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java @@ -1,43 +1,17 @@ package hdvtdev.blockandseek.eventListeners; -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 hdvtdev.blockandseek.*; +import hdvtdev.blockandseek.managers.PartyManager; import hdvtdev.blockandseek.objects.BlockAndSeekItem; -import net.kyori.adventure.text.Component; -import org.bukkit.Material; -import org.bukkit.block.Block; 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.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 org.bukkit.util.RayTraceResult; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - public class RequiredEventListener implements Listener { @@ -51,42 +25,16 @@ public class RequiredEventListener implements Listener { //player.setResourcePack("https://gitea.hdvtdev.tech/hdvt/idk/raw/branch/main/pack.zip", "f32bf084b01b57601d7ae3711e5c88e31ce637a3", true); } - @EventHandler - public void onBlockDamage(BlockDamageEvent event) { - - } - @EventHandler public void onPlayerClick(PlayerInteractEvent event) { - BlockAndSeekItem item = BlockAndSeekItem.tryCast(event.getItem()); - if (item != null) { - item.onRawInteract(event); - } - + if (item != null) item.onRawInteract(event); } @EventHandler - public void onEntityDismount(EntityDismountEvent event) { - - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - - } - - @EventHandler - public void onPlayerDeath(PlayerDeathEvent event) { - - } - - @EventHandler - public void onInventoryClose(InventoryCloseEvent event) { - - - - + private void onPlayerLeave(PlayerQuitEvent event) { + Player player = event.getPlayer(); + //todo party leave } @EventHandler @@ -97,14 +45,4 @@ public class RequiredEventListener implements Listener { } } - @EventHandler - public void onRegainHealth(EntityRegainHealthEvent event) { - - } - - @EventHandler - public void onPlayerDamage(EntityDamageByEntityEvent event) { - - } - } diff --git a/src/main/java/hdvtdev/blockandseek/items/DashItem.java b/src/main/java/hdvtdev/blockandseek/items/DashItem.java index b87901c..3e127ca 100644 --- a/src/main/java/hdvtdev/blockandseek/items/DashItem.java +++ b/src/main/java/hdvtdev/blockandseek/items/DashItem.java @@ -25,7 +25,7 @@ public class DashItem extends BlockAndSeekItem { public DashItem() { - super(Items.DASH, Duration.ofSeconds(75), ClickAction.RIGHT_CLICK); + super(Items.DASH, Duration.ofSeconds(75), ClickAction.RIGHT_CLICK, false); } @Override diff --git a/src/main/java/hdvtdev/blockandseek/items/Grenade.java b/src/main/java/hdvtdev/blockandseek/items/Grenade.java index 226231e..4aa9347 100644 --- a/src/main/java/hdvtdev/blockandseek/items/Grenade.java +++ b/src/main/java/hdvtdev/blockandseek/items/Grenade.java @@ -13,6 +13,7 @@ import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; @@ -30,7 +31,7 @@ import java.util.stream.Collectors; public class Grenade extends BlockAndSeekItem { public Grenade() { - super(Items.GRENADE, Duration.ofSeconds(10), ClickAction.RIGHT_CLICK); + super(Items.GRENADE, Duration.ofSeconds(20), ClickAction.RIGHT_CLICK); } @Override @@ -69,7 +70,7 @@ public class Grenade extends BlockAndSeekItem { Location hitLoc = hit.getHitPosition().toLocation(location.getWorld()); int radius = 4; - List props = hitLoc.getNearbyEntities(radius, radius, radius).stream().filter(entity -> entity instanceof Player p && !p.equals(player)) + List props = hitLoc.getNearbyEntities(radius, radius, radius).stream().filter(entity -> entity instanceof LivingEntity p && !p.equals(player)) .map(Entity::getUniqueId).collect(Collectors.toCollection(ArrayList::new)); @@ -106,11 +107,15 @@ public class Grenade extends BlockAndSeekItem { if (!props.isEmpty()) { player.playSound(player, Sound.ENTITY_ARROW_HIT_PLAYER, 1f, 1f); + World world = location.getWorld(); for (UUID uuid : props) { - Player hider = Bukkit.getPlayer(uuid); + + LivingEntity hider = (LivingEntity) world.getEntity(uuid); if (hider != null) { hider.damage(13.5); - Utils.healSeeker(player, 13.5); + if (hider instanceof Player) { + Utils.healSeeker(player, 13.5); + } else Utils.healSeeker(player, 5); } } } else Utils.damageSeeker(player, 25); diff --git a/src/main/java/hdvtdev/blockandseek/items/Pistol.java b/src/main/java/hdvtdev/blockandseek/items/Pistol.java index fb9dd18..9a973be 100644 --- a/src/main/java/hdvtdev/blockandseek/items/Pistol.java +++ b/src/main/java/hdvtdev/blockandseek/items/Pistol.java @@ -11,6 +11,7 @@ import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; @@ -70,14 +71,16 @@ public class Pistol extends BlockAndSeekItem { if (result != null) { Entity hitEntity = result.getHitEntity(); - if (hitEntity instanceof Player target) { + if (hitEntity instanceof LivingEntity target) { target.damage(5); double strength = 0.1; double x = -target.getLocation().getDirection().getX(); double z = -target.getLocation().getDirection().getZ(); target.knockback(strength, x, z); player.playSound(player, Sound.ENTITY_ARROW_HIT_PLAYER, 1f, 1f); - Utils.healSeeker(player, 5); + if (target instanceof Player) { + Utils.healSeeker(player, 5); + } else Utils.healSeeker(player, 2.5); } else { Block hitBlock = result.getHitBlock(); if (hitBlock != null) { diff --git a/src/main/java/hdvtdev/blockandseek/items/special/AntiGravity.java b/src/main/java/hdvtdev/blockandseek/items/special/AntiGravity.java new file mode 100644 index 0000000..8228c6c --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/items/special/AntiGravity.java @@ -0,0 +1,60 @@ +package hdvtdev.blockandseek.items.special; + +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.managers.PropManager; +import hdvtdev.blockandseek.managers.TranslationManager; +import hdvtdev.blockandseek.objects.BlockAndSeekItem; +import hdvtdev.blockandseek.objects.Items; +import hdvtdev.blockandseek.objects.TranslationKey; +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; + +public class AntiGravity extends BlockAndSeekItem { + public AntiGravity() { + super(Items.ANTI_GRAVITY); + } + + @Override + protected void onInteract(@NotNull PlayerInteractEvent event) { + Location location = event.getPlayer().getLocation(); + var players = location.getWorld().getNearbyPlayers(location, 64); + for (Player player : players) { + PropManager.forceUnfreeze(player.getUniqueId()); + player.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, 2, 20, false, false, false)); + player.setGravity(false); + player.setAllowFlight(true); + } + + new BukkitRunnable() { + @Override + public void run() { + for (Player player : players) { + player.setGravity(true); + player.setAllowFlight(false); + } + } + }.runTaskLater(BlockAndSeek.getInstance(), 15 * 20); + } + + @Override + protected @NotNull ItemStack buildRawItem() { + ItemStack itemStack = new ItemStack(Material.POPPED_CHORUS_FRUIT); + itemStack.editMeta(itemMeta -> itemMeta.addEnchant(Enchantment.INFINITY, 1, true)); + return itemStack; + } + + @Override + public @NotNull ItemStack getTranslated(Player player) { + return TranslationManager.translateItem(player, getCloned(), TranslationKey.ANTI_GRAVITY); + } +} diff --git a/src/main/java/hdvtdev/blockandseek/items/special/Chorus.java b/src/main/java/hdvtdev/blockandseek/items/special/Chorus.java new file mode 100644 index 0000000..b754389 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/items/special/Chorus.java @@ -0,0 +1,99 @@ +package hdvtdev.blockandseek.items.special; + +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.managers.TranslationManager; +import hdvtdev.blockandseek.objects.BlockAndSeekItem; +import hdvtdev.blockandseek.objects.Items; +import hdvtdev.blockandseek.objects.TranslationKey; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ThreadLocalRandom; + +@ApiStatus.Experimental +public class Chorus extends BlockAndSeekItem { + + private static final int distantion = 24; + + public Chorus() { + super(Items.CHORUS); + } + + @Override + protected void onInteract(@NotNull PlayerInteractEvent event) { + Player player = event.getPlayer(); + if (event.getAction().isRightClick()) { + teleport(player); + } else { + Location location = player.getLocation(); + location.getWorld().getNearbyPlayers(location, 5).stream().filter(p -> !p.equals(player)).findAny().ifPresent(Chorus::teleport); + } + } + + + private static void teleport(Player player) { + + new BukkitRunnable() { + int jumpsLeft = 5; + + @Override + public void run() { + if (!player.isOnline() || jumpsLeft <= 0) { + this.cancel(); + return; + } + + Location origin = player.getLocation(); + + for (int i = 0; i < 48; i++) { + //i probably need distantion + 1 but im too lazy) + int x = ThreadLocalRandom.current().nextInt(-distantion, distantion); + int y = ThreadLocalRandom.current().nextInt(-distantion, distantion); + int z = ThreadLocalRandom.current().nextInt(-distantion, distantion); + + Location target = origin.clone().add(x, y, z); + + if (target.getBlock().isPassable() && + target.clone().add(0, 1, 0).getBlock().isPassable() && + target.clone().add(0, -1, 0).getBlock().getType().isSolid()) { + + target.setX(Math.floor(target.getX()) + 0.5); + target.setZ(Math.floor(target.getZ()) + 0.5); + target.setYaw(origin.getYaw()); + target.setPitch(origin.getPitch()); + + player.teleport(target, PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT); + player.getWorld().playSound(target, Sound.ITEM_CHORUS_FRUIT_TELEPORT, 1.0f, 1.0f); + + break; + } + } + + + jumpsLeft--; + } + }.runTaskTimer(BlockAndSeek.getInstance(), 0L, 4); + } + + @Override + protected @NotNull ItemStack buildRawItem() { + ItemStack itemStack = new ItemStack(Material.CHORUS_FRUIT); + itemStack.editMeta(itemMeta -> itemMeta.addEnchant(Enchantment.INFINITY, 1, true)); + return itemStack; + } + + @Override + public @NotNull ItemStack getTranslated(Player player) { + return TranslationManager.translateItem(player, getCloned(), TranslationKey.CHORUS); + } +} diff --git a/src/main/java/hdvtdev/blockandseek/items/special/DeathBelt.java b/src/main/java/hdvtdev/blockandseek/items/special/DeathBelt.java new file mode 100644 index 0000000..6941911 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/items/special/DeathBelt.java @@ -0,0 +1,52 @@ +package hdvtdev.blockandseek.items.special; + +import hdvtdev.blockandseek.managers.TranslationManager; +import hdvtdev.blockandseek.objects.BlockAndSeekItem; +import hdvtdev.blockandseek.objects.Items; +import hdvtdev.blockandseek.objects.TranslationKey; +import org.bukkit.*; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.time.Duration; + +public class DeathBelt extends BlockAndSeekItem { + public DeathBelt() { + super(Items.DEATH_BELT); + } + + private static final double radius = 3.0; + + @Override + protected void onInteract(@NotNull PlayerInteractEvent event) { + Player player = event.getPlayer(); + player.getInventory().remove(event.getItem()); + Location location = player.getLocation(); + World world = location.getWorld(); + world.spawnParticle(Particle.EXPLOSION, location, 1); + world.playSound(location, Sound.ENTITY_GENERIC_EXPLODE, 1f, 1f); + + for (Entity entity : location.getWorld().getNearbyEntities(location, radius, radius, radius)) { + if (entity instanceof LivingEntity victim && entity.getLocation().distance(location) <= radius) { + victim.damage(55.0); + } + } + } + + @Override + protected @NotNull ItemStack buildRawItem() { + ItemStack itemStack = new ItemStack(Material.TNT_MINECART); + itemStack.editMeta(itemMeta -> itemMeta.addEnchant(Enchantment.INFINITY, 1, true)); + return itemStack; + } + + @Override + public @NotNull ItemStack getTranslated(Player player) { + return TranslationManager.translateItem(player, getCloned(), TranslationKey.DEATH_BELT); + } +} diff --git a/src/main/java/hdvtdev/blockandseek/items/special/Decoy.java b/src/main/java/hdvtdev/blockandseek/items/special/Decoy.java new file mode 100644 index 0000000..d3895ac --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/items/special/Decoy.java @@ -0,0 +1,72 @@ +package hdvtdev.blockandseek.items.special; + +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.managers.PropManager; +import hdvtdev.blockandseek.managers.TranslationManager; +import hdvtdev.blockandseek.objects.BlockAndSeekItem; +import hdvtdev.blockandseek.objects.Items; +import hdvtdev.blockandseek.objects.TranslationKey; + +import me.libraryaddict.disguise.DisguiseAPI; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import org.jetbrains.annotations.NotNull; + +import java.time.Duration; + +public class Decoy extends BlockAndSeekItem { + public Decoy() { + super(Items.DECOY, Duration.ZERO, ClickAction.RIGHT_CLICK, true); + } + + @Override + protected void onInteract(@NotNull PlayerInteractEvent event) { + Player player = event.getPlayer(); + Location location = player.getLocation(); + player.getInventory().remove(event.getItem()); + if (PropManager.getProp(location.toBlockLocation()) != null) { + PropManager.forceUnfreeze(player.getUniqueId()); + } + player.setVisibleByDefault(false); + + DisguiseAPI.disguiseNextEntity(DisguiseAPI.getDisguise(player)); + + Villager villager = location.getWorld().spawn(location, Villager.class, v -> { + v.setProfession(Villager.Profession.NITWIT); + v.setAdult(); + v.setAgeLock(true); + v.setSilent(true); + v.setAI(false); + }); + + new BukkitRunnable() { + @Override + public void run() { + villager.setAI(true); + player.setVisibleByDefault(true); + } + }.runTaskLater(BlockAndSeek.getInstance(), 3 * 20); + + + } + + @Override + protected @NotNull ItemStack buildRawItem() { + ItemStack itemStack = new ItemStack(Material.FIREWORK_STAR); + itemStack.editMeta(itemMeta -> itemMeta.addEnchant(Enchantment.INFINITY, 1, true)); + return itemStack; + } + + @Override + public @NotNull ItemStack getTranslated(Player player) { + return TranslationManager.translateItem(player, getCloned(), TranslationKey.DECOY); + } +} diff --git a/src/main/java/hdvtdev/blockandseek/items/MorphItem.java b/src/main/java/hdvtdev/blockandseek/items/special/MorphItem.java similarity index 83% rename from src/main/java/hdvtdev/blockandseek/items/MorphItem.java rename to src/main/java/hdvtdev/blockandseek/items/special/MorphItem.java index 52f226e..d0e36e0 100644 --- a/src/main/java/hdvtdev/blockandseek/items/MorphItem.java +++ b/src/main/java/hdvtdev/blockandseek/items/special/MorphItem.java @@ -1,5 +1,6 @@ -package hdvtdev.blockandseek.items; +package hdvtdev.blockandseek.items.special; +import hdvtdev.blockandseek.BlocksGenerator; import hdvtdev.blockandseek.managers.TranslationManager; import hdvtdev.blockandseek.objects.BlockAndSeekItem; import hdvtdev.blockandseek.objects.Items; @@ -26,14 +27,25 @@ public class MorphItem extends BlockAndSeekItem { protected void onInteract(@NotNull PlayerInteractEvent event) { Block block = event.getClickedBlock(); Player player = event.getPlayer(); + + ItemStack itemStack = event.getItem(); + if (block == null) { RayTraceResult result = player.rayTraceBlocks(128); if (result != null) { block = result.getHitBlock(); } else return; } - if (block == null) return; + + if (!BlocksGenerator.isSupported(block.getType())) { + player.sendMessage(TranslationKey.BLOCK_NOT_SUPPORTED.translate(player)); + return; + } + + player.getInventory().remove(itemStack); + + DisguiseAPI.disguiseToAll(player, new MiscDisguise(DisguiseType.FALLING_BLOCK, new ItemStack(block.getType()))); } diff --git a/src/main/java/hdvtdev/blockandseek/managers/CommandManager.java b/src/main/java/hdvtdev/blockandseek/managers/CommandManager.java new file mode 100644 index 0000000..6f8766c --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/managers/CommandManager.java @@ -0,0 +1,143 @@ +package hdvtdev.blockandseek.managers; + +import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.Config; +import hdvtdev.blockandseek.GlowUtil; +import hdvtdev.blockandseek.objects.BlockAndSeekGame; +import hdvtdev.blockandseek.objects.Items; +import hdvtdev.blockandseek.objects.TranslationKey; +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.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.block.Block; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.RayTraceResult; +import org.incendo.cloud.Command; +import org.incendo.cloud.bukkit.CloudBukkitCapabilities; +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.StringParser; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Stream; + +public final class CommandManager { + + private static final LegacyPaperCommandManager commandManager; + private static final String perm = "blockandseek.manage"; + + static { + commandManager = LegacyPaperCommandManager.createNative( + BlockAndSeek.getInstance(), + ExecutionCoordinator.simpleCoordinator() + ); + + if ( + commandManager.hasCapability( + CloudBukkitCapabilities.NATIVE_BRIGADIER + ) + ) { + try { + commandManager.registerBrigadier(); + } catch (IllegalStateException ignored) { + } + } + } + + public static void registerCommands() { + + var root = commandManager.commandBuilder("blockandseek", "bs"); + if (Config.debugEnabled()) testCommands(root); + + var partyBase = root.literal("party"); + var reloadBase = root.literal("reload").permission(perm); //all, config, langs, maps + var createBase = root.literal("create"); //party, map, game + var mapBase = root.literal("map").permission(perm); //name + var editMapBase = mapBase.literal("set"); + + commandManager.command( + createBase + .literal("map") + .required("worldName", StringParser.stringParser(), MapsManager.worldSuggestions) + .handler(ctx -> { + + MapsManager.addMap(ctx.get("worldName")); + }) + ); + + + + + commandManager.command( + partyBase + + .required("name", StringParser.stringParser(), + SuggestionProvider.blockingStrings((ctx, input) -> + Stream.concat(Bukkit.getOnlinePlayers().stream() + .map(Player::getName).filter(n -> !n.equals(ctx.sender().getName())), Stream.of("leave", "info")) + .toList() + ) + ) + .handler(ctx -> { /* ... */ }) + ); + + + commandManager.command( + partyBase + .literal("join") + .required("playerId", StringParser.stringParser()) + .required("partyId", StringParser.stringParser()) + .handler(ctx -> { + if (ctx.sender() instanceof Player player) { + Player owner = Bukkit.getPlayer(UUID.fromString(ctx.get("playerId"))); + if (owner != null) { + PartyManager.joinParty(player.getUniqueId(), ctx.get("partyID")); + player.sendMessage("Вы вступили в пати " + owner.getUniqueId()); + } else player.sendMessage("Пати не существует!"); + } + }) + + ); + + + commandManager.command( + reloadBase.literal("languages").handler(ctx -> TranslationManager.loadLanguages()) + ); + + commandManager.command( + reloadBase.literal("maps").handler(ctx -> MapsManager.loadMaps()) + ); + + commandManager.command( + reloadBase.literal("config").handler(ctx -> Config.loadConfig()) + ); + + commandManager.command( + reloadBase.literal("all").handler(ctx -> { + Config.loadConfig(); + MapsManager.loadMaps(); + TranslationManager.loadLanguages(); + }) + ); + + + + } + + private static void testCommands(Command.Builder root) { + + } + + +} diff --git a/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java b/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java index c3f9366..1326cf4 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java @@ -29,6 +29,10 @@ public class GamesManager { public static BlockAndSeekGame createGame(String name) { + if (games.containsKey(name)) { + return games.get(name); + } + BlockAndSeekMap map = MapsManager.getMap(name); BlockAndSeekGame game = new BlockAndSeekGame(name, map); games.put(name, game); diff --git a/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java b/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java index 1b47436..28343f0 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java @@ -1,12 +1,11 @@ package hdvtdev.blockandseek.managers; -import hdvtdev.blockandseek.Keys; import hdvtdev.blockandseek.items.*; +import hdvtdev.blockandseek.items.special.*; import hdvtdev.blockandseek.objects.BlockAndSeekItem; import hdvtdev.blockandseek.objects.Items; import hdvtdev.blockandseek.objects.TranslationKey; import lombok.Getter; -import net.kyori.adventure.text.Component; import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; @@ -16,18 +15,14 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; -import org.bukkit.persistence.PersistentDataType; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; - -import static hdvtdev.blockandseek.objects.TranslationKey.*; +import java.util.*; public class ItemManager { private static final Map items = new EnumMap<>(Items.class); + private static final Map specialItems = new EnumMap<>(Items.class); static { items.put(Items.MORPH, new MorphItem()); @@ -38,6 +33,16 @@ public class ItemManager { items.put(Items.PISTOL, new Pistol()); items.put(Items.GRENADE, new Grenade()); items.put(Items.FREEZE, new FreezeItem()); + items.put(Items.DEATH_BELT, new DeathBelt()); + items.put(Items.DECOY, new Decoy()); + items.put(Items.CHORUS, new Chorus()); + items.put(Items.ANTI_GRAVITY, new AntiGravity()); + + specialItems.put(Items.DEATH_BELT, new DeathBelt()); + specialItems.put(Items.DECOY, new Decoy()); + specialItems.put(Items.MORPH, new MorphItem()); + specialItems.put(Items.ANTI_GRAVITY, new AntiGravity()); + //specialItems.put(Items.CHORUS, new Chorus()); } @@ -45,6 +50,12 @@ public class ItemManager { return items.get(item); } + public static List getSpecItems() { + List itemList = new ArrayList<>(specialItems.values()); + Collections.shuffle(itemList); + return itemList; + } + private static final ItemStack seekerSword = new ItemStack(Material.WOODEN_SWORD); private static final ItemStack seekerHelmet = new ItemStack(Material.LEATHER_HELMET); private static final ItemStack seekerChestplate = new ItemStack(Material.LEATHER_CHESTPLATE); diff --git a/src/main/java/hdvtdev/blockandseek/managers/PartyManager.java b/src/main/java/hdvtdev/blockandseek/managers/PartyManager.java new file mode 100644 index 0000000..fb57843 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/managers/PartyManager.java @@ -0,0 +1,127 @@ +package hdvtdev.blockandseek.managers; + +import hdvtdev.blockandseek.objects.Party; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.*; + +import java.util.*; + +public class PartyManager { + + public enum Code { + NOT_EXIST, // Пати не существует + ALREADY_IN_PARTY, // Игрок уже в пати + NOT_IN_PARTY, // Игрок не в пати (для команд выхода/кика) + NOT_AN_OWNER, OK // Успешно + } + + private static final Map playerPartyMap = new HashMap<>(); + private static final Map partiesById = new HashMap<>(); + + /** + * Создать новую пати. + */ + public static Code createParty(@NotNull UUID owner) { + if (playerPartyMap.containsKey(owner)) { + return Code.ALREADY_IN_PARTY; + } + + Party party = new Party(owner); + partiesById.put(party.getPartyId(), party); + playerPartyMap.put(owner, party); + + return Code.OK; + } + + + public static Code joinParty(@NotNull UUID player, @NotNull UUID partyId) { + if (playerPartyMap.containsKey(player)) { + return Code.ALREADY_IN_PARTY; + } + + Party party = partiesById.get(partyId); + if (party == null) { + return Code.NOT_EXIST; + } + + party.addMember(player); + playerPartyMap.put(player, party); + + return Code.OK; + } + + public static Code joinPartyByMember(@NotNull UUID player, @NotNull UUID memberInParty) { + Party party = playerPartyMap.get(memberInParty); + if (party == null) { + return Code.NOT_EXIST; + } + return joinParty(player, party.getPartyId()); + } + + public static Code leaveParty(@NotNull UUID player) { + Party party = playerPartyMap.get(player); + if (party == null) { + return Code.NOT_IN_PARTY; + } + + // Удаляем игрока из списка участников и из мапы + party.removeMember(player); + playerPartyMap.remove(player); + + // Если пати опустела - удаляем её полностью + if (party.getMembers().isEmpty()) { + partiesById.remove(party.getPartyId()); + return Code.OK; + } + + if (party.getOwner().equals(player)) { + UUID newOwner = party.getMembers().iterator().next(); + party.setOwner(newOwner); + //todo send message to owner + } + + return Code.OK; + } + + + public static Code disbandParty(@NotNull UUID requester) { + Party party = playerPartyMap.get(requester); + if (party == null) { + return Code.NOT_IN_PARTY; + } + + // Проверяем, является ли запрашивающий лидером + if (!party.getOwner().equals(requester)) { + return Code.NOT_AN_OWNER; // Технически "права не существуют" + } + + // Удаляем записи о пати у всех участников + for (UUID member : party.getMembers()) { + playerPartyMap.remove(member); + } + + // Удаляем саму пати + partiesById.remove(party.getPartyId()); + + party.getMembers().clear(); + + return Code.OK; + } + + @Nullable + public static Party getParty(@NotNull UUID player) { + return playerPartyMap.get(player); + } +} \ 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 1c7e83c..08d15d8 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/PropManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/PropManager.java @@ -18,14 +18,15 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.Nullable; +import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class PropManager { - private static final Map players = new ConcurrentHashMap<>(); - private static final Map props = new ConcurrentHashMap<>(); + private static final Map players = new HashMap<>(); + private static final Map props = new HashMap<>(); private PropManager() {} @@ -73,6 +74,7 @@ public class PropManager { player.teleport(propLocation.toCenterLocation()); player.setInvulnerable(false); + player.setInvisible(false); player.setVisibleByDefault(true); player.setGameMode(GameMode.SURVIVAL); @@ -103,6 +105,7 @@ public class PropManager { centerLocation.setY(centerLocation.getY() - 0.85); player.setInvulnerable(true); + player.setInvisible(true); player.setVisibleByDefault(false); player.setFreezeTicks(40); diff --git a/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java b/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java index 19f4a90..c7c5169 100644 --- a/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java +++ b/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java @@ -1,14 +1,12 @@ 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.BlockAndSeekItem; import hdvtdev.blockandseek.objects.Translation; import hdvtdev.blockandseek.objects.TranslationKey; import lombok.Getter; @@ -21,6 +19,7 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.*; @@ -28,7 +27,8 @@ import java.util.concurrent.atomic.AtomicReference; public final class TranslationManager { - private TranslationManager() {} + private TranslationManager() { + } public static final String defaultLanguage = "en_US"; public static final MiniMessage mm = MiniMessage.miniMessage(); @@ -38,7 +38,6 @@ public final class TranslationManager { public static final String bracedPrefix = "[BlockAndSeek]"; private static final Map> translations = new HashMap<>(); - private static final Map itemTranslations = new HashMap<>(); public static Component get(Player player, TranslationKey key, String... placeholders) { return get(player.locale().toString(), key, placeholders); @@ -55,7 +54,7 @@ public final class TranslationManager { } public static ItemStack translateItem(Player player, ItemStack itemStack, TranslationKey key, String... placeholders) { - ItemMeta itemMeta = itemStack.getItemMeta(); + ItemMeta itemMeta = itemStack.getItemMeta(); itemMeta.displayName(get(player, key, placeholders)); itemStack.setItemMeta(itemMeta); return itemStack; @@ -89,6 +88,55 @@ public final class TranslationManager { } + @SafeVarargs + private static String processPlaceholders(@NotNull String text, @NotNull Map.Entry... placeholders) { + if (placeholders.length == 0) return text; + + Map params = Map.ofEntries(placeholders); + + StringBuilder sb = new StringBuilder(text.length() + 32); + int cursor = 0; + int len = text.length(); + + while (cursor < len) { + int start = text.indexOf('%', cursor); + + if (start == -1) { + sb.append(text, cursor, len); + break; + } + + if (start > cursor && text.charAt(start - 1) == '\\') { + sb.append(text, cursor, start - 1); + sb.append('%'); + cursor = start + 1; + continue; + } + + int end = text.indexOf('%', start + 1); + + if (end == -1) { + sb.append(text, cursor, len); + break; + } + + sb.append(text, cursor, start); + + String key = text.substring(start + 1, end); + + String replacement = params.get(key); + + if (replacement != null) { + sb.append(replacement); + } else { + sb.append('%').append(key).append('%'); + } + + cursor = end + 1; + } + + return sb.toString(); + } diff --git a/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java b/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java index 98d4546..59054df 100644 --- a/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java +++ b/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java @@ -1,12 +1,15 @@ package hdvtdev.blockandseek.menus; +import hdvtdev.blockandseek.managers.PartyManager; import hdvtdev.blockandseek.managers.TranslationManager; import hdvtdev.blockandseek.GuiHolder; import hdvtdev.blockandseek.managers.GamesManager; import hdvtdev.blockandseek.managers.ItemManager; +import hdvtdev.blockandseek.objects.Party; 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; @@ -14,9 +17,11 @@ 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; +import java.util.UUID; public class GamesMenu implements GuiHolder { @@ -58,9 +63,22 @@ public class GamesMenu implements GuiHolder { 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)); + Party party = PartyManager.getParty(player.getUniqueId()); + if (party != null) { + for (UUID member : party.getMembers()) { + Player p = Bukkit.getPlayer(member); + if (p != null) { + if (!game.addPlayer(p)) { + p.sendMessage(TranslationManager.get(p, TranslationKey.GAME_IS_FULL, "%game%", gameName)); + } + } + } + } else { + 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 index 8fe8ac9..15ac227 100644 --- a/src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java +++ b/src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java @@ -1,11 +1,9 @@ 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.managers.*; import hdvtdev.blockandseek.objects.BlockAndSeekMap; +import hdvtdev.blockandseek.objects.Party; import hdvtdev.blockandseek.objects.TranslationKey; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; @@ -18,6 +16,7 @@ import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; import static hdvtdev.blockandseek.objects.TranslationKey.UNKNOWN_MAP; @@ -52,7 +51,29 @@ public class MapsMenu implements GuiHolder { Player player = (Player) event.getWhoClicked(); String mapName = TranslationManager.plaintText.serialize(item.displayName()).replaceAll("[\\[\\]]", ""); if (MapsManager.hasMap(mapName)) { - GamesManager.createGame(mapName).addPlayer(player); + Party party = PartyManager.getParty(player.getUniqueId()); + if (party != null) { + var members = party.getMembers(); + var game = GamesManager.createGame(mapName); + if (members.size() + game.playerCount() > game.maxPlayers()) { + Player owner = Bukkit.getPlayer(party.getOwner()); + if (owner != null) { + owner.sendMessage("Пати слишком жирная чтобы уместица в игре"); + } + } else { + for (UUID uuid : members) { + Player member = Bukkit.getPlayer(uuid); + if (member != null) { + game.addPlayer(member); + } + } + } + + + } else { + GamesManager.createGame(mapName).addPlayer(player); + } + } else { player.sendMessage(UNKNOWN_MAP.translate(player, "%map%", mapName, "%maps%", String.join(", ", MapsManager.getAllMaps()))); } diff --git a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java index 1df3546..1cce249 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java +++ b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java @@ -11,6 +11,7 @@ import hdvtdev.blockandseek.managers.PropManager; import hdvtdev.blockandseek.managers.StateManager; import hdvtdev.blockandseek.roulette.RouletteCreator; +import hdvtdev.blockandseek.roulette.RouletteList; import me.libraryaddict.disguise.DisguiseAPI; import me.libraryaddict.disguise.disguisetypes.DisguiseType; import me.libraryaddict.disguise.disguisetypes.MiscDisguise; @@ -18,10 +19,10 @@ import me.libraryaddict.disguise.disguisetypes.MiscDisguise; import net.kyori.adventure.text.Component; import net.kyori.adventure.title.Title; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Sound; +import org.bukkit.*; import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.HandlerList; @@ -40,6 +41,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.Vector; import org.bukkit.plugin.Plugin; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; @@ -75,6 +77,14 @@ public class BlockAndSeekGame { return stateManager.getPlayers().size() + "/" + map.getMaxPlayers(); } + public int playerCount() { + return stateManager.playerCount(); + } + + public int maxPlayers() { + return map.getMaxPlayers(); + } + private void start() { phase = new LobbyPhase(); phase.onEnable(); @@ -169,6 +179,8 @@ public class BlockAndSeekGame { private long gameDuration = map.getGameDuration().toSeconds(); private final long midGame = gameDuration / 2; + private final long suddenDeath = map.getSuddenDeath().toSeconds(); + @Override public void onTick() { @@ -192,6 +204,17 @@ public class BlockAndSeekGame { new RouletteCreator(player, map.getBlocks()); } } + } else if (gameDuration == suddenDeath) { + for (UUID uuid : stateManager.getPlayersInState(PlayerType.SEEKER)) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + BlockAndSeekItem.addCooldownImune(uuid); + player.setWalkSpeed(0.5f); + player.setInvulnerable(true); + player.setGlowing(false); + player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP_BOOST, Integer.MAX_VALUE, 1, false, false, false)); + } + } } actionBarToAll(TranslationKey.TIME_LEFT, "%time%", String.valueOf(gameDuration)); } @@ -213,6 +236,37 @@ public class BlockAndSeekGame { player.setInvulnerable(false); } else BlockAndSeek.getPluginLogger().warning("Player is null. "); } + long specialItemSpawnTime = map.getSpawnSpecialItems().toSeconds() * 20; + new BukkitRunnable() { + + private final RouletteList specialItems = new RouletteList<>(ItemManager.getSpecItems()); + private final Location spawn = map.getSpawn().getLocation(); + private final Vector zero = new Vector(0, 0, 0); + private UUID prevItem; + + @Override + public void run() { + if (phase == null) { + this.cancel(); + } else { + Location location = spawn.clone().toCenterLocation(); + ItemStack specialItem = specialItems.next().getTranslated(location.getNearbyPlayers(256).iterator().next()); //fixme: translation for all + location.setY(location.getY() + 1.5); + World world = location.getWorld(); + if (prevItem != null) { + Entity entity = world.getEntity(prevItem); + if (entity != null) entity.remove(); + } + Item item = world.dropItem(location, specialItem); + prevItem = item.getUniqueId(); + item.setGlowing(true); + item.setCanMobPickup(false); + item.setGravity(false); + item.setVelocity(zero); + item.setUnlimitedLifetime(true); + } + } + }.runTaskTimer(BlockAndSeek.getInstance(), specialItemSpawnTime, specialItemSpawnTime); } private void selectSeekers(int count) { @@ -230,8 +284,8 @@ public class BlockAndSeekGame { Player player = Bukkit.getPlayer(seeker); if (player != null) { stateManager.setPlayerState(seeker, PlayerType.SEEKER); - player.setWalkSpeed(0.27f); - + player.setWalkSpeed(0.25f); + player.setGlowing(true); player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, (int) spawnDelay, 2)); ItemManager.setSeekerSet(player); Utils.setLevelWithBar(player, 100); @@ -270,6 +324,21 @@ public class BlockAndSeekGame { } } + @EventHandler + private void onItemPickup(EntityPickupItemEvent event) { + if (event.getEntity() instanceof Player player) { + if (stateManager.getState(player.getUniqueId()) == PlayerType.PROP) { + Item item = event.getItem(); + BlockAndSeekItem blockAndSeekItem = BlockAndSeekItem.tryCast(item.getItemStack()); + if (blockAndSeekItem != null) { + item.remove(); + player.getInventory().addItem(blockAndSeekItem.getTranslated(player)); + } + } + event.setCancelled(true); + } + } + @EventHandler private void onItemDrop(PlayerDropItemEvent event) { if (stateManager.hasPlayer(event.getPlayer().getUniqueId())) { @@ -283,6 +352,8 @@ public class BlockAndSeekGame { if (stateManager.hasPlayer(player.getUniqueId())) { if (event.getCause() == EntityDamageEvent.DamageCause.FALL) { event.setCancelled(true); + } else if (stateManager.getState(player.getUniqueId()) == PlayerType.SEEKER) { + Utils.setLevelWithBar(player, (int) Math.round(player.getHealth() * 5)); } } } @@ -351,12 +422,9 @@ public class BlockAndSeekGame { 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)); - } + Utils.healSeeker(damager, event.getDamage()); + } else if (victimType == PlayerType.SEEKER) { + Utils.setLevelWithBar(damager, (int) Math.round(damager.getHealth() * 5)); } } } @@ -440,11 +508,14 @@ public class BlockAndSeekGame { if (player != null) { //propManager.removePlayer(player); Utils.clearPlayer(player); - player.setInvulnerable(true); + player.setInvulnerable(false); ItemManager.defaultInventory(player); player.teleport(Config.spawn()); } } + for (Entity entity : map.getSpawn().getLocation().getWorld().getEntities()) { + entity.remove(); + } endGame(); } diff --git a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekItem.java b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekItem.java index 2eb245a..c5ef7eb 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekItem.java +++ b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekItem.java @@ -3,6 +3,7 @@ package hdvtdev.blockandseek.objects; import hdvtdev.blockandseek.BlockAndSeek; import hdvtdev.blockandseek.managers.ItemManager; +import hdvtdev.blockandseek.managers.PropManager; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.entity.Player; @@ -15,7 +16,9 @@ import org.jetbrains.annotations.Nullable; import java.time.Duration; import java.util.EnumSet; +import java.util.HashSet; import java.util.Set; +import java.util.UUID; public abstract class BlockAndSeekItem { @@ -24,6 +27,7 @@ public abstract class BlockAndSeekItem { private final long cooldown; private final ItemStack rawItem; private final Set actions; + private final boolean availableForProp; private static final Set rightClickOnly = EnumSet.of(Action.RIGHT_CLICK_BLOCK, Action.RIGHT_CLICK_AIR); private static final Set leftClickOnly = EnumSet.of(Action.LEFT_CLICK_BLOCK, Action.LEFT_CLICK_AIR); @@ -32,7 +36,9 @@ public abstract class BlockAndSeekItem { Action.LEFT_CLICK_BLOCK, Action.LEFT_CLICK_AIR ); - public BlockAndSeekItem(@NotNull Items id, @NotNull Duration cooldown, @NotNull ClickAction clickAction) { + private static final Set cooldownImune = new HashSet<>(); + + public BlockAndSeekItem(@NotNull Items id, @NotNull Duration cooldown, @NotNull ClickAction clickAction, boolean availableForProp) { this.actions = switch (clickAction) { case RIGHT_CLICK -> rightClickOnly; case LEFT_CLICK -> leftClickOnly; @@ -40,18 +46,35 @@ public abstract class BlockAndSeekItem { }; this.cooldown = cooldown.toMillis() / 50; this.rawItem = asItemStack(id); + this.availableForProp = availableForProp; } public BlockAndSeekItem(@NotNull Items id) { - this(id, Duration.ZERO, ClickAction.ANY); + this(id, Duration.ZERO, ClickAction.ANY, true); } public BlockAndSeekItem(@NotNull Items id, @NotNull ClickAction action) { - this(id, Duration.ZERO, action); + this(id, Duration.ZERO, action, true); } public BlockAndSeekItem(@NotNull Items id, @NotNull Duration cooldown) { - this(id, cooldown, ClickAction.ANY); + this(id, cooldown, ClickAction.ANY, true); + } + + public BlockAndSeekItem(@NotNull Items id, boolean availableForProp) { + this(id, Duration.ZERO, ClickAction.ANY, availableForProp); + } + + public BlockAndSeekItem(@NotNull Items id, @NotNull Duration cooldown, @NotNull ClickAction clickAction) { + this(id, cooldown, clickAction, true); + } + + public static void addCooldownImune(UUID uuid) { + cooldownImune.add(uuid); + } + + public static void removeCooldownImune(UUID uuid) { + cooldownImune.remove(uuid); } @NotNull @@ -63,16 +86,19 @@ public abstract class BlockAndSeekItem { public final boolean onRawInteract(@NotNull PlayerInteractEvent event) { if (this.actions.contains(event.getAction())) { - if (cooldown != 0) { - Player player = event.getPlayer(); - Material material = event.getMaterial(); - if (!player.hasCooldown(material)) { - player.setCooldown(material, (int) cooldown); + Player player = event.getPlayer(); + UUID uuid = player.getUniqueId(); + if (availableForProp || !PropManager.isProped(uuid)) { + if (cooldown != 0) { + Material material = event.getMaterial(); + if (!player.hasCooldown(material)) { + player.setCooldown(material, cooldownImune.contains(uuid) ? 6 : (int) cooldown); + onInteract(event); + } + return false; + } else { onInteract(event); } - return false; - } else { - onInteract(event); } } diff --git a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java index 6eb41eb..0f8bf8d 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java +++ b/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java @@ -48,7 +48,13 @@ public class BlockAndSeekMap extends OkaeriConfig { private Duration delayBeforeGameEnd = Duration.ofSeconds(10); @Comment("Create blocks roulette for all hiders to select a new prop") - private boolean midGameBlockSwap = true; + @CustomKey("midgame-block-swap") + private boolean midgameBlockSwap = true; + + @Comment("If not zero, spawns random super items (for ex: morph item, decoy) every n time on map spawn (a bit higher)") + @Comment("Format examples: 1m, 300s") + @CustomKey("spawn-special-items") + private Duration spawnSpecialItems = Duration.ofMinutes(4); @Comment("Grants seeker infinite health, speed, and jump boost for the specified time before the game ends.") @Comment("Format examples: 10m, 300s, 1h. If duration is zero, sudden death will be disabled") @@ -58,9 +64,4 @@ public class BlockAndSeekMap extends OkaeriConfig { @Comment("Available prop blocks for hiders") private List blocks = new ArrayList<>(List.of(new PropBlock(new ItemStack(Material.TARGET), Rarity.LEGENDARY))); - - - -} - - +} \ No newline at end of file diff --git a/src/main/java/hdvtdev/blockandseek/objects/Items.java b/src/main/java/hdvtdev/blockandseek/objects/Items.java index 6af9fe0..040fec5 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/Items.java +++ b/src/main/java/hdvtdev/blockandseek/objects/Items.java @@ -15,7 +15,7 @@ public enum Items implements PersistentDataType { MENU, SOUND_MAKER, DASH, - MORPH, GRENADE; + MORPH, GRENADE, DECOY, DEATH_BELT, CHORUS, ANTI_GRAVITY; public static final PersistentDataType TYPE = PISTOL; diff --git a/src/main/java/hdvtdev/blockandseek/objects/LazyLocation.java b/src/main/java/hdvtdev/blockandseek/objects/LazyLocation.java index da049a8..6f69082 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/LazyLocation.java +++ b/src/main/java/hdvtdev/blockandseek/objects/LazyLocation.java @@ -7,12 +7,10 @@ import eu.okaeri.configs.annotation.Exclude; import hdvtdev.blockandseek.BlockAndSeek; +import hdvtdev.blockandseek.Utils; import lombok.NoArgsConstructor; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.WorldCreator; +import org.bukkit.*; import org.bukkit.entity.Player; @NoArgsConstructor @@ -34,9 +32,18 @@ public class LazyLocation extends OkaeriConfig { @Exclude private Location location; + @SuppressWarnings("deprecation") // for world.setGameRuleValue because 1.20.6 does not have GameRule.LOCATORBAR private void loadLocation() { BlockAndSeek.getPluginLogger().info("Loading world \"" + worldName + "\""); World world = Bukkit.createWorld(new WorldCreator(worldName)); + world.setGameRule(GameRule.DO_MOB_SPAWNING, false); + world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); + world.setGameRule(GameRule.DO_WEATHER_CYCLE, false); + world.setGameRule(GameRule.RANDOM_TICK_SPEED, 0); + world.setAutoSave(false); + if (Utils.isVersionAtLeast("1.21.5")) { + world.setGameRuleValue("locatorbar", "false"); + } this.location = new Location(world, x, y, z, yaw, pitch); } diff --git a/src/main/java/hdvtdev/blockandseek/objects/Party.java b/src/main/java/hdvtdev/blockandseek/objects/Party.java new file mode 100644 index 0000000..6da12e3 --- /dev/null +++ b/src/main/java/hdvtdev/blockandseek/objects/Party.java @@ -0,0 +1,33 @@ +package hdvtdev.blockandseek.objects; + +import lombok.Getter; +import lombok.Setter; + +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + + +@Getter +public class Party { + @Setter + private UUID owner; + private final Set members = new HashSet<>(); + private final UUID partyId = UUID.randomUUID(); + + public Party(@NotNull UUID owner) { + this.owner = owner; + this.members.add(owner); + } + + public void addMember(@NotNull UUID member) { + members.add(member); + } + + public void removeMember(@NotNull UUID member) { + members.remove(member); + } + +} \ 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 index 7dbb4da..dc53f5b 100644 --- a/src/main/java/hdvtdev/blockandseek/objects/TranslationKey.java +++ b/src/main/java/hdvtdev/blockandseek/objects/TranslationKey.java @@ -6,11 +6,22 @@ import org.bukkit.entity.Player; public enum TranslationKey { // Misc + CHORUS, + BLOCK_NOT_SUPPORTED, UNKNOWN_COMMAND, SEEKER_TEMPLATE, + CONFIG_RELOADED, // Maps management UNKNOWN_MAP, + MAP_CREATED, + MAP_NOT_CREATED, + MAP_EXIST, + PARTY_INVITE, + PARTY_KICK, + PARTY_LEAVE, + PARTY_INFO, + PARTY_JOIN, SUCCESSFUL_MAP_CREATION, // Menus @@ -29,18 +40,35 @@ public enum TranslationKey { PLAYER_JOINED, PLAYER_LEFT, SEEKERS_WIN, + SEEKERS_SPAWN, + SEEKERS_SPAWNED, + SEEKER_DIED, + HIDER_FOUND, + HIDER_DIED, + HIDER_DIED_BY_HIDER, HIDERS_WIN, HIDER_SOLO_WIN, ROULETTE, GAME_IS_FULL, WAITING_FOR_PLAYERS, + GAME_STARTED, + SUPER_ITEM_SPAWN, + SUPER_ITEM_SPAWNED, + BLOCK_SWAP, + BLOCK_SWAPPING, // Items FREEZE_ITEM, FACE_CHANGING_ITEM, SOUND_ITEM, LEAVE_ITEM, - DASH_ITEM, MORPH_ITEM, PISTOL, GRENADE; + GAME_START_ITEM, + DASH_ITEM, + MORPH_ITEM, + PISTOL, GRENADE, + DECOY, + DEATH_BELT, + ANTI_GRAVITY; public Component translate(Player player, String... placeholders) { return TranslationManager.get(player, this, placeholders);