Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ object Versions {

const val PLACEHOLDER_API = "2.12.3"
const val LANDS_API = "7.25.4"
const val WORLDEDIT = "3ISh7ADm" //cannot use numeric version bc of duplicated version on modrinth
const val PACKETEVENTS = "2.11.1"
const val WORLDGUARD = "7.0.15-beta-01"
const val LUCKPERMS = "5.5.17"

}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.eternalcode.combat.fight.spear;

import java.time.Duration;
import java.util.UUID;

public interface SpearService {
boolean isOnCooldown(UUID uuid);
void saveCooldown(UUID uuid);
Duration getRemainingCooldown(UUID uuid);
}
Comment thread
CitralFlo marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
import com.eternalcode.combat.fight.pearl.PearlController;
import com.eternalcode.combat.fight.pearl.PearlService;
import com.eternalcode.combat.fight.pearl.PearlServiceImpl;
import com.eternalcode.combat.fight.spear.SpearLungeController;
import com.eternalcode.combat.fight.spear.SpearService;
import com.eternalcode.combat.fight.spear.SpearServiceImpl;
import com.eternalcode.combat.fight.tagout.FightTagOutCommand;
import com.eternalcode.combat.fight.tagout.FightTagOutController;
import com.eternalcode.combat.fight.tagout.FightTagOutService;
Expand Down Expand Up @@ -128,7 +131,7 @@
this.dropService = new DropServiceImpl();
this.dropKeepInventoryService = new DropKeepInventoryServiceImpl();

UpdaterService updaterService = new UpdaterService(this.getDescription());

Check warning on line 134 in eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java

View workflow job for this annotation

GitHub Actions / build

[deprecation] getDescription() in JavaPlugin has been deprecated

MiniMessage miniMessage = MiniMessage.builder()
.postProcessor(new AdventureLegacyColorPostProcessor())
Expand All @@ -150,6 +153,8 @@
BorderService borderService = new BorderServiceImpl(scheduler, server, regionProvider, eventManager, () -> pluginConfig.border);
KnockbackService knockbackService = new KnockbackService(pluginConfig, scheduler, regionProvider);

SpearService spearService = new SpearServiceImpl(pluginConfig.spear);

this.liteCommands = LiteBukkitFactory.builder(FALLBACK_PREFIX, this, server)
.message(LiteBukkitMessages.PLAYER_NOT_FOUND, pluginConfig.messagesSettings.playerNotFound)
.message(LiteBukkitMessages.PLAYER_ONLY, pluginConfig.messagesSettings.admin.onlyForPlayers)
Expand Down Expand Up @@ -214,6 +219,8 @@

new KnockbackMountController(noticeService, this.regionProvider, this.fightManager).register(this);

new SpearLungeController(this, fightManager, spearService, pluginConfig, noticeService);
Comment thread
CitralFlo marked this conversation as resolved.
Outdated

eventManager.subscribe(
PlayerDeathEvent.class,
pluginConfig.drop.dropEventPriority,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.eternalcode.combat.fight.effect.FightEffectSettings;
import com.eternalcode.combat.fight.knockback.KnockbackSettings;
import com.eternalcode.combat.fight.pearl.PearlSettings;
import com.eternalcode.combat.fight.spear.SpearSettings;
import com.eternalcode.combat.fight.trident.TridentSettings;
import eu.okaeri.configs.OkaeriConfig;
import eu.okaeri.configs.annotation.Comment;
Expand Down Expand Up @@ -44,6 +45,13 @@ public class PluginConfig extends OkaeriConfig {
})
public TridentSettings trident = new TridentSettings();

@Comment({
" ",
"# Settings related to Spears with lunge",
"# Set cooldown for spear lunging"
})
public SpearSettings spear = new SpearSettings();

