diff --git a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/api/ATPlayer.java b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/api/ATPlayer.java index 7fa91b66..7131106c 100644 --- a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/api/ATPlayer.java +++ b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/api/ATPlayer.java @@ -12,10 +12,7 @@ import io.github.niestrat99.advancedteleport.api.events.players.ToggleTeleportationEvent; import io.github.niestrat99.advancedteleport.config.CustomMessages; import io.github.niestrat99.advancedteleport.config.MainConfig; -import io.github.niestrat99.advancedteleport.managers.CooldownManager; -import io.github.niestrat99.advancedteleport.managers.MovementManager; -import io.github.niestrat99.advancedteleport.managers.ParticleManager; -import io.github.niestrat99.advancedteleport.managers.PluginHookManager; +import io.github.niestrat99.advancedteleport.managers.*; import io.github.niestrat99.advancedteleport.payments.PaymentManager; import io.github.niestrat99.advancedteleport.sql.BlocklistManager; import io.github.niestrat99.advancedteleport.sql.HomeSQLManager; @@ -211,6 +208,7 @@ public void teleport( PaymentManager.getInstance() .withdraw( command, player, event.getToLocation().getWorld()); + InvulnerabilityManager.createInvulnerability(player, getInvulnerability(command, event.getToLocation().getWorld())); if (MainConfig.get() .APPLY_COOLDOWN_AFTER .get() @@ -218,6 +216,7 @@ public void teleport( CooldownManager.addToCooldown( command, player, event.getToLocation().getWorld()); } + InvulnerabilityManager.createInvulnerability(player, getInvulnerability(command, event.getToLocation().getWorld())); }); } } @@ -607,7 +606,7 @@ public boolean hasHome(@NotNull final String name) { if (home == null) return; HomeSQLManager.get().removeHome(uuid, home.getName()); - + }, CoreClass.async); } @@ -809,6 +808,17 @@ public int getCooldown(@NotNull final String command, @NotNull final World desti MainConfig.get().COOLDOWNS.valueOf(command).get()); } + @Range(from = 0, to = Integer.MAX_VALUE) + @Contract(pure = true) + public int getInvulnerability(@NotNull final String command, @NotNull final World destinationWorld) { + return determineValue("at.member.invulnerability", + command, + MainConfig.get().COMMAND_INVULNERABILITY_DURATIONS.valueOf(command).get(), + MainConfig.get().CUSTOM_INVULNERABILITY_DURATIONS.get(), + destinationWorld, + Math::max); + } + @Range(from = 0, to = Integer.MAX_VALUE) @Contract(pure = true) public @Deprecated int getCooldown(@NotNull final String command) { diff --git a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/commands/home/HomesCommand.java b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/commands/home/HomesCommand.java index e0fb2bff..791b75fc 100644 --- a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/commands/home/HomesCommand.java +++ b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/commands/home/HomesCommand.java @@ -162,6 +162,7 @@ private void getHomes(CommandSender sender, OfflinePlayer target, ImmutableColle + home.getName())); }) .toList()); + CoreClass.debug("Message text built."); if (!body.content().isEmpty() || !body.children().isEmpty()) { diff --git a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/config/CustomMessages.java b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/config/CustomMessages.java index c030cb84..7b34bc3f 100644 --- a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/config/CustomMessages.java +++ b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/config/CustomMessages.java @@ -144,6 +144,9 @@ If you prefer to use the Legacy Code format (i.e. &a, &b, etc.) then you can sti addDefault( "Teleport.eventMovement", " Teleport has been cancelled due to movement."); + addDefault( + "Teleport.eventDamage", + " Teleport has been cancelled due to damage being taken."); addDefault("Teleport.eventMovement_title.length", 60); addDefault("Teleport.eventMovement_title.fade-in", 0); addDefault("Teleport.eventMovement_title.fade-out", 10); diff --git a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/config/MainConfig.java b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/config/MainConfig.java index 2b379c95..9d87a268 100644 --- a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/config/MainConfig.java +++ b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/config/MainConfig.java @@ -30,6 +30,7 @@ public final class MainConfig extends ATConfig { public ConfigOption WARM_UP_TIMER_DURATION; public ConfigOption CANCEL_WARM_UP_ON_ROTATION; public ConfigOption CANCEL_WARM_UP_ON_MOVEMENT; + public ConfigOption CANCEL_WARM_UP_ON_DAMAGE; public ConfigOption CHECK_EXACT_COORDINATES; public PerCommandOption WARM_UPS; public ConfigOption CUSTOM_WARM_UPS; @@ -43,6 +44,10 @@ public final class MainConfig extends ATConfig { public ConfigOption COST_AMOUNT; public PerCommandOption COSTS; public ConfigOption CUSTOM_COSTS; + public ConfigOption INVULNERABILITY_DURATION; + public ConfigOption> INVULNERABILITY_DAMAGE_BLACKLIST; + public PerCommandOption COMMAND_INVULNERABILITY_DURATIONS; + public ConfigOption CUSTOM_INVULNERABILITY_DURATIONS; public ConfigOption USE_PARTICLES; public PerCommandOption TELEPORT_PARTICLES; public PerCommandOption WAITING_PARTICLES; @@ -204,6 +209,12 @@ public void addDefaults() { "cancel-warm-up-on-movement", true, "Whether or not teleportation should be cancelled upon movement only."); + addDefault( + "cancel-warm-up-on-damage", + true, + "Whether or not teleportation should be cancelled when the player receives damage.\n" + + "Best option to accompany the invulnerability system if your server has it enabled, so that " + + "players can't cheese it. :thumbsup:"); addDefault("check-exact-coordinates", false, "Whether the plugin should check for change in exact X, Y and Z vs. block X, Y, Z.\n" + @@ -290,7 +301,7 @@ The key (vip-warm-up) and group name (VIP) do not have to be different, this is vip-cooldown: 3 Giving a group, such as VIP, the permission at.member.cooldown.vip-cooldown will have a cooldown of 3. The key (vip-cooldown) and group name (VIP) do not have to be different, this is just an example. - You can also add at.member.cooldown.3, but this is more efficient if you find permissions lag.To make it per-command, use at.member.cooldown..vip-cooldown. To make it per-world, use at.member.cooldown..vip-cooldown. + You can also add at.member.cooldown.3, but this is more efficient if you find permissions lag. To make it per-command, use at.member.cooldown..vip-cooldown. To make it per-world, use at.member.cooldown..vip-cooldown. To combine the two, you can use at.member.cooldown...vip-cooldown.\ """); @@ -333,6 +344,32 @@ The key (vip-cooldown) and group name (VIP) do not have to be different, this is To make it per-command, add the permission at.member.cost.tpa.vip-cost (for tpa) instead.\ """); + addDefault("invulnerability-duration", 0, "Invulnerability", "How long the invulnerability period lasts in seconds."); + addDefault("damage-blacklist", new ArrayList<>(), "All damage causes that are not cancelled by invulnerability.\n" + + "The full list is accessible here: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/entity/EntityDamageEvent.DamageCause.html"); + + addComment("per-command-invulnerability", "Command-specific invulnerability durations."); + addDefault("per-command-invulnerability.tpa", "default", "Invulnerability duration for /tpa."); + addDefault("per-command-invulnerability.tpahere", "default", "Invulnerability duration for /tpahere."); + addDefault("per-command-invulnerability.tpr", "default", "Invulnerability duration for /tpr, or /rtp."); + addDefault("per-command-invulnerability.warp", "default", "Invulnerability duration for /warp"); + addDefault("per-command-invulnerability.spawn", "default", "Invulnerability duration for /spawn"); + addDefault("per-command-invulnerability.home", "default", "Invulnerability duration for /home"); + addDefault("per-command-invulnerability.back", "default", "Invulnerability duration for /back"); + + makeSectionLenient("custom-invulnerability-periods"); + addComment( + "custom-invulnerability-periods", + """ + Use this section to create custom invulnerability periods per-group. + Use the following format: + custom-invulnerability-periods: + vip: 5 + Giving a group, such as VIP, the permission at.member.invulnerability.vip will have an invulnerable period of 5 seconds. + To make it per-command, add the permission at.member.invulnerability.tpa.vip (for tpa) instead.\ + You can also add at.member.invulnerability.5, but this is more efficient if you find permissions lag. + """); + addDefault( "use-particles", true, @@ -1010,6 +1047,7 @@ public void postSave() { WARM_UP_TIMER_DURATION = new ConfigOption<>("warm-up-timer-duration"); CANCEL_WARM_UP_ON_ROTATION = new ConfigOption<>("cancel-warm-up-on-rotation"); CANCEL_WARM_UP_ON_MOVEMENT = new ConfigOption<>("cancel-warm-up-on-movement"); + CANCEL_WARM_UP_ON_DAMAGE = new ConfigOption<>("cancel-warm-up-on-damage"); CHECK_EXACT_COORDINATES = new ConfigOption<>("check-exact-coordinates"); WARM_UPS = new PerCommandOption<>("per-command-warm-ups", "warm-up-timer-duration"); CUSTOM_WARM_UPS = new ConfigOption<>("custom-warm-ups"); @@ -1041,6 +1079,11 @@ public void postSave() { COSTS = new PerCommandOption<>("per-command-cost", "cost-amount"); CUSTOM_COSTS = new ConfigOption<>("custom-costs"); + INVULNERABILITY_DURATION = new ConfigOption<>("invulnerability-duration"); + INVULNERABILITY_DAMAGE_BLACKLIST = new ConfigOption<>("damage-blacklist"); + COMMAND_INVULNERABILITY_DURATIONS = new PerCommandOption<>("per-command-invulnerability", "invulnerability-duration"); + CUSTOM_INVULNERABILITY_DURATIONS = new ConfigOption<>("custom-invulnerability-periods"); + USE_PARTICLES = new ConfigOption<>("use-particles"); WAITING_PARTICLES = new PerCommandOption<>("waiting-particles", "default-waiting-particles"); diff --git a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/managers/InvulnerabilityManager.java b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/managers/InvulnerabilityManager.java new file mode 100644 index 00000000..b3183e83 --- /dev/null +++ b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/managers/InvulnerabilityManager.java @@ -0,0 +1,48 @@ +package io.github.niestrat99.advancedteleport.managers; + +import io.github.niestrat99.advancedteleport.CoreClass; +import io.github.niestrat99.advancedteleport.config.MainConfig; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.jetbrains.annotations.NotNull; + +public class InvulnerabilityManager { + + public static void createInvulnerability(Player player, int duration) { + DamageListener damage = new DamageListener(player); + + Bukkit.getScheduler().runTaskLater(CoreClass.getInstance(), task -> { + damage.destroy(); + }, duration * 20L); + } + + private static class DamageListener implements Listener { + + private final @NotNull Player player; + + public DamageListener(@NotNull Player player) { + this.player = player; + Bukkit.getPluginManager().registerEvents(this, CoreClass.getInstance()); + } + + @EventHandler + public void onDamage(EntityDamageEvent event) { + + // If it's not this player, stop there + if (event.getEntity() != this.player) return; + + // Check cause of damage in the damage list + if (MainConfig.get().INVULNERABILITY_DAMAGE_BLACKLIST.get().contains(event.getCause().name())) return; + + event.setCancelled(true); + } + + protected void destroy() { + HandlerList.unregisterAll(this); + } + } +} diff --git a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/managers/MovementManager.java b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/managers/MovementManager.java index e3dca84b..321124d7 100644 --- a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/managers/MovementManager.java +++ b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/managers/MovementManager.java @@ -13,6 +13,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.potion.PotionEffect; @@ -41,6 +42,24 @@ public void onMovement(PlayerMoveEvent event) { } } + @EventHandler + public void onDamage(EntityDamageEvent event) { + + // Make sure it's a player and someone on a timer + if (!(event.getEntity() instanceof Player player)) return; + if (!movement.containsKey(player.getUniqueId())) return; + + // Verify that the option is enabled and the player is not bypassing the option + if (MainConfig.get().CANCEL_WARM_UP_ON_DAMAGE.get() && !player.hasPermission("at.admin.bypass.damage")) return; + + // Cancel the timer + final var timer = movement.get(player.getUniqueId()); + timer.cancel(); + CustomMessages.sendMessage(player, "Teleport.eventDamage"); + ParticleManager.removeParticles(player, timer.command); + movement.remove(player.getUniqueId()); + } + private static boolean willCancelTimer(PlayerMoveEvent event) { boolean cancelOnRotate = MainConfig.get().CANCEL_WARM_UP_ON_ROTATION.get() && !event.getPlayer().hasPermission("at.admin.bypass.rotation"); boolean cancelOnMove = MainConfig.get().CANCEL_WARM_UP_ON_MOVEMENT.get() && !event.getPlayer().hasPermission("at.admin.bypass.movement"); @@ -140,6 +159,10 @@ public void run() { CustomMessages.sendMessage(teleportingPlayer, message, placeholders); PaymentManager.getInstance() .withdraw(command, payingPlayer, location.getWorld()); + InvulnerabilityManager.createInvulnerability( + teleportingPlayer, + ATPlayer.getPlayer(teleportingPlayer) + .getInvulnerability(command, location.getWorld())); // If the cooldown is to be applied after only after a teleport takes place, // apply it now if (MainConfig.get() diff --git a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/utilities/AcceptRequest.java b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/utilities/AcceptRequest.java index ce8eb345..5cf62aee 100644 --- a/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/utilities/AcceptRequest.java +++ b/AdvancedTeleport-Bukkit/src/main/java/io/github/niestrat99/advancedteleport/utilities/AcceptRequest.java @@ -7,6 +7,7 @@ import io.github.niestrat99.advancedteleport.config.CustomMessages; import io.github.niestrat99.advancedteleport.config.MainConfig; import io.github.niestrat99.advancedteleport.managers.CooldownManager; +import io.github.niestrat99.advancedteleport.managers.InvulnerabilityManager; import io.github.niestrat99.advancedteleport.managers.MovementManager; import io.github.niestrat99.advancedteleport.payments.PaymentManager; @@ -71,6 +72,7 @@ private static void teleport(Player toPlayer, Player fromPlayer, String type) { fromPlayer, toLocation, PlayerTeleportEvent.TeleportCause.COMMAND); CustomMessages.sendMessage(fromPlayer, "Teleport.eventTeleport"); PaymentManager.getInstance().withdraw(type, payingPlayer, toLocation.getWorld()); + InvulnerabilityManager.createInvulnerability(fromPlayer, atPlayer.getInvulnerability(type, event.getToLocation().getWorld())); // If the cooldown is to be applied after only after a teleport takes place, apply it now if (MainConfig.get().APPLY_COOLDOWN_AFTER.get().equalsIgnoreCase("teleport")) {