From 689c1e9ddb8a0aa5434716b61ea099a2852aa27f Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Wed, 19 Aug 2026 14:43:48 +0200 Subject: [PATCH] Add GriefPrevention region support for combat restrictions --- buildSrc/src/main/kotlin/Versions.kt | 1 + .../kotlin/eternalcombat-runserver.gradle.kts | 1 + eternalcombat-plugin/build.gradle.kts | 10 ++ .../combat/bridge/BridgeService.java | 7 ++ .../config/implementation/RegionSettings.java | 3 +- .../GriefPreventionRegion.java | 34 +++++++ .../GriefPreventionRegionProvider.java | 93 +++++++++++++++++++ 7 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 eternalcombat-plugin/src/main/java/com/eternalcode/combat/region/griefprevention/GriefPreventionRegion.java create mode 100644 eternalcombat-plugin/src/main/java/com/eternalcode/combat/region/griefprevention/GriefPreventionRegionProvider.java diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 4582d118..0c7f6b69 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -26,6 +26,7 @@ object Versions { const val PLACEHOLDER_API = "2.12.3" const val LANDS_API = "7.25.4" + const val GRIEF_PREVENTION = "16.18.7" 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" diff --git a/buildSrc/src/main/kotlin/eternalcombat-runserver.gradle.kts b/buildSrc/src/main/kotlin/eternalcombat-runserver.gradle.kts index f7bc1e6f..52e2fa09 100644 --- a/buildSrc/src/main/kotlin/eternalcombat-runserver.gradle.kts +++ b/buildSrc/src/main/kotlin/eternalcombat-runserver.gradle.kts @@ -18,5 +18,6 @@ tasks { downloadPlugins.modrinth("PacketEvents", "2.12.2+spigot") downloadPlugins.modrinth("WorldGuard", "7.0.17") downloadPlugins.modrinth("LuckPerms", "v5.5.53-bukkit") + downloadPlugins.modrinth("GriefPrevention", Versions.GRIEF_PREVENTION) } } diff --git a/eternalcombat-plugin/build.gradle.kts b/eternalcombat-plugin/build.gradle.kts index 1b9e66aa..2307c411 100644 --- a/eternalcombat-plugin/build.gradle.kts +++ b/eternalcombat-plugin/build.gradle.kts @@ -62,6 +62,11 @@ dependencies { // Lands compileOnly("com.github.angeschossen:LandsAPI:${Versions.LANDS_API}") + // GriefPrevention + compileOnly("com.github.GriefPrevention:GriefPrevention:${Versions.GRIEF_PREVENTION}") { + isTransitive = false + } + // Multification implementation("com.eternalcode:multification-paper:${Versions.MULTIFICATION}") implementation("com.eternalcode:multification-okaeri:${Versions.MULTIFICATION}") @@ -96,6 +101,11 @@ paper { load = PaperPluginDescription.RelativeLoadOrder.BEFORE } + register("GriefPrevention") { + required = false + load = PaperPluginDescription.RelativeLoadOrder.BEFORE + } + register("PlaceholderAPI") { required = false load = PaperPluginDescription.RelativeLoadOrder.BEFORE diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/bridge/BridgeService.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/bridge/BridgeService.java index 1eb42a23..860d8c48 100644 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/bridge/BridgeService.java +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/bridge/BridgeService.java @@ -7,6 +7,7 @@ import com.eternalcode.combat.region.CompositeRegionProvider; import com.eternalcode.combat.region.bukkit.DefaultRegionProvider; import com.eternalcode.combat.region.RegionProvider; +import com.eternalcode.combat.region.griefprevention.GriefPreventionRegionProvider; import com.eternalcode.combat.region.worldguard.WorldGuardRegionProvider; import java.util.ArrayList; import java.util.List; @@ -55,6 +56,12 @@ public void init(Server server) { () -> this.logger.warning("WorldGuard not found; skipping WorldGuardRegionProvider.") ); + this.initialize( + "GriefPrevention", + () -> providers.add(new GriefPreventionRegionProvider(this.config)), + () -> this.logger.warning("GriefPrevention not found; skipping GriefPreventionRegionProvider.") + ); + if (providers.isEmpty()) { providers.add(new DefaultRegionProvider(this.config.regions.restrictedRegionRadius)); this.logger.warning("No region plugin found; using DefaultRegionProvider."); diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/config/implementation/RegionSettings.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/config/implementation/RegionSettings.java index d5551cbb..aaab459f 100644 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/config/implementation/RegionSettings.java +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/config/implementation/RegionSettings.java @@ -13,7 +13,8 @@ public class RegionSettings extends OkaeriConfig { public List blockedRegions = Collections.singletonList("your_region"); @Comment({ - "# Prevent players from entering regions where PVP is disabled by WorldGuard.", + "# Prevent players from entering regions where PVP is disabled by the region plugin", + "# (WorldGuard PVP flag, GriefPrevention no-combat-in-claims settings).", "# Set to 'true' to enforce this restriction, or 'false' to allow PVP in all regions." }) public boolean preventPvpInRegions = true; diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/region/griefprevention/GriefPreventionRegion.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/region/griefprevention/GriefPreventionRegion.java new file mode 100644 index 00000000..9c5efd1c --- /dev/null +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/region/griefprevention/GriefPreventionRegion.java @@ -0,0 +1,34 @@ +package com.eternalcode.combat.region.griefprevention; + +import com.eternalcode.combat.region.Point; +import com.eternalcode.combat.region.Region; +import me.ryanhamshire.GriefPrevention.Claim; +import org.bukkit.Location; +import org.bukkit.World; + +record GriefPreventionRegion(World world, Claim claim) implements Region { + + @Override + public Point getCenter() { + Location min = this.claim.getLesserBoundaryCorner(); + Location max = this.claim.getGreaterBoundaryCorner(); + + double x = (min.getX() + max.getX()) / 2.0; + double z = (min.getZ() + max.getZ()) / 2.0; + + return new Point(this.world, x, z); + } + + @Override + public Location getMin() { + Location min = this.claim.getLesserBoundaryCorner(); + return new Location(this.world, min.getBlockX(), this.world.getMinHeight(), min.getBlockZ()); + } + + @Override + public Location getMax() { + Location max = this.claim.getGreaterBoundaryCorner(); + return new Location(this.world, max.getBlockX(), this.world.getMaxHeight() - 1, max.getBlockZ()); + } + +} diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/region/griefprevention/GriefPreventionRegionProvider.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/region/griefprevention/GriefPreventionRegionProvider.java new file mode 100644 index 00000000..dc66e3ae --- /dev/null +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/region/griefprevention/GriefPreventionRegionProvider.java @@ -0,0 +1,93 @@ +package com.eternalcode.combat.region.griefprevention; + +import com.eternalcode.combat.config.implementation.PluginConfig; +import com.eternalcode.combat.region.Region; +import com.eternalcode.combat.region.RegionProvider; +import java.util.ArrayList; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.List; +import java.util.Optional; +import java.util.TreeSet; +import me.ryanhamshire.GriefPrevention.Claim; +import me.ryanhamshire.GriefPrevention.GriefPrevention; +import org.bukkit.Location; +import org.bukkit.World; + +public class GriefPreventionRegionProvider implements RegionProvider { + + private final TreeSet claims = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + private final PluginConfig pluginConfig; + + public GriefPreventionRegionProvider(PluginConfig pluginConfig) { + this.claims.addAll(pluginConfig.regions.blockedRegions); + this.pluginConfig = pluginConfig; + } + + @Override + public Optional getRegion(Location location) { + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(location, true, null); + + if (claim == null || !this.isCombatClaim(claim)) { + return Optional.empty(); + } + + return Optional.of(new GriefPreventionRegion(location.getWorld(), claim)); + } + + @Override + public Collection getRegions(World world) { + List regions = new ArrayList<>(); + + for (Claim claim : this.snapshotClaims()) { + if (!world.equals(claim.getLesserBoundaryCorner().getWorld())) { + continue; + } + + if (this.isCombatClaim(claim)) { + regions.add(new GriefPreventionRegion(world, claim)); + } + } + + return regions; + } + + private boolean isCombatClaim(Claim claim) { + if (this.claims.contains(String.valueOf(claim.getID()))) { + return true; + } + + if (!this.pluginConfig.regions.preventPvpInRegions) { + return false; + } + + World world = claim.getLesserBoundaryCorner().getWorld(); + GriefPrevention griefPrevention = GriefPrevention.instance; + + if (world == null || !griefPrevention.pvpRulesApply(world)) { + return false; + } + + if (!claim.isAdminClaim()) { + return griefPrevention.config_pvp_noCombatInPlayerLandClaims; + } + + if (claim.parent == null) { + return griefPrevention.config_pvp_noCombatInAdminLandClaims; + } + + return griefPrevention.config_pvp_noCombatInAdminSubdivisions; + } + + // GriefPrevention returns a live view of its claim list, and the border index reads regions asynchronously. + // A failed snapshot is retried by the next border index refresh, so an empty result is safe here. + private List snapshotClaims() { + try { + return List.copyOf(GriefPrevention.instance.dataStore.getClaims()); + } + catch (ConcurrentModificationException exception) { + return List.of(); + } + } + +}