diff --git a/CHANGES.md b/CHANGES.md index e6e0ed1b..9c020ea9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,11 +1,13 @@ **New Plugin [Infinite Elytra Parkour](https://www.spigotmc.org/resources/115322/) | [IP+](https://www.spigotmc.org/resources/105019/)** -- Fixed schematics being unusable when it contains unknown materials -- Fixed difficulty going above 1 -- Fixed schematic points being based on all settings difficulty, not schematic difficulty -- Fixed inventories not being cleared -- Fixed inventories being cleared on leave with inventory handling off -- Fixed teleporting not being async when possible -- Fixed incorrect rewards documentation -- Added debugging messages -- Improved unsupported schematic message clarity \ No newline at end of file +- Added item for IEP support +- Added option to disable players opening blocks with inventories +- Fixed players occasionally being reset to previous location while switching mode +- Fixed errors showing up in console on disable when nobody joined parkour +- Fixed world being deleted even if delete-on-reload is enabled +- Fixed not loading if delete-on-reload is enabled with Multiverse worlds +- Fixed bad parkour pathfinding near edges +- Fixed player mounting causing issues +- Fixed players being able to transfer inventory items with some plugins +- Fixed not being able to close leaderboard if not using IP+ +- Fixed errors when joining as spectator \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4177e0c6..330b4e1c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ dev.efnilite IP - 5.2.0 + 5.2.1 16 @@ -97,7 +97,7 @@ com.github.Efnilite vilib - ed66743ad8 + 66840fa513 compile diff --git a/src/main/java/dev/efnilite/ip/Command.java b/src/main/java/dev/efnilite/ip/Command.java index 09db623a..3de12bf8 100644 --- a/src/main/java/dev/efnilite/ip/Command.java +++ b/src/main/java/dev/efnilite/ip/Command.java @@ -138,7 +138,7 @@ private void sendHelpMessages(CommandSender sender) { send(sender, ""); send(sender, "/parkour - Main command"); if (sender.hasPermission(ParkourOption.JOIN.permission)) { - send(sender, "/parkour join [mode] - Join the default mode or specify one."); + send(sender, "/parkour join [mode/player] - Join the default mode or specify one."); send(sender, "/parkour leave - Leave the game on this server"); } if (sender.hasPermission(ParkourOption.MAIN.permission)) { diff --git a/src/main/java/dev/efnilite/ip/Events.java b/src/main/java/dev/efnilite/ip/Events.java index fe6093b7..1208416b 100644 --- a/src/main/java/dev/efnilite/ip/Events.java +++ b/src/main/java/dev/efnilite/ip/Events.java @@ -28,6 +28,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityMountEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.*; @@ -80,7 +81,7 @@ public void join(PlayerJoinEvent event) { if (player.isOp() && WorldManagerMV.MANAGER != null && VoidGenerator.getMultiverseGenerator() == null) { send(player, ""); - send(player, IP.PREFIX + "You are running Multiverse without VoidGen. This causes extreme lag spikes and performance issues while playing. Please visit the wiki to fix this."); + send(player, IP.PREFIX + "You are running Multiverse without VoidGen. This causes extreme lag spikes and performance issues while playing. Please install the plugin 'VoidGen' to fix this."); send(player, ""); } @@ -227,7 +228,9 @@ public void interact(PlayerInteractEvent event) { } else if (held == quit) { ParkourUser.leave(player); } else { - event.setCancelled(false); + if (!Config.CONFIG.getBoolean("options.disable-inventory-blocks")) { + event.setCancelled(false); + } } } @@ -278,7 +281,7 @@ public void damage(EntityDamageEvent event) { handleRestriction(player, event); } - @EventHandler + @EventHandler(priority = EventPriority.HIGHEST) public void inventory(InventoryClickEvent event) { if (!(event.getWhoClicked() instanceof Player player) || event.getInventory().getType() == InventoryType.CRAFTING) { return; @@ -296,6 +299,15 @@ public void spectate(PlayerTeleportEvent event) { handleRestriction(event.getPlayer(), event); } + @EventHandler(priority = EventPriority.HIGHEST) + public void mount(EntityMountEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + + handleRestriction(player, event); + } + private void handleRestriction(Player player, Cancellable event) { if (!ParkourUser.isUser(player)) { return; diff --git a/src/main/java/dev/efnilite/ip/IP.java b/src/main/java/dev/efnilite/ip/IP.java index 4d9f7bf1..89be9cb3 100644 --- a/src/main/java/dev/efnilite/ip/IP.java +++ b/src/main/java/dev/efnilite/ip/IP.java @@ -19,7 +19,6 @@ import dev.efnilite.vilib.bstats.charts.SingleLineChart; import dev.efnilite.vilib.inventory.Menu; import dev.efnilite.vilib.util.Logging; -import dev.efnilite.vilib.util.elevator.GitElevator; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -107,20 +106,19 @@ public void enable() { @Override public void disable() { - for (ParkourUser user : ParkourUser.getUsers()) { - ParkourUser.leave(user); - } + try { + for (ParkourUser user : ParkourUser.getUsers()) { + ParkourUser.leave(user); + } - // write all IP gamemodes - Modes.DEFAULT.getLeaderboard().write(false); + // write all IP gamemodes + Modes.DEFAULT.getLeaderboard().write(false); - Storage.close(); - WorldManager.delete(); - } + Storage.close(); + WorldManager.delete(); + } catch (Throwable ignored) { - @Override - public GitElevator getElevator() { - return null; + } } public static void log(String message) { diff --git a/src/main/java/dev/efnilite/ip/config/Config.java b/src/main/java/dev/efnilite/ip/config/Config.java index d618acae..9994887d 100644 --- a/src/main/java/dev/efnilite/ip/config/Config.java +++ b/src/main/java/dev/efnilite/ip/config/Config.java @@ -49,7 +49,6 @@ public enum Config { if (!path.exists()) { IP.getPlugin().saveResource(fileName, false); - IP.log("Created config file %s".formatted(fileName)); } update(); diff --git a/src/main/java/dev/efnilite/ip/generator/Island.java b/src/main/java/dev/efnilite/ip/generator/Island.java index 562e6c37..68b0fa48 100644 --- a/src/main/java/dev/efnilite/ip/generator/Island.java +++ b/src/main/java/dev/efnilite/ip/generator/Island.java @@ -3,7 +3,6 @@ import dev.efnilite.ip.IP; import dev.efnilite.ip.config.Config; import dev.efnilite.ip.session.Session; -import dev.efnilite.ip.world.Divider; import dev.efnilite.vilib.schematic.Schematic; import org.bukkit.Location; import org.bukkit.Material; @@ -44,22 +43,20 @@ public Island(@NotNull Session session, @Nullable Schematic schematic) { /** * Builds the island and teleports the player. */ - public void build() { + public void build(Location location) { if (schematic == null) { return; } IP.log("Building island"); - IP.log("Building island"); - - blocks = schematic.paste(Divider.toLocation(session).subtract(0, schematic.getDimensions().getY(), 0)); + blocks = schematic.paste(location.subtract(0, schematic.getDimensions().getY(), 0)); Material playerMaterial = Material.getMaterial(Config.GENERATION.getString("advanced.island.spawn.player-block").toUpperCase()); Material parkourMaterial = Material.getMaterial(Config.GENERATION.getString("advanced.island.parkour.begin-block").toUpperCase()); try { - Block player = blocks.stream().filter(block -> block.getType() == playerMaterial).findAny().get(); - Block parkour = blocks.stream().filter(block -> block.getType() == parkourMaterial).findAny().get(); + Block player = blocks.stream().filter(block -> block.getType() == playerMaterial).findAny().orElseThrow(); + Block parkour = blocks.stream().filter(block -> block.getType() == parkourMaterial).findAny().orElseThrow(); player.setType(Material.AIR); parkour.setType(Material.AIR); diff --git a/src/main/java/dev/efnilite/ip/generator/JumpDirector.java b/src/main/java/dev/efnilite/ip/generator/JumpDirector.java index 9a2f2a81..59655d83 100644 --- a/src/main/java/dev/efnilite/ip/generator/JumpDirector.java +++ b/src/main/java/dev/efnilite/ip/generator/JumpDirector.java @@ -68,10 +68,10 @@ private double[][] calculateParameterization(@NotNull Vector point) { * the heading will automatically be turned around to ensure that the edge does not get * destroyed. * - * @return The recommended new heading. (0,0,0) if no modification is needed. + * @return The recommended new heading. Current heading if no modification is needed. */ @NotNull - public Vector getRecommendedHeading() { + public Vector getRecommendedHeading(Vector current) { // get x values from progress array double tx = progress[0][0]; double borderMarginX = progress[0][1]; @@ -84,21 +84,25 @@ public Vector getRecommendedHeading() { // check border if (tx < borderMarginX) { // x should increase - recommendedHeading.add(new Vector(1, 0, 0)); + recommendedHeading = new Vector(1, 0, 1); } else if (tx > 1 - borderMarginX) { // x should decrease - recommendedHeading.add(new Vector(-1, 0, 0)); + recommendedHeading = new Vector(-1, 0, -1); } if (tz < borderMarginZ) { // z should increase - recommendedHeading.add(new Vector(0, 0, 1)); + recommendedHeading = new Vector(1, 0, 1); } else if (tz > 1 - borderMarginZ) { // z should decrease - recommendedHeading.add(new Vector(0, 0, -1)); + recommendedHeading = new Vector(-1, 0, -1); } - return recommendedHeading; + if (recommendedHeading.isZero()) { + return current; + } else { + return recommendedHeading; + } } /** @@ -109,7 +113,7 @@ public Vector getRecommendedHeading() { * * @return The recommended new height. 0 if no modification is needed. */ - public int getRecommendedHeight() { + public int getRecommendedHeight(int current) { double ty = progress[1][0]; double borderMarginY = progress[1][1]; @@ -120,7 +124,7 @@ public int getRecommendedHeight() { // y should decrease return -1; } - return 0; + return current; } /** diff --git a/src/main/java/dev/efnilite/ip/generator/ParkourGenerator.java b/src/main/java/dev/efnilite/ip/generator/ParkourGenerator.java index 72dda25a..f26bd3fd 100644 --- a/src/main/java/dev/efnilite/ip/generator/ParkourGenerator.java +++ b/src/main/java/dev/efnilite/ip/generator/ParkourGenerator.java @@ -304,17 +304,8 @@ protected List selectBlocks() { protected Block selectNext(Block current, int distance, int height) { JumpDirector director = new JumpDirector(BoundingBox.of(zone[0], zone[1]), getLatest().getLocation().toVector()); - Vector recommendedHeading = director.getRecommendedHeading(); - - if (!recommendedHeading.equals(new Vector(0, 0, 0))) { - heading = recommendedHeading; - } - - int recommendedHeight = director.getRecommendedHeight(); - - if (recommendedHeight != 0) { - height = recommendedHeight; - } + heading = director.getRecommendedHeading(heading); + height = director.getRecommendedHeight(height); // ensure special is possible switch (getLatest().getType()) { diff --git a/src/main/java/dev/efnilite/ip/menu/community/SingleLeaderboardMenu.java b/src/main/java/dev/efnilite/ip/menu/community/SingleLeaderboardMenu.java index 4055422d..17ea6160 100644 --- a/src/main/java/dev/efnilite/ip/menu/community/SingleLeaderboardMenu.java +++ b/src/main/java/dev/efnilite/ip/menu/community/SingleLeaderboardMenu.java @@ -1,6 +1,7 @@ package dev.efnilite.ip.menu.community; import dev.efnilite.ip.IP; +import dev.efnilite.ip.api.Registry; import dev.efnilite.ip.config.Locales; import dev.efnilite.ip.config.Option; import dev.efnilite.ip.leaderboard.Leaderboard; @@ -118,7 +119,19 @@ public void open(Player player, Mode mode, Sort sort) { .nextPage(26, new Item(Material.LIME_DYE, "<#0DCB07>»").click(event -> menu.page(1))) .prevPage(18, new Item(Material.RED_DYE, "<#DE1F1F>«").click(event -> menu.page(-1))) .item(22, Locales.getItem(player, ParkourOption.LEADERBOARDS.path + ".sort", name.toLowerCase()).click(event -> open(player, mode, next))) - .item(23, Locales.getItem(player, "other.close").click(event -> Menus.LEADERBOARDS.open(event.getPlayer()))) + .item(23, Locales.getItem(player, "other.close").click(event -> { + List modes = Registry.getModes() + .stream() + .filter(m -> m.getLeaderboard() != null && m.getItem(locale) != null) + .toList(); + + if (modes.size() == 1) { + Menus.COMMUNITY.open(player); + return; + } + + Menus.LEADERBOARDS.open(event.getPlayer()); + })) .fillBackground(ParkourUser.isBedrockPlayer(player) ? Material.AIR : Material.GRAY_STAINED_GLASS_PANE) .open(player); } diff --git a/src/main/java/dev/efnilite/ip/menu/play/PlayMenu.java b/src/main/java/dev/efnilite/ip/menu/play/PlayMenu.java index 3ed99a2d..1e05d2c8 100644 --- a/src/main/java/dev/efnilite/ip/menu/play/PlayMenu.java +++ b/src/main/java/dev/efnilite/ip/menu/play/PlayMenu.java @@ -7,6 +7,7 @@ import dev.efnilite.ip.player.ParkourUser; import dev.efnilite.vilib.inventory.Menu; import dev.efnilite.vilib.inventory.animation.RandomAnimation; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -16,9 +17,21 @@ public class PlayMenu extends DynamicMenu { public PlayMenu() { - registerMainItem(1, 0, (player, user) -> Locales.getItem(player, "play.single.item").click(event -> Menus.SINGLE.open(event.getPlayer())), ParkourOption.SINGLE::mayPerform); - registerMainItem(1, 2, (player, user) -> Locales.getItem(player, "play.spectator.item").click(event -> Menus.SPECTATOR.open(event.getPlayer())), ParkourOption.SPECTATOR::mayPerform); - registerMainItem(2, 0, (player, user) -> Locales.getItem(player, "other.close").click(event -> event.getPlayer().closeInventory()), player -> true); + registerMainItem(1, 0, (player, user) -> Locales.getItem(player, "play.single.item") + .click(event -> Menus.SINGLE.open(event.getPlayer())), + ParkourOption.SINGLE::mayPerform); + + registerMainItem(1, 1, (player, user) -> Locales.getItem(player, "other.iep") + .click(event -> event.getPlayer().performCommand("iep play")), + player -> Bukkit.getPluginManager().isPluginEnabled("IEP")); + + registerMainItem(1, 6, (player, user) -> Locales.getItem(player, "play.spectator.item") + .click(event -> Menus.SPECTATOR.open(event.getPlayer())), + ParkourOption.SPECTATOR::mayPerform); + + registerMainItem(2, 0, (player, user) -> Locales.getItem(player, "other.close") + .click(event -> event.getPlayer().closeInventory()), + player -> true); } public void open(Player player) { diff --git a/src/main/java/dev/efnilite/ip/player/ParkourSpectator.java b/src/main/java/dev/efnilite/ip/player/ParkourSpectator.java index 1b33fc83..bb416da2 100644 --- a/src/main/java/dev/efnilite/ip/player/ParkourSpectator.java +++ b/src/main/java/dev/efnilite/ip/player/ParkourSpectator.java @@ -79,6 +79,11 @@ public void update() { player.setGameMode(GameMode.SPECTATOR); updateScoreboard(session.generator); + // spectator is still being teleported to world + if (closest.getLocation().getWorld() != player.getLocation().getWorld()) { + return; + } + if (closest.getLocation().distanceSquared(player.getLocation()) < 100 * 100) { // avoid sqrt return; } diff --git a/src/main/java/dev/efnilite/ip/player/ParkourUser.java b/src/main/java/dev/efnilite/ip/player/ParkourUser.java index 5bf5395b..26db56f2 100644 --- a/src/main/java/dev/efnilite/ip/player/ParkourUser.java +++ b/src/main/java/dev/efnilite/ip/player/ParkourUser.java @@ -123,6 +123,8 @@ public static void unregister(@NotNull ParkourUser user, boolean restorePrevious return; } + if (!restorePreviousData) return; + user.previousData.apply(user.player, urgent); if (user instanceof ParkourPlayer player) { diff --git a/src/main/java/dev/efnilite/ip/player/data/PreviousData.java b/src/main/java/dev/efnilite/ip/player/data/PreviousData.java index c8ea0262..1c5dcff6 100644 --- a/src/main/java/dev/efnilite/ip/player/data/PreviousData.java +++ b/src/main/java/dev/efnilite/ip/player/data/PreviousData.java @@ -58,11 +58,7 @@ public PreviousData(@NotNull Player player) { inventoryData = null; } - // health handling after removing effects and inventory to avoid them affecting it - if (Config.CONFIG.getBoolean("options.health-handling")) { - player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(20); - player.setHealth(maxHealth); - } + player.setHealth(maxHealth); } public void apply(Player player, boolean urgent) { @@ -83,11 +79,7 @@ private void apply(Player player) { player.setGameMode(gamemode); player.setAllowFlight(allowFlight); player.setFlying(flying); - - if (Config.CONFIG.getBoolean("options.health-handling")) { - player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(maxHealth); - player.setHealth(health); - } + player.setHealth(health); for (PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); diff --git a/src/main/java/dev/efnilite/ip/session/Session.java b/src/main/java/dev/efnilite/ip/session/Session.java index 59a4b03f..61c60db6 100644 --- a/src/main/java/dev/efnilite/ip/session/Session.java +++ b/src/main/java/dev/efnilite/ip/session/Session.java @@ -70,7 +70,7 @@ public static Session create(Function generatorFuncti Session session = new Session(); - Divider.add(session); + var location = Divider.add(session); if (isAcceptingPlayers != null) session.isAcceptingPlayers = isAcceptingPlayers; if (isAcceptingSpectators != null) session.isAcceptingSpectators = isAcceptingSpectators; @@ -90,7 +90,7 @@ public static Session create(Function generatorFuncti pps.forEach(p -> p.updateGeneratorSettings(session.generator)); } - session.generator.island.build(); + session.generator.island.build(location); return session; } diff --git a/src/main/java/dev/efnilite/ip/world/Divider.java b/src/main/java/dev/efnilite/ip/world/Divider.java index cfc0b370..ec445ea2 100644 --- a/src/main/java/dev/efnilite/ip/world/Divider.java +++ b/src/main/java/dev/efnilite/ip/world/Divider.java @@ -29,7 +29,7 @@ public class Divider { * * @param session The session. */ - public static synchronized void add(Session session) { + public static synchronized Location add(Session session) { // attempts to get the closest available section to the center var missing = IntStream.range(0, sections.size() + 1) .filter(i -> !sections.containsValue(i)) @@ -38,7 +38,11 @@ public static synchronized void add(Session session) { sections.put(session, missing); - IP.log("Added session at %s".formatted(Locations.toString(toLocation(session), true))); + var location = toLocation(session); + + IP.log("Added session at %s".formatted(Locations.toString(location, true))); + + return location; } /** @@ -56,7 +60,7 @@ public static void remove(Session session) { * @param session The session. * @return The location at the center of section n. */ - public static Location toLocation(Session session) { + private static Location toLocation(Session session) { int[] xz = spiralAt(sections.get(session)); return new Location(WorldManager.getWorld(), @@ -65,7 +69,6 @@ public static Location toLocation(Session session) { xz[1] * Option.BORDER_SIZE); } - /** * @param session The session. * @return Array where the first item is the smallest location and second item is the largest. diff --git a/src/main/java/dev/efnilite/ip/world/WorldManager.java b/src/main/java/dev/efnilite/ip/world/WorldManager.java index 2a170791..542691eb 100644 --- a/src/main/java/dev/efnilite/ip/world/WorldManager.java +++ b/src/main/java/dev/efnilite/ip/world/WorldManager.java @@ -28,7 +28,7 @@ public interface WorldManager { static void create() { World world = getWorld(); - if (!Config.CONFIG.getBoolean("joining") || (!Config.CONFIG.getBoolean("world.delete-on-reload") && world != null)) { + if (!Config.CONFIG.getBoolean("joining")) { return; } @@ -40,7 +40,10 @@ static void create() { IP.log("Initializing world rules"); - manager.deleteWorld(); + if (Config.CONFIG.getBoolean("world.delete-on-reload")) { + manager.deleteWorld(); + } + world = manager.createWorld(); world.setGameRule(GameRule.DO_FIRE_TICK, false); diff --git a/src/main/java/dev/efnilite/ip/world/WorldManagerMV.java b/src/main/java/dev/efnilite/ip/world/WorldManagerMV.java index a6a273e9..ebdf755c 100644 --- a/src/main/java/dev/efnilite/ip/world/WorldManagerMV.java +++ b/src/main/java/dev/efnilite/ip/world/WorldManagerMV.java @@ -30,6 +30,13 @@ public World createWorld() { if (MANAGER == null) { return null; } + + // world has already been loaded + var existing = MANAGER.getMVWorld(Option.WORLD_NAME); + if (existing != null) { + return existing.getCBWorld(); + } + IP.log("Creating MV world"); MANAGER.addWorld(Option.WORLD_NAME, World.Environment.NORMAL, null, WorldType.NORMAL, false, VoidGenerator.getMultiverseGenerator()); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 93beabcf..0b429e26 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -158,10 +158,9 @@ options: # This command will be executed by console. alt-inventory-saving-command: '' - # -= Health handling =- - # Enables/disables the health handling system. This will reset (max) health to default values on join of the parkour. - # Disable this if you're experiencing errors with max health, etc. - health-handling: true + # -= Disables inventory blocks =- + # Disables the ability for a player to open blocks with an inventory. + disable-inventory-blocks: false # -= Permissions options =- # These permissions are used to determine which things the player can change. diff --git a/src/main/resources/locales/en.yml b/src/main/resources/locales/en.yml index c5368755..ac63aa5c 100644 --- a/src/main/resources/locales/en.yml +++ b/src/main/resources/locales/en.yml @@ -253,3 +253,8 @@ other: material: "arrow" name: "<#F5A3A3>Close" lore: "" + + iep: + material: "elytra" + name: "<#4800FF>Flying" + lore: "Parkour with elytra!" \ No newline at end of file diff --git a/src/main/resources/locales/fr.yml b/src/main/resources/locales/fr.yml index 3b95f1a6..0ec5614b 100644 --- a/src/main/resources/locales/fr.yml +++ b/src/main/resources/locales/fr.yml @@ -253,3 +253,8 @@ other: material: "arrow" name: "<#F5A3A3>Fermé" lore: "" + + iep: + material: "elytra" + name: "<#4800FF>Flying" + lore: "Parkour with elytra!" \ No newline at end of file diff --git a/src/main/resources/locales/jp.yml b/src/main/resources/locales/jp.yml index ab9e3874..f0d83760 100644 --- a/src/main/resources/locales/jp.yml +++ b/src/main/resources/locales/jp.yml @@ -252,4 +252,9 @@ other: close: material: "arrow" name: "<#F5A3A3>戻る" - lore: "" \ No newline at end of file + lore: "" + + iep: + material: "elytra" + name: "<#4800FF>Flying" + lore: "Parkour with elytra!" \ No newline at end of file diff --git a/src/main/resources/locales/nl.yml b/src/main/resources/locales/nl.yml index f33e1044..e796954e 100644 --- a/src/main/resources/locales/nl.yml +++ b/src/main/resources/locales/nl.yml @@ -252,4 +252,9 @@ other: close: material: "arrow" name: "<#F5A3A3>Sluiten" - lore: "" \ No newline at end of file + lore: "" + + iep: + material: "elytra" + name: "<#4800FF>Vliegen" + lore: "Parkour met elytra!" \ No newline at end of file diff --git a/src/main/resources/locales/zh_cn.yml b/src/main/resources/locales/zh_cn.yml index af6ba196..d2656f8a 100644 --- a/src/main/resources/locales/zh_cn.yml +++ b/src/main/resources/locales/zh_cn.yml @@ -253,3 +253,8 @@ other: material: "arrow" name: "<#F5A3A3>关闭" lore: "" + + iep: + material: "elytra" + name: "<#4800FF>Flying" + lore: "Parkour with elytra!" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 352face6..bb245778 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: 'IP' description: 'Infinitely automatically generating parkour plugin.' author: Efnilite -version: 5.2.0 +version: 5.2.1 api-version: 1.16 main: dev.efnilite.ip.IP softdepend: [floodgate, Vault, PlaceholderAPI, Multiverse-Core, VoidGen]