diff --git a/eternalcombat-api/src/main/java/com/eternalcode/combat/EternalCombatApi.java b/eternalcombat-api/src/main/java/com/eternalcode/combat/EternalCombatApi.java index a45af55d..55e1fbc5 100644 --- a/eternalcombat-api/src/main/java/com/eternalcode/combat/EternalCombatApi.java +++ b/eternalcombat-api/src/main/java/com/eternalcode/combat/EternalCombatApi.java @@ -4,7 +4,7 @@ import com.eternalcode.combat.fight.FightManager; import com.eternalcode.combat.fight.drop.DropService; import com.eternalcode.combat.fight.effect.FightEffectService; -import com.eternalcode.combat.fight.pearl.FightPearlService; +import com.eternalcode.combat.fight.pearl.PearlService; import com.eternalcode.combat.region.RegionProvider; import com.eternalcode.combat.fight.tagout.FightTagOutService; @@ -14,7 +14,7 @@ public interface EternalCombatApi { RegionProvider getRegionProvider(); - FightPearlService getFightPearlService(); + PearlService getFightPearlService(); FightTagOutService getFightTagOutService(); diff --git a/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/event/CauseOfTag.java b/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/event/CauseOfTag.java index 32ec7eaa..9cbc001e 100644 --- a/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/event/CauseOfTag.java +++ b/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/event/CauseOfTag.java @@ -23,6 +23,17 @@ public enum CauseOfTag { */ CRYSTAL, + /** + * Trident usage extending combat tag. + */ + TRIDENT, + + /** + * Ender pearl usage extending combat tag. + */ + ENDER_PEARL, + + /** * A custom cause, typically defined by external plugins or systems, applied the combat tag. */ diff --git a/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlService.java b/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/pearl/PearlService.java similarity index 54% rename from eternalcombat-api/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlService.java rename to eternalcombat-api/src/main/java/com/eternalcode/combat/fight/pearl/PearlService.java index 18d2b84f..f0f29cd2 100644 --- a/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlService.java +++ b/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/pearl/PearlService.java @@ -1,16 +1,16 @@ package com.eternalcode.combat.fight.pearl; import java.time.Duration; -import java.time.Instant; import java.util.UUID; +import org.bukkit.entity.Player; -public interface FightPearlService { +public interface PearlService { - Instant getDelay(UUID uuid); + boolean shouldCancelEvent(UUID playerId); Duration getRemainingDelay(UUID uuid); boolean hasDelay(UUID uuid); - void markDelay(UUID uuid); + void handleDelay(Player uuid); } diff --git a/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/trident/TridentService.java b/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/trident/TridentService.java new file mode 100644 index 00000000..8f87187e --- /dev/null +++ b/eternalcombat-api/src/main/java/com/eternalcode/combat/fight/trident/TridentService.java @@ -0,0 +1,35 @@ +package com.eternalcode.combat.fight.trident; + +import java.time.Duration; +import java.util.UUID; +import org.bukkit.entity.Player; + +public interface TridentService { + + /** + * returns remaining delay for the player to use trident again + * @param uuid unique id of the player + * @return remaining duration left to use trident again by the player or zero + */ + Duration getRemainingDelay(UUID uuid); + + /** + * checks if player still has delay left to use trident + * @param uuid unique id of the player + * @return true if user still has cooldown left to use trident + */ + boolean hasDelay(UUID uuid); + + /** + * marks start of the delay for the user + * @param uuid unique id of the player + */ + void markDelay(UUID uuid); + + /** + * handles the trident cooldown for the player, should be called when player uses riptide in combat + * @param player the player who used riptide in combat needed to apply cooldown to item + */ + void handleTridentDelay(Player player); + +} diff --git a/eternalcombat-plugin/build.gradle.kts b/eternalcombat-plugin/build.gradle.kts index fb3a8d48..6630cd11 100644 --- a/eternalcombat-plugin/build.gradle.kts +++ b/eternalcombat-plugin/build.gradle.kts @@ -1,6 +1,6 @@ -import net.minecrell.pluginyml.bukkit.BukkitPluginDescription + import io.papermc.hangarpublishplugin.model.Platforms -import org.gradle.kotlin.dsl.shadowJar +import net.minecrell.pluginyml.bukkit.BukkitPluginDescription plugins { `eternalcombat-java` @@ -93,7 +93,7 @@ bukkit { tasks { runServer { - minecraftVersion("1.21.10") + minecraftVersion("1.21.11") downloadPlugins.modrinth("WorldEdit", Versions.WORLDEDIT) downloadPlugins.modrinth("PacketEvents", "${Versions.PACKETEVENTS}+spigot") downloadPlugins.modrinth("WorldGuard", Versions.WORLDGUARD) diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java index 4b492fc1..337d3ee9 100644 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java @@ -20,7 +20,10 @@ import com.eternalcode.combat.fight.firework.FireworkController; import com.eternalcode.combat.fight.knockback.KnockbackService; import com.eternalcode.combat.fight.tagout.FightTagOutService; -import com.eternalcode.combat.fight.pearl.FightPearlService; +import com.eternalcode.combat.fight.pearl.PearlService; +import com.eternalcode.combat.fight.trident.TridentController; +import com.eternalcode.combat.fight.trident.TridentService; +import com.eternalcode.combat.fight.trident.TridentServiceImpl; import com.eternalcode.combat.handler.InvalidUsageHandlerImpl; import com.eternalcode.combat.handler.MissingPermissionHandlerImpl; import com.eternalcode.combat.config.ConfigService; @@ -42,8 +45,8 @@ import com.eternalcode.combat.fight.effect.FightEffectServiceImpl; import com.eternalcode.combat.fight.logout.LogoutController; import com.eternalcode.combat.fight.logout.LogoutService; -import com.eternalcode.combat.fight.pearl.FightPearlController; -import com.eternalcode.combat.fight.pearl.FightPearlServiceImpl; +import com.eternalcode.combat.fight.pearl.PearlController; +import com.eternalcode.combat.fight.pearl.PearlServiceImpl; import com.eternalcode.combat.fight.tagout.FightTagOutController; import com.eternalcode.combat.fight.tagout.FightTagOutServiceImpl; import com.eternalcode.combat.fight.tagout.FightTagOutCommand; @@ -82,7 +85,8 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi { private static final int BSTATS_METRICS_ID = 17803; private FightManager fightManager; - private FightPearlService fightPearlService; + private PearlService pearlService; + private TridentService tridentService; private FightTagOutService fightTagOutService; private FightEffectService fightEffectService; @@ -110,7 +114,8 @@ public void onEnable() { MinecraftScheduler scheduler = CombatSchedulerAdapter.getAdaptiveScheduler(this); this.fightManager = new FightManagerImpl(eventManager); - this.fightPearlService = new FightPearlServiceImpl(pluginConfig.pearl); + this.pearlService = new PearlServiceImpl(this.fightManager, pluginConfig, scheduler); + this.tridentService = new TridentServiceImpl(this.fightManager, pluginConfig); this.fightTagOutService = new FightTagOutServiceImpl(); this.fightEffectService = new FightEffectServiceImpl(); @@ -181,7 +186,8 @@ public void onEnable() { new FightBypassPermissionController(server, pluginConfig), new FightBypassCreativeController(server, pluginConfig), new FightActionBlockerController(this.fightManager, noticeService, pluginConfig, server), - new FightPearlController(pluginConfig.pearl, noticeService, this.fightManager, this.fightPearlService), + new PearlController(pluginConfig, this.pearlService, noticeService), + new TridentController(pluginConfig, noticeService, this.fightManager, this.tridentService, server), new DeathEffectController(pluginConfig), new UpdaterNotificationController(updaterService, pluginConfig, this.audienceProvider, miniMessage), new KnockbackRegionController(noticeService, this.regionProvider, this.fightManager, knockbackService, server), @@ -241,8 +247,8 @@ public RegionProvider getRegionProvider() { } @Override - public FightPearlService getFightPearlService() { - return this.fightPearlService; + public PearlService getFightPearlService() { + return this.pearlService; } @Override diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/config/implementation/PluginConfig.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/config/implementation/PluginConfig.java index bc29665f..6534cf0f 100644 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/config/implementation/PluginConfig.java +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/config/implementation/PluginConfig.java @@ -5,7 +5,8 @@ import com.eternalcode.combat.fight.drop.DropSettings; import com.eternalcode.combat.fight.effect.FightEffectSettings; import com.eternalcode.combat.fight.knockback.KnockbackSettings; -import com.eternalcode.combat.fight.pearl.FightPearlSettings; +import com.eternalcode.combat.fight.pearl.PearlSettings; +import com.eternalcode.combat.fight.trident.TridentSettings; import eu.okaeri.configs.OkaeriConfig; import eu.okaeri.configs.annotation.Comment; import java.time.Duration; @@ -34,7 +35,14 @@ public class PluginConfig extends OkaeriConfig { "# Settings related to Ender Pearls.", "# Configure cooldowns, restrictions, and other behaviors for Ender Pearls during combat." }) - public FightPearlSettings pearl = new FightPearlSettings(); + public PearlSettings pearl = new PearlSettings(); + + @Comment({ + " ", + "# Settings related to Trident", + "# Configure cooldowns, restrictions, and other behaviors for Trident during combat." + }) + public TridentSettings trident = new TridentSettings(); @Comment({ " ", diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlController.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlController.java deleted file mode 100644 index bfd35700..00000000 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlController.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.eternalcode.combat.fight.pearl; - -import com.eternalcode.combat.fight.FightManager; -import com.eternalcode.combat.notification.NoticeService; -import com.eternalcode.combat.util.DurationUtil; -import java.time.Duration; -import java.util.UUID; -import org.bukkit.Material; -import org.bukkit.entity.EnderPearl; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.ProjectileLaunchEvent; -import org.bukkit.inventory.ItemStack; - -public class FightPearlController implements Listener { - - private final FightPearlSettings settings; - private final NoticeService noticeService; - private final FightManager fightManager; - private final FightPearlService fightPearlService; - - public FightPearlController( - FightPearlSettings settings, - NoticeService noticeService, - FightManager fightManager, - FightPearlService fightPearlService - ) { - this.settings = settings; - this.noticeService = noticeService; - this.fightManager = fightManager; - this.fightPearlService = fightPearlService; - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onPearlThrow(ProjectileLaunchEvent event) { - if (!(event.getEntity() instanceof EnderPearl)) { - return; - } - - if (!(event.getEntity().getShooter() instanceof Player player)) { - return; - } - - UUID playerId = player.getUniqueId(); - - if (!this.fightManager.isInCombat(playerId)) { - return; - } - - if (this.settings.pearlThrowDisabledDuringCombat) { - event.setCancelled(true); - this.noticeService.create() - .player(playerId) - .notice(this.settings.pearlThrowBlockedDuringCombat) - .send(); - return; - } - - if (this.settings.pearlCooldownEnabled) { - handlePearlCooldown(event, player, playerId); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPearlDamage(EntityDamageByEntityEvent event) { - if (this.settings.pearlThrowDamageEnabled) { - return; - } - - if (!(event.getEntity() instanceof Player) || - !(event.getDamager() instanceof EnderPearl) || - event.getCause() != EntityDamageEvent.DamageCause.FALL) { - return; - } - - event.setDamage(0.0); - } - - private void handlePearlCooldown(ProjectileLaunchEvent event, Player player, UUID playerId) { - if (this.settings.pearlThrowDelay.isZero()) { - return; - } - - if (this.fightPearlService.hasDelay(playerId)) { - event.setCancelled(true); - Duration remainingDelay = this.fightPearlService.getRemainingDelay(playerId); - - this.noticeService.create() - .player(playerId) - .notice(this.settings.pearlThrowBlockedDelayDuringCombat) - .placeholder("{TIME}", DurationUtil.format(remainingDelay)) - .send(); - return; - } - - this.fightPearlService.markDelay(playerId); - int cooldownTicks = (int) (this.settings.pearlThrowDelay.toMillis() / 50); - player.setCooldown(Material.ENDER_PEARL, cooldownTicks); - } -} diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlServiceImpl.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlServiceImpl.java deleted file mode 100644 index 584d275d..00000000 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlServiceImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.eternalcode.combat.fight.pearl; - -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; - -import java.time.Duration; -import java.time.Instant; -import java.util.UUID; - -public class FightPearlServiceImpl implements FightPearlService { - - private final FightPearlSettings pearlSettings; - private final Cache pearlStartTimes; - - public FightPearlServiceImpl(FightPearlSettings pearlSettings) { - this.pearlSettings = pearlSettings; - this.pearlStartTimes = Caffeine.newBuilder() - .expireAfterWrite(pearlSettings.pearlThrowDelay) - .build(); - } - - @Override - public void markDelay(UUID uuid) { - this.pearlStartTimes.put(uuid, Instant.now()); - } - - @Override - public boolean hasDelay(UUID uuid) { - return this.pearlStartTimes.getIfPresent(uuid) != null; - } - - @Override - public Duration getRemainingDelay(UUID uuid) { - Instant startTime = this.pearlStartTimes.getIfPresent(uuid); - if (startTime == null) { - return Duration.ZERO; - } - - Duration elapsed = Duration.between(startTime, Instant.now()); - Duration remaining = this.pearlSettings.pearlThrowDelay.minus(elapsed); - - return remaining.isNegative() ? Duration.ZERO : remaining; - } - - @Override - public Instant getDelay(UUID uuid) { - Instant startTime = this.pearlStartTimes.getIfPresent(uuid); - return startTime != null ? startTime.plus(this.pearlSettings.pearlThrowDelay) : Instant.MIN; - } -} diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlController.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlController.java new file mode 100644 index 00000000..823e6c4b --- /dev/null +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlController.java @@ -0,0 +1,82 @@ +package com.eternalcode.combat.fight.pearl; + +import com.eternalcode.combat.config.implementation.PluginConfig; +import com.eternalcode.combat.notification.NoticeService; +import com.eternalcode.combat.util.DurationUtil; +import java.time.Duration; +import java.util.UUID; +import org.bukkit.entity.EnderPearl; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; + +public class PearlController implements Listener { + + private final PluginConfig pluginConfig; + private final PearlService pearlService; + private final NoticeService noticeService; + + public PearlController( + PluginConfig pluginConfig, + PearlService pearlService, NoticeService noticeService + ) { + this.pluginConfig = pluginConfig; + this.pearlService = pearlService; + this.noticeService = noticeService; + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPearlThrow(ProjectileLaunchEvent event) { + if (!(event.getEntity() instanceof EnderPearl)) { + return; + } + + if (!(event.getEntity().getShooter() instanceof Player player)) { + return; + } + + UUID playerId = player.getUniqueId(); + + if (this.pearlService.shouldCancelEvent(playerId)) { + event.setCancelled(true); + + if (this.pluginConfig.pearl.pearlThrowDisabledDuringCombat) { + this.noticeService.create() + .player(playerId) + .notice(this.pluginConfig.pearl.pearlThrowBlockedDuringCombat) + .send(); + return; + } + + Duration remainingDelay = this.pearlService.getRemainingDelay(playerId); + this.noticeService.create() + .player(playerId) + .notice(this.pluginConfig.pearl.pearlThrowBlockedDelayDuringCombat) + .placeholder("{TIME}", DurationUtil.format(remainingDelay)) + .send(); + + } + + this.pearlService.handleDelay(player); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPearlDamage(EntityDamageByEntityEvent event) { + if (this.pluginConfig.pearl.pearlThrowDamageEnabled) { + return; + } + + if (!(event.getEntity() instanceof Player) || + !(event.getDamager() instanceof EnderPearl) || + event.getCause() != EntityDamageEvent.DamageCause.PROJECTILE) { + return; + } + + event.setDamage(0.0); + } + +} diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlServiceImpl.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlServiceImpl.java new file mode 100644 index 00000000..978049d3 --- /dev/null +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlServiceImpl.java @@ -0,0 +1,81 @@ +package com.eternalcode.combat.fight.pearl; + +import com.eternalcode.combat.config.implementation.PluginConfig; +import com.eternalcode.combat.fight.FightManager; +import com.eternalcode.combat.fight.event.CauseOfTag; +import com.eternalcode.commons.delay.Delay; +import com.eternalcode.commons.scheduler.Scheduler; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +import java.time.Duration; +import java.util.UUID; + +public class PearlServiceImpl implements PearlService { + + private final FightManager fightManager; + private final PluginConfig pluginConfig; + private final Scheduler scheduler; + + private final Delay pearlStartTimes; + + public PearlServiceImpl(FightManager fightManager, PluginConfig pluginConfig, Scheduler scheduler) { + this.fightManager = fightManager; + this.pluginConfig = pluginConfig; + + this.pearlStartTimes = Delay.withDefault(() -> pluginConfig.pearl.pearlThrowDelay); + this.scheduler = scheduler; + } + + @Override + public boolean shouldCancelEvent(UUID playerId) { + if (fightManager.isInCombat(playerId)) { + if (this.pluginConfig.pearl.pearlCooldownEnabled) { + return this.pearlStartTimes.hasDelay(playerId); + } + + return pluginConfig.pearl.pearlThrowDisabledDuringCombat; + } + + return false; + } + + @Override + public void handleDelay(Player player) { + UUID uniqueId = player.getUniqueId(); + + if (this.hasDelay(uniqueId)) { + return; + } + + if (this.fightManager.isInCombat(uniqueId)) { + if (this.pluginConfig.pearl.pearlResetsTimer) { + Duration combatTime = this.pluginConfig.settings.combatTimerDuration; + this.fightManager.tag(uniqueId, combatTime, CauseOfTag.ENDER_PEARL); + } + + if (this.pluginConfig.pearl.pearlCooldownEnabled && !this.pluginConfig.pearl.pearlThrowDelay.isZero()) { + this.pearlStartTimes.markDelay(uniqueId); + this.scheduler.runLater( + () -> player.setCooldown( + Material.ENDER_PEARL, + (int) this.pluginConfig.pearl.pearlThrowDelay.toMillis() / 50 + ), Duration.ofMillis(50) + ); + + } + + } + } + + @Override + public boolean hasDelay(UUID uuid) { + return this.pearlStartTimes.hasDelay(uuid); + } + + @Override + public Duration getRemainingDelay(UUID uuid) { + return this.pearlStartTimes.getRemaining(uuid); + } + +} diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlSettings.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlSettings.java similarity index 89% rename from eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlSettings.java rename to eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlSettings.java index 4cb29803..0c25c2e7 100644 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/FightPearlSettings.java +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/pearl/PearlSettings.java @@ -7,7 +7,7 @@ import java.time.Duration; -public class FightPearlSettings extends OkaeriConfig { +public class PearlSettings extends OkaeriConfig { @Comment({ "# Is pearl damage to be enabled?", "# This will work globally" }) public boolean pearlThrowDamageEnabled = true; @@ -21,6 +21,9 @@ public class FightPearlSettings extends OkaeriConfig { @Comment("# Set true, If you want add cooldown to pearls") public boolean pearlCooldownEnabled = false; + @Comment("# Set true, If you want to reset timer when player throws ender pearl") + public boolean pearlResetsTimer = true; + @Comment({ "# Block throwing pearls with delay?", "# If you set this to for example 3s, player will have to wait 3 seconds before throwing another pearl" diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentController.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentController.java new file mode 100644 index 00000000..9ceeff01 --- /dev/null +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentController.java @@ -0,0 +1,185 @@ +package com.eternalcode.combat.fight.trident; + +import com.eternalcode.combat.config.implementation.PluginConfig; +import com.eternalcode.combat.fight.FightManager; +import com.eternalcode.combat.fight.event.CauseOfTag; +import com.eternalcode.combat.fight.event.FightTagEvent; +import com.eternalcode.combat.notification.NoticeService; +import com.eternalcode.combat.util.DurationUtil; +import java.time.Duration; +import java.util.UUID; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerRiptideEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; + +public class TridentController implements Listener { + + private static final int TAG_INTERRUPT_COOLDOWN_TICKS = 4; + + private final PluginConfig pluginConfig; + private final NoticeService noticeService; + private final FightManager fightManager; + private final TridentService tridentService; + private final Server server; + + public TridentController( + PluginConfig pluginConfig, + NoticeService noticeService, + FightManager fightManager, + TridentService tridentService, + Server server + ) { + this.pluginConfig = pluginConfig; + this.noticeService = noticeService; + this.fightManager = fightManager; + this.tridentService = tridentService; + this.server = server; + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void onRiptideInteractLow(PlayerInteractEvent event) { + this.blockRiptideInteract(event, true); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) + public void onRiptideInteractHigh(PlayerInteractEvent event) { + this.blockRiptideInteract(event, false); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFightTag(FightTagEvent event) { + if (!this.pluginConfig.trident.tridentRiptideDisabledDuringCombat) { + return; + } + + Player player = this.server.getPlayer(event.getPlayer()); + if (player == null || !player.isHandRaised()) { + return; + } + + ItemStack mainHandItem = player.getInventory().getItemInMainHand(); + ItemStack offHandItem = player.getInventory().getItemInOffHand(); + + if (!this.isRiptideTrident(mainHandItem) && !this.isRiptideTrident(offHandItem)) { + return; + } + + if (this.isRiptideTrident(mainHandItem)) { + player.getInventory().setItemInMainHand(mainHandItem.clone()); + } + + if (this.isRiptideTrident(offHandItem)) { + player.getInventory().setItemInOffHand(offHandItem.clone()); + } + + player.updateInventory(); + player.setCooldown(Material.TRIDENT, TAG_INTERRUPT_COOLDOWN_TICKS); + + this.noticeService.create() + .player(player.getUniqueId()) + .notice(this.pluginConfig.trident.tridentRiptideBlocked) + .send(); + } + + @EventHandler(ignoreCancelled = true) + public void onRiptide(PlayerRiptideEvent event) { + Player player = event.getPlayer(); + UUID uniqueId = player.getUniqueId(); + + if (!this.fightManager.isInCombat(uniqueId)) { + return; + } + + if (this.pluginConfig.trident.tridentRiptideDisabledDuringCombat) { + return; + } + + if (this.tridentService.hasDelay(uniqueId)) { + return; + } + + this.tridentService.handleTridentDelay(player); + + if (this.pluginConfig.trident.riptideResetsTimerEnabled) { + this.fightManager.tag(uniqueId, this.pluginConfig.settings.combatTimerDuration, CauseOfTag.TRIDENT); + } + } + + private void blockRiptideInteract(PlayerInteractEvent event, boolean sendNotice) { + if (!this.isRiptideInteract(event)) { + return; + } + + Player player = event.getPlayer(); + UUID uniqueId = player.getUniqueId(); + + if (!this.fightManager.isInCombat(uniqueId)) { + return; + } + + if (this.pluginConfig.trident.tridentRiptideDisabledDuringCombat) { + this.denyUse(event); + + if (sendNotice) { + this.noticeService.create() + .player(uniqueId) + .notice(this.pluginConfig.trident.tridentRiptideBlocked) + .send(); + } + return; + } + + if (!this.tridentService.hasDelay(uniqueId)) { + return; + } + + this.denyUse(event); + + if (!sendNotice) { + return; + } + + Duration remainingDelay = this.tridentService.getRemainingDelay(uniqueId); + this.noticeService.create() + .player(uniqueId) + .notice(this.pluginConfig.trident.tridentRiptideOnCooldown) + .placeholder("{TIME}", DurationUtil.format(remainingDelay)) + .send(); + } + + private void denyUse(PlayerInteractEvent event) { + event.setUseInteractedBlock(Event.Result.DENY); + event.setUseItemInHand(Event.Result.DENY); + event.setCancelled(true); + } + + private boolean isRiptideInteract(PlayerInteractEvent event) { + EquipmentSlot hand = event.getHand(); + if (hand != EquipmentSlot.HAND && hand != EquipmentSlot.OFF_HAND) { + return false; + } + + Action action = event.getAction(); + if (action != Action.RIGHT_CLICK_AIR && action != Action.RIGHT_CLICK_BLOCK) { + return false; + } + + return this.isRiptideTrident(event.getItem()); + } + + private boolean isRiptideTrident(ItemStack itemStack) { + return itemStack != null + && itemStack.getType() == Material.TRIDENT + && itemStack.containsEnchantment(Enchantment.RIPTIDE); + } +} diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentServiceImpl.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentServiceImpl.java new file mode 100644 index 00000000..1b4f8587 --- /dev/null +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentServiceImpl.java @@ -0,0 +1,63 @@ +package com.eternalcode.combat.fight.trident; + +import com.eternalcode.combat.config.implementation.PluginConfig; +import com.eternalcode.combat.fight.FightManager; +import com.eternalcode.commons.delay.Delay; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +import java.time.Duration; +import java.util.UUID; + +public class TridentServiceImpl implements TridentService { + + private final FightManager fightManager; + private final PluginConfig pluginConfig; + + private final Delay delay; + + public TridentServiceImpl(FightManager fightManager, PluginConfig pluginConfig) { + this.fightManager = fightManager; + this.pluginConfig = pluginConfig; + + this.delay = Delay.withDefault(() -> pluginConfig.trident.tridentRiptideDelay); + } + + @Override + public void handleTridentDelay(Player player) { + UUID uniqueId = player.getUniqueId(); + + if (this.pluginConfig.trident.tridentRiptideDelay.isZero()) { + return; + } + + if (!this.fightManager.isInCombat(uniqueId)) { + return; + } + + if (this.hasDelay(uniqueId)) { + return; + } + + + this.markDelay(uniqueId); + player.setCooldown(Material.TRIDENT, (int) this.pluginConfig.trident.tridentRiptideDelay.toMillis() / 50); + + } + + @Override + public void markDelay(UUID uuid) { + this.delay.markDelay(uuid); + } + + @Override + public boolean hasDelay(UUID uuid) { + return this.delay.hasDelay(uuid); + } + + @Override + public Duration getRemainingDelay(UUID uuid) { + return this.delay.getRemaining(uuid); + } +} + diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentSettings.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentSettings.java new file mode 100644 index 00000000..3e96381c --- /dev/null +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/trident/TridentSettings.java @@ -0,0 +1,40 @@ +package com.eternalcode.combat.fight.trident; + +import com.eternalcode.multification.bukkit.notice.BukkitNotice; +import com.eternalcode.multification.notice.Notice; +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.annotation.Comment; + +import java.time.Duration; + +public class TridentSettings extends OkaeriConfig { + + @Comment({ + "# Set to true to disable riptide usage during combat", + "# This setting works globally, but can be overridden by region settings" + }) + public boolean tridentRiptideDisabledDuringCombat = false; + + @Comment("# Set to true so the users will get combat log when they use riptide") + public boolean riptideResetsTimerEnabled = false; + + @Comment({ + "# Should riptide enchantment be on cooldown during combat?", + "# Setting this option to 3s will make players wait 3 seconds between trident throws", + "# Setting this to 0s or below will remove cooldown" + }) + public Duration tridentRiptideDelay = Duration.ofSeconds(10); + + @Comment("# Message shown when riptide is blocked during combat") + public Notice tridentRiptideBlocked = BukkitNotice.builder() + .chat("Using riptide is prohibited during combat!") + .build(); + + @Comment({ + "# Message sent to the player when riptide is on cooldown", + "# Available placeholder: {TIME} - remaining time left to use riptide again" + }) + public Notice tridentRiptideOnCooldown = BukkitNotice.builder() + .chat("You must wait {TIME} before next riptide!") + .build(); +}