@Comment({
" ",
"# Custom effects applied during combat.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.eternalcode.combat.fight.spear;

import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.notification.NoticeService;
import com.eternalcode.combat.util.DurationUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
Comment thread
CitralFlo marked this conversation as resolved.

import java.lang.reflect.Method;
import java.time.Duration;
import java.util.UUID;

public class SpearLungeController implements Listener {

public SpearLungeController(Plugin plugin, FightManager fightManager, SpearService spearService, PluginConfig settings, NoticeService noticeService) {
try {
Class<? extends Event> lungeEventClass = (Class<? extends Event>) Class.forName("io.papermc.paper.event.entity.EntityLungeEvent");

Method getEntityMethod = lungeEventClass.getMethod("getEntity");
Method setCancelledMethod = lungeEventClass.getMethod("setCancelled", boolean.class);

Bukkit.getPluginManager().registerEvent(
lungeEventClass,
this,
EventPriority.NORMAL,
(listener, event) -> {
if (!settings.spear.lungeCooldown) return;
if (!lungeEventClass.isInstance(event)) return;

try {
Object entity = getEntityMethod.invoke(event);

if (entity instanceof Player player) {
UUID uuid = player.getUniqueId();

boolean inCombat = fightManager.isInCombat(uuid);

if (settings.spear.onlyForFight && !inCombat) {
return;
}

if (spearService.isOnCooldown(uuid)) {
setCancelledMethod.invoke(event, true);

Duration remaining = spearService.getRemainingCooldown(uuid);

noticeService.create()
.player(uuid)
.notice(settings.spear.lungeOnCooldown)
.placeholder("{TIME}", DurationUtil.format(remaining, !settings.spear.useMillis))
.send();
} else {
spearService.saveCooldown(uuid);
}
Comment thread
CitralFlo marked this conversation as resolved.
Outdated
}
} catch (Exception e) {
plugin.getLogger().warning("Failed to handle EntityLungeEvent reflectively: " + e.getMessage());
}
},
plugin
);
} catch (ClassNotFoundException e) {
plugin.getLogger().info("EntityLungeEvent not found, skipping spear lunge cooldown registration.");
} catch (NoSuchMethodException e) {
plugin.getLogger().warning("Failed to find necessary methods for EntityLungeEvent: " + e.getMessage());
}
}
Comment on lines +3 to +79

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.notification.NoticeService;
import com.eternalcode.combat.util.DurationUtil;
import org.bukkit.Bukkit;
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.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.UUID;
public class SpearLungeController implements Listener {
private final SpearService spearService;
public SpearLungeController(Plugin plugin, FightManager fightManager, SpearService spearService, SpearSettings settings, NoticeService noticeService) {
this.spearService = spearService;
Bukkit.getPluginManager().registerEvents(this, plugin);
try {
Class<? extends Event> lungeEventClass = (Class<? extends Event>) Class.forName("io.papermc.paper.event.entity.EntityLungeEvent");
Method getEntityMethod = lungeEventClass.getMethod("getEntity");
Method setCancelledMethod = lungeEventClass.getMethod("setCancelled", boolean.class);
Bukkit.getPluginManager().registerEvent(
lungeEventClass,
this,
EventPriority.NORMAL,
(listener, event) -> {
if (!settings.lungeCooldown) return;
if (!lungeEventClass.isInstance(event)) return;
try {
Object entity = getEntityMethod.invoke(event);
if (entity instanceof Player player) {
UUID uuid = player.getUniqueId();
if (settings.onlyForFight && !fightManager.isInCombat(uuid)) {
return;
}
// Query the remaining cooldown once to avoid redundant lookups and race conditions
Duration remaining = spearService.getRemainingCooldown(uuid);
if (!remaining.isZero() && !remaining.isNegative()) {
setCancelledMethod.invoke(event, true);
noticeService.create()
.player(uuid)
.notice(settings.lungeOnCooldown)
.placeholder("{TIME}", DurationUtil.format(remaining, !settings.useMillis))
.send();
} else {
spearService.saveCooldown(uuid);
}
}
} catch (Exception e) {
plugin.getLogger().warning("Failed to handle EntityLungeEvent reflectively: " + e.getMessage());
}
},
plugin
);
} catch (ClassNotFoundException e) {
plugin.getLogger().info("EntityLungeEvent not found, skipping spear lunge cooldown registration.");
} catch (NoSuchMethodException e) {
plugin.getLogger().warning("Failed to find necessary methods for EntityLungeEvent: " + e.getMessage());
}
}
import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.notification.NoticeService;
import com.eternalcode.combat.util.DurationUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import java.time.Duration;
import java.util.UUID;
public class SpearLungeController implements Listener {
private final SpearService spearService;
public SpearLungeController(Plugin plugin, FightManager fightManager, SpearService spearService, SpearSettings settings, NoticeService noticeService) {
this.spearService = spearService;
Bukkit.getPluginManager().registerEvents(this, plugin);
try {
Class<? extends Event> lungeEventClass = Class.forName("io.papermc.paper.event.entity.EntityLungeEvent").asSubclass(EntityEvent.class);
Bukkit.getPluginManager().registerEvent(
lungeEventClass,
this,
EventPriority.NORMAL,
(listener, event) -> {
if (!settings.lungeCooldown) return;
if (!(event instanceof EntityEvent entityEvent)) return;
if (!(entityEvent.getEntity() instanceof Player player)) return;
UUID uuid = player.getUniqueId();
if (settings.onlyForFight && !fightManager.isInCombat(uuid)) return;
Duration remaining = spearService.getRemainingCooldown(uuid);
if (!remaining.isZero() && !remaining.isNegative()) {
((Cancellable) event).setCancelled(true);
noticeService.create()
.player(uuid)
.notice(settings.lungeOnCooldown)
.placeholder("{TIME}", DurationUtil.format(remaining, !settings.useMillis))
.send();
} else {
spearService.saveCooldown(uuid);
}
},
plugin
);
} catch (ClassNotFoundException e) {
plugin.getLogger().info("EntityLungeEvent not found, skipping spear lunge cooldown registration.");
}
}

}
Comment thread
CitralFlo marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.eternalcode.combat.fight.spear;

import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class SpearServiceImpl implements SpearService {

private final SpearSettings settings;
private final Map<UUID, Instant> cooldowns = new ConcurrentHashMap<>();

public SpearServiceImpl(SpearSettings settings) {
this.settings = settings;
}

@Override
public boolean isOnCooldown(UUID uuid) {
Instant expiration = this.cooldowns.get(uuid);

if (expiration == null) {
return false;
}

if (Instant.now().isAfter(expiration)) {
this.cooldowns.remove(uuid);
return false;
}

return true;
}

@Override
public void saveCooldown(UUID uuid) {
this.cooldowns.put(uuid, Instant.now().plus(this.settings.lungeCooldownDuration));
}

@Override
public Duration getRemainingCooldown(UUID uuid) {
Instant expiration = this.cooldowns.get(uuid);

if (expiration == null) {
return Duration.ZERO;
}

Duration remaining = Duration.between(Instant.now(), expiration);
return remaining.isNegative() ? Duration.ZERO : remaining;
}
}
Comment thread
CitralFlo marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.eternalcode.combat.fight.spear;

import com.eternalcode.multification.notice.Notice;
import eu.okaeri.configs.OkaeriConfig;
import eu.okaeri.configs.annotation.Comment;
import java.time.Duration;

public class SpearSettings extends OkaeriConfig {

@Comment("# Should spears have lunge cooldown or delay between uses? True for cooldown, False for vanilla mechanics")
public boolean lungeCooldown = false;

@Comment("# Should cooldown be applied only during fights")
public boolean onlyForFight = true;

@Comment("# Duration of cooldown")
public Duration lungeCooldownDuration = Duration.ofSeconds(5);

@Comment("# Should milliseconds be used for last second of cooldown for more precise time")
public boolean useMillis = true;

@Comment({
"# Notice sent to the players that try to use spears before cooldown ends.",
"# Placeholder: {TIME} - time left of cooldown"
})
public Notice lungeOnCooldown = Notice.builder().actionBar("<dark_red>Spear cannot be used for next <red>{TIME}</red></dark_red>")
.build();

}
Loading