From 2330e5441f7a30c33bc3c1dc12f2c65078878e73 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 12 Jul 2024 14:05:03 -0400 Subject: [PATCH 01/10] handle windcharges with new explosion type api + refactoring * Update to 1.21 * Update to Java 21 * Move to more maintainable `PotionEffectTypeCategory` for potion handling * Use `Tag.REPLACEABLE` instead of manual material listing * This is the tag of blocks where placement on any surface becomes `BlockFace.SELF`. Includes long grass, dead shrubs, snow, short grass, the works. * Extract `GriefPrevention#allowBuild`/`GriefPrevention#allowBreak` to a helper method * These methods have been hacky since the introduction of the `ClaimPermissionCheckEvent`, and as we saw with damage events, Spigot is serious about event constructors not being API. Moving away from constructing events is a good idea in general. * Improves accuracy of event funnel by not masking various events with fake `BlockPlaceEvent`/`BlockBreakEvent` constructions. * Deprecate `PreventBlockBreakEvent` instead listen to `ClaimPermissionCheckEvent`, check `#getTriggeringEvent`. * Prevent claim lookup if ignoring the result anyway when milking cows * Update BanList to use modern version * Fix wind charges being blocked without `/claimexplosions` enabled This requires a recent build of Spigot - explosion type was only added to the API in [`a4ee40b7`](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/a4ee40b749f614482f5b5e52cda1b35c19df75be), 4 days ago as of this edit. Closes #2320 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- jitpack.yml | 5 +- pom.xml | 6 +- .../protection/ProtectionHelper.java | 108 ++++++++++++++ .../GriefPrevention/BlockEventHandler.java | 17 ++- .../GriefPrevention/EntityDamageHandler.java | 38 ++--- .../GriefPrevention/EntityEventHandler.java | 124 ++++++++++++---- .../GriefPrevention/GriefPrevention.java | 140 ++++++------------ .../GriefPrevention/PlayerEventHandler.java | 55 ++++--- .../events/PreventBlockBreakEvent.java | 5 +- 11 files changed, 305 insertions(+), 197 deletions(-) create mode 100644 src/main/java/com/griefprevention/protection/ProtectionHelper.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed74c45..bda4954 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ 17 ] + java: [ 21 ] steps: - name: "Checkout" uses: actions/checkout@v4 diff --git a/appveyor.yml b/appveyor.yml index f9837f4..4cd5c65 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ clone_depth: 10 environment: matrix: - appveyor_build_worker_image: Visual Studio 2022 - JAVA_HOME: C:\Program Files\Java\jdk17 + JAVA_HOME: C:\Program Files\Java\jdk21 branches: only: - master diff --git a/jitpack.yml b/jitpack.yml index d9bb5ab..a1dbc50 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,3 +1,4 @@ before_install: - - sdk install java 17.0.1-open - - sdk use java 17.0.1-open + - sdk install java 21.0.3-tem + - sdk use java 21.0.3-tem + - mvn wrapper:wrapper -Dmaven=3.6.3 diff --git a/pom.xml b/pom.xml index 32badaa..895bfe2 100644 --- a/pom.xml +++ b/pom.xml @@ -61,8 +61,8 @@ maven-compiler-plugin 3.8.1 - 16 - 16 + 21 + 21 @@ -142,7 +142,7 @@ org.spigotmc spigot-api - 1.20.4-R0.1-SNAPSHOT + 1.21-R0.1-SNAPSHOT provided diff --git a/src/main/java/com/griefprevention/protection/ProtectionHelper.java b/src/main/java/com/griefprevention/protection/ProtectionHelper.java new file mode 100644 index 0000000..f5c8daa --- /dev/null +++ b/src/main/java/com/griefprevention/protection/ProtectionHelper.java @@ -0,0 +1,108 @@ +package com.griefprevention.protection; + +import me.ryanhamshire.GriefPrevention.Claim; +import me.ryanhamshire.GriefPrevention.ClaimPermission; +import me.ryanhamshire.GriefPrevention.ClaimsMode; +import me.ryanhamshire.GriefPrevention.DataStore; +import me.ryanhamshire.GriefPrevention.GriefPrevention; +import me.ryanhamshire.GriefPrevention.Messages; +import me.ryanhamshire.GriefPrevention.PlayerData; +import me.ryanhamshire.GriefPrevention.events.PreventBlockBreakEvent; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +/** + * A utility used to simplify various protection-related checks. + */ +public final class ProtectionHelper +{ + + private ProtectionHelper() {} + + /** + * Check the {@link ClaimPermission} state for a {@link Player} at a particular {@link Location}. + * + *

This respects ignoring claims, wilderness rules, etc.

+ * + * @param player the person performing the action + * @param location the affected {@link Location} + * @param permission the required permission + * @param trigger the triggering {@link Event}, if any + * @return the denial message supplier, or {@code null} if the action is not denied + */ + public static @Nullable Supplier checkPermission( + @NotNull Player player, + @NotNull Location location, + @NotNull ClaimPermission permission, + @Nullable Event trigger) + { + World world = location.getWorld(); + if (world == null || !GriefPrevention.instance.claimsEnabledForWorld(world)) return null; + + PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()); + + // Administrators ignoring claims always have permission. + if (playerData.ignoreClaims) return null; + + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(location, false, playerData.lastClaim); + + + // If there is no claim here, use wilderness rules. + if (claim == null) + { + ClaimsMode mode = GriefPrevention.instance.config_claims_worldModes.get(world); + if (mode == ClaimsMode.Creative || mode == ClaimsMode.SurvivalRequiringClaims) + { + // Allow placing chest if it would create an automatic claim. + if (trigger instanceof BlockPlaceEvent placeEvent + && placeEvent.getBlock().getType() == Material.CHEST + && playerData.getClaims().isEmpty() + && GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius > -1) + return null; + + // If claims are required, provide relevant information. + return () -> + { + String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildOutsideClaims); + if (player.hasPermission("griefprevention.ignoreclaims")) + reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement); + reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.CreativeBasicsVideo2, DataStore.CREATIVE_VIDEO_URL); + return reason; + }; + } + + // If claims are not required, then the player has permission. + return null; + } + + // Update cached claim. + playerData.lastClaim = claim; + + // Apply claim rules. + Supplier cancel = claim.checkPermission(player, permission, trigger); + + // Apply additional specific rules. + if (cancel != null && trigger instanceof BlockBreakEvent breakEvent) + { + PreventBlockBreakEvent preventionEvent = new PreventBlockBreakEvent(breakEvent); + Bukkit.getPluginManager().callEvent(preventionEvent); + if (preventionEvent.isCancelled()) + { + cancel = null; + } + } + + return cancel; + } + +} diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/BlockEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/BlockEventHandler.java index 35fa5da..2c341dd 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/BlockEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/BlockEventHandler.java @@ -21,6 +21,7 @@ import com.griefprevention.visualization.BoundaryVisualization; import com.griefprevention.visualization.VisualizationType; import me.ryanhamshire.GriefPrevention.util.BoundingBox; +import com.griefprevention.protection.ProtectionHelper; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.GameMode; @@ -126,10 +127,10 @@ public void onBlockBreak(BlockBreakEvent breakEvent) Block block = breakEvent.getBlock(); //make sure the player is allowed to break at the location - String noBuildReason = GriefPrevention.instance.allowBreak(player, block, block.getLocation(), breakEvent); + Supplier noBuildReason = ProtectionHelper.checkPermission(player, block.getLocation(), ClaimPermission.Build, breakEvent); if (noBuildReason != null) { - GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); breakEvent.setCancelled(true); return; } @@ -144,10 +145,10 @@ public void onSignChanged(SignChangeEvent event) if (player == null || sign == null) return; - String noBuildReason = GriefPrevention.instance.allowBuild(player, sign.getLocation(), sign.getType()); + Supplier noBuildReason = ProtectionHelper.checkPermission(player, sign.getLocation(), ClaimPermission.Build, event); if (noBuildReason != null) { - GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); event.setCancelled(true); return; } @@ -213,10 +214,10 @@ public void onBlocksPlace(BlockMultiPlaceEvent placeEvent) //make sure the player is allowed to build at the location for (BlockState block : placeEvent.getReplacedBlockStates()) { - String noBuildReason = GriefPrevention.instance.allowBuild(player, block.getLocation(), block.getType()); + Supplier noBuildReason = ProtectionHelper.checkPermission(player, block.getLocation(), ClaimPermission.Build, placeEvent); if (noBuildReason != null) { - GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); placeEvent.setCancelled(true); return; } @@ -271,7 +272,7 @@ public void onBlockPlace(BlockPlaceEvent placeEvent) if (!GriefPrevention.instance.claimsEnabledForWorld(placeEvent.getBlock().getWorld())) return; //make sure the player is allowed to build at the location - String noBuildReason = GriefPrevention.instance.allowBuild(player, block.getLocation(), block.getType()); + Supplier noBuildReason = ProtectionHelper.checkPermission(player, block.getLocation(), ClaimPermission.Build, placeEvent); if (noBuildReason != null) { // Allow players with container trust to place books in lecterns @@ -291,7 +292,7 @@ public void onBlockPlace(BlockPlaceEvent placeEvent) return; } } - GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); placeEvent.setCancelled(true); return; } diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/EntityDamageHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/EntityDamageHandler.java index 4e523bb..9a81d22 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/EntityDamageHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/EntityDamageHandler.java @@ -45,6 +45,7 @@ import org.bukkit.persistence.PersistentDataType; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionEffectTypeCategory; import org.bukkit.projectiles.ProjectileSource; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; @@ -63,34 +64,13 @@ public class EntityDamageHandler implements Listener private static final Set GRIEF_EFFECTS = Set.of( // Damaging effects - PotionEffectType.HARM, + PotionEffectType.INSTANT_DAMAGE, PotionEffectType.POISON, PotionEffectType.WITHER, // Effects that could remove entities from normally-secure pens - PotionEffectType.JUMP, + PotionEffectType.JUMP_BOOST, PotionEffectType.LEVITATION ); - private static final Set POSITIVE_EFFECTS = Set.of( - PotionEffectType.ABSORPTION, - PotionEffectType.CONDUIT_POWER, - PotionEffectType.DAMAGE_RESISTANCE, - PotionEffectType.DOLPHINS_GRACE, - PotionEffectType.FAST_DIGGING, - PotionEffectType.FIRE_RESISTANCE, - PotionEffectType.HEAL, - PotionEffectType.HEALTH_BOOST, - PotionEffectType.HERO_OF_THE_VILLAGE, - PotionEffectType.INCREASE_DAMAGE, - PotionEffectType.INVISIBILITY, - PotionEffectType.JUMP, - PotionEffectType.LUCK, - PotionEffectType.NIGHT_VISION, - PotionEffectType.REGENERATION, - PotionEffectType.SATURATION, - PotionEffectType.SLOW_FALLING, - PotionEffectType.SPEED, - PotionEffectType.WATER_BREATHING - ); private static final Set TEMPTABLE_SEMI_HOSTILES = Set.of( EntityType.HOGLIN, EntityType.POLAR_BEAR, @@ -150,7 +130,7 @@ private void handleEntityDamageEvent(@NotNull EntityDamageInstance event, boolea if (event.damaged() instanceof Mule && !instance.config_claims_protectDonkeys) return; if (event.damaged() instanceof Llama && !instance.config_claims_protectLlamas) return; //protected death loot can't be destroyed, only picked up or despawned due to expiration - if (event.damaged().getType() == EntityType.DROPPED_ITEM) + if (event.damaged().getType() == EntityType.ITEM) { if (event.damaged().hasMetadata("GP_ITEMOWNER")) { @@ -582,7 +562,7 @@ private boolean handleClaimedBuildTrustDamageByEntity( && entityType != EntityType.GLOW_ITEM_FRAME && entityType != EntityType.ARMOR_STAND && entityType != EntityType.VILLAGER - && entityType != EntityType.ENDER_CRYSTAL) + && entityType != EntityType.END_CRYSTAL) { return false; } @@ -663,7 +643,7 @@ private boolean handleCreatureDamageByEntity( if (attacker == null && damageSourceType != EntityType.CREEPER && damageSourceType != EntityType.WITHER - && damageSourceType != EntityType.ENDER_CRYSTAL + && damageSourceType != EntityType.END_CRYSTAL && damageSourceType != EntityType.AREA_EFFECT_CLOUD && damageSourceType != EntityType.WITCH && !(damageSource instanceof Projectile) @@ -699,7 +679,7 @@ private boolean handleCreatureDamageByEntity( playerData.lastClaim = claim; // Do not message players about fireworks to prevent spam due to multi-hits. - sendMessages &= damageSourceType != EntityType.FIREWORK; + sendMessages &= damageSourceType != EntityType.FIREWORK_ROCKET; Supplier override = null; if (sendMessages) @@ -880,7 +860,7 @@ else if (damageSource instanceof Projectile projectile) } //if not a player and not an explosion, always allow - if (attacker == null && damageSourceType != EntityType.CREEPER && damageSourceType != EntityType.WITHER && damageSourceType != EntityType.PRIMED_TNT) + if (attacker == null && damageSourceType != EntityType.CREEPER && damageSourceType != EntityType.WITHER && damageSourceType != EntityType.TNT) { return; } @@ -999,7 +979,7 @@ public void onPotionSplash(@NotNull PotionSplashEvent event) if (thrower == null) return; //otherwise, no restrictions for positive effects - if (POSITIVE_EFFECTS.contains(effectType)) continue; + if (effectType.getCategory() == PotionEffectTypeCategory.BENEFICIAL) continue; for (LivingEntity affected : event.getAffectedEntities()) { diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java index 2ff2667..449144a 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java @@ -18,8 +18,10 @@ package me.ryanhamshire.GriefPrevention; +import com.griefprevention.protection.ProtectionHelper; import me.ryanhamshire.GriefPrevention.events.ProtectDeathDropsEvent; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.OfflinePlayer; @@ -36,6 +38,7 @@ import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.entity.Vehicle; +import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -89,14 +92,10 @@ public EntityEventHandler(DataStore dataStore, GriefPrevention plugin) public void onEntityFormBlock(EntityBlockFormEvent event) { Entity entity = event.getEntity(); - if (entity.getType() == EntityType.PLAYER) + if (entity instanceof Player player + && ProtectionHelper.checkPermission(player, event.getBlock().getLocation(), ClaimPermission.Build, event) != null) { - Player player = (Player) event.getEntity(); - String noBuildReason = GriefPrevention.instance.allowBuild(player, event.getBlock().getLocation(), event.getNewState().getType()); - if (noBuildReason != null) - { - event.setCancelled(true); - } + event.setCancelled(true); } } @@ -148,15 +147,14 @@ else if (event.getEntityType() == EntityType.WITHER) //don't allow crops to be trampled, except by a player with build permission else if (event.getTo() == Material.DIRT && event.getBlock().getType() == Material.FARMLAND) { - if (event.getEntityType() != EntityType.PLAYER) + if (!(event.getEntity() instanceof Player player)) { event.setCancelled(true); } else { - Player player = (Player) event.getEntity(); Block block = event.getBlock(); - if (GriefPrevention.instance.allowBreak(player, block, block.getLocation()) != null) + if (ProtectionHelper.checkPermission(player, block.getLocation(), ClaimPermission.Build, event) != null) { event.setCancelled(true); } @@ -173,10 +171,10 @@ else if (event.getBlock().getType() == Material.POWDER_SNOW && event.getTo() == else if (event.getEntity() instanceof Vehicle && !event.getEntity().getPassengers().isEmpty()) { Entity driver = event.getEntity().getPassengers().get(0); - if (driver instanceof Player) + if (driver instanceof Player player) { Block block = event.getBlock(); - if (GriefPrevention.instance.allowBreak((Player) driver, block, block.getLocation()) != null) + if (ProtectionHelper.checkPermission(player, block.getLocation(), ClaimPermission.Build, event) != null) { event.setCancelled(true); } @@ -327,7 +325,7 @@ else if (mob.isLeashed() && mob.getLeashHolder() instanceof Player localPlayer) if (player != null) { Block block = event.getBlock(); - if (GriefPrevention.instance.allowBreak(player, block, block.getLocation()) != null) + if (ProtectionHelper.checkPermission(player, block.getLocation(), ClaimPermission.Build, event) != null) { event.setCancelled(true); } @@ -379,23 +377,99 @@ public void onEntityInteract(EntityInteractEvent event) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onEntityExplode(EntityExplodeEvent explodeEvent) { - this.handleExplosion(explodeEvent.getLocation(), explodeEvent.getEntity(), explodeEvent.blockList()); + // If there aren't any affected blocks, there's nothing to do. Vanilla mob griefing rule causes this. + if (explodeEvent.blockList().isEmpty()) return; + + // Explosion causes interactable blocks (levers, buttons, etc.) to change state. + if (explodeEvent.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK) + { + handleExplodeInteract(explodeEvent.getLocation(), explodeEvent.getEntity(), explodeEvent.blockList(), explodeEvent); + } + // Explosion damages world. + else + { + handleExplosion(explodeEvent.getLocation(), explodeEvent.getEntity(), explodeEvent.blockList()); + } } //when a block explodes... @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onBlockExplode(BlockExplodeEvent explodeEvent) { - this.handleExplosion(explodeEvent.getBlock().getLocation(), null, explodeEvent.blockList()); + // If there aren't any affected blocks, there's nothing to do. Vanilla mob griefing rule causes this. + if (explodeEvent.blockList().isEmpty()) return; + + // Explosion causes interactable blocks (levers, buttons, etc.) to change state. + if (explodeEvent.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK) + { + handleExplodeInteract(explodeEvent.getBlock().getLocation(), null, explodeEvent.blockList(), explodeEvent); + } + // Explosion damages world. + else + { + handleExplosion(explodeEvent.getBlock().getLocation(), null, explodeEvent.blockList()); + } } + void handleExplodeInteract(@NotNull Location location, @Nullable Entity entity, @NotNull List blocks, @NotNull Event event) + { + World world = location.getWorld(); + + if (world == null || !GriefPrevention.instance.claimsEnabledForWorld(world)) return; - void handleExplosion(Location location, Entity entity, List blocks) + Player player = null; + PlayerData playerData = null; + ProjectileSource source = null; + if (entity instanceof Projectile projectile) + { + source = projectile.getShooter(); + if (source instanceof Player) + { + player = (Player) source; + playerData = dataStore.getPlayerData(player.getUniqueId()); + } + } + + List removed = new ArrayList<>(); + Claim cachedClaim = playerData != null ? playerData.lastClaim : null; + + for (Block block : blocks) + { + // Always ignore air blocks. + if (block.getType().isAir()) continue; + + Claim claim = this.dataStore.getClaimAt(block.getLocation(), false, cachedClaim); + + // Is it in a land claim? + if (claim == null) continue; + + cachedClaim = claim; + + if (player == null) + { + // If the source is not part of the claim, prevent interaction. + if (!isBlockSourceInClaim(source, claim)) + removed.add(block); + continue; + } + + // If the player is not allowed to interact with blocks, prevent interaction. + if (claim.checkPermission(player, ClaimPermission.Access, event) != null) + removed.add(block); + } + + if (playerData != null && cachedClaim != null) + playerData.lastClaim = cachedClaim; + + blocks.removeAll(removed); + } + + void handleExplosion(@NotNull Location location, @Nullable Entity entity, @NotNull List blocks) { //only applies to claims-enabled worlds World world = location.getWorld(); - if (!GriefPrevention.instance.claimsEnabledForWorld(world)) return; + if (world == null || !GriefPrevention.instance.claimsEnabledForWorld(world)) return; //FEATURE: explosions don't destroy surface blocks by default boolean isCreeper = (entity != null && entity.getType() == EntityType.CREEPER); @@ -407,8 +481,6 @@ void handleExplosion(Location location, Entity entity, List blocks) { for (int i = 0; i < blocks.size(); i++) { - Block block = blocks.get(i); - blocks.remove(i--); } @@ -421,7 +493,7 @@ void handleExplosion(Location location, Entity entity, List blocks) for (Block block : blocks) { //always ignore air blocks - if (block.getType() == Material.AIR) continue; + if (block.getType().isAir()) continue; //is it in a land claim? Claim claim = this.dataStore.getClaimAt(block.getLocation(), false, cachedClaim); @@ -652,19 +724,18 @@ public void onHangingBreak(HangingBreakEvent event) Entity remover = entityEvent.getRemover(); //again, making sure the breaker is a player - if (remover.getType() != EntityType.PLAYER) + if (!(remover instanceof Player playerRemover)) { event.setCancelled(true); return; } //if the player doesn't have build permission, don't allow the breakage - Player playerRemover = (Player) entityEvent.getRemover(); - String noBuildReason = GriefPrevention.instance.allowBuild(playerRemover, event.getEntity().getLocation(), Material.AIR); + Supplier noBuildReason = ProtectionHelper.checkPermission(playerRemover, event.getEntity().getLocation(), ClaimPermission.Build, event); if (noBuildReason != null) { event.setCancelled(true); - GriefPrevention.sendMessage(playerRemover, TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(playerRemover, TextMode.Err, noBuildReason.get()); } } @@ -674,15 +745,16 @@ public void onPaintingPlace(HangingPlaceEvent event) { //don't track in worlds where claims are not enabled if (!GriefPrevention.instance.claimsEnabledForWorld(event.getBlock().getWorld())) return; + if (event.getPlayer() == null) return; //FEATURE: similar to above, placing a painting requires build permission in the claim //if the player doesn't have permission, don't allow the placement - String noBuildReason = GriefPrevention.instance.allowBuild(event.getPlayer(), event.getEntity().getLocation(), Material.PAINTING); + Supplier noBuildReason = ProtectionHelper.checkPermission(event.getPlayer(), event.getEntity().getLocation(), ClaimPermission.Build, event); if (noBuildReason != null) { event.setCancelled(true); - GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, noBuildReason.get()); return; } } diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java index efe27cb..c9352cc 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -22,8 +22,8 @@ import com.google.common.cache.CacheBuilder; import com.griefprevention.commands.ClaimCommand; import com.griefprevention.metrics.MetricsHandler; +import com.griefprevention.protection.ProtectionHelper; import me.ryanhamshire.GriefPrevention.DataStore.NoTransferException; -import me.ryanhamshire.GriefPrevention.events.PreventBlockBreakEvent; import me.ryanhamshire.GriefPrevention.events.SaveTrappedPlayerEvent; import me.ryanhamshire.GriefPrevention.events.TrustChangedEvent; import org.bukkit.BanList; @@ -53,6 +53,7 @@ import org.bukkit.inventory.PlayerInventory; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.profile.PlayerProfile; import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -2947,125 +2948,72 @@ public boolean creativeRulesApply(@NotNull Location location) return this.config_claims_worldModes.get(location.getWorld()) == ClaimsMode.Creative; } - public String allowBuild(Player player, Location location) + /** + * @deprecated use {@link ProtectionHelper#checkPermission(Player, Location, ClaimPermission, org.bukkit.event.Event)} + */ + @Deprecated(forRemoval = true, since = "17.0.0") + public @Nullable String allowBuild(Player player, Location location) { - // TODO check all derivatives and rework API return this.allowBuild(player, location, location.getBlock().getType()); } - public String allowBuild(Player player, Location location, Material material) + /** + * @deprecated use {@link ProtectionHelper#checkPermission(Player, Location, ClaimPermission, org.bukkit.event.Event)} + */ + @Deprecated(forRemoval = true, since = "17.0.0") + public @Nullable String allowBuild(Player player, Location location, Material material) { if (!GriefPrevention.instance.claimsEnabledForWorld(location.getWorld())) return null; - PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); - Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim); - - //exception: administrators in ignore claims mode - if (playerData.ignoreClaims) return null; - - //wilderness rules - if (claim == null) + ItemStack placed; + if (material.isItem()) + { + placed = new ItemStack(material); + } + else { - //no building in the wilderness in creative mode - if (this.creativeRulesApply(location) || this.config_claims_worldModes.get(location.getWorld()) == ClaimsMode.SurvivalRequiringClaims) + var blockType = material.asBlockType(); + if (blockType != null && blockType.hasItemType()) { - //exception: when chest claims are enabled, players who have zero land claims and are placing a chest - if (material != Material.CHEST || playerData.getClaims().size() > 0 || GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius == -1) - { - String reason = this.dataStore.getMessage(Messages.NoBuildOutsideClaims); - if (player.hasPermission("griefprevention.ignoreclaims")) - reason += " " + this.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement); - reason += " " + this.dataStore.getMessage(Messages.CreativeBasicsVideo2, DataStore.CREATIVE_VIDEO_URL); - return reason; - } - else - { - return null; - } + placed = blockType.getItemType().createItemStack(); } - - //but it's fine in survival mode else { - return null; + placed = new ItemStack(Material.DIRT); } } - //if not in the wilderness, then apply claim rules (permissions, etc) - else - { - //cache the claim for later reference - playerData.lastClaim = claim; - Block block = location.getBlock(); - - Supplier supplier = claim.checkPermission(player, ClaimPermission.Build, new BlockPlaceEvent(block, block.getState(), block, new ItemStack(material), player, true, EquipmentSlot.HAND)); - - if (supplier == null) return null; - - return supplier.get(); - } + Block block = location.getBlock(); + Supplier result = ProtectionHelper.checkPermission(player, location, ClaimPermission.Build, new BlockPlaceEvent(block, block.getState(), block, placed, player, true, EquipmentSlot.HAND)); + return result == null ? null : result.get(); } - public String allowBreak(Player player, Block block, Location location) + /** + * @deprecated use {@link ProtectionHelper#checkPermission(Player, Location, ClaimPermission, org.bukkit.event.Event)} + */ + @Deprecated(forRemoval = true, since = "17.0.0") + public @Nullable String allowBreak(Player player, Block block, Location location) { return this.allowBreak(player, block, location, new BlockBreakEvent(block, player)); } - public String allowBreak(Player player, Material material, Location location, BlockBreakEvent breakEvent) + /** + * @deprecated use {@link ProtectionHelper#checkPermission(Player, Location, ClaimPermission, org.bukkit.event.Event)} + */ + @Deprecated(forRemoval = true, since = "17.0.0") + public @Nullable String allowBreak(Player player, Material material, Location location, BlockBreakEvent breakEvent) { return this.allowBreak(player, location.getBlock(), location, breakEvent); } - public String allowBreak(Player player, Block block, Location location, BlockBreakEvent breakEvent) + /** + * @deprecated use {@link ProtectionHelper#checkPermission(Player, Location, ClaimPermission, org.bukkit.event.Event)} + */ + @Deprecated(forRemoval = true, since = "17.0.0") + public @Nullable String allowBreak(Player player, Block block, Location location, BlockBreakEvent breakEvent) { - if (!GriefPrevention.instance.claimsEnabledForWorld(location.getWorld())) return null; - - PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); - Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim); - - //exception: administrators in ignore claims mode - if (playerData.ignoreClaims) return null; - - //wilderness rules - if (claim == null) - { - //no building in the wilderness in creative mode - if (this.creativeRulesApply(location) || this.config_claims_worldModes.get(location.getWorld()) == ClaimsMode.SurvivalRequiringClaims) - { - String reason = this.dataStore.getMessage(Messages.NoBuildOutsideClaims); - if (player.hasPermission("griefprevention.ignoreclaims")) - reason += " " + this.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement); - reason += " " + this.dataStore.getMessage(Messages.CreativeBasicsVideo2, DataStore.CREATIVE_VIDEO_URL); - return reason; - } - - //but it's fine in survival mode - else - { - return null; - } - } - else - { - //cache the claim for later reference - playerData.lastClaim = claim; - - //if not in the wilderness, then apply claim rules (permissions, etc) - Supplier cancel = claim.checkPermission(player, ClaimPermission.Build, breakEvent); - if (cancel != null && breakEvent != null) - { - PreventBlockBreakEvent preventionEvent = new PreventBlockBreakEvent(breakEvent); - Bukkit.getPluginManager().callEvent(preventionEvent); - if (preventionEvent.isCancelled()) - { - cancel = null; - } - } - - if (cancel == null) return null; - - return cancel.get(); - } + Supplier result = ProtectionHelper.checkPermission(player, location, ClaimPermission.Build, breakEvent); + return result == null ? null : result.get(); } //restores nature in multiple chunks, as described by a claim instance @@ -3219,8 +3167,8 @@ static void banPlayer(Player player, String reason, String source) } else { - BanList bans = Bukkit.getServer().getBanList(Type.NAME); - bans.addBan(player.getName(), reason, (Date) null, source); + BanList bans = Bukkit.getServer().getBanList(Type.PROFILE); + bans.addBan(player.getPlayerProfile(), reason, (Date) null, source); //kick if (player.isOnline()) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index b0ca1ad..f5cadbf 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -24,6 +24,7 @@ import com.griefprevention.visualization.VisualizationType; import me.ryanhamshire.GriefPrevention.events.ClaimInspectionEvent; import me.ryanhamshire.GriefPrevention.util.BoundingBox; +import com.griefprevention.protection.ProtectionHelper; import org.bukkit.BanList; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -87,6 +88,7 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.profile.PlayerProfile; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.BlockIterator; import org.jetbrains.annotations.NotNull; @@ -686,7 +688,8 @@ else if (address.equals(playerData.ipAddress.toString())) if (info2.address.toString().equals(address)) { OfflinePlayer bannedAccount = instance.getServer().getOfflinePlayer(info2.bannedAccountName); - instance.getServer().getBanList(BanList.Type.NAME).pardon(bannedAccount.getName()); + BanList banList = instance.getServer().getBanList(BanList.Type.PROFILE); + banList.pardon(bannedAccount.getPlayerProfile()); this.tempBannedIps.remove(j--); } } @@ -1136,10 +1139,10 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) //don't allow interaction with item frames or armor stands in claimed areas without build permission if (entity.getType() == EntityType.ARMOR_STAND || entity instanceof Hanging) { - String noBuildReason = instance.allowBuild(player, entity.getLocation(), Material.ITEM_FRAME); + Supplier noBuildReason = ProtectionHelper.checkPermission(player, entity.getLocation(), ClaimPermission.Build, event); if (noBuildReason != null) { - GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); event.setCancelled(true); return; } @@ -1358,10 +1361,10 @@ public void onPlayerBucketEmpty(PlayerBucketEmptyEvent bucketEvent) } //make sure the player is allowed to build at the location - String noBuildReason = instance.allowBuild(player, block.getLocation(), Material.WATER); + Supplier noBuildReason = ProtectionHelper.checkPermission(player, block.getLocation(), ClaimPermission.Build, bucketEvent); if (noBuildReason != null) { - GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); bucketEvent.setCancelled(true); return; } @@ -1457,22 +1460,22 @@ public void onPlayerBucketFill(PlayerBucketFillEvent bucketEvent) if (!instance.claimsEnabledForWorld(block.getWorld())) return; - //make sure the player is allowed to build at the location - String noBuildReason = instance.allowBuild(player, block.getLocation(), Material.AIR); - if (noBuildReason != null) + //exemption for cow milking (permissions will be handled by player interact with entity event instead) + Material blockType = block.getType(); + if (blockType == Material.AIR) + return; + if (blockType.isSolid()) { - //exemption for cow milking (permissions will be handled by player interact with entity event instead) - Material blockType = block.getType(); - if (blockType == Material.AIR) + BlockData blockData = block.getBlockData(); + if (!(blockData instanceof Waterlogged) || !((Waterlogged) blockData).isWaterlogged()) return; - if (blockType.isSolid()) - { - BlockData blockData = block.getBlockData(); - if (!(blockData instanceof Waterlogged) || !((Waterlogged) blockData).isWaterlogged()) - return; - } + } - GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); + //make sure the player is allowed to build at the location + Supplier noBuildReason = ProtectionHelper.checkPermission(player, block.getLocation(), ClaimPermission.Build, bucketEvent); + if (noBuildReason != null) + { + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); bucketEvent.setCancelled(true); return; } @@ -1489,14 +1492,14 @@ void onPlayerSignOpen(@NotNull PlayerSignOpenEvent event) } Player player = event.getPlayer(); - String denial = instance.allowBuild(player, event.getSign().getLocation(), event.getSign().getType()); + Supplier denial = ProtectionHelper.checkPermission(player, event.getSign().getLocation(), ClaimPermission.Build, event); // If user is allowed to build, do nothing. if (denial == null) return; // If user is not allowed to build, prevent sign UI opening and send message. - GriefPrevention.sendMessage(player, TextMode.Err, denial); + GriefPrevention.sendMessage(player, TextMode.Err, denial.get()); event.setCancelled(true); } @@ -1729,13 +1732,10 @@ else if (clickedBlock != null && || materialInHand == Material.HONEYCOMB || dyes.contains(materialInHand))) { - String noBuildReason = instance - .allowBuild(player, clickedBlock - .getLocation(), - clickedBlockType); + Supplier noBuildReason = ProtectionHelper.checkPermission(player, event.getClickedBlock().getLocation(), ClaimPermission.Build, event); if (noBuildReason != null) { - GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); event.setCancelled(true); } @@ -2437,10 +2437,7 @@ static Block getTargetBlock(Player player, int maxDistance) throws IllegalStateE { result = iterator.next(); Material type = result.getType(); - if (type != Material.AIR && - (!passThroughWater || type != Material.WATER) && - type != Material.SHORT_GRASS && - type != Material.SNOW) return result; + if (!Tag.REPLACEABLE.isTagged(type) || (!passThroughWater && type == Material.WATER)) return result; } return result; diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/events/PreventBlockBreakEvent.java b/src/main/java/me/ryanhamshire/GriefPrevention/events/PreventBlockBreakEvent.java index fee8190..03e4c72 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/events/PreventBlockBreakEvent.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/events/PreventBlockBreakEvent.java @@ -7,9 +7,10 @@ import org.jetbrains.annotations.NotNull; /** - * An {@link Event} called when GriefPrevention prevents a {@link BlockBreakEvent}. - * If cancelled, GriefPrevention will allow the event to complete normally. + * @deprecated Listen to {@link ClaimPermissionCheckEvent} and check if + * {@link ClaimPermissionCheckEvent#getTriggeringEvent()} {@code instanceof} {@link BlockBreakEvent}. */ +@Deprecated(forRemoval = true, since = "17.0.0") public class PreventBlockBreakEvent extends Event implements Cancellable { private final @NotNull BlockBreakEvent innerEvent; From 4507ba1dd1b9cd953aedd6ebc44e4f8b0660fbd3 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 14 Jul 2024 16:30:41 -0400 Subject: [PATCH 02/10] Bundle default messages into Messages enum (#2329) * Bundle defaults into Messages enum * Defaults are guaranteed to be updated this way - no more risk of missing adding the default. * IDE can now properly identify unused messages as unused because they are not being used to add defaults. * Update Minecraft wiki link * Use new comments API for comments --- .../GriefPrevention/CustomizableMessage.java | 33 -- .../GriefPrevention/DataStore.java | 265 ++--------- .../GriefPrevention/Messages.java | 417 +++++++++--------- 3 files changed, 245 insertions(+), 470 deletions(-) delete mode 100644 src/main/java/me/ryanhamshire/GriefPrevention/CustomizableMessage.java diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/CustomizableMessage.java b/src/main/java/me/ryanhamshire/GriefPrevention/CustomizableMessage.java deleted file mode 100644 index b0cb406..0000000 --- a/src/main/java/me/ryanhamshire/GriefPrevention/CustomizableMessage.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - GriefPrevention Server Plugin for Minecraft - Copyright (C) 2012 Ryan Hamshire - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -package me.ryanhamshire.GriefPrevention; - -public class CustomizableMessage -{ - public Messages id; - public String text; - public String notes; - - public CustomizableMessage(Messages id, String text, String notes) - { - this.id = id; - this.text = text; - this.notes = notes; - } -} \ No newline at end of file diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java b/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java index 1f24737..fc521c2 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java @@ -48,7 +48,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -1354,268 +1353,60 @@ else if (player.hasPermission("griefprevention.adjustclaimblocks")) protected void loadMessages() { Messages[] messageIDs = Messages.values(); - this.messages = new String[Messages.values().length]; - - HashMap defaults = new HashMap<>(); - - //initialize defaults - this.addDefault(defaults, Messages.RespectingClaims, "Now respecting claims.", null); - this.addDefault(defaults, Messages.IgnoringClaims, "Now ignoring claims.", null); - this.addDefault(defaults, Messages.NoCreativeUnClaim, "You can't unclaim this land. You can only make this claim larger or create additional claims.", null); - this.addDefault(defaults, Messages.SuccessfulAbandon, "Claims abandoned. You now have {0} available claim blocks.", "0: remaining blocks"); - this.addDefault(defaults, Messages.RestoreNatureActivate, "Ready to restore some nature! Right click to restore nature, and use /basicclaims to stop.", null); - this.addDefault(defaults, Messages.RestoreNatureAggressiveActivate, "Aggressive mode activated. Do NOT use this underneath anything you want to keep! Right click to aggressively restore nature, and use /basicclaims to stop.", null); - this.addDefault(defaults, Messages.FillModeActive, "Fill mode activated with radius {0}. Right click an area to fill.", "0: fill radius"); - this.addDefault(defaults, Messages.TransferClaimPermission, "That command requires the administrative claims permission.", null); - this.addDefault(defaults, Messages.TransferClaimMissing, "There's no claim here. Stand in the administrative claim you want to transfer.", null); - this.addDefault(defaults, Messages.TransferClaimAdminOnly, "Only administrative claims may be transferred to a player.", null); - this.addDefault(defaults, Messages.PlayerNotFound2, "No player by that name has logged in recently.", null); - this.addDefault(defaults, Messages.TransferTopLevel, "Only top level claims (not subdivisions) may be transferred. Stand outside of the subdivision and try again.", null); - this.addDefault(defaults, Messages.TransferSuccess, "Claim transferred.", null); - this.addDefault(defaults, Messages.TrustListNoClaim, "Stand inside the claim you're curious about.", null); - this.addDefault(defaults, Messages.ClearPermsOwnerOnly, "Only the claim owner can clear all permissions.", null); - this.addDefault(defaults, Messages.UntrustIndividualAllClaims, "Revoked {0}'s access to ALL your claims. To set permissions for a single claim, stand inside it.", "0: untrusted player"); - this.addDefault(defaults, Messages.UntrustEveryoneAllClaims, "Cleared permissions in ALL your claims. To set permissions for a single claim, stand inside it.", null); - this.addDefault(defaults, Messages.NoPermissionTrust, "You don't have {0}'s permission to manage permissions here.", "0: claim owner's name"); - this.addDefault(defaults, Messages.ClearPermissionsOneClaim, "Cleared permissions in this claim. To set permission for ALL your claims, stand outside them.", null); - this.addDefault(defaults, Messages.UntrustIndividualSingleClaim, "Revoked {0}'s access to this claim. To set permissions for a ALL your claims, stand outside them.", "0: untrusted player"); - this.addDefault(defaults, Messages.AdminClaimsMode, "Administrative claims mode active. Any claims created will be free and editable by other administrators.", null); - this.addDefault(defaults, Messages.BasicClaimsMode, "Returned to basic claim creation mode.", null); - this.addDefault(defaults, Messages.SubdivisionMode, "Subdivision mode. Use your shovel to create subdivisions in your existing claims. Use /basicclaims to exit.", null); - this.addDefault(defaults, Messages.SubdivisionVideo2, "Click for Subdivision Help: {0}", "0:video URL"); - this.addDefault(defaults, Messages.DeleteClaimMissing, "There's no claim here.", null); - this.addDefault(defaults, Messages.DeletionSubdivisionWarning, "This claim includes subdivisions. If you're sure you want to delete it, use /deleteclaim again.", null); - this.addDefault(defaults, Messages.DeleteSuccess, "Claim deleted.", null); - this.addDefault(defaults, Messages.CantDeleteAdminClaim, "You don't have permission to delete administrative claims.", null); - this.addDefault(defaults, Messages.DeleteAllSuccess, "Deleted all of {0}'s claims.", "0: owner's name"); - this.addDefault(defaults, Messages.NoDeletePermission, "You don't have permission to delete claims.", null); - this.addDefault(defaults, Messages.AllAdminDeleted, "Deleted all administrative claims.", null); - this.addDefault(defaults, Messages.AdjustBlocksSuccess, "Adjusted {0}'s bonus claim blocks by {1}. New total bonus blocks: {2}.", "0: player; 1: adjustment; 2: new total"); - this.addDefault(defaults, Messages.AdjustBlocksAllSuccess, "Adjusted all online players' bonus claim blocks by {0}.", "0: adjustment amount"); - this.addDefault(defaults, Messages.NotTrappedHere, "You can build here. Save yourself.", null); - this.addDefault(defaults, Messages.RescuePending, "If you stay put for 10 seconds, you'll be teleported out. Please wait.", null); - this.addDefault(defaults, Messages.AbandonClaimMissing, "Stand in the claim you want to delete, or consider /abandonallclaims.", null); - this.addDefault(defaults, Messages.NotYourClaim, "This isn't your claim.", null); - this.addDefault(defaults, Messages.DeleteTopLevelClaim, "To delete a subdivision, stand inside it. Otherwise, use /abandontoplevelclaim to delete this claim and all subdivisions.", null); - this.addDefault(defaults, Messages.AbandonSuccess, "Claim abandoned. You now have {0} available claim blocks.", "0: remaining claim blocks"); - this.addDefault(defaults, Messages.ConfirmAbandonAllClaims, "Are you sure you want to abandon ALL of your claims? Please confirm with /abandonallclaims confirm", null); - this.addDefault(defaults, Messages.CantGrantThatPermission, "You can't grant a permission you don't have yourself.", null); - this.addDefault(defaults, Messages.GrantPermissionNoClaim, "Stand inside the claim where you want to grant permission.", null); - this.addDefault(defaults, Messages.GrantPermissionConfirmation, "Granted {0} permission to {1} {2}.", "0: target player; 1: permission description; 2: scope (changed claims)"); - this.addDefault(defaults, Messages.ManageUniversalPermissionsInstruction, "To manage permissions for ALL your claims, stand outside them.", null); - this.addDefault(defaults, Messages.ManageOneClaimPermissionsInstruction, "To manage permissions for a specific claim, stand inside it.", null); - this.addDefault(defaults, Messages.CollectivePublic, "the public", "as in 'granted the public permission to...'"); - this.addDefault(defaults, Messages.BuildPermission, "build", null); - this.addDefault(defaults, Messages.ContainersPermission, "access containers and animals", null); - this.addDefault(defaults, Messages.AccessPermission, "use buttons and levers", null); - this.addDefault(defaults, Messages.PermissionsPermission, "manage permissions", null); - this.addDefault(defaults, Messages.LocationCurrentClaim, "in this claim", null); - this.addDefault(defaults, Messages.LocationAllClaims, "in all your claims", null); - this.addDefault(defaults, Messages.PvPImmunityStart, "You're protected from attack by other players as long as your inventory is empty.", null); - this.addDefault(defaults, Messages.DonateItemsInstruction, "To give away the item(s) in your hand, left-click the chest again.", null); - this.addDefault(defaults, Messages.ChestFull, "This chest is full.", null); - this.addDefault(defaults, Messages.DonationSuccess, "Item(s) transferred to chest!", null); - this.addDefault(defaults, Messages.PlayerTooCloseForFire2, "You can't start a fire this close to another player.", null); - this.addDefault(defaults, Messages.TooDeepToClaim, "This chest can't be protected because it's too deep underground. Consider moving it.", null); - this.addDefault(defaults, Messages.ChestClaimConfirmation, "This chest is protected.", null); - this.addDefault(defaults, Messages.AutomaticClaimNotification, "This chest and nearby blocks are protected from breakage and theft.", null); - this.addDefault(defaults, Messages.AutomaticClaimOtherClaimTooClose, "Cannot create a claim for your chest, there is another claim too close!", null); - this.addDefault(defaults, Messages.UnprotectedChestWarning, "This chest is NOT protected. Consider using a golden shovel to expand an existing claim or to create a new one.", null); - this.addDefault(defaults, Messages.ThatPlayerPvPImmune, "You can't injure defenseless players.", null); - this.addDefault(defaults, Messages.CantFightWhileImmune, "You can't fight someone while you're protected from PvP.", null); - this.addDefault(defaults, Messages.NoDamageClaimedEntity, "That belongs to {0}.", "0: owner name"); - this.addDefault(defaults, Messages.ShovelBasicClaimMode, "Shovel returned to basic claims mode.", null); - this.addDefault(defaults, Messages.RemainingBlocks, "You may claim up to {0} more blocks.", "0: remaining blocks"); - this.addDefault(defaults, Messages.CreativeBasicsVideo2, "Click for Land Claim Help: {0}", "{0}: video URL"); - this.addDefault(defaults, Messages.SurvivalBasicsVideo2, "Click for Land Claim Help: {0}", "{0}: video URL"); - this.addDefault(defaults, Messages.TrappedChatKeyword, "trapped;stuck", "When mentioned in chat, players get information about the /trapped command (multiple words can be separated with semi-colons)"); - this.addDefault(defaults, Messages.TrappedInstructions, "Are you trapped in someone's land claim? Try the /trapped command.", null); - this.addDefault(defaults, Messages.PvPNoDrop, "You can't drop items while in PvP combat.", null); - this.addDefault(defaults, Messages.PvPNoContainers, "You can't access containers during PvP combat.", null); - this.addDefault(defaults, Messages.PvPImmunityEnd, "Now you can fight with other players.", null); - this.addDefault(defaults, Messages.NoBedPermission, "{0} hasn't given you permission to sleep here.", "0: claim owner"); - this.addDefault(defaults, Messages.NoWildernessBuckets, "You may only dump buckets inside your claim(s) or underground.", null); - this.addDefault(defaults, Messages.NoLavaNearOtherPlayer, "You can't place lava this close to {0}.", "0: nearby player"); - this.addDefault(defaults, Messages.TooFarAway, "That's too far away.", null); - this.addDefault(defaults, Messages.BlockNotClaimed, "No one has claimed this block.", null); - this.addDefault(defaults, Messages.BlockClaimed, "That block has been claimed by {0}.", "0: claim owner"); - this.addDefault(defaults, Messages.RestoreNaturePlayerInChunk, "Unable to restore. {0} is in that chunk.", "0: nearby player"); - this.addDefault(defaults, Messages.NoCreateClaimPermission, "You don't have permission to claim land.", null); - this.addDefault(defaults, Messages.ResizeClaimTooNarrow, "This new size would be too small. Claims must be at least {0} blocks wide.", "0: minimum claim width"); - this.addDefault(defaults, Messages.ResizeNeedMoreBlocks, "You don't have enough blocks for this size. You need {0} more.", "0: how many needed"); - this.addDefault(defaults, Messages.ClaimResizeSuccess, "Claim resized. {0} available claim blocks remaining.", "0: remaining blocks"); - this.addDefault(defaults, Messages.ResizeFailOverlap, "Can't resize here because it would overlap another nearby claim.", null); - this.addDefault(defaults, Messages.ResizeStart, "Resizing claim. Use your shovel again at the new location for this corner.", null); - this.addDefault(defaults, Messages.ResizeFailOverlapSubdivision, "You can't create a subdivision here because it would overlap another subdivision. Consider /abandonclaim to delete it, or use your shovel at a corner to resize it.", null); - this.addDefault(defaults, Messages.SubdivisionStart, "Subdivision corner set! Use your shovel at the location for the opposite corner of this new subdivision.", null); - this.addDefault(defaults, Messages.CreateSubdivisionOverlap, "Your selected area overlaps another subdivision.", null); - this.addDefault(defaults, Messages.SubdivisionSuccess, "Subdivision created! Use /trust to share it with friends.", null); - this.addDefault(defaults, Messages.CreateClaimFailOverlap, "You can't create a claim here because it would overlap your other claim. Use /abandonclaim to delete it, or use your shovel at a corner to resize it.", null); - this.addDefault(defaults, Messages.CreateClaimFailOverlapOtherPlayer, "You can't create a claim here because it would overlap {0}'s claim.", "0: other claim owner"); - this.addDefault(defaults, Messages.ClaimsDisabledWorld, "Land claims are disabled in this world.", null); - this.addDefault(defaults, Messages.ClaimStart, "Claim corner set! Use the shovel again at the opposite corner to claim a rectangle of land. To cancel, put your shovel away.", null); - this.addDefault(defaults, Messages.NewClaimTooNarrow, "This claim would be too small. Any claim must be at least {0} blocks wide.", "0: minimum claim width"); - this.addDefault(defaults, Messages.ResizeClaimInsufficientArea, "This claim would be too small. Any claim must use at least {0} total claim blocks.", "0: minimum claim area"); - this.addDefault(defaults, Messages.CreateClaimInsufficientBlocks, "You don't have enough blocks to claim that entire area. You need {0} more blocks.", "0: additional blocks needed"); - this.addDefault(defaults, Messages.AbandonClaimAdvertisement, "To delete another claim and free up some blocks, use /abandonclaim.", null); - this.addDefault(defaults, Messages.CreateClaimFailOverlapShort, "Your selected area overlaps an existing claim.", null); - this.addDefault(defaults, Messages.CreateClaimSuccess, "Claim created! Use /trust to share it with friends.", null); - this.addDefault(defaults, Messages.RescueAbortedMoved, "You moved! Rescue cancelled.", null); - this.addDefault(defaults, Messages.OnlyOwnersModifyClaims, "Only {0} can modify this claim.", "0: owner name"); - this.addDefault(defaults, Messages.NoBuildPvP, "You can't build in claims during PvP combat.", null); - this.addDefault(defaults, Messages.NoBuildPermission, "You don't have {0}'s permission to build here.", "0: owner name"); - this.addDefault(defaults, Messages.NoAccessPermission, "You don't have {0}'s permission to use that.", "0: owner name. access permission controls buttons, levers, and beds"); - this.addDefault(defaults, Messages.NoContainersPermission, "You don't have {0}'s permission to use that.", "0: owner's name. containers also include crafting blocks"); - this.addDefault(defaults, Messages.OwnerNameForAdminClaims, "an administrator", "as in 'You don't have an administrator's permission to build here.'"); - this.addDefault(defaults, Messages.UnknownPlayerName, "someone", "Name used for unknown players. UUID will be appended if available: \"someone (01234567-0123-0123-0123-0123456789ab)\""); - this.addDefault(defaults, Messages.ClaimTooSmallForEntities, "This claim isn't big enough for that. Try enlarging it.", null); - this.addDefault(defaults, Messages.TooManyEntitiesInClaim, "This claim has too many entities already. Try enlarging the claim or removing some animals, monsters, paintings, or minecarts.", null); - this.addDefault(defaults, Messages.YouHaveNoClaims, "You don't have any land claims.", null); - this.addDefault(defaults, Messages.ConfirmFluidRemoval, "Abandoning this claim will remove lava inside the claim. If you're sure, use /abandonclaim again.", null); - this.addDefault(defaults, Messages.AutoBanNotify, "Auto-banned {0}({1}). See logs for details.", null); - this.addDefault(defaults, Messages.AdjustGroupBlocksSuccess, "Adjusted bonus claim blocks for players with the {0} permission by {1}. New total: {2}.", "0: permission; 1: adjustment amount; 2: new total bonus"); - this.addDefault(defaults, Messages.InvalidPermissionID, "Please specify a player name, or a permission in [brackets].", null); - this.addDefault(defaults, Messages.HowToClaimRegex, "(^|.*\\W)how\\W.*\\W(claim|protect|lock)(\\W.*|$)", "This is a Java Regular Expression. Look it up before editing! It's used to tell players about the demo video when they ask how to claim land."); - this.addDefault(defaults, Messages.NoBuildOutsideClaims, "You can't build here unless you claim some land first.", null); - this.addDefault(defaults, Messages.PlayerOfflineTime, " Last login: {0} days ago.", "0: number of full days since last login"); - this.addDefault(defaults, Messages.BuildingOutsideClaims, "Other players can build here, too. Consider creating a land claim to protect your work!", null); - this.addDefault(defaults, Messages.TrappedWontWorkHere, "Sorry, unable to find a safe location to teleport you to. Contact an admin.", null); - this.addDefault(defaults, Messages.CommandBannedInPvP, "You can't use that command while in PvP combat.", null); - this.addDefault(defaults, Messages.UnclaimCleanupWarning, "The land you've unclaimed may be changed by other players or cleaned up by administrators. If you've built something there you want to keep, you should reclaim it.", null); - this.addDefault(defaults, Messages.NoTeleportPvPCombat, "You can't teleport while fighting another player.", null); - this.addDefault(defaults, Messages.NoTNTDamageAboveSeaLevel, "Warning: TNT will not destroy blocks above sea level.", null); - this.addDefault(defaults, Messages.NoTNTDamageClaims, "Warning: TNT will not destroy claimed blocks.", null); - this.addDefault(defaults, Messages.IgnoreClaimsAdvertisement, "To override, use /ignoreclaims.", null); - this.addDefault(defaults, Messages.NoPermissionForCommand, "You don't have permission to do that.", null); - this.addDefault(defaults, Messages.ClaimsListNoPermission, "You don't have permission to get information about another player's land claims.", null); - this.addDefault(defaults, Messages.ExplosivesDisabled, "This claim is now protected from explosions. Use /claimexplosions again to disable.", null); - this.addDefault(defaults, Messages.ExplosivesEnabled, "This claim is now vulnerable to explosions. Use /claimexplosions again to re-enable protections.", null); - this.addDefault(defaults, Messages.ClaimExplosivesAdvertisement, "To allow explosives to destroy blocks in this land claim, use /claimexplosions.", null); - this.addDefault(defaults, Messages.PlayerInPvPSafeZone, "That player is in a PvP safe zone.", null); - this.addDefault(defaults, Messages.NoPistonsOutsideClaims, "Warning: Pistons won't move blocks outside land claims.", null); - this.addDefault(defaults, Messages.SoftMuted, "Soft-muted {0}.", "0: The changed player's name."); - this.addDefault(defaults, Messages.UnSoftMuted, "Un-soft-muted {0}.", "0: The changed player's name."); - this.addDefault(defaults, Messages.DropUnlockAdvertisement, "Other players can't pick up your dropped items unless you /unlockdrops first.", null); - this.addDefault(defaults, Messages.PickupBlockedExplanation, "You can't pick this up unless {0} uses /unlockdrops.", "0: The item stack's owner."); - this.addDefault(defaults, Messages.DropUnlockConfirmation, "Unlocked your drops. Other players may now pick them up (until you die again).", null); - this.addDefault(defaults, Messages.DropUnlockOthersConfirmation, "Unlocked {0}'s drops.", "0: The owner of the unlocked drops."); - this.addDefault(defaults, Messages.AdvertiseACandACB, "You may use /acb to give yourself more claim blocks, or /adminclaims to create a free administrative claim.", null); - this.addDefault(defaults, Messages.AdvertiseAdminClaims, "You could create an administrative land claim instead using /adminclaims, which you'd share with other administrators.", null); - this.addDefault(defaults, Messages.AdvertiseACB, "You may use /acb to give yourself more claim blocks.", null); - this.addDefault(defaults, Messages.NotYourPet, "That belongs to {0} until it's given to you with /givepet.", "0: owner name"); - this.addDefault(defaults, Messages.PetGiveawayConfirmation, "Pet transferred.", null); - this.addDefault(defaults, Messages.PetTransferCancellation, "Pet giveaway cancelled.", null); - this.addDefault(defaults, Messages.ReadyToTransferPet, "Ready to transfer! Right-click the pet you'd like to give away, or cancel with /givepet cancel.", null); - this.addDefault(defaults, Messages.AvoidGriefClaimLand, "Prevent grief! If you claim your land, you will be grief-proof.", null); - this.addDefault(defaults, Messages.BecomeMayor, "Subdivide your land claim and become a mayor!", null); - this.addDefault(defaults, Messages.ClaimCreationFailedOverClaimCountLimit, "You've reached your limit on land claims. Use /abandonclaim to remove one before creating another.", null); - this.addDefault(defaults, Messages.CreateClaimFailOverlapRegion, "You can't claim all of this because you're not allowed to build here.", null); - this.addDefault(defaults, Messages.ResizeFailOverlapRegion, "You don't have permission to build there, so you can't claim that area.", null); - this.addDefault(defaults, Messages.ShowNearbyClaims, "Found {0} land claims.", "0: Number of claims found."); - this.addDefault(defaults, Messages.NoChatUntilMove, "Sorry, but you have to move a little more before you can chat. We get lots of spam bots here. :)", null); - this.addDefault(defaults, Messages.SetClaimBlocksSuccess, "Updated accrued claim blocks.", null); - this.addDefault(defaults, Messages.IgnoreConfirmation, "You're now ignoring chat messages from that player.", null); - this.addDefault(defaults, Messages.UnIgnoreConfirmation, "You're no longer ignoring chat messages from that player.", null); - this.addDefault(defaults, Messages.NotIgnoringPlayer, "You're not ignoring that player.", null); - this.addDefault(defaults, Messages.SeparateConfirmation, "Those players will now ignore each other in chat.", null); - this.addDefault(defaults, Messages.UnSeparateConfirmation, "Those players will no longer ignore each other in chat.", null); - this.addDefault(defaults, Messages.NotIgnoringAnyone, "You're not ignoring anyone.", null); - this.addDefault(defaults, Messages.TrustListHeader, "Explicit permissions here:", "0: The claim's owner"); - this.addDefault(defaults, Messages.Manage, "Manage", null); - this.addDefault(defaults, Messages.Build, "Build", null); - this.addDefault(defaults, Messages.Containers, "Containers", null); - this.addDefault(defaults, Messages.Access, "Access", null); - this.addDefault(defaults, Messages.HasSubclaimRestriction, "This subclaim does not inherit permissions from the parent", null); - this.addDefault(defaults, Messages.StartBlockMath, "{0} blocks from play + {1} bonus = {2} total.", null); - this.addDefault(defaults, Messages.ClaimsListHeader, "Claims:", null); - this.addDefault(defaults, Messages.ContinueBlockMath, " (-{0} blocks)", null); - this.addDefault(defaults, Messages.EndBlockMath, " = {0} blocks left to spend", null); - this.addDefault(defaults, Messages.NoClaimDuringPvP, "You can't claim lands during PvP combat.", null); - this.addDefault(defaults, Messages.UntrustAllOwnerOnly, "Only the claim owner can clear all its permissions.", null); - this.addDefault(defaults, Messages.ManagersDontUntrustManagers, "Only the claim owner can demote a manager.", null); - this.addDefault(defaults, Messages.PlayerNotIgnorable, "You can't ignore that player.", null); - this.addDefault(defaults, Messages.NoEnoughBlocksForChestClaim, "Because you don't have any claim blocks available, no automatic land claim was created for you. You can use /claimslist to monitor your available claim block total.", null); - this.addDefault(defaults, Messages.MustHoldModificationToolForThat, "You must be holding a golden shovel to do that.", null); - this.addDefault(defaults, Messages.StandInClaimToResize, "Stand inside the land claim you want to resize.", null); - this.addDefault(defaults, Messages.ClaimsExtendToSky, "Land claims always extend to max build height.", null); - this.addDefault(defaults, Messages.ClaimsAutoExtendDownward, "Land claims auto-extend deeper into the ground when you place blocks under them.", null); - this.addDefault(defaults, Messages.MinimumRadius, "Minimum radius is {0}.", "0: minimum radius"); - this.addDefault(defaults, Messages.RadiusRequiresGoldenShovel, "You must be holding a golden shovel when specifying a radius.", null); - this.addDefault(defaults, Messages.ClaimTooSmallForActiveBlocks, "This claim isn't big enough to support any active block types (hoppers, spawners, beacons...). Make the claim bigger first.", null); - this.addDefault(defaults, Messages.TooManyActiveBlocksInClaim, "This claim is at its limit for active block types (hoppers, spawners, beacons...). Either make it bigger, or remove other active blocks first.", null); - - this.addDefault(defaults, Messages.BookAuthor, "BigScary", null); - this.addDefault(defaults, Messages.BookTitle, "How to Claim Land", null); - this.addDefault(defaults, Messages.BookLink, "Click: {0}", "{0}: video URL"); - this.addDefault(defaults, Messages.BookIntro, "Claim land to protect your stuff! Click the link above to learn land claims in 3 minutes or less. :)", null); - this.addDefault(defaults, Messages.BookTools, "Our claim tools are {0} and {1}.", "0: claim modification tool name; 1:claim information tool name"); - this.addDefault(defaults, Messages.BookDisabledChestClaims, " On this server, placing a chest will NOT claim land for you.", null); - this.addDefault(defaults, Messages.BookUsefulCommands, "Useful Commands:", null); - this.addDefault(defaults, Messages.NoProfanity, "Please moderate your language.", null); - this.addDefault(defaults, Messages.IsIgnoringYou, "That player is ignoring you.", null); - this.addDefault(defaults, Messages.ConsoleOnlyCommand, "That command may only be executed from the server console.", null); - this.addDefault(defaults, Messages.WorldNotFound, "World not found.", null); - this.addDefault(defaults, Messages.TooMuchIpOverlap, "Sorry, there are too many players logged in with your IP address.", null); - - this.addDefault(defaults, Messages.StandInSubclaim, "You need to be standing in a subclaim to restrict it", null); - this.addDefault(defaults, Messages.SubclaimRestricted, "This subclaim's permissions will no longer inherit from the parent claim", null); - this.addDefault(defaults, Messages.SubclaimUnrestricted, "This subclaim's permissions will now inherit from the parent claim", null); - - this.addDefault(defaults, Messages.NetherPortalTrapDetectionMessage, "It seems you might be stuck inside a nether portal. We will rescue you in a few seconds if that is the case!", "Sent to player on join, if they left while inside a nether portal."); + this.messages = new String[messageIDs.length]; //load the config file FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath)); //for each message ID - for (Messages messageID : messageIDs) + for (Messages message : messageIDs) { - //get default for this message - CustomizableMessage messageData = defaults.get(messageID.name()); - - //if default is missing, log an error and use some fake data for now so that the plugin can run - if (messageData == null) + String messagePath = "Messages." + message.name(); + // If available, migrate legacy path. + if (config.isString(messagePath + ".Text")) { - GriefPrevention.AddLogEntry("Missing message for " + messageID.name() + ". Please contact the developer."); - messageData = new CustomizableMessage(messageID, "Missing message! ID: " + messageID.name() + ". Please contact a server admin.", null); + this.messages[message.ordinal()] = config.getString(messagePath + ".Text", message.defaultValue); } - - //read the message from the file, use default if necessary - this.messages[messageID.ordinal()] = config.getString("Messages." + messageID.name() + ".Text", messageData.text); - config.set("Messages." + messageID.name() + ".Text", this.messages[messageID.ordinal()]); + // Otherwise prefer current value if available. + else + { + this.messages[message.ordinal()] = config.getString(messagePath, this.messages[message.ordinal()]); + } + config.set(messagePath, this.messages[message.ordinal()]); //support color codes - if (messageID != Messages.HowToClaimRegex) + if (message != Messages.HowToClaimRegex) { - this.messages[messageID.ordinal()] = this.messages[messageID.ordinal()].replace('$', (char) 0x00A7); + this.messages[message.ordinal()] = this.messages[message.ordinal()].replace('$', (char) 0x00A7); } - if (messageData.notes != null) + if (message.notes != null) { - messageData.notes = config.getString("Messages." + messageID.name() + ".Notes", messageData.notes); - config.set("Messages." + messageID.name() + ".Notes", messageData.notes); + // Import old non-comment notes. + String notesString = config.getString(messagePath + ".Notes", message.notes); + // Import existing comment notes. + List notes = config.getComments(messagePath); + if (notes.isEmpty()) { + notes = List.of(notesString); + } + config.setComments(messagePath, notes); } } //save any changes try { - config.options().header("Use a YAML editor like NotepadPlusPlus to edit this file. \nAfter editing, back up your changes before reloading the server in case you made a syntax error. \nUse dollar signs ($) for formatting codes, which are documented here: http://minecraft.gamepedia.com/Formatting_codes"); + config.options().setHeader(List.of( + "Use a YAML editor like NotepadPlusPlus to edit this file.", + "After editing, back up your changes before reloading the server in case you made a syntax error.", + "Use dollar signs ($) for formatting codes, which are documented here: http://minecraft.wiki/Formatting_codes#Color_codes" + )); config.save(DataStore.messagesFilePath); } catch (IOException exception) { GriefPrevention.AddLogEntry("Unable to write to the configuration file at \"" + DataStore.messagesFilePath + "\""); } - - defaults.clear(); - System.gc(); - } - - private void addDefault(HashMap defaults, - Messages id, String text, String notes) - { - CustomizableMessage message = new CustomizableMessage(id, text, notes); - defaults.put(id.name(), message); } synchronized public String getMessage(Messages messageID, String... args) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java b/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java index df9e6cb..f487d68 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java @@ -18,206 +18,223 @@ package me.ryanhamshire.GriefPrevention; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public enum Messages { - RespectingClaims, - IgnoringClaims, - SuccessfulAbandon, - RestoreNatureActivate, - RestoreNatureAggressiveActivate, - FillModeActive, - TransferClaimPermission, - TransferClaimMissing, - TransferClaimAdminOnly, - PlayerNotFound2, - TransferTopLevel, - TransferSuccess, - TrustListNoClaim, - ClearPermsOwnerOnly, - UntrustIndividualAllClaims, - UntrustEveryoneAllClaims, - NoPermissionTrust, - ClearPermissionsOneClaim, - UntrustIndividualSingleClaim, - AdminClaimsMode, - BasicClaimsMode, - SubdivisionMode, - SubdivisionVideo2, - DeleteClaimMissing, - DeletionSubdivisionWarning, - DeleteSuccess, - CantDeleteAdminClaim, - DeleteAllSuccess, - NoDeletePermission, - AllAdminDeleted, - AdjustBlocksSuccess, - NotTrappedHere, - RescuePending, - AbandonClaimMissing, - NotYourClaim, - DeleteTopLevelClaim, - AbandonSuccess, - ConfirmAbandonAllClaims, - CantGrantThatPermission, - GrantPermissionNoClaim, - GrantPermissionConfirmation, - ManageUniversalPermissionsInstruction, - ManageOneClaimPermissionsInstruction, - CollectivePublic, - BuildPermission, - ContainersPermission, - AccessPermission, - PermissionsPermission, - LocationCurrentClaim, - LocationAllClaims, - PvPImmunityStart, - DonateItemsInstruction, - ChestFull, - DonationSuccess, - PlayerTooCloseForFire2, - TooDeepToClaim, - ChestClaimConfirmation, - AutomaticClaimNotification, - AutomaticClaimOtherClaimTooClose, - UnprotectedChestWarning, - ThatPlayerPvPImmune, - CantFightWhileImmune, - NoDamageClaimedEntity, - ShovelBasicClaimMode, - RemainingBlocks, - CreativeBasicsVideo2, - SurvivalBasicsVideo2, - TrappedChatKeyword, - TrappedInstructions, - PvPNoDrop, - PvPNoContainers, - PvPImmunityEnd, - NoBedPermission, - NoWildernessBuckets, - NoLavaNearOtherPlayer, - TooFarAway, - BlockNotClaimed, - BlockClaimed, - RestoreNaturePlayerInChunk, - NoCreateClaimPermission, - ResizeNeedMoreBlocks, - NoCreativeUnClaim, - ClaimResizeSuccess, - ResizeFailOverlap, - ResizeStart, - ResizeFailOverlapSubdivision, - SubdivisionStart, - CreateSubdivisionOverlap, - SubdivisionSuccess, - CreateClaimFailOverlap, - CreateClaimFailOverlapOtherPlayer, - ClaimsDisabledWorld, - ClaimStart, - NewClaimTooNarrow, - CreateClaimInsufficientBlocks, - AbandonClaimAdvertisement, - CreateClaimFailOverlapShort, - CreateClaimSuccess, - RescueAbortedMoved, - OnlyOwnersModifyClaims, - NoBuildPvP, - NoBuildPermission, - NoAccessPermission, - NoContainersPermission, - OwnerNameForAdminClaims, - UnknownPlayerName, - ClaimTooSmallForEntities, - TooManyEntitiesInClaim, - YouHaveNoClaims, - ConfirmFluidRemoval, - AutoBanNotify, - AdjustGroupBlocksSuccess, - InvalidPermissionID, - HowToClaimRegex, - NoBuildOutsideClaims, - PlayerOfflineTime, - BuildingOutsideClaims, - TrappedWontWorkHere, - CommandBannedInPvP, - UnclaimCleanupWarning, - NoTeleportPvPCombat, - NoTNTDamageAboveSeaLevel, - NoTNTDamageClaims, - IgnoreClaimsAdvertisement, - NoPermissionForCommand, - ClaimsListNoPermission, - ExplosivesDisabled, - ExplosivesEnabled, - ClaimExplosivesAdvertisement, - PlayerInPvPSafeZone, - NoPistonsOutsideClaims, - SoftMuted, - UnSoftMuted, - DropUnlockAdvertisement, - PickupBlockedExplanation, - DropUnlockConfirmation, - DropUnlockOthersConfirmation, - AdvertiseACandACB, - AdvertiseAdminClaims, - AdvertiseACB, - NotYourPet, - PetGiveawayConfirmation, - PetTransferCancellation, - ReadyToTransferPet, - AvoidGriefClaimLand, - BecomeMayor, - ClaimCreationFailedOverClaimCountLimit, - CreateClaimFailOverlapRegion, - ResizeFailOverlapRegion, - ShowNearbyClaims, - NoChatUntilMove, - SetClaimBlocksSuccess, - IgnoreConfirmation, - NotIgnoringPlayer, - UnIgnoreConfirmation, - SeparateConfirmation, - UnSeparateConfirmation, - NotIgnoringAnyone, - TrustListHeader, - Manage, - Build, - Containers, - Access, - HasSubclaimRestriction, - StartBlockMath, - ClaimsListHeader, - ContinueBlockMath, - EndBlockMath, - NoClaimDuringPvP, - UntrustAllOwnerOnly, - ManagersDontUntrustManagers, - BookAuthor, - BookTitle, - BookIntro, - BookDisabledChestClaims, - BookUsefulCommands, - BookLink, - BookTools, - ResizeClaimTooNarrow, - ResizeClaimInsufficientArea, - NoProfanity, - PlayerNotIgnorable, - NoEnoughBlocksForChestClaim, - IsIgnoringYou, - MustHoldModificationToolForThat, - StandInClaimToResize, - ClaimsExtendToSky, - ClaimsAutoExtendDownward, - MinimumRadius, - RadiusRequiresGoldenShovel, - ClaimTooSmallForActiveBlocks, - TooManyActiveBlocksInClaim, - ConsoleOnlyCommand, - WorldNotFound, - AdjustBlocksAllSuccess, - TooMuchIpOverlap, - StandInSubclaim, - SubclaimRestricted, - SubclaimUnrestricted, - NetherPortalTrapDetectionMessage + RespectingClaims("Now respecting claims."), + IgnoringClaims("Now ignoring claims."), + NoCreativeUnClaim("You can't unclaim this land. You can only make this claim larger or create additional claims."), + SuccessfulAbandon("Claims abandoned. You now have {0} available claim blocks.", "0: remaining blocks"), + RestoreNatureActivate("Ready to restore some nature! Right click to restore nature, and use /basicclaims to stop."), + RestoreNatureAggressiveActivate("Aggressive mode activated. Do NOT use this underneath anything you want to keep! Right click to aggressively restore nature, and use /basicclaims to stop."), + FillModeActive("Fill mode activated with radius {0}. Right click an area to fill.", "0: fill radius"), + TransferClaimPermission("That command requires the administrative claims permission."), + TransferClaimMissing("There's no claim here. Stand in the administrative claim you want to transfer."), + TransferClaimAdminOnly("Only administrative claims may be transferred to a player."), + PlayerNotFound2("No player by that name has logged in recently."), + TransferTopLevel("Only top level claims (not subdivisions) may be transferred. Stand outside of the subdivision and try again."), + TransferSuccess("Claim transferred."), + TrustListNoClaim("Stand inside the claim you're curious about."), + ClearPermsOwnerOnly("Only the claim owner can clear all permissions."), + UntrustIndividualAllClaims("Revoked {0}'s access to ALL your claims. To set permissions for a single claim, stand inside it.", "0: untrusted player"), + UntrustEveryoneAllClaims("Cleared permissions in ALL your claims. To set permissions for a single claim, stand inside it."), + NoPermissionTrust("You don't have {0}'s permission to manage permissions here.", "0: claim owner's name"), + ClearPermissionsOneClaim("Cleared permissions in this claim. To set permission for ALL your claims, stand outside them."), + UntrustIndividualSingleClaim("Revoked {0}'s access to this claim. To set permissions for a ALL your claims, stand outside them.", "0: untrusted player"), + AdminClaimsMode("Administrative claims mode active. Any claims created will be free and editable by other administrators."), + BasicClaimsMode("Returned to basic claim creation mode."), + SubdivisionMode("Subdivision mode. Use your shovel to create subdivisions in your existing claims. Use /basicclaims to exit."), + SubdivisionVideo2("Click for Subdivision Help: {0}", "0:video URL"), + DeleteClaimMissing("There's no claim here."), + DeletionSubdivisionWarning("This claim includes subdivisions. If you're sure you want to delete it, use /deleteclaim again."), + DeleteSuccess("Claim deleted."), + CantDeleteAdminClaim("You don't have permission to delete administrative claims."), + DeleteAllSuccess("Deleted all of {0}'s claims.", "0: owner's name"), + NoDeletePermission("You don't have permission to delete claims."), + AllAdminDeleted("Deleted all administrative claims."), + AdjustBlocksSuccess("Adjusted {0}'s bonus claim blocks by {1}. New total bonus blocks: {2}.", "0: player; 1: adjustment; 2: new total"), + AdjustBlocksAllSuccess("Adjusted all online players' bonus claim blocks by {0}.", "0: adjustment amount"), + NotTrappedHere("You can build here. Save yourself."), + RescuePending("If you stay put for 10 seconds, you'll be teleported out. Please wait."), + AbandonClaimMissing("Stand in the claim you want to delete, or consider /abandonallclaims."), + NotYourClaim("This isn't your claim."), + DeleteTopLevelClaim("To delete a subdivision, stand inside it. Otherwise, use /abandontoplevelclaim to delete this claim and all subdivisions."), + AbandonSuccess("Claim abandoned. You now have {0} available claim blocks.", "0: remaining claim blocks"), + ConfirmAbandonAllClaims("Are you sure you want to abandon ALL of your claims? Please confirm with /abandonallclaims confirm"), + CantGrantThatPermission("You can't grant a permission you don't have yourself."), + GrantPermissionNoClaim("Stand inside the claim where you want to grant permission."), + GrantPermissionConfirmation("Granted {0} permission to {1} {2}.", "0: target player; 1: permission description; 2: scope (changed claims)"), + ManageUniversalPermissionsInstruction("To manage permissions for ALL your claims, stand outside them."), + ManageOneClaimPermissionsInstruction("To manage permissions for a specific claim, stand inside it."), + CollectivePublic("the public", "as in 'granted the public permission to...'"), + BuildPermission("build"), + ContainersPermission("access containers and animals"), + AccessPermission("use buttons and levers"), + PermissionsPermission("manage permissions"), + LocationCurrentClaim("in this claim"), + LocationAllClaims("in all your claims"), + PvPImmunityStart("You're protected from attack by other players as long as your inventory is empty."), + DonateItemsInstruction("To give away the item(s) in your hand, left-click the chest again."), + ChestFull("This chest is full."), + DonationSuccess("Item(s) transferred to chest!"), + PlayerTooCloseForFire2("You can't start a fire this close to another player."), + TooDeepToClaim("This chest can't be protected because it's too deep underground. Consider moving it."), + ChestClaimConfirmation("This chest is protected."), + AutomaticClaimNotification("This chest and nearby blocks are protected from breakage and theft."), + AutomaticClaimOtherClaimTooClose("Cannot create a claim for your chest, there is another claim too close!"), + UnprotectedChestWarning("This chest is NOT protected. Consider using a golden shovel to expand an existing claim or to create a new one."), + ThatPlayerPvPImmune("You can't injure defenseless players."), + CantFightWhileImmune("You can't fight someone while you're protected from PvP."), + NoDamageClaimedEntity("That belongs to {0}.", "0: owner name"), + ShovelBasicClaimMode("Shovel returned to basic claims mode."), + RemainingBlocks("You may claim up to {0} more blocks.", "0: remaining blocks"), + CreativeBasicsVideo2("Click for Land Claim Help: {0}", "{0}: video URL"), + SurvivalBasicsVideo2("Click for Land Claim Help: {0}", "{0}: video URL"), + TrappedChatKeyword("trapped;stuck", "When mentioned in chat, players get information about the /trapped command (multiple words can be separated with semi-colons)"), + TrappedInstructions("Are you trapped in someone's land claim? Try the /trapped command."), + PvPNoDrop("You can't drop items while in PvP combat."), + PvPNoContainers("You can't access containers during PvP combat."), + PvPImmunityEnd("Now you can fight with other players."), + NoBedPermission("{0} hasn't given you permission to sleep here.", "0: claim owner"), + NoWildernessBuckets("You may only dump buckets inside your claim(s) or underground."), + NoLavaNearOtherPlayer("You can't place lava this close to {0}.", "0: nearby player"), + TooFarAway("That's too far away."), + BlockNotClaimed("No one has claimed this block."), + BlockClaimed("That block has been claimed by {0}.", "0: claim owner"), + RestoreNaturePlayerInChunk("Unable to restore. {0} is in that chunk.", "0: nearby player"), + NoCreateClaimPermission("You don't have permission to claim land."), + ResizeClaimTooNarrow("This new size would be too small. Claims must be at least {0} blocks wide.", "0: minimum claim width"), + ResizeNeedMoreBlocks("You don't have enough blocks for this size. You need {0} more.", "0: how many needed"), + ClaimResizeSuccess("Claim resized. {0} available claim blocks remaining.", "0: remaining blocks"), + ResizeFailOverlap("Can't resize here because it would overlap another nearby claim."), + ResizeStart("Resizing claim. Use your shovel again at the new location for this corner."), + ResizeFailOverlapSubdivision("You can't create a subdivision here because it would overlap another subdivision. Consider /abandonclaim to delete it, or use your shovel at a corner to resize it."), + SubdivisionStart("Subdivision corner set! Use your shovel at the location for the opposite corner of this new subdivision."), + CreateSubdivisionOverlap("Your selected area overlaps another subdivision."), + SubdivisionSuccess("Subdivision created! Use /trust to share it with friends."), + CreateClaimFailOverlap("You can't create a claim here because it would overlap your other claim. Use /abandonclaim to delete it, or use your shovel at a corner to resize it."), + CreateClaimFailOverlapOtherPlayer("You can't create a claim here because it would overlap {0}'s claim.", "0: other claim owner"), + ClaimsDisabledWorld("Land claims are disabled in this world."), + ClaimStart("Claim corner set! Use the shovel again at the opposite corner to claim a rectangle of land. To cancel, put your shovel away."), + NewClaimTooNarrow("This claim would be too small. Any claim must be at least {0} blocks wide.", "0: minimum claim width"), + ResizeClaimInsufficientArea("This claim would be too small. Any claim must use at least {0} total claim blocks.", "0: minimum claim area"), + CreateClaimInsufficientBlocks("You don't have enough blocks to claim that entire area. You need {0} more blocks.", "0: additional blocks needed"), + AbandonClaimAdvertisement("To delete another claim and free up some blocks, use /abandonclaim."), + CreateClaimFailOverlapShort("Your selected area overlaps an existing claim."), + CreateClaimSuccess("Claim created! Use /trust to share it with friends."), + RescueAbortedMoved("You moved! Rescue cancelled."), + OnlyOwnersModifyClaims("Only {0} can modify this claim.", "0: owner name"), + NoBuildPvP("You can't build in claims during PvP combat."), + NoBuildPermission("You don't have {0}'s permission to build here.", "0: owner name"), + NoAccessPermission("You don't have {0}'s permission to use that.", "0: owner name. access permission controls buttons, levers, and beds"), + NoContainersPermission("You don't have {0}'s permission to use that.", "0: owner's name. containers also include crafting blocks"), + OwnerNameForAdminClaims("an administrator", "as in 'You don't have an administrator's permission to build here.'"), + UnknownPlayerName("someone", "Name used for unknown players. UUID will be appended if available: \"someone (01234567-0123-0123-0123-0123456789ab)\""), + ClaimTooSmallForEntities("This claim isn't big enough for that. Try enlarging it."), + TooManyEntitiesInClaim("This claim has too many entities already. Try enlarging the claim or removing some animals, monsters, paintings, or minecarts."), + YouHaveNoClaims("You don't have any land claims."), + ConfirmFluidRemoval("Abandoning this claim will remove lava inside the claim. If you're sure, use /abandonclaim again."), + AutoBanNotify("Auto-banned {0}({1}). See logs for details."), + AdjustGroupBlocksSuccess("Adjusted bonus claim blocks for players with the {0} permission by {1}. New total: {2}.", "0: permission; 1: adjustment amount; 2: new total bonus"), + InvalidPermissionID("Please specify a player name, or a permission in [brackets]."), + HowToClaimRegex("(^|.*\\W)how\\W.*\\W(claim|protect|lock)(\\W.*|$)", "This is a Java Regular Expression. Look it up before editing! It's used to tell players about the demo video when they ask how to claim land."), + NoBuildOutsideClaims("You can't build here unless you claim some land first."), + PlayerOfflineTime(" Last login: {0} days ago.", "0: number of full days since last login"), + BuildingOutsideClaims("Other players can build here, too. Consider creating a land claim to protect your work!"), + TrappedWontWorkHere("Sorry, unable to find a safe location to teleport you to. Contact an admin."), + CommandBannedInPvP("You can't use that command while in PvP combat."), + UnclaimCleanupWarning("The land you've unclaimed may be changed by other players or cleaned up by administrators. If you've built something there you want to keep, you should reclaim it."), + NoTeleportPvPCombat("You can't teleport while fighting another player."), + NoTNTDamageAboveSeaLevel("Warning: TNT will not destroy blocks above sea level."), + NoTNTDamageClaims("Warning: TNT will not destroy claimed blocks."), + IgnoreClaimsAdvertisement("To override, use /ignoreclaims."), + NoPermissionForCommand("You don't have permission to do that."), + ClaimsListNoPermission("You don't have permission to get information about another player's land claims."), + ExplosivesDisabled("This claim is now protected from explosions. Use /claimexplosions again to disable."), + ExplosivesEnabled("This claim is now vulnerable to explosions. Use /claimexplosions again to re-enable protections."), + ClaimExplosivesAdvertisement("To allow explosives to destroy blocks in this land claim, use /claimexplosions."), + PlayerInPvPSafeZone("That player is in a PvP safe zone."), + NoPistonsOutsideClaims("Warning: Pistons won't move blocks outside land claims."), + SoftMuted("Soft-muted {0}.", "0: The changed player's name."), + UnSoftMuted("Un-soft-muted {0}.", "0: The changed player's name."), + DropUnlockAdvertisement("Other players can't pick up your dropped items unless you /unlockdrops first."), + PickupBlockedExplanation("You can't pick this up unless {0} uses /unlockdrops.", "0: The item stack's owner."), + DropUnlockConfirmation("Unlocked your drops. Other players may now pick them up (until you die again)."), + DropUnlockOthersConfirmation("Unlocked {0}'s drops.", "0: The owner of the unlocked drops."), + AdvertiseACandACB("You may use /acb to give yourself more claim blocks, or /adminclaims to create a free administrative claim."), + AdvertiseAdminClaims("You could create an administrative land claim instead using /adminclaims, which you'd share with other administrators."), + AdvertiseACB("You may use /acb to give yourself more claim blocks."), + NotYourPet("That belongs to {0} until it's given to you with /givepet.", "0: owner name"), + PetGiveawayConfirmation("Pet transferred."), + PetTransferCancellation("Pet giveaway cancelled."), + ReadyToTransferPet("Ready to transfer! Right-click the pet you'd like to give away, or cancel with /givepet cancel."), + AvoidGriefClaimLand("Prevent grief! If you claim your land, you will be grief-proof."), + BecomeMayor("Subdivide your land claim and become a mayor!"), + ClaimCreationFailedOverClaimCountLimit("You've reached your limit on land claims. Use /abandonclaim to remove one before creating another."), + CreateClaimFailOverlapRegion("You can't claim all of this because you're not allowed to build here."), + ResizeFailOverlapRegion("You don't have permission to build there, so you can't claim that area."), + ShowNearbyClaims("Found {0} land claims.", "0: Number of claims found."), + NoChatUntilMove("Sorry, but you have to move a little more before you can chat. We get lots of spam bots here. :)"), + SetClaimBlocksSuccess("Updated accrued claim blocks."), + IgnoreConfirmation("You're now ignoring chat messages from that player."), + UnIgnoreConfirmation("You're no longer ignoring chat messages from that player."), + NotIgnoringPlayer("You're not ignoring that player."), + SeparateConfirmation("Those players will now ignore each other in chat."), + UnSeparateConfirmation("Those players will no longer ignore each other in chat."), + NotIgnoringAnyone("You're not ignoring anyone."), + TrustListHeader("Explicit permissions here:", "0: The claim's owner"), + Manage("Manage"), + Build("Build"), + Containers("Containers"), + Access("Access"), + HasSubclaimRestriction("This subclaim does not inherit permissions from the parent"), + StartBlockMath("{0} blocks from play + {1} bonus = {2} total."), + ClaimsListHeader("Claims:"), + ContinueBlockMath(" (-{0} blocks)"), + EndBlockMath(" = {0} blocks left to spend"), + NoClaimDuringPvP("You can't claim lands during PvP combat."), + UntrustAllOwnerOnly("Only the claim owner can clear all its permissions."), + ManagersDontUntrustManagers("Only the claim owner can demote a manager."), + PlayerNotIgnorable("You can't ignore that player."), + NoEnoughBlocksForChestClaim("Because you don't have any claim blocks available, no automatic land claim was created for you. You can use /claimslist to monitor your available claim block total."), + MustHoldModificationToolForThat("You must be holding a golden shovel to do that."), + StandInClaimToResize("Stand inside the land claim you want to resize."), + ClaimsExtendToSky("Land claims always extend to max build height."), + ClaimsAutoExtendDownward("Land claims auto-extend deeper into the ground when you place blocks under them."), + MinimumRadius("Minimum radius is {0}.", "0: minimum radius"), + RadiusRequiresGoldenShovel("You must be holding a golden shovel when specifying a radius."), + ClaimTooSmallForActiveBlocks("This claim isn't big enough to support any active block types (hoppers, spawners, beacons...). Make the claim bigger first."), + TooManyActiveBlocksInClaim("This claim is at its limit for active block types (hoppers, spawners, beacons...). Either make it bigger, or remove other active blocks first."), + BookAuthor("BigScary"), + BookTitle("How to Claim Land"), + BookLink("Click: {0}", "{0}: video URL"), + BookIntro("Claim land to protect your stuff! Click the link above to learn land claims in 3 minutes or less. :)"), + BookTools("Our claim tools are {0} and {1}.", "0: claim modification tool name; 1:claim information tool name"), + BookDisabledChestClaims(" On this server, placing a chest will NOT claim land for you."), + BookUsefulCommands("Useful Commands:"), + NoProfanity("Please moderate your language."), + IsIgnoringYou("That player is ignoring you."), + ConsoleOnlyCommand("That command may only be executed from the server console."), + WorldNotFound("World not found."), + TooMuchIpOverlap("Sorry, there are too many players logged in with your IP address."), + StandInSubclaim("You need to be standing in a subclaim to restrict it"), + SubclaimRestricted("This subclaim's permissions will no longer inherit from the parent claim"), + SubclaimUnrestricted("This subclaim's permissions will now inherit from the parent claim"), + NetherPortalTrapDetectionMessage("It seems you might be stuck inside a nether portal. We will rescue you in a few seconds if that is the case!", "Sent to player on join, if they left while inside a nether portal."); + + final @NotNull String defaultValue; + final @Nullable String notes; + + Messages(@NotNull String defaultValue, @NotNull String notes) { + this.defaultValue = defaultValue; + this.notes = notes; + } + + Messages(@NotNull String defaultValue) { + this.defaultValue = defaultValue; + this.notes = null; + } + } From 5d0ebdec36cd9c043d855c6ace15029709ec7c69 Mon Sep 17 00:00:00 2001 From: RoboMWM Date: Tue, 16 Jul 2024 23:30:03 -0700 Subject: [PATCH 03/10] Remove restorenature (#2332) Additionally: - removes claimexpiration `unusedclaimdays` feature and config - gitignores .vscode directory - refactors `RestoreNatureProcessingTask#getPlayerBlocks` to AutoExtendClaimTask Closes #2324 Closes #2292 --- .gitignore | 8 +- .../visualization/BoundaryVisualization.java | 2 +- .../visualization/VisualizationType.java | 4 +- .../impl/FakeBlockVisualization.java | 4 +- .../GriefPrevention/AutoExtendClaimTask.java | 231 ++++- .../GriefPrevention/BlockSnapshot.java | 39 - .../ryanhamshire/GriefPrevention/Claim.java | 137 --- .../CleanupUnusedClaimTask.java | 44 - .../GriefPrevention/DataStore.java | 31 - .../GriefPrevention/GriefPrevention.java | 114 --- .../GriefPrevention/Messages.java | 6 - .../GriefPrevention/PlayerData.java | 3 - .../GriefPrevention/PlayerEventHandler.java | 164 +--- .../RestoreNatureExecutionTask.java | 131 --- .../RestoreNatureProcessingTask.java | 875 ------------------ .../GriefPrevention/ShovelMode.java | 5 +- .../GriefPrevention/VisualizationType.java | 3 - src/main/resources/plugin.yml | 23 - 18 files changed, 243 insertions(+), 1581 deletions(-) delete mode 100644 src/main/java/me/ryanhamshire/GriefPrevention/BlockSnapshot.java delete mode 100644 src/main/java/me/ryanhamshire/GriefPrevention/RestoreNatureExecutionTask.java delete mode 100644 src/main/java/me/ryanhamshire/GriefPrevention/RestoreNatureProcessingTask.java diff --git a/.gitignore b/.gitignore index 4f687f7..dc07a15 100644 --- a/.gitignore +++ b/.gitignore @@ -63,7 +63,8 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -# ZEINTELLIJ + +# IntelliJ workspace.xml tasks.xml .idea/libraries @@ -73,4 +74,7 @@ target/ *.MF *.name .idea -*.iml \ No newline at end of file +*.iml + +# VS Code +.vscode/ \ No newline at end of file diff --git a/src/main/java/com/griefprevention/visualization/BoundaryVisualization.java b/src/main/java/com/griefprevention/visualization/BoundaryVisualization.java index 3de003d..d8070f2 100644 --- a/src/main/java/com/griefprevention/visualization/BoundaryVisualization.java +++ b/src/main/java/com/griefprevention/visualization/BoundaryVisualization.java @@ -25,7 +25,7 @@ /** * A representation of a system for displaying rectangular {@link Boundary Boundaries} to {@link Player Players}. - * This is used to display claim areas, visualize affected area during nature restoration, and more. + * This is used to display claim areas, conflicting claims, and more. */ public abstract class BoundaryVisualization { diff --git a/src/main/java/com/griefprevention/visualization/VisualizationType.java b/src/main/java/com/griefprevention/visualization/VisualizationType.java index 3af0691..4c0ab31 100644 --- a/src/main/java/com/griefprevention/visualization/VisualizationType.java +++ b/src/main/java/com/griefprevention/visualization/VisualizationType.java @@ -15,8 +15,6 @@ public enum VisualizationType /** Boundaries for a new claim area. */ INITIALIZE_ZONE, /** Boundaries for a conflicting area. */ - CONFLICT_ZONE, - /** Boundaries for area in which nature has been restored. */ - NATURE_RESTORATION_ZONE + CONFLICT_ZONE } diff --git a/src/main/java/com/griefprevention/visualization/impl/FakeBlockVisualization.java b/src/main/java/com/griefprevention/visualization/impl/FakeBlockVisualization.java index fe106e4..03ded33 100644 --- a/src/main/java/com/griefprevention/visualization/impl/FakeBlockVisualization.java +++ b/src/main/java/com/griefprevention/visualization/impl/FakeBlockVisualization.java @@ -44,7 +44,7 @@ public FakeBlockVisualization(@NotNull World world, @NotNull IntVector visualize return addBlockElement(switch (boundary.type()) { case SUBDIVISION -> Material.IRON_BLOCK.createBlockData(); - case INITIALIZE_ZONE, NATURE_RESTORATION_ZONE -> Material.DIAMOND_BLOCK.createBlockData(); + case INITIALIZE_ZONE -> Material.DIAMOND_BLOCK.createBlockData(); case CONFLICT_ZONE -> { BlockData fakeData = Material.REDSTONE_ORE.createBlockData(); ((Lightable) fakeData).setLit(true); @@ -63,7 +63,7 @@ public FakeBlockVisualization(@NotNull World world, @NotNull IntVector visualize { case ADMIN_CLAIM -> Material.PUMPKIN.createBlockData(); case SUBDIVISION -> Material.WHITE_WOOL.createBlockData(); - case INITIALIZE_ZONE, NATURE_RESTORATION_ZONE -> Material.DIAMOND_BLOCK.createBlockData(); + case INITIALIZE_ZONE -> Material.DIAMOND_BLOCK.createBlockData(); case CONFLICT_ZONE -> Material.NETHERRACK.createBlockData(); default -> Material.GOLD_BLOCK.createBlockData(); }); diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/AutoExtendClaimTask.java b/src/main/java/me/ryanhamshire/GriefPrevention/AutoExtendClaimTask.java index 8ee2e4e..6933fa8 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/AutoExtendClaimTask.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/AutoExtendClaimTask.java @@ -5,6 +5,8 @@ import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; import org.bukkit.World; import org.bukkit.World.Environment; import org.bukkit.block.Biome; @@ -15,6 +17,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -78,6 +81,12 @@ public static void scheduleAsync(@NotNull Claim claim) private final Map> biomePlayerMaterials = new HashMap<>(); private final int minY; private final int lowestExistingY; + // Definitions of biomes where sand covers surfaces instead of grass. + static final Set SAND_SOIL_BIOMES = Set.of( + NamespacedKey.minecraft("snowy_beach"), + NamespacedKey.minecraft("beach"), + NamespacedKey.minecraft("desert") + ); private AutoExtendClaimTask( @NotNull Claim claim, @@ -176,12 +185,232 @@ private Set getBiomePlayerBlocks(Biome biome) { return biomePlayerMaterials.computeIfAbsent(biome, newBiome -> { - Set playerBlocks = RestoreNatureProcessingTask.getPlayerBlocks(this.worldType, newBiome); + Set playerBlocks = AutoExtendClaimTask.getPlayerBlocks(this.worldType, newBiome); playerBlocks.removeAll(BlockEventHandler.TRASH_BLOCKS); return playerBlocks; }); } + static Set getPlayerBlocks(Environment environment, Biome biome) + { + Set playerBlocks = new HashSet<>(); + playerBlocks.addAll(Tag.ANVIL.getValues()); + playerBlocks.addAll(Tag.BANNERS.getValues()); + playerBlocks.addAll(Tag.BEACON_BASE_BLOCKS.getValues()); + playerBlocks.addAll(Tag.BEDS.getValues()); + playerBlocks.addAll(Tag.BUTTONS.getValues()); + playerBlocks.addAll(Tag.CAMPFIRES.getValues()); + playerBlocks.addAll(Tag.CANDLE_CAKES.getValues()); + playerBlocks.addAll(Tag.CANDLES.getValues()); + playerBlocks.addAll(Tag.WOOL_CARPETS.getValues()); + playerBlocks.addAll(Tag.CAULDRONS.getValues()); + playerBlocks.addAll(Tag.DOORS.getValues()); + playerBlocks.addAll(Tag.FENCE_GATES.getValues()); + playerBlocks.addAll(Tag.FENCES.getValues()); + playerBlocks.addAll(Tag.FIRE.getValues()); + playerBlocks.addAll(Tag.FLOWER_POTS.getValues()); + playerBlocks.addAll(Tag.IMPERMEABLE.getValues()); // Glass block variants + playerBlocks.addAll(Tag.LOGS.getValues()); + playerBlocks.addAll(Tag.PLANKS.getValues()); + playerBlocks.addAll(Tag.PRESSURE_PLATES.getValues()); + playerBlocks.addAll(Tag.RAILS.getValues()); + playerBlocks.addAll(Tag.SHULKER_BOXES.getValues()); + playerBlocks.addAll(Tag.SIGNS.getValues()); + playerBlocks.addAll(Tag.SLABS.getValues()); + playerBlocks.addAll(Tag.STAIRS.getValues()); + playerBlocks.addAll(Tag.STONE_BRICKS.getValues()); + playerBlocks.addAll(Tag.TRAPDOORS.getValues()); + playerBlocks.addAll(Tag.WALLS.getValues()); + playerBlocks.addAll(Tag.WOOL.getValues()); + playerBlocks.add(Material.BOOKSHELF); + playerBlocks.add(Material.BREWING_STAND); + playerBlocks.add(Material.BRICK); + playerBlocks.add(Material.COBBLESTONE); + playerBlocks.add(Material.LAPIS_BLOCK); + playerBlocks.add(Material.DISPENSER); + playerBlocks.add(Material.NOTE_BLOCK); + playerBlocks.add(Material.STICKY_PISTON); + playerBlocks.add(Material.PISTON); + playerBlocks.add(Material.PISTON_HEAD); + playerBlocks.add(Material.MOVING_PISTON); + playerBlocks.add(Material.WHEAT); + playerBlocks.add(Material.TNT); + playerBlocks.add(Material.MOSSY_COBBLESTONE); + playerBlocks.add(Material.TORCH); + playerBlocks.add(Material.CHEST); + playerBlocks.add(Material.REDSTONE_WIRE); + playerBlocks.add(Material.CRAFTING_TABLE); + playerBlocks.add(Material.FURNACE); + playerBlocks.add(Material.LADDER); + playerBlocks.add(Material.SCAFFOLDING); + playerBlocks.add(Material.LEVER); + playerBlocks.add(Material.REDSTONE_TORCH); + playerBlocks.add(Material.SNOW_BLOCK); + playerBlocks.add(Material.JUKEBOX); + playerBlocks.add(Material.NETHER_PORTAL); + playerBlocks.add(Material.JACK_O_LANTERN); + playerBlocks.add(Material.CAKE); + playerBlocks.add(Material.REPEATER); + playerBlocks.add(Material.MUSHROOM_STEM); + playerBlocks.add(Material.RED_MUSHROOM_BLOCK); + playerBlocks.add(Material.BROWN_MUSHROOM_BLOCK); + playerBlocks.add(Material.IRON_BARS); + playerBlocks.add(Material.GLASS_PANE); + playerBlocks.add(Material.MELON_STEM); + playerBlocks.add(Material.ENCHANTING_TABLE); + playerBlocks.add(Material.COBWEB); + playerBlocks.add(Material.GRAVEL); + playerBlocks.add(Material.SANDSTONE); + playerBlocks.add(Material.ENDER_CHEST); + playerBlocks.add(Material.COMMAND_BLOCK); + playerBlocks.add(Material.REPEATING_COMMAND_BLOCK); + playerBlocks.add(Material.CHAIN_COMMAND_BLOCK); + playerBlocks.add(Material.BEACON); + playerBlocks.add(Material.CARROT); + playerBlocks.add(Material.POTATO); + playerBlocks.add(Material.SKELETON_SKULL); + playerBlocks.add(Material.WITHER_SKELETON_SKULL); + playerBlocks.add(Material.CREEPER_HEAD); + playerBlocks.add(Material.ZOMBIE_HEAD); + playerBlocks.add(Material.PLAYER_HEAD); + playerBlocks.add(Material.DRAGON_HEAD); + playerBlocks.add(Material.SPONGE); + playerBlocks.add(Material.WHITE_STAINED_GLASS_PANE); + playerBlocks.add(Material.ORANGE_STAINED_GLASS_PANE); + playerBlocks.add(Material.MAGENTA_STAINED_GLASS_PANE); + playerBlocks.add(Material.LIGHT_BLUE_STAINED_GLASS_PANE); + playerBlocks.add(Material.YELLOW_STAINED_GLASS_PANE); + playerBlocks.add(Material.LIME_STAINED_GLASS_PANE); + playerBlocks.add(Material.PINK_STAINED_GLASS_PANE); + playerBlocks.add(Material.GRAY_STAINED_GLASS_PANE); + playerBlocks.add(Material.LIGHT_GRAY_STAINED_GLASS_PANE); + playerBlocks.add(Material.CYAN_STAINED_GLASS_PANE); + playerBlocks.add(Material.PURPLE_STAINED_GLASS_PANE); + playerBlocks.add(Material.BLUE_STAINED_GLASS_PANE); + playerBlocks.add(Material.BROWN_STAINED_GLASS_PANE); + playerBlocks.add(Material.GREEN_STAINED_GLASS_PANE); + playerBlocks.add(Material.RED_STAINED_GLASS_PANE); + playerBlocks.add(Material.BLACK_STAINED_GLASS_PANE); + playerBlocks.add(Material.TRAPPED_CHEST); + playerBlocks.add(Material.COMPARATOR); + playerBlocks.add(Material.DAYLIGHT_DETECTOR); + playerBlocks.add(Material.REDSTONE_BLOCK); + playerBlocks.add(Material.HOPPER); + playerBlocks.add(Material.QUARTZ_BLOCK); + playerBlocks.add(Material.DROPPER); + playerBlocks.add(Material.SLIME_BLOCK); + playerBlocks.add(Material.PRISMARINE); + playerBlocks.add(Material.HAY_BLOCK); + playerBlocks.add(Material.SEA_LANTERN); + playerBlocks.add(Material.COAL_BLOCK); + playerBlocks.add(Material.REDSTONE_LAMP); + playerBlocks.add(Material.RED_NETHER_BRICKS); + playerBlocks.add(Material.POLISHED_ANDESITE); + playerBlocks.add(Material.POLISHED_DIORITE); + playerBlocks.add(Material.POLISHED_GRANITE); + playerBlocks.add(Material.POLISHED_BASALT); + playerBlocks.add(Material.POLISHED_DEEPSLATE); + playerBlocks.add(Material.DEEPSLATE_BRICKS); + playerBlocks.add(Material.CRACKED_DEEPSLATE_BRICKS); + playerBlocks.add(Material.DEEPSLATE_TILES); + playerBlocks.add(Material.CRACKED_DEEPSLATE_TILES); + playerBlocks.add(Material.CHISELED_DEEPSLATE); + playerBlocks.add(Material.RAW_COPPER_BLOCK); + playerBlocks.add(Material.RAW_IRON_BLOCK); + playerBlocks.add(Material.RAW_GOLD_BLOCK); + playerBlocks.add(Material.LIGHTNING_ROD); + playerBlocks.add(Material.DECORATED_POT); + + //these are unnatural in the nether and end + if (environment != Environment.NORMAL && environment != Environment.CUSTOM) + { + playerBlocks.addAll(Tag.BASE_STONE_OVERWORLD.getValues()); + playerBlocks.addAll(Tag.DIRT.getValues()); + playerBlocks.addAll(Tag.SAND.getValues()); + } + + //these are unnatural in the standard world, but not in the nether + if (environment != Environment.NETHER) + { + playerBlocks.addAll(Tag.NYLIUM.getValues()); + playerBlocks.addAll(Tag.WART_BLOCKS.getValues()); + playerBlocks.addAll(Tag.BASE_STONE_NETHER.getValues()); + playerBlocks.add(Material.POLISHED_BLACKSTONE); + playerBlocks.add(Material.CHISELED_POLISHED_BLACKSTONE); + playerBlocks.add(Material.CRACKED_POLISHED_BLACKSTONE_BRICKS); + playerBlocks.add(Material.GILDED_BLACKSTONE); + playerBlocks.add(Material.BONE_BLOCK); + playerBlocks.add(Material.SOUL_SAND); + playerBlocks.add(Material.SOUL_SOIL); + playerBlocks.add(Material.GLOWSTONE); + playerBlocks.add(Material.NETHER_BRICK); + playerBlocks.add(Material.MAGMA_BLOCK); + playerBlocks.add(Material.ANCIENT_DEBRIS); + playerBlocks.add(Material.CHAIN); + playerBlocks.add(Material.SHROOMLIGHT); + playerBlocks.add(Material.NETHER_GOLD_ORE); + playerBlocks.add(Material.NETHER_SPROUTS); + playerBlocks.add(Material.CRIMSON_FUNGUS); + playerBlocks.add(Material.CRIMSON_ROOTS); + playerBlocks.add(Material.NETHER_WART_BLOCK); + playerBlocks.add(Material.WEEPING_VINES); + playerBlocks.add(Material.WEEPING_VINES_PLANT); + playerBlocks.add(Material.WARPED_FUNGUS); + playerBlocks.add(Material.WARPED_ROOTS); + playerBlocks.add(Material.WARPED_WART_BLOCK); + playerBlocks.add(Material.TWISTING_VINES); + playerBlocks.add(Material.TWISTING_VINES_PLANT); + } + //blocks from tags that are natural in the nether + else + { + playerBlocks.remove(Material.CRIMSON_STEM); + playerBlocks.remove(Material.CRIMSON_HYPHAE); + playerBlocks.remove(Material.NETHER_BRICK_FENCE); + playerBlocks.remove(Material.NETHER_BRICK_STAIRS); + playerBlocks.remove(Material.SOUL_FIRE); + playerBlocks.remove(Material.WARPED_STEM); + playerBlocks.remove(Material.WARPED_HYPHAE); + } + + //these are unnatural in the standard and nether worlds, but not in the end + if (environment != Environment.THE_END) + { + playerBlocks.add(Material.CHORUS_PLANT); + playerBlocks.add(Material.CHORUS_FLOWER); + playerBlocks.add(Material.END_ROD); + playerBlocks.add(Material.END_STONE); + playerBlocks.add(Material.END_STONE_BRICKS); + playerBlocks.add(Material.OBSIDIAN); + playerBlocks.add(Material.PURPUR_BLOCK); + playerBlocks.add(Material.PURPUR_PILLAR); + } + //blocks from tags that are natural in the end + else + { + playerBlocks.remove(Material.PURPUR_SLAB); + playerBlocks.remove(Material.PURPUR_STAIRS); + } + + //these are unnatural in sandy biomes, but not elsewhere + if (SAND_SOIL_BIOMES.contains(biome.getKey()) || environment != Environment.NORMAL) + { + playerBlocks.addAll(Tag.LEAVES.getValues()); + } + //blocks from tags that are natural in non-sandy normal biomes + else + { + playerBlocks.remove(Material.OAK_LOG); + playerBlocks.remove(Material.SPRUCE_LOG); + playerBlocks.remove(Material.BIRCH_LOG); + playerBlocks.remove(Material.JUNGLE_LOG); + playerBlocks.remove(Material.ACACIA_LOG); + playerBlocks.remove(Material.DARK_OAK_LOG); + } + + return playerBlocks; + } + //runs in the main execution thread, where it can safely change claims and save those changes private record ExecuteExtendClaimTask(Claim claim, int newY) implements Runnable { diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/BlockSnapshot.java b/src/main/java/me/ryanhamshire/GriefPrevention/BlockSnapshot.java deleted file mode 100644 index 8f19893..0000000 --- a/src/main/java/me/ryanhamshire/GriefPrevention/BlockSnapshot.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - GriefPrevention Server Plugin for Minecraft - Copyright (C) 2012 Ryan Hamshire - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -package me.ryanhamshire.GriefPrevention; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.data.BlockData; - -//basically, just a few data points from a block conveniently encapsulated in a class -//this is used only by the RestoreNature code -public class BlockSnapshot -{ - public Location location; - public Material typeId; - public BlockData data; - - public BlockSnapshot(Location location, Material typeId, BlockData data) - { - this.location = location; - this.typeId = typeId; - this.data = data; - } -} diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/Claim.java b/src/main/java/me/ryanhamshire/GriefPrevention/Claim.java index 1b7d3df..332f3d3 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/Claim.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/Claim.java @@ -116,86 +116,6 @@ public Long getID() this.modifiedDate = Calendar.getInstance().getTime(); } - //removes any lava above sea level in a claim - //exclusionClaim is another claim indicating an sub-area to be excluded from this operation - //it may be null - public void removeSurfaceFluids(Claim exclusionClaim) - { - //don't do this for administrative claims - if (this.isAdminClaim()) return; - - //don't do it for very large claims - if (this.getArea() > 10000) return; - - //only in creative mode worlds - if (!GriefPrevention.instance.creativeRulesApply(this.lesserBoundaryCorner)) return; - - Location lesser = this.getLesserBoundaryCorner(); - Location greater = this.getGreaterBoundaryCorner(); - - if (lesser.getWorld().getEnvironment() == Environment.NETHER) return; //don't clean up lava in the nether - - int seaLevel = 0; //clean up all fluids in the end - - //respect sea level in normal worlds - if (lesser.getWorld().getEnvironment() == Environment.NORMAL) - seaLevel = GriefPrevention.instance.getSeaLevel(lesser.getWorld()); - - for (int x = lesser.getBlockX(); x <= greater.getBlockX(); x++) - { - for (int z = lesser.getBlockZ(); z <= greater.getBlockZ(); z++) - { - for (int y = seaLevel - 1; y <= lesser.getWorld().getMaxHeight(); y++) - { - //dodge the exclusion claim - Block block = lesser.getWorld().getBlockAt(x, y, z); - if (exclusionClaim != null && exclusionClaim.contains(block.getLocation(), true, false)) continue; - - if (block.getType() == Material.LAVA || block.getType() == Material.WATER) - { - block.setType(Material.AIR); - } - } - } - } - } - - //determines whether or not a claim has surface lava - //used to warn players when they abandon their claims about automatic fluid cleanup - boolean hasSurfaceFluids() - { - Location lesser = this.getLesserBoundaryCorner(); - Location greater = this.getGreaterBoundaryCorner(); - - //don't bother for very large claims, too expensive - if (this.getArea() > 10000) return false; - - int seaLevel = 0; //clean up all fluids in the end - - //respect sea level in normal worlds - if (lesser.getWorld().getEnvironment() == Environment.NORMAL) - seaLevel = GriefPrevention.instance.getSeaLevel(lesser.getWorld()); - - for (int x = lesser.getBlockX(); x <= greater.getBlockX(); x++) - { - for (int z = lesser.getBlockZ(); z <= greater.getBlockZ(); z++) - { - for (int y = seaLevel - 1; y <= lesser.getWorld().getMaxHeight(); y++) - { - //dodge the exclusion claim - Block block = lesser.getWorld().getBlockAt(x, y, z); - - if (block.getType() == Material.WATER || block.getType() == Material.LAVA) - { - return true; - } - } - } - } - - return false; - } - //main constructor. note that only creating a claim instance does nothing - a claim must be added to the data store to be effective Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, UUID ownerID, List builderIDs, List containerIDs, List accessorIDs, List managerIDs, boolean inheritNothing, Long id) { @@ -858,63 +778,6 @@ boolean greaterThan(Claim otherClaim) } - long getPlayerInvestmentScore() - { - //decide which blocks will be considered player placed - Location lesserBoundaryCorner = this.getLesserBoundaryCorner(); - Set playerBlocks = RestoreNatureProcessingTask.getPlayerBlocks(lesserBoundaryCorner.getWorld().getEnvironment(), lesserBoundaryCorner.getBlock().getBiome()); - - //scan the claim for player placed blocks - double score = 0; - - boolean creativeMode = GriefPrevention.instance.creativeRulesApply(lesserBoundaryCorner); - - for (int x = this.lesserBoundaryCorner.getBlockX(); x <= this.greaterBoundaryCorner.getBlockX(); x++) - { - for (int z = this.lesserBoundaryCorner.getBlockZ(); z <= this.greaterBoundaryCorner.getBlockZ(); z++) - { - int y = this.lesserBoundaryCorner.getBlockY(); - for (; y < GriefPrevention.instance.getSeaLevel(this.lesserBoundaryCorner.getWorld()) - 5; y++) - { - Block block = this.lesserBoundaryCorner.getWorld().getBlockAt(x, y, z); - if (playerBlocks.contains(block.getType())) - { - if (block.getType() == Material.CHEST && !creativeMode) - { - score += 10; - } - else - { - score += .5; - } - } - } - - for (; y < this.lesserBoundaryCorner.getWorld().getMaxHeight(); y++) - { - Block block = this.lesserBoundaryCorner.getWorld().getBlockAt(x, y, z); - if (playerBlocks.contains(block.getType())) - { - if (block.getType() == Material.CHEST && !creativeMode) - { - score += 10; - } - else if (creativeMode && (block.getType() == Material.LAVA)) - { - score -= 10; - } - else - { - score += 1; - } - } - } - } - } - - return (long) score; - } - public ArrayList getChunks() { ArrayList chunks = new ArrayList<>(); diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/CleanupUnusedClaimTask.java b/src/main/java/me/ryanhamshire/GriefPrevention/CleanupUnusedClaimTask.java index ce3f1c6..81189a8 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/CleanupUnusedClaimTask.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/CleanupUnusedClaimTask.java @@ -61,15 +61,8 @@ public void run() { if (expireEventCanceled()) return; - claim.removeSurfaceFluids(null); GriefPrevention.instance.dataStore.deleteClaim(claim, true, true); - //if configured to do so, restore the land to natural - if (GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration) - { - GriefPrevention.instance.restoreClaim(claim, 0); - } - GriefPrevention.AddLogEntry(" " + claim.getOwnerName() + "'s new player claim expired.", CustomLogEntryTypes.AdminActivity); } } @@ -92,43 +85,6 @@ else if (GriefPrevention.instance.config_claims_expirationDays > 0) GriefPrevention.AddLogEntry(" All of " + claim.getOwnerName() + "'s claims have expired.", CustomLogEntryTypes.AdminActivity); GriefPrevention.AddLogEntry("earliestPermissibleLastLogin#getTime: " + earliestPermissibleLastLogin.getTime(), CustomLogEntryTypes.Debug, true); GriefPrevention.AddLogEntry("ownerInfo#getLastPlayed: " + ownerInfo.getLastPlayed(), CustomLogEntryTypes.Debug, true); - - for (Claim claim : claims) - { - //if configured to do so, restore the land to natural - if (GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration) - { - GriefPrevention.instance.restoreClaim(claim, 0); - } - } - } - } - else if (GriefPrevention.instance.config_claims_unusedClaimExpirationDays > 0 && GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) - { - //avoid scanning large claims and administrative claims - if (claim.isAdminClaim() || claim.getWidth() > 25 || claim.getHeight() > 25) return; - - //otherwise scan the claim content - int minInvestment = 400; - - long investmentScore = claim.getPlayerInvestmentScore(); - - if (investmentScore < minInvestment) - { - //if the owner has been gone at least a week, and if he has ONLY the new player claim, it will be removed - Calendar sevenDaysAgo = Calendar.getInstance(); - sevenDaysAgo.add(Calendar.DATE, -GriefPrevention.instance.config_claims_unusedClaimExpirationDays); - boolean claimExpired = sevenDaysAgo.getTime().after(new Date(ownerInfo.getLastPlayed())); - if (claimExpired) - { - if (expireEventCanceled()) - return; - GriefPrevention.instance.dataStore.deleteClaim(claim, true, true); - GriefPrevention.AddLogEntry("Removed " + claim.getOwnerName() + "'s unused claim @ " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner()), CustomLogEntryTypes.AdminActivity); - - //restore the claim area to natural state - GriefPrevention.instance.restoreClaim(claim, 0); - } } } } diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java b/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java index fc521c2..5795df8 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java @@ -1124,15 +1124,7 @@ synchronized public void deleteClaimsForPlayer(UUID playerID, boolean releasePet //delete them one by one for (Claim claim : claimsToDelete) { - claim.removeSurfaceFluids(null); - this.deleteClaim(claim); - - //if in a creative mode world, delete the claim - if (GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) - { - GriefPrevention.instance.restoreClaim(claim, 0); - } } } @@ -1234,21 +1226,6 @@ void resizeClaimWithChecks(Player player, PlayerData playerData, int newx1, int //return here if event is cancelled if (event.isCancelled()) return; - //special rule for making a top-level claim smaller. to check this, verifying the old claim's corners are inside the new claim's boundaries. - //rule: in any mode, shrinking a claim removes any surface fluids - boolean smaller = false; - if (oldClaim.parent == null) - { - //if the new claim is smaller - if (!newClaim.contains(oldClaim.getLesserBoundaryCorner(), true, false) || !newClaim.contains(oldClaim.getGreaterBoundaryCorner(), true, false)) - { - smaller = true; - - //remove surface fluids about to be unclaimed - oldClaim.removeSurfaceFluids(newClaim); - } - } - //ask the datastore to try and resize the claim, this checks for conflicts with other claims CreateClaimResult result = GriefPrevention.instance.dataStore.resizeClaim( playerData.claimResizing, @@ -1304,14 +1281,6 @@ void resizeClaimWithChecks(Player player, PlayerData playerData, int newx1, int GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SubdivisionVideo2, 201L, DataStore.SUBDIVISION_VIDEO_URL); } - //if in a creative mode world and shrinking an existing claim, restore any unclaimed area - if (smaller && GriefPrevention.instance.creativeRulesApply(oldClaim.getLesserBoundaryCorner())) - { - GriefPrevention.sendMessage(player, TextMode.Warn, Messages.UnclaimCleanupWarning); - GriefPrevention.instance.restoreClaim(oldClaim, 20L * 60 * 2); //2 minutes - GriefPrevention.AddLogEntry(player.getName() + " shrank a claim @ " + GriefPrevention.getfriendlyLocationString(playerData.claimResizing.getLesserBoundaryCorner())); - } - //clean up playerData.claimResizing = null; playerData.lastShovelLocation = null; diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java index c9352cc..d2e5bff 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -140,8 +140,6 @@ public class GriefPrevention extends JavaPlugin public int config_claims_minArea; //minimum area for non-admin claims public int config_claims_chestClaimExpirationDays; //number of days of inactivity before an automatic chest claim will be deleted - public int config_claims_unusedClaimExpirationDays; //number of days of inactivity before an unused (nothing build) claim will be deleted - public boolean config_claims_survivalAutoNatureRestoration; //whether survival claims will be automatically restored to nature when auto-deleted public boolean config_claims_allowTrappedInAdminClaims; //whether it should be allowed to use /trapped in adminclaims. public Material config_claims_investigationTool; //which material will be used to investigate claims with a right click @@ -563,11 +561,9 @@ else if (world.getEnvironment() == Environment.NORMAL) AddLogEntry("Updated default value for GriefPrevention.Claims.MaximumDepth to " + Integer.MIN_VALUE); } this.config_claims_chestClaimExpirationDays = config.getInt("GriefPrevention.Claims.Expiration.ChestClaimDays", 7); - this.config_claims_unusedClaimExpirationDays = config.getInt("GriefPrevention.Claims.Expiration.UnusedClaimDays", 14); this.config_claims_expirationDays = config.getInt("GriefPrevention.Claims.Expiration.AllClaims.DaysInactive", 60); this.config_claims_expirationExemptionTotalBlocks = config.getInt("GriefPrevention.Claims.Expiration.AllClaims.ExceptWhenOwnerHasTotalClaimBlocks", 10000); this.config_claims_expirationExemptionBonusBlocks = config.getInt("GriefPrevention.Claims.Expiration.AllClaims.ExceptWhenOwnerHasBonusClaimBlocks", 5000); - this.config_claims_survivalAutoNatureRestoration = config.getBoolean("GriefPrevention.Claims.Expiration.AutomaticNatureRestoration.SurvivalWorlds", false); this.config_claims_allowTrappedInAdminClaims = config.getBoolean("GriefPrevention.Claims.AllowTrappedInAdminClaims", false); this.config_claims_maxClaimsPerPlayer = config.getInt("GriefPrevention.Claims.MaximumNumberOfClaimsPerPlayer", 0); @@ -727,11 +723,9 @@ else if (world.getEnvironment() == Environment.NORMAL) outConfig.set("GriefPrevention.Claims.InvestigationTool", this.config_claims_investigationTool.name()); outConfig.set("GriefPrevention.Claims.ModificationTool", this.config_claims_modificationTool.name()); outConfig.set("GriefPrevention.Claims.Expiration.ChestClaimDays", this.config_claims_chestClaimExpirationDays); - outConfig.set("GriefPrevention.Claims.Expiration.UnusedClaimDays", this.config_claims_unusedClaimExpirationDays); outConfig.set("GriefPrevention.Claims.Expiration.AllClaims.DaysInactive", this.config_claims_expirationDays); outConfig.set("GriefPrevention.Claims.Expiration.AllClaims.ExceptWhenOwnerHasTotalClaimBlocks", this.config_claims_expirationExemptionTotalBlocks); outConfig.set("GriefPrevention.Claims.Expiration.AllClaims.ExceptWhenOwnerHasBonusClaimBlocks", this.config_claims_expirationExemptionBonusBlocks); - outConfig.set("GriefPrevention.Claims.Expiration.AutomaticNatureRestoration.SurvivalWorlds", this.config_claims_survivalAutoNatureRestoration); outConfig.set("GriefPrevention.Claims.AllowTrappedInAdminClaims", this.config_claims_allowTrappedInAdminClaims); outConfig.set("GriefPrevention.Claims.MaximumNumberOfClaimsPerPlayer", this.config_claims_maxClaimsPerPlayer); outConfig.set("GriefPrevention.Claims.VillagerTradingRequiresPermission", this.config_claims_villagerTradingRequiresTrust); @@ -1126,50 +1120,6 @@ else if (cmd.getName().equalsIgnoreCase("abandonallclaims") && player != null) return true; } - //restore nature - else if (cmd.getName().equalsIgnoreCase("restorenature") && player != null) - { - //change shovel mode - PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); - playerData.shovelMode = ShovelMode.RestoreNature; - GriefPrevention.sendMessage(player, TextMode.Instr, Messages.RestoreNatureActivate); - return true; - } - - //restore nature aggressive mode - else if (cmd.getName().equalsIgnoreCase("restorenatureaggressive") && player != null) - { - //change shovel mode - PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); - playerData.shovelMode = ShovelMode.RestoreNatureAggressive; - GriefPrevention.sendMessage(player, TextMode.Warn, Messages.RestoreNatureAggressiveActivate); - return true; - } - - //restore nature fill mode - else if (cmd.getName().equalsIgnoreCase("restorenaturefill") && player != null) - { - //change shovel mode - PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); - playerData.shovelMode = ShovelMode.RestoreNatureFill; - - //set radius based on arguments - playerData.fillRadius = 2; - if (args.length > 0) - { - try - { - playerData.fillRadius = Integer.parseInt(args[0]); - } - catch (Exception exception) { } - } - - if (playerData.fillRadius < 0) playerData.fillRadius = 2; - - GriefPrevention.sendMessage(player, TextMode.Success, Messages.FillModeActive, String.valueOf(playerData.fillRadius)); - return true; - } - //trust else if (cmd.getName().equalsIgnoreCase("trust") && player != null) { @@ -1624,15 +1574,8 @@ else if (cmd.getName().equalsIgnoreCase("deleteclaim") && player != null) } else { - claim.removeSurfaceFluids(null); this.dataStore.deleteClaim(claim, true, true); - //if in a creative mode world, /restorenature the claim - if (GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration) - { - GriefPrevention.instance.restoreClaim(claim, 0); - } - GriefPrevention.sendMessage(player, TextMode.Success, Messages.DeleteSuccess); GriefPrevention.AddLogEntry(player.getName() + " deleted " + claim.getOwnerName() + "'s claim at " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner()), CustomLogEntryTypes.AdminActivity); @@ -2400,17 +2343,8 @@ else if (claim.children.size() > 0 && !deleteTopLevelClaim) else { //delete it - claim.removeSurfaceFluids(null); this.dataStore.deleteClaim(claim, true, false); - //if in a creative mode world, restore the claim area - if (GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) - { - GriefPrevention.AddLogEntry(player.getName() + " abandoned a claim @ " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner())); - GriefPrevention.sendMessage(player, TextMode.Warn, Messages.UnclaimCleanupWarning); - GriefPrevention.instance.restoreClaim(claim, 20L * 60 * 2); - } - //adjust claim blocks when abandoning a top level claim if (this.config_claims_abandonReturnRatio != 1.0D && claim.parent == null && claim.ownerID.equals(playerData.playerID)) { @@ -3016,54 +2950,6 @@ public boolean creativeRulesApply(@NotNull Location location) return result == null ? null : result.get(); } - //restores nature in multiple chunks, as described by a claim instance - //this restores all chunks which have ANY number of claim blocks from this claim in them - //if the claim is still active (in the data store), then the claimed blocks will not be changed (only the area bordering the claim) - public void restoreClaim(Claim claim, long delayInTicks) - { - //admin claims aren't automatically cleaned up when deleted or abandoned - if (claim.isAdminClaim()) return; - - //it's too expensive to do this for huge claims - if (claim.getArea() > 10000 || claim.getWidth() > 250 || claim.getHeight() > 250) return; - - ArrayList chunks = claim.getChunks(); - for (Chunk chunk : chunks) - { - this.restoreChunk(chunk, this.getSeaLevel(chunk.getWorld()) - 15, false, delayInTicks, null); - } - } - - - public void restoreChunk(Chunk chunk, int miny, boolean aggressiveMode, long delayInTicks, Player playerReceivingVisualization) - { - //build a snapshot of this chunk, including 1 block boundary outside of the chunk all the way around - int maxHeight = chunk.getWorld().getMaxHeight(); - BlockSnapshot[][][] snapshots = new BlockSnapshot[18][maxHeight][18]; - Block startBlock = chunk.getBlock(0, 0, 0); - Location startLocation = new Location(chunk.getWorld(), startBlock.getX() - 1, 0, startBlock.getZ() - 1); - for (int x = 0; x < snapshots.length; x++) - { - for (int z = 0; z < snapshots[0][0].length; z++) - { - for (int y = 0; y < snapshots[0].length; y++) - { - Block block = chunk.getWorld().getBlockAt(startLocation.getBlockX() + x, startLocation.getBlockY() + y, startLocation.getBlockZ() + z); - snapshots[x][y][z] = new BlockSnapshot(block.getLocation(), block.getType(), block.getBlockData()); - } - } - } - - //create task to process those data in another thread - Location lesserBoundaryCorner = chunk.getBlock(0, 0, 0).getLocation(); - Location greaterBoundaryCorner = chunk.getBlock(15, 0, 15).getLocation(); - - //create task - //when done processing, this task will create a main thread task to actually update the world with processing results - RestoreNatureProcessingTask task = new RestoreNatureProcessingTask(snapshots, miny, chunk.getWorld().getEnvironment(), lesserBoundaryCorner.getBlock().getBiome(), lesserBoundaryCorner, greaterBoundaryCorner, this.getSeaLevel(chunk.getWorld()), aggressiveMode, GriefPrevention.instance.creativeRulesApply(lesserBoundaryCorner), playerReceivingVisualization); - GriefPrevention.instance.getServer().getScheduler().runTaskLaterAsynchronously(GriefPrevention.instance, task, delayInTicks); - } - private Set parseMaterialListFromConfig(List stringsToParse) { Set materials = new HashSet<>(); diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java b/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java index f487d68..e03dfa5 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java @@ -27,9 +27,6 @@ public enum Messages IgnoringClaims("Now ignoring claims."), NoCreativeUnClaim("You can't unclaim this land. You can only make this claim larger or create additional claims."), SuccessfulAbandon("Claims abandoned. You now have {0} available claim blocks.", "0: remaining blocks"), - RestoreNatureActivate("Ready to restore some nature! Right click to restore nature, and use /basicclaims to stop."), - RestoreNatureAggressiveActivate("Aggressive mode activated. Do NOT use this underneath anything you want to keep! Right click to aggressively restore nature, and use /basicclaims to stop."), - FillModeActive("Fill mode activated with radius {0}. Right click an area to fill.", "0: fill radius"), TransferClaimPermission("That command requires the administrative claims permission."), TransferClaimMissing("There's no claim here. Stand in the administrative claim you want to transfer."), TransferClaimAdminOnly("Only administrative claims may be transferred to a player."), @@ -103,7 +100,6 @@ public enum Messages TooFarAway("That's too far away."), BlockNotClaimed("No one has claimed this block."), BlockClaimed("That block has been claimed by {0}.", "0: claim owner"), - RestoreNaturePlayerInChunk("Unable to restore. {0} is in that chunk.", "0: nearby player"), NoCreateClaimPermission("You don't have permission to claim land."), ResizeClaimTooNarrow("This new size would be too small. Claims must be at least {0} blocks wide.", "0: minimum claim width"), ResizeNeedMoreBlocks("You don't have enough blocks for this size. You need {0} more.", "0: how many needed"), @@ -135,7 +131,6 @@ public enum Messages ClaimTooSmallForEntities("This claim isn't big enough for that. Try enlarging it."), TooManyEntitiesInClaim("This claim has too many entities already. Try enlarging the claim or removing some animals, monsters, paintings, or minecarts."), YouHaveNoClaims("You don't have any land claims."), - ConfirmFluidRemoval("Abandoning this claim will remove lava inside the claim. If you're sure, use /abandonclaim again."), AutoBanNotify("Auto-banned {0}({1}). See logs for details."), AdjustGroupBlocksSuccess("Adjusted bonus claim blocks for players with the {0} permission by {1}. New total: {2}.", "0: permission; 1: adjustment amount; 2: new total bonus"), InvalidPermissionID("Please specify a player name, or a permission in [brackets]."), @@ -145,7 +140,6 @@ public enum Messages BuildingOutsideClaims("Other players can build here, too. Consider creating a land claim to protect your work!"), TrappedWontWorkHere("Sorry, unable to find a safe location to teleport you to. Contact an admin."), CommandBannedInPvP("You can't use that command while in PvP combat."), - UnclaimCleanupWarning("The land you've unclaimed may be changed by other players or cleaned up by administrators. If you've built something there you want to keep, you should reclaim it."), NoTeleportPvPCombat("You can't teleport while fighting another player."), NoTNTDamageAboveSeaLevel("Warning: TNT will not destroy blocks above sea level."), NoTNTDamageClaims("Warning: TNT will not destroy claimed blocks."), diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerData.java b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerData.java index 5631303..2b8ecea 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerData.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerData.java @@ -54,9 +54,6 @@ public class PlayerData //what "mode" the shovel is in determines what it will do when it's used public ShovelMode shovelMode = ShovelMode.Basic; - //radius for restore nature fill mode - int fillRadius = 0; - //last place the player used the shovel, useful in creating and resizing claims, //because the player must use the shovel twice in those instances public Location lastShovelLocation = null; diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index f5cadbf..722ae19 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -1919,168 +1919,6 @@ else if (materialInHand == instance.config_claims_investigationTool && hand == E return; } - //if the player is in restore nature mode, do only that - UUID playerID = player.getUniqueId(); - playerData = this.dataStore.getPlayerData(player.getUniqueId()); - if (playerData.shovelMode == ShovelMode.RestoreNature || playerData.shovelMode == ShovelMode.RestoreNatureAggressive) - { - //if the clicked block is in a claim, visualize that claim and deliver an error message - Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim); - if (claim != null) - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.BlockClaimed, claim.getOwnerName()); - BoundaryVisualization.visualizeClaim(player, claim, VisualizationType.CONFLICT_ZONE, clickedBlock); - return; - } - - //figure out which chunk to repair - Chunk chunk = player.getWorld().getChunkAt(clickedBlock.getLocation()); - //start the repair process - - //set boundaries for processing - int miny = clickedBlock.getY(); - - //if not in aggressive mode, extend the selection down to a little below sea level - if (!(playerData.shovelMode == ShovelMode.RestoreNatureAggressive)) - { - if (miny > instance.getSeaLevel(chunk.getWorld()) - 10) - { - miny = instance.getSeaLevel(chunk.getWorld()) - 10; - } - } - - instance.restoreChunk(chunk, miny, playerData.shovelMode == ShovelMode.RestoreNatureAggressive, 0, player); - - return; - } - - //if in restore nature fill mode - if (playerData.shovelMode == ShovelMode.RestoreNatureFill) - { - ArrayList allowedFillBlocks = new ArrayList<>(); - Environment environment = clickedBlock.getWorld().getEnvironment(); - if (environment == Environment.NETHER) - { - allowedFillBlocks.add(Material.NETHERRACK); - } - else if (environment == Environment.THE_END) - { - allowedFillBlocks.add(Material.END_STONE); - } - else - { - allowedFillBlocks.add(Material.SHORT_GRASS); - allowedFillBlocks.add(Material.DIRT); - allowedFillBlocks.add(Material.STONE); - allowedFillBlocks.add(Material.SAND); - allowedFillBlocks.add(Material.SANDSTONE); - allowedFillBlocks.add(Material.ICE); - } - - Block centerBlock = clickedBlock; - - int maxHeight = centerBlock.getY(); - int minx = centerBlock.getX() - playerData.fillRadius; - int maxx = centerBlock.getX() + playerData.fillRadius; - int minz = centerBlock.getZ() - playerData.fillRadius; - int maxz = centerBlock.getZ() + playerData.fillRadius; - int minHeight = maxHeight - 10; - minHeight = Math.max(minHeight, clickedBlock.getWorld().getMinHeight()); - - Claim cachedClaim = null; - for (int x = minx; x <= maxx; x++) - { - for (int z = minz; z <= maxz; z++) - { - //circular brush - Location location = new Location(centerBlock.getWorld(), x, centerBlock.getY(), z); - if (location.distance(centerBlock.getLocation()) > playerData.fillRadius) continue; - - //default fill block is initially the first from the allowed fill blocks list above - Material defaultFiller = allowedFillBlocks.get(0); - - //prefer to use the block the player clicked on, if it's an acceptable fill block - if (allowedFillBlocks.contains(centerBlock.getType())) - { - defaultFiller = centerBlock.getType(); - } - - //if the player clicks on water, try to sink through the water to find something underneath that's useful for a filler - else if (centerBlock.getType() == Material.WATER) - { - Block block = centerBlock.getWorld().getBlockAt(centerBlock.getLocation()); - while (!allowedFillBlocks.contains(block.getType()) && block.getY() > centerBlock.getY() - 10) - { - block = block.getRelative(BlockFace.DOWN); - } - if (allowedFillBlocks.contains(block.getType())) - { - defaultFiller = block.getType(); - } - } - - //fill bottom to top - for (int y = minHeight; y <= maxHeight; y++) - { - Block block = centerBlock.getWorld().getBlockAt(x, y, z); - - //respect claims - Claim claim = this.dataStore.getClaimAt(block.getLocation(), false, cachedClaim); - if (claim != null) - { - cachedClaim = claim; - break; - } - - //only replace air, spilling water, snow, long grass - if (block.getType() == Material.AIR || block.getType() == Material.SNOW || (block.getType() == Material.WATER && ((Levelled) block.getBlockData()).getLevel() != 0) || block.getType() == Material.SHORT_GRASS) - { - //if the top level, always use the default filler picked above - if (y == maxHeight) - { - block.setType(defaultFiller); - } - - //otherwise look to neighbors for an appropriate fill block - else - { - Block eastBlock = block.getRelative(BlockFace.EAST); - Block westBlock = block.getRelative(BlockFace.WEST); - Block northBlock = block.getRelative(BlockFace.NORTH); - Block southBlock = block.getRelative(BlockFace.SOUTH); - - //first, check lateral neighbors (ideally, want to keep natural layers) - if (allowedFillBlocks.contains(eastBlock.getType())) - { - block.setType(eastBlock.getType()); - } - else if (allowedFillBlocks.contains(westBlock.getType())) - { - block.setType(westBlock.getType()); - } - else if (allowedFillBlocks.contains(northBlock.getType())) - { - block.setType(northBlock.getType()); - } - else if (allowedFillBlocks.contains(southBlock.getType())) - { - block.setType(southBlock.getType()); - } - - //if all else fails, use the default filler selected above - else - { - block.setType(defaultFiller); - } - } - } - } - } - } - - return; - } - //if the player doesn't have claims permission, don't do anything if (!player.hasPermission("griefprevention.createclaims")) { @@ -2307,6 +2145,8 @@ else if (playerData.shovelMode == ShovelMode.Subdivide) } } + UUID playerID = player.getUniqueId(); + //if not an administrative claim, verify the player has enough claim blocks for this new claim if (playerData.shovelMode != ShovelMode.Admin) { diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/RestoreNatureExecutionTask.java b/src/main/java/me/ryanhamshire/GriefPrevention/RestoreNatureExecutionTask.java deleted file mode 100644 index f0c5c62..0000000 --- a/src/main/java/me/ryanhamshire/GriefPrevention/RestoreNatureExecutionTask.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - GriefPrevention Server Plugin for Minecraft - Copyright (C) 2012 Ryan Hamshire - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -package me.ryanhamshire.GriefPrevention; - -import com.griefprevention.visualization.BoundaryVisualization; -import com.griefprevention.visualization.VisualizationType; -import me.ryanhamshire.GriefPrevention.util.BoundingBox; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Animals; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Hanging; -import org.bukkit.entity.Player; - -//this main thread task takes the output from the RestoreNatureProcessingTask\ -//and updates the world accordingly -class RestoreNatureExecutionTask implements Runnable -{ - //results from processing thread - //will be applied to the world - private final BlockSnapshot[][][] snapshots; - - //boundaries for changes - private final int miny; - private final Location lesserCorner; - private final Location greaterCorner; - - //player who should be notified about the result (will see a visualization when the restoration is complete) - private final Player player; - - public RestoreNatureExecutionTask(BlockSnapshot[][][] snapshots, int miny, Location lesserCorner, Location greaterCorner, Player player) - { - this.snapshots = snapshots; - this.miny = miny; - this.lesserCorner = lesserCorner; - this.greaterCorner = greaterCorner; - this.player = player; - } - - - @Override - public void run() - { - //apply changes to the world, but ONLY to unclaimed blocks - //note that the edge of the results is not applied (the 1-block-wide band around the outside of the chunk) - //those data were sent to the processing thread for referernce purposes, but aren't part of the area selected for restoration - Claim cachedClaim = null; - for (int x = 1; x < this.snapshots.length - 1; x++) - { - for (int z = 1; z < this.snapshots[0][0].length - 1; z++) - { - for (int y = this.miny; y < this.snapshots[0].length; y++) - { - BlockSnapshot blockUpdate = this.snapshots[x][y][z]; - Block currentBlock = blockUpdate.location.getBlock(); - if (blockUpdate.typeId != currentBlock.getType() || !blockUpdate.data.equals(currentBlock.getBlockData())) - { - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(blockUpdate.location, false, cachedClaim); - if (claim != null) - { - cachedClaim = claim; - break; - } - - try - { - currentBlock.setType(blockUpdate.typeId, false); - // currentBlock.setBlockData(blockUpdate.data, false); - } - catch (IllegalArgumentException e) - { - //just don't update this block and continue trying to update other blocks - } - } - } - } - } - - //clean up any entities in the chunk, ensure no players are suffocated - Chunk chunk = this.lesserCorner.getChunk(); - Entity[] entities = chunk.getEntities(); - for (Entity entity : entities) - { - if (!(entity instanceof Player || entity instanceof Animals)) - { - //hanging entities (paintings, item frames) are protected when they're in land claims - if (!(entity instanceof Hanging) || GriefPrevention.instance.dataStore.getClaimAt(entity.getLocation(), false, null) == null) - { - //everything else is removed - entity.remove(); - } - } - - //for players, always ensure there's air where the player is standing - else - { - Block feetBlock = entity.getLocation().getBlock(); - feetBlock.setType(Material.AIR); - feetBlock.getRelative(BlockFace.UP).setType(Material.AIR); - } - } - - //show visualization to player who started the restoration - if (player != null) - { - BoundaryVisualization.visualizeArea( - player, - new BoundingBox(lesserCorner, greaterCorner), - VisualizationType.NATURE_RESTORATION_ZONE); - } - } -} diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/RestoreNatureProcessingTask.java b/src/main/java/me/ryanhamshire/GriefPrevention/RestoreNatureProcessingTask.java deleted file mode 100644 index c03fbd1..0000000 --- a/src/main/java/me/ryanhamshire/GriefPrevention/RestoreNatureProcessingTask.java +++ /dev/null @@ -1,875 +0,0 @@ -/* - GriefPrevention Server Plugin for Minecraft - Copyright (C) 2012 Ryan Hamshire - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -package me.ryanhamshire.GriefPrevention; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Tag; -import org.bukkit.World.Environment; -import org.bukkit.block.Biome; -import org.bukkit.block.data.Levelled; -import org.bukkit.block.data.type.Leaves; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -//non-main-thread task which processes world data to repair the unnatural -//after processing is complete, creates a main thread task to make the necessary changes to the world -class RestoreNatureProcessingTask implements Runnable -{ - - // Definitions of biomes with particularly dense log distribution. These biomes will not have logs reduced. - private static final Set DENSE_LOG_BIOMES = Set.of( - NamespacedKey.minecraft("jungle"), - NamespacedKey.minecraft("bamboo_jungle") - ); - - // Definitions of biomes where sand covers surfaces instead of grass. - private static final Set SAND_SOIL_BIOMES = Set.of( - NamespacedKey.minecraft("snowy_beach"), - NamespacedKey.minecraft("beach"), - NamespacedKey.minecraft("desert") - ); - - //world information captured from the main thread - //will be updated and sent back to main thread to be applied to the world - private final BlockSnapshot[][][] snapshots; - - //other information collected from the main thread. - //not to be updated, only to be passed back to main thread to provide some context about the operation - private int miny; - private final Environment environment; - private final Location lesserBoundaryCorner; - private final Location greaterBoundaryCorner; - private final Player player; //absolutely must not be accessed. not thread safe. - private final Biome biome; - private final boolean creativeMode; - private final int seaLevel; - private final boolean aggressiveMode; - - //two lists of materials - private final Set notAllowedToHang; //natural blocks which don't naturally hang in their air - private final Set playerBlocks; //a "complete" list of player-placed blocks. MUST BE MAINTAINED as patches introduce more - - - public RestoreNatureProcessingTask(BlockSnapshot[][][] snapshots, int miny, Environment environment, Biome biome, Location lesserBoundaryCorner, Location greaterBoundaryCorner, int seaLevel, boolean aggressiveMode, boolean creativeMode, Player player) - { - this.snapshots = snapshots; - this.miny = miny; - if (this.miny < 0) this.miny = 0; - this.environment = environment; - this.lesserBoundaryCorner = lesserBoundaryCorner; - this.greaterBoundaryCorner = greaterBoundaryCorner; - this.biome = biome; - this.seaLevel = seaLevel; - this.aggressiveMode = aggressiveMode; - this.player = player; - this.creativeMode = creativeMode; - - this.notAllowedToHang = new HashSet<>(); - this.notAllowedToHang.add(Material.DIRT); - this.notAllowedToHang.add(Material.SHORT_GRASS); - this.notAllowedToHang.add(Material.SNOW); - this.notAllowedToHang.add(Material.OAK_LOG); - this.notAllowedToHang.add(Material.SPRUCE_LOG); - this.notAllowedToHang.add(Material.BIRCH_LOG); - this.notAllowedToHang.add(Material.JUNGLE_LOG); - this.notAllowedToHang.add(Material.ACACIA_LOG); - this.notAllowedToHang.add(Material.DARK_OAK_LOG); - - if (this.aggressiveMode) - { - this.notAllowedToHang.add(Material.SHORT_GRASS); - this.notAllowedToHang.add(Material.STONE); - } - - this.playerBlocks = new HashSet<>(); - this.playerBlocks.addAll(RestoreNatureProcessingTask.getPlayerBlocks(this.environment, this.biome)); - - //in aggressive or creative world mode, also treat these blocks as user placed, to be removed - //this is helpful in the few cases where griefers intentionally use natural blocks to grief, - //like a single-block tower of iron ore or a giant penis constructed with melons - if (this.aggressiveMode || this.creativeMode) - { - this.playerBlocks.addAll(Tag.COPPER_ORES.getValues()); - this.playerBlocks.addAll(Tag.IRON_ORES.getValues()); - this.playerBlocks.addAll(Tag.GOLD_ORES.getValues()); - this.playerBlocks.addAll(Tag.DIAMOND_ORES.getValues()); - this.playerBlocks.addAll(Tag.COAL_ORES.getValues()); - this.playerBlocks.add(Material.MELON); - this.playerBlocks.add(Material.MELON_STEM); - this.playerBlocks.add(Material.BEDROCK); - this.playerBlocks.add(Material.PUMPKIN); - this.playerBlocks.add(Material.PUMPKIN_STEM); - } - - if (this.aggressiveMode) - { - this.playerBlocks.addAll(Tag.LEAVES.getValues()); - this.playerBlocks.addAll(Tag.LOGS.getValues()); - this.playerBlocks.add(Material.VINE); - } - } - - @Override - public void run() - { - //order is important! - - //remove sandstone which appears to be unnatural - this.removeSandstone(); - - //remove any blocks which are definitely player placed - this.removePlayerBlocks(); - - //reduce large outcroppings of stone, sandstone - this.reduceStone(); - - //reduce logs, except in jungle biomes - this.reduceLogs(); - - //remove natural blocks which are unnaturally hanging in the air - this.removeHanging(); - - //remove natural blocks which are unnaturally stacked high - this.removeWallsAndTowers(); - - //fill unnatural thin trenches and single-block potholes - this.fillHolesAndTrenches(); - - //fill water depressions and fix unnatural surface ripples - //this.fixWater(); - - //remove water/lava above sea level - this.removeDumpedFluids(); - - //cover surface stone and gravel with sand or grass, as the biome requires - this.coverSurfaceStone(); - - //remove any player-placed leaves - ///this.removePlayerLeaves(); - - //schedule main thread task to apply the result to the world - RestoreNatureExecutionTask task = new RestoreNatureExecutionTask(this.snapshots, this.miny, this.lesserBoundaryCorner, this.greaterBoundaryCorner, this.player); - GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task); - } - - - private void removePlayerLeaves() - { - if (this.seaLevel < 1) return; - - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - for (int y = this.seaLevel - 1; y < snapshots[0].length; y++) - { - BlockSnapshot block = snapshots[x][y][z]; - if (Tag.LEAVES.isTagged(block.typeId) && ((Leaves) block.data).isPersistent()) - { - block.typeId = Material.AIR; - } - } - } - } - } - - //converts sandstone adjacent to sand to sand, and any other sandstone to air - - private void removeSandstone() - { - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - for (int y = snapshots[0].length - 2; y > miny; y--) - { - if (snapshots[x][y][z].typeId != Material.SANDSTONE) continue; - - BlockSnapshot leftBlock = this.snapshots[x + 1][y][z]; - BlockSnapshot rightBlock = this.snapshots[x - 1][y][z]; - BlockSnapshot upBlock = this.snapshots[x][y][z + 1]; - BlockSnapshot downBlock = this.snapshots[x][y][z - 1]; - BlockSnapshot underBlock = this.snapshots[x][y - 1][z]; - BlockSnapshot aboveBlock = this.snapshots[x][y + 1][z]; - - //skip blocks which may cause a cave-in - if (aboveBlock.typeId == Material.SAND && underBlock.typeId == Material.AIR) continue; - - //count adjacent non-air/non-leaf blocks - if (leftBlock.typeId == Material.SAND || - rightBlock.typeId == Material.SAND || - upBlock.typeId == Material.SAND || - downBlock.typeId == Material.SAND || - aboveBlock.typeId == Material.SAND || - underBlock.typeId == Material.SAND) - { - snapshots[x][y][z].typeId = Material.SAND; - } - else - { - snapshots[x][y][z].typeId = Material.AIR; - } - } - } - } - } - - - private void reduceStone() - { - if (this.seaLevel < 1) return; - - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - int thisy = this.highestY(x, z, true); - - while (thisy > this.seaLevel - 1 && (this.snapshots[x][thisy][z].typeId == Material.STONE || this.snapshots[x][thisy][z].typeId == Material.SANDSTONE)) - { - BlockSnapshot leftBlock = this.snapshots[x + 1][thisy][z]; - BlockSnapshot rightBlock = this.snapshots[x - 1][thisy][z]; - BlockSnapshot upBlock = this.snapshots[x][thisy][z + 1]; - BlockSnapshot downBlock = this.snapshots[x][thisy][z - 1]; - - //count adjacent non-air/non-leaf blocks - byte adjacentBlockCount = 0; - if (leftBlock.typeId != Material.AIR && !Tag.LEAVES.isTagged(leftBlock.typeId) && leftBlock.typeId != Material.VINE) - { - adjacentBlockCount++; - } - if (rightBlock.typeId != Material.AIR && !Tag.LEAVES.isTagged(rightBlock.typeId) && rightBlock.typeId != Material.VINE) - { - adjacentBlockCount++; - } - if (downBlock.typeId != Material.AIR && !Tag.LEAVES.isTagged(downBlock.typeId) && downBlock.typeId != Material.VINE) - { - adjacentBlockCount++; - } - if (upBlock.typeId != Material.AIR && !Tag.LEAVES.isTagged(upBlock.typeId) && upBlock.typeId != Material.VINE) - { - adjacentBlockCount++; - } - - if (adjacentBlockCount < 3) - { - this.snapshots[x][thisy][z].typeId = Material.AIR; - } - - thisy--; - } - } - } - } - - - private void reduceLogs() - { - if (this.seaLevel < 1) return; - - boolean jungleBiome = DENSE_LOG_BIOMES.contains(this.biome.getKey()); - - //scan all blocks above sea level - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - for (int y = this.seaLevel - 1; y < snapshots[0].length; y++) - { - BlockSnapshot block = snapshots[x][y][z]; - - //skip non-logs - if (!Tag.LOGS.isTagged(block.typeId)) continue; - - //if in jungle biome, skip jungle logs - if (jungleBiome && block.typeId == Material.JUNGLE_LOG) continue; - - //examine adjacent blocks for logs - BlockSnapshot leftBlock = this.snapshots[x + 1][y][z]; - BlockSnapshot rightBlock = this.snapshots[x - 1][y][z]; - BlockSnapshot upBlock = this.snapshots[x][y][z + 1]; - BlockSnapshot downBlock = this.snapshots[x][y][z - 1]; - - //if any, remove the log - if (Tag.LOGS.isTagged(leftBlock.typeId) || Tag.LOGS.isTagged(rightBlock.typeId) || Tag.LOGS.isTagged(upBlock.typeId) || Tag.LOGS.isTagged(downBlock.typeId)) - { - this.snapshots[x][y][z].typeId = Material.AIR; - } - } - } - } - } - - - private void removePlayerBlocks() - { - int miny = this.miny; - if (miny < 1) miny = 1; - - //remove all player blocks - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - for (int y = miny; y < snapshots[0].length - 1; y++) - { - BlockSnapshot block = snapshots[x][y][z]; - - if (this.playerBlocks.contains(block.typeId)) - { - block.typeId = Material.AIR; - } - } - } - } - } - - - private void removeHanging() - { - int miny = this.miny; - if (miny < 1) miny = 1; - - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - for (int y = miny; y < snapshots[0].length - 1; y++) - { - BlockSnapshot block = snapshots[x][y][z]; - BlockSnapshot underBlock = snapshots[x][y - 1][z]; - - if (underBlock.typeId == Material.AIR || underBlock.typeId == Material.WATER || Tag.LEAVES.isTagged(underBlock.typeId)) - { - if (this.notAllowedToHang.contains(block.typeId)) - { - block.typeId = Material.AIR; - } - } - } - } - } - } - - - private void removeWallsAndTowers() - { - Material[] excludedBlocksArray = new Material[] - { - Material.CACTUS, - Material.SHORT_GRASS, - Material.RED_MUSHROOM, - Material.BROWN_MUSHROOM, - Material.DEAD_BUSH, - Material.DANDELION, - Material.POPPY, - Material.ALLIUM, - Material.BLUE_ORCHID, - Material.AZURE_BLUET, - Material.RED_TULIP, - Material.ORANGE_TULIP, - Material.WHITE_TULIP, - Material.PINK_TULIP, - Material.OXEYE_DAISY, - Material.SUGAR_CANE, - Material.VINE, - Material.PUMPKIN, - Material.LILY_PAD - }; - - ArrayList excludedBlocks = new ArrayList<>(Arrays.asList(excludedBlocksArray)); - - excludedBlocks.addAll(Tag.SAPLINGS.getValues()); - excludedBlocks.addAll(Tag.LEAVES.getValues()); - - boolean changed; - do - { - changed = false; - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - int thisy = this.highestY(x, z, false); - if (excludedBlocks.contains(this.snapshots[x][thisy][z].typeId)) continue; - - int righty = this.highestY(x + 1, z, false); - int lefty = this.highestY(x - 1, z, false); - while (lefty < thisy && righty < thisy) - { - this.snapshots[x][thisy--][z].typeId = Material.AIR; - changed = true; - } - - int upy = this.highestY(x, z + 1, false); - int downy = this.highestY(x, z - 1, false); - while (upy < thisy && downy < thisy) - { - this.snapshots[x][thisy--][z].typeId = Material.AIR; - changed = true; - } - } - } - } while (changed); - } - - - private void coverSurfaceStone() - { - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - int y = this.highestY(x, z, true); - BlockSnapshot block = snapshots[x][y][z]; - - if (block.typeId == Material.STONE || block.typeId == Material.GRAVEL || block.typeId == Material.FARMLAND || block.typeId == Material.DIRT || block.typeId == Material.SANDSTONE) - { - if (SAND_SOIL_BIOMES.contains(this.biome.getKey())) - { - this.snapshots[x][y][z].typeId = Material.SAND; - } - else - { - this.snapshots[x][y][z].typeId = Material.GRASS_BLOCK; - } - } - } - } - } - - - private void fillHolesAndTrenches() - { - ArrayList fillableBlocks = new ArrayList<>(); - fillableBlocks.add(Material.AIR); - fillableBlocks.add(Material.WATER); - fillableBlocks.add(Material.LAVA); - fillableBlocks.add(Material.SHORT_GRASS); - - ArrayList notSuitableForFillBlocks = new ArrayList<>(); - notSuitableForFillBlocks.add(Material.SHORT_GRASS); - notSuitableForFillBlocks.add(Material.CACTUS); - notSuitableForFillBlocks.add(Material.WATER); - notSuitableForFillBlocks.add(Material.LAVA); - notSuitableForFillBlocks.addAll(Tag.LOGS.getValues()); - - boolean changed; - do - { - changed = false; - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - for (int y = 0; y < snapshots[0].length - 1; y++) - { - BlockSnapshot block = this.snapshots[x][y][z]; - if (!fillableBlocks.contains(block.typeId)) continue; - - BlockSnapshot leftBlock = this.snapshots[x + 1][y][z]; - BlockSnapshot rightBlock = this.snapshots[x - 1][y][z]; - - if (!fillableBlocks.contains(leftBlock.typeId) && !fillableBlocks.contains(rightBlock.typeId)) - { - if (!notSuitableForFillBlocks.contains(rightBlock.typeId)) - { - block.typeId = rightBlock.typeId; - changed = true; - } - } - - BlockSnapshot upBlock = this.snapshots[x][y][z + 1]; - BlockSnapshot downBlock = this.snapshots[x][y][z - 1]; - - if (!fillableBlocks.contains(upBlock.typeId) && !fillableBlocks.contains(downBlock.typeId)) - { - if (!notSuitableForFillBlocks.contains(downBlock.typeId)) - { - block.typeId = downBlock.typeId; - changed = true; - } - } - } - } - } - } while (changed); - } - - - private void fixWater() - { - int miny = this.miny; - if (miny < 1) miny = 1; - - boolean changed; - - //remove hanging water or lava - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - for (int y = miny; y < snapshots[0].length - 1; y++) - { - BlockSnapshot block = this.snapshots[x][y][z]; - BlockSnapshot underBlock = this.snapshots[x][y--][z]; - if (block.typeId == Material.WATER || block.typeId == Material.LAVA) - { - // check if block below is air or is a non-source fluid block (level 1-7 = flowing, 8 = falling) - if (underBlock.typeId == Material.AIR || (underBlock.typeId == Material.WATER && (((Levelled) underBlock.data).getLevel() != 0))) - { - block.typeId = Material.AIR; - } - } - } - } - } - - //fill water depressions - do - { - changed = false; - for (int y = Math.max(this.seaLevel - 10, 0); y <= this.seaLevel; y++) - { - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - BlockSnapshot block = snapshots[x][y][z]; - - //only consider air blocks and flowing water blocks for upgrade to water source blocks - if (block.typeId == Material.AIR || (block.typeId == Material.WATER && ((Levelled) block.data).getLevel() != 0)) - { - BlockSnapshot leftBlock = this.snapshots[x + 1][y][z]; - BlockSnapshot rightBlock = this.snapshots[x - 1][y][z]; - BlockSnapshot upBlock = this.snapshots[x][y][z + 1]; - BlockSnapshot downBlock = this.snapshots[x][y][z - 1]; - BlockSnapshot underBlock = this.snapshots[x][y - 1][z]; - - //block underneath MUST be source water - if (!(underBlock.typeId == Material.WATER && ((Levelled) underBlock.data).getLevel() == 0)) - continue; - - //count adjacent source water blocks - byte adjacentSourceWaterCount = 0; - if (leftBlock.typeId == Material.WATER && ((Levelled) leftBlock.data).getLevel() == 0) - { - adjacentSourceWaterCount++; - } - if (rightBlock.typeId == Material.WATER && ((Levelled) rightBlock.data).getLevel() == 0) - { - adjacentSourceWaterCount++; - } - if (upBlock.typeId == Material.WATER && ((Levelled) upBlock.data).getLevel() == 0) - { - adjacentSourceWaterCount++; - } - if (downBlock.typeId == Material.WATER && ((Levelled) downBlock.data).getLevel() == 0) - { - adjacentSourceWaterCount++; - } - - //at least two adjacent blocks must be source water - if (adjacentSourceWaterCount >= 2) - { - block.typeId = Material.WATER; - ((Levelled) downBlock.data).setLevel(0); - changed = true; - } - } - } - } - } - } while (changed); - } - - - private void removeDumpedFluids() - { - if (this.seaLevel < 1) return; - - //remove any surface water or lava above sea level, presumed to be placed by players - //sometimes, this is naturally generated. but replacing it is very easy with a bucket, so overall this is a good plan - if (this.environment == Environment.NETHER) return; - for (int x = 1; x < snapshots.length - 1; x++) - { - for (int z = 1; z < snapshots[0][0].length - 1; z++) - { - for (int y = this.seaLevel; y < snapshots[0].length - 1; y++) - { - BlockSnapshot block = snapshots[x][y][z]; - if (block.typeId == Material.WATER || block.typeId == Material.LAVA) - { - block.typeId = Material.AIR; - } - } - } - } - } - - - private int highestY(int x, int z, boolean ignoreLeaves) - { - int y; - for (y = snapshots[0].length - 1; y > 0; y--) - { - BlockSnapshot block = this.snapshots[x][y][z]; - if (block.typeId != Material.AIR && - !(ignoreLeaves && block.typeId == Material.SNOW) && - !(ignoreLeaves && Tag.LEAVES.isTagged(block.typeId)) && - !(block.typeId == Material.WATER) && - !(block.typeId == Material.LAVA)) - { - return y; - } - } - - return y; - } - - - static Set getPlayerBlocks(Environment environment, Biome biome) - { - //NOTE on this list. why not make a list of natural blocks? - //answer: better to leave a few player blocks than to remove too many natural blocks. remember we're "restoring nature" - //a few extra player blocks can be manually removed, but it will be impossible to guess exactly which natural materials to use in manual repair of an overzealous block removal - Set playerBlocks = new HashSet<>(); - playerBlocks.addAll(Tag.ANVIL.getValues()); - playerBlocks.addAll(Tag.BANNERS.getValues()); - playerBlocks.addAll(Tag.BEACON_BASE_BLOCKS.getValues()); - playerBlocks.addAll(Tag.BEDS.getValues()); - playerBlocks.addAll(Tag.BUTTONS.getValues()); - playerBlocks.addAll(Tag.CAMPFIRES.getValues()); - playerBlocks.addAll(Tag.CANDLE_CAKES.getValues()); - playerBlocks.addAll(Tag.CANDLES.getValues()); - playerBlocks.addAll(Tag.WOOL_CARPETS.getValues()); - playerBlocks.addAll(Tag.CAULDRONS.getValues()); - playerBlocks.addAll(Tag.DOORS.getValues()); - playerBlocks.addAll(Tag.FENCE_GATES.getValues()); - playerBlocks.addAll(Tag.FENCES.getValues()); - playerBlocks.addAll(Tag.FIRE.getValues()); - playerBlocks.addAll(Tag.FLOWER_POTS.getValues()); - playerBlocks.addAll(Tag.IMPERMEABLE.getValues()); // Glass block variants - playerBlocks.addAll(Tag.LOGS.getValues()); - playerBlocks.addAll(Tag.PLANKS.getValues()); - playerBlocks.addAll(Tag.PRESSURE_PLATES.getValues()); - playerBlocks.addAll(Tag.RAILS.getValues()); - playerBlocks.addAll(Tag.SHULKER_BOXES.getValues()); - playerBlocks.addAll(Tag.SIGNS.getValues()); - playerBlocks.addAll(Tag.SLABS.getValues()); - playerBlocks.addAll(Tag.STAIRS.getValues()); - playerBlocks.addAll(Tag.STONE_BRICKS.getValues()); - playerBlocks.addAll(Tag.TRAPDOORS.getValues()); - playerBlocks.addAll(Tag.WALLS.getValues()); - playerBlocks.addAll(Tag.WOOL.getValues()); - playerBlocks.add(Material.BOOKSHELF); - playerBlocks.add(Material.BREWING_STAND); - playerBlocks.add(Material.BRICK); - playerBlocks.add(Material.COBBLESTONE); - playerBlocks.add(Material.LAPIS_BLOCK); - playerBlocks.add(Material.DISPENSER); - playerBlocks.add(Material.NOTE_BLOCK); - playerBlocks.add(Material.STICKY_PISTON); - playerBlocks.add(Material.PISTON); - playerBlocks.add(Material.PISTON_HEAD); - playerBlocks.add(Material.MOVING_PISTON); - playerBlocks.add(Material.WHEAT); - playerBlocks.add(Material.TNT); - playerBlocks.add(Material.MOSSY_COBBLESTONE); - playerBlocks.add(Material.TORCH); - playerBlocks.add(Material.CHEST); - playerBlocks.add(Material.REDSTONE_WIRE); - playerBlocks.add(Material.CRAFTING_TABLE); - playerBlocks.add(Material.FURNACE); - playerBlocks.add(Material.LADDER); - playerBlocks.add(Material.SCAFFOLDING); - playerBlocks.add(Material.LEVER); - playerBlocks.add(Material.REDSTONE_TORCH); - playerBlocks.add(Material.SNOW_BLOCK); - playerBlocks.add(Material.JUKEBOX); - playerBlocks.add(Material.NETHER_PORTAL); - playerBlocks.add(Material.JACK_O_LANTERN); - playerBlocks.add(Material.CAKE); - playerBlocks.add(Material.REPEATER); - playerBlocks.add(Material.MUSHROOM_STEM); - playerBlocks.add(Material.RED_MUSHROOM_BLOCK); - playerBlocks.add(Material.BROWN_MUSHROOM_BLOCK); - playerBlocks.add(Material.IRON_BARS); - playerBlocks.add(Material.GLASS_PANE); - playerBlocks.add(Material.MELON_STEM); - playerBlocks.add(Material.ENCHANTING_TABLE); - playerBlocks.add(Material.COBWEB); - playerBlocks.add(Material.GRAVEL); - playerBlocks.add(Material.SANDSTONE); - playerBlocks.add(Material.ENDER_CHEST); - playerBlocks.add(Material.COMMAND_BLOCK); - playerBlocks.add(Material.REPEATING_COMMAND_BLOCK); - playerBlocks.add(Material.CHAIN_COMMAND_BLOCK); - playerBlocks.add(Material.BEACON); - playerBlocks.add(Material.CARROT); - playerBlocks.add(Material.POTATO); - playerBlocks.add(Material.SKELETON_SKULL); - playerBlocks.add(Material.WITHER_SKELETON_SKULL); - playerBlocks.add(Material.CREEPER_HEAD); - playerBlocks.add(Material.ZOMBIE_HEAD); - playerBlocks.add(Material.PLAYER_HEAD); - playerBlocks.add(Material.DRAGON_HEAD); - playerBlocks.add(Material.SPONGE); - playerBlocks.add(Material.WHITE_STAINED_GLASS_PANE); - playerBlocks.add(Material.ORANGE_STAINED_GLASS_PANE); - playerBlocks.add(Material.MAGENTA_STAINED_GLASS_PANE); - playerBlocks.add(Material.LIGHT_BLUE_STAINED_GLASS_PANE); - playerBlocks.add(Material.YELLOW_STAINED_GLASS_PANE); - playerBlocks.add(Material.LIME_STAINED_GLASS_PANE); - playerBlocks.add(Material.PINK_STAINED_GLASS_PANE); - playerBlocks.add(Material.GRAY_STAINED_GLASS_PANE); - playerBlocks.add(Material.LIGHT_GRAY_STAINED_GLASS_PANE); - playerBlocks.add(Material.CYAN_STAINED_GLASS_PANE); - playerBlocks.add(Material.PURPLE_STAINED_GLASS_PANE); - playerBlocks.add(Material.BLUE_STAINED_GLASS_PANE); - playerBlocks.add(Material.BROWN_STAINED_GLASS_PANE); - playerBlocks.add(Material.GREEN_STAINED_GLASS_PANE); - playerBlocks.add(Material.RED_STAINED_GLASS_PANE); - playerBlocks.add(Material.BLACK_STAINED_GLASS_PANE); - playerBlocks.add(Material.TRAPPED_CHEST); - playerBlocks.add(Material.COMPARATOR); - playerBlocks.add(Material.DAYLIGHT_DETECTOR); - playerBlocks.add(Material.REDSTONE_BLOCK); - playerBlocks.add(Material.HOPPER); - playerBlocks.add(Material.QUARTZ_BLOCK); - playerBlocks.add(Material.DROPPER); - playerBlocks.add(Material.SLIME_BLOCK); - playerBlocks.add(Material.PRISMARINE); - playerBlocks.add(Material.HAY_BLOCK); - playerBlocks.add(Material.SEA_LANTERN); - playerBlocks.add(Material.COAL_BLOCK); - playerBlocks.add(Material.REDSTONE_LAMP); - playerBlocks.add(Material.RED_NETHER_BRICKS); - playerBlocks.add(Material.POLISHED_ANDESITE); - playerBlocks.add(Material.POLISHED_DIORITE); - playerBlocks.add(Material.POLISHED_GRANITE); - playerBlocks.add(Material.POLISHED_BASALT); - playerBlocks.add(Material.POLISHED_DEEPSLATE); - playerBlocks.add(Material.DEEPSLATE_BRICKS); - playerBlocks.add(Material.CRACKED_DEEPSLATE_BRICKS); - playerBlocks.add(Material.DEEPSLATE_TILES); - playerBlocks.add(Material.CRACKED_DEEPSLATE_TILES); - playerBlocks.add(Material.CHISELED_DEEPSLATE); - playerBlocks.add(Material.RAW_COPPER_BLOCK); - playerBlocks.add(Material.RAW_IRON_BLOCK); - playerBlocks.add(Material.RAW_GOLD_BLOCK); - playerBlocks.add(Material.LIGHTNING_ROD); - playerBlocks.add(Material.DECORATED_POT); - - //these are unnatural in the nether and end - if (environment != Environment.NORMAL && environment != Environment.CUSTOM) - { - playerBlocks.addAll(Tag.BASE_STONE_OVERWORLD.getValues()); - playerBlocks.addAll(Tag.DIRT.getValues()); - playerBlocks.addAll(Tag.SAND.getValues()); - } - - //these are unnatural in the standard world, but not in the nether - if (environment != Environment.NETHER) - { - playerBlocks.addAll(Tag.NYLIUM.getValues()); - playerBlocks.addAll(Tag.WART_BLOCKS.getValues()); - playerBlocks.addAll(Tag.BASE_STONE_NETHER.getValues()); - playerBlocks.add(Material.POLISHED_BLACKSTONE); - playerBlocks.add(Material.CHISELED_POLISHED_BLACKSTONE); - playerBlocks.add(Material.CRACKED_POLISHED_BLACKSTONE_BRICKS); - playerBlocks.add(Material.GILDED_BLACKSTONE); - playerBlocks.add(Material.BONE_BLOCK); - playerBlocks.add(Material.SOUL_SAND); - playerBlocks.add(Material.SOUL_SOIL); - playerBlocks.add(Material.GLOWSTONE); - playerBlocks.add(Material.NETHER_BRICK); - playerBlocks.add(Material.MAGMA_BLOCK); - playerBlocks.add(Material.ANCIENT_DEBRIS); - playerBlocks.add(Material.CHAIN); - playerBlocks.add(Material.SHROOMLIGHT); - playerBlocks.add(Material.NETHER_GOLD_ORE); - playerBlocks.add(Material.NETHER_SPROUTS); - playerBlocks.add(Material.CRIMSON_FUNGUS); - playerBlocks.add(Material.CRIMSON_ROOTS); - playerBlocks.add(Material.NETHER_WART_BLOCK); - playerBlocks.add(Material.WEEPING_VINES); - playerBlocks.add(Material.WEEPING_VINES_PLANT); - playerBlocks.add(Material.WARPED_FUNGUS); - playerBlocks.add(Material.WARPED_ROOTS); - playerBlocks.add(Material.WARPED_WART_BLOCK); - playerBlocks.add(Material.TWISTING_VINES); - playerBlocks.add(Material.TWISTING_VINES_PLANT); - } - //blocks from tags that are natural in the nether - else - { - playerBlocks.remove(Material.CRIMSON_STEM); - playerBlocks.remove(Material.CRIMSON_HYPHAE); - playerBlocks.remove(Material.NETHER_BRICK_FENCE); - playerBlocks.remove(Material.NETHER_BRICK_STAIRS); - playerBlocks.remove(Material.SOUL_FIRE); - playerBlocks.remove(Material.WARPED_STEM); - playerBlocks.remove(Material.WARPED_HYPHAE); - } - - //these are unnatural in the standard and nether worlds, but not in the end - if (environment != Environment.THE_END) - { - playerBlocks.add(Material.CHORUS_PLANT); - playerBlocks.add(Material.CHORUS_FLOWER); - playerBlocks.add(Material.END_ROD); - playerBlocks.add(Material.END_STONE); - playerBlocks.add(Material.END_STONE_BRICKS); - playerBlocks.add(Material.OBSIDIAN); - playerBlocks.add(Material.PURPUR_BLOCK); - playerBlocks.add(Material.PURPUR_PILLAR); - } - //blocks from tags that are natural in the end - else - { - playerBlocks.remove(Material.PURPUR_SLAB); - playerBlocks.remove(Material.PURPUR_STAIRS); - } - - //these are unnatural in sandy biomes, but not elsewhere - if (SAND_SOIL_BIOMES.contains(biome.getKey()) || environment != Environment.NORMAL) - { - playerBlocks.addAll(Tag.LEAVES.getValues()); - } - //blocks from tags that are natural in non-sandy normal biomes - else - { - playerBlocks.remove(Material.OAK_LOG); - playerBlocks.remove(Material.SPRUCE_LOG); - playerBlocks.remove(Material.BIRCH_LOG); - playerBlocks.remove(Material.JUNGLE_LOG); - playerBlocks.remove(Material.ACACIA_LOG); - playerBlocks.remove(Material.DARK_OAK_LOG); - } - - return playerBlocks; - } -} diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/ShovelMode.java b/src/main/java/me/ryanhamshire/GriefPrevention/ShovelMode.java index 3985be4..af49301 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/ShovelMode.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/ShovelMode.java @@ -23,8 +23,5 @@ public enum ShovelMode { Basic, Admin, - Subdivide, - RestoreNature, - RestoreNatureAggressive, - RestoreNatureFill + Subdivide } diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/VisualizationType.java b/src/main/java/me/ryanhamshire/GriefPrevention/VisualizationType.java index 669e01e..88aa9fb 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/VisualizationType.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/VisualizationType.java @@ -29,7 +29,6 @@ public enum VisualizationType Claim, Subdivision, ErrorClaim, - RestoreNature, AdminClaim; @Deprecated(forRemoval = true, since = "16.18") @@ -40,7 +39,6 @@ com.griefprevention.visualization.VisualizationType convert() case Claim -> com.griefprevention.visualization.VisualizationType.CLAIM; case Subdivision -> com.griefprevention.visualization.VisualizationType.SUBDIVISION; case ErrorClaim -> com.griefprevention.visualization.VisualizationType.CONFLICT_ZONE; - case RestoreNature -> com.griefprevention.visualization.VisualizationType.NATURE_RESTORATION_ZONE; case AdminClaim -> com.griefprevention.visualization.VisualizationType.ADMIN_CLAIM; }; } @@ -50,7 +48,6 @@ static com.griefprevention.visualization.VisualizationType ofBlockData(BlockData return switch (accent.getMaterial()) { case WHITE_WOOL -> com.griefprevention.visualization.VisualizationType.SUBDIVISION; case NETHERRACK -> com.griefprevention.visualization.VisualizationType.CONFLICT_ZONE; - case DIAMOND_BLOCK -> com.griefprevention.visualization.VisualizationType.NATURE_RESTORATION_ZONE; case PUMPKIN -> com.griefprevention.visualization.VisualizationType.ADMIN_CLAIM; default -> com.griefprevention.visualization.VisualizationType.CLAIM; }; diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index aee5dbc..64f2d81 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -91,21 +91,6 @@ commands: usage: / permission: griefprevention.adminclaims aliases: ac - restorenature: - description: Switches the shovel tool to restoration mode. - usage: / - permission: griefprevention.restorenature - aliases: rn - restorenatureaggressive: - description: Switches the shovel tool to aggressive restoration mode. - usage: / - permission: griefprevention.restorenatureaggressive - aliases: rna - restorenaturefill: - description: Switches the shovel tool to fill mode. - usage: / - permission: griefprevention.restorenatureaggressive - aliases: rnf basicclaims: description: Switches the shovel tool back to basic claims mode. usage: / @@ -211,8 +196,6 @@ permissions: griefprevention.admin.*: description: Grants all administrative functionality. children: - griefprevention.restorenature: true - griefprevention.restorenatureaggressive: true griefprevention.ignoreclaims: true griefprevention.adminclaims: true griefprevention.adjustclaimblocks: true @@ -251,9 +234,6 @@ permissions: griefprevention.claimslistother: description: Grants permission to use /claimslist to get another player's information. default: op - griefprevention.restorenature: - description: Grants permission to use /restorenature. - default: op griefprevention.transferclaim: description: Grants permission to use /transferclaim. default: op @@ -281,9 +261,6 @@ permissions: griefprevention.eavesdropsigns: description: Allows a player to see sign placements as chat messages. default: op - griefprevention.restorenatureaggressive: - description: Grants access to /restorenatureaggressive and /restorenaturefill. - default: op griefprevention.reload: description: Grants access to /gpreload. default: op From 9cb754e44f3d21590a1e119d43ef46a20dc07ed9 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 22 Jul 2024 01:15:10 -0400 Subject: [PATCH 04/10] Remove /givepet (#2338) --- .../GriefPrevention/GriefPrevention.java | 35 ------------------- .../GriefPrevention/Messages.java | 5 +-- .../GriefPrevention/PlayerData.java | 3 -- .../GriefPrevention/PlayerEventHandler.java | 16 ++------- src/main/resources/plugin.yml | 7 ---- 5 files changed, 3 insertions(+), 63 deletions(-) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java index d2e5bff..f2f49ad 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -2089,41 +2089,6 @@ else if (cmd.getName().equalsIgnoreCase("gpreload")) return true; } - //givepet - else if (cmd.getName().equalsIgnoreCase("givepet") && player != null) - { - //requires one parameter - if (args.length < 1) return false; - - PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); - - //special case: cancellation - if (args[0].equalsIgnoreCase("cancel")) - { - playerData.petGiveawayRecipient = null; - GriefPrevention.sendMessage(player, TextMode.Success, Messages.PetTransferCancellation); - return true; - } - - //find the specified player - OfflinePlayer targetPlayer = this.resolvePlayerByName(args[0]); - if (targetPlayer == null - || !targetPlayer.isOnline() && !targetPlayer.hasPlayedBefore() - || targetPlayer.getName() == null) - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound2); - return true; - } - - //remember the player's ID for later pet transfer - playerData.petGiveawayRecipient = targetPlayer; - - //send instructions - GriefPrevention.sendMessage(player, TextMode.Instr, Messages.ReadyToTransferPet); - - return true; - } - //gpblockinfo else if (cmd.getName().equalsIgnoreCase("gpblockinfo") && player != null) { diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java b/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java index e03dfa5..af95e7a 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/Messages.java @@ -160,10 +160,7 @@ public enum Messages AdvertiseACandACB("You may use /acb to give yourself more claim blocks, or /adminclaims to create a free administrative claim."), AdvertiseAdminClaims("You could create an administrative land claim instead using /adminclaims, which you'd share with other administrators."), AdvertiseACB("You may use /acb to give yourself more claim blocks."), - NotYourPet("That belongs to {0} until it's given to you with /givepet.", "0: owner name"), - PetGiveawayConfirmation("Pet transferred."), - PetTransferCancellation("Pet giveaway cancelled."), - ReadyToTransferPet("Ready to transfer! Right-click the pet you'd like to give away, or cancel with /givepet cancel."), + NotYourPet("That belongs to {0}.", "0: owner name"), AvoidGriefClaimLand("Prevent grief! If you claim your land, you will be grief-proof."), BecomeMayor("Subdivide your land claim and become a mayor!"), ClaimCreationFailedOverClaimCountLimit("You've reached your limit on land claims. Use /abandonclaim to remove one before creating another."), diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerData.java b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerData.java index 2b8ecea..6072f7d 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerData.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerData.java @@ -111,9 +111,6 @@ public class PlayerData //message to send to player after he respawns String messageOnRespawn = null; - //player which a pet will be given to when it's right-clicked - OfflinePlayer petGiveawayRecipient = null; - //timestamp for last "you're building outside your land claims" message Long buildWarningTimestamp = null; diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index 722ae19..5d30a57 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -18,17 +18,16 @@ package me.ryanhamshire.GriefPrevention; +import com.griefprevention.protection.ProtectionHelper; import com.griefprevention.util.command.MonitorableCommand; import com.griefprevention.util.command.MonitoredCommands; import com.griefprevention.visualization.BoundaryVisualization; import com.griefprevention.visualization.VisualizationType; import me.ryanhamshire.GriefPrevention.events.ClaimInspectionEvent; import me.ryanhamshire.GriefPrevention.util.BoundingBox; -import com.griefprevention.protection.ProtectionHelper; import org.bukkit.BanList; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.Chunk; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; @@ -39,7 +38,6 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Levelled; import org.bukkit.block.data.Waterlogged; import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.Animals; @@ -1086,9 +1084,8 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); //if entity is tameable and has an owner, apply special rules - if (entity instanceof Tameable) + if (entity instanceof Tameable tameable) { - Tameable tameable = (Tameable) entity; if (tameable.isTamed()) { if (tameable.getOwner() != null) @@ -1098,15 +1095,6 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) //if the player interacting is the owner or an admin in ignore claims mode, always allow if (player.getUniqueId().equals(ownerID) || playerData.ignoreClaims) { - //if giving away pet, do that instead - if (playerData.petGiveawayRecipient != null) - { - tameable.setOwner(playerData.petGiveawayRecipient); - playerData.petGiveawayRecipient = null; - GriefPrevention.sendMessage(player, TextMode.Success, Messages.PetGiveawayConfirmation); - event.setCancelled(true); - } - return; } if (!instance.pvpRulesApply(entity.getLocation().getWorld()) || instance.config_pvp_protectPets) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 64f2d81..5a0fd0e 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -154,10 +154,6 @@ commands: description: Reloads Grief Prevention's configuration settings. Does NOT totally reload the entire plugin. usage: / permission: griefprevention.reload - givepet: - description: Allows a player to give away a pet he or she tamed. - usage: / - permission: griefprevention.givepet gpblockinfo: description: Allows an administrator to get technical information about blocks in the world and items in hand. usage: / @@ -219,9 +215,6 @@ permissions: griefprevention.deleteclaimsinworld: true griefprevention.unlockothersdrops: true griefprevention.seeclaimsize: true - griefprevention.givepet: - description: Grants permission to use /givepet. - default: true griefprevention.unlockdrops: description: Grants permission to use /unlockdrops. default: true From 87bfac64dd3bcf07cb7edd40102a58b2a03ac2b4 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 26 Jul 2024 03:03:39 -0400 Subject: [PATCH 05/10] Fix loading modern messages (#2342) --- src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java b/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java index 5795df8..5504918 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/DataStore.java @@ -1339,7 +1339,7 @@ protected void loadMessages() // Otherwise prefer current value if available. else { - this.messages[message.ordinal()] = config.getString(messagePath, this.messages[message.ordinal()]); + this.messages[message.ordinal()] = config.getString(messagePath, message.defaultValue); } config.set(messagePath, this.messages[message.ordinal()]); From 2debfaff074a07325cdfc9c623fb69a0fca93452 Mon Sep 17 00:00:00 2001 From: MajdT51 <50261972+MajdT51@users.noreply.github.com> Date: Sun, 4 Aug 2024 01:11:45 +0200 Subject: [PATCH 06/10] update maven git commit id plugin (#2347) --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 895bfe2..7061208 100644 --- a/pom.xml +++ b/pom.xml @@ -67,9 +67,9 @@ - pl.project13.maven - git-commit-id-plugin - 4.0.3 + io.github.git-commit-id + git-commit-id-maven-plugin + 9.0.1 get-the-git-infos From 9dca78a56b5c9ac975df4a3acc230f3ae4b1cf91 Mon Sep 17 00:00:00 2001 From: MaksyKun <77341370+MaksyKun@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:35:20 +0200 Subject: [PATCH 07/10] Deny cauldron interactions from untrusted players (#2354) --- .../GriefPrevention/EntityEventHandler.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java index 449144a..8fb4c46 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java @@ -43,6 +43,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockExplodeEvent; +import org.bukkit.event.block.CauldronLevelChangeEvent; import org.bukkit.event.block.EntityBlockFormEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; @@ -778,6 +779,26 @@ public void onEntityPickUpItem(@NotNull EntityPickupItemEvent event) preventPvpSpawnCamp(event, player); } + @EventHandler + public void onCauldron(@NotNull CauldronLevelChangeEvent event) + { + //don't track in worlds where claims are not enabled + if (!GriefPrevention.instance.claimsEnabledForWorld(event.getBlock().getWorld())) return; + + // Check if the entity is a player + Entity entity = event.getEntity(); + if (entity == null) return; + if (!(entity instanceof Player player)) return; + + //if the player doesn't have build permission, don't allow the interaction + Supplier noBuildReason = ProtectionHelper.checkPermission(player, player.getLocation(), ClaimPermission.Build, event); + if (noBuildReason != null) + { + event.setCancelled(true); + GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason.get()); + } + } + private void protectLockedDrops(@NotNull EntityPickupItemEvent event, @Nullable Player player) { Item item = event.getItem(); From 330fd1e15a3ec8c9ed90bc445e2501110c6f64ef Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 23 Aug 2024 14:47:01 -0400 Subject: [PATCH 08/10] Fix NPE, restore PlayerData when using claim tool (#2359) Initialization missed in 5d0ebde#diff-3e987f7e8304fdcbd9f9f571afbbebec186bc70583b97676a68c6b5aac604478L1924 --- .../me/ryanhamshire/GriefPrevention/PlayerEventHandler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index 5d30a57..f6a5a4c 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -1914,6 +1914,8 @@ else if (materialInHand == instance.config_claims_investigationTool && hand == E return; } + playerData = this.dataStore.getPlayerData(player.getUniqueId()); + //if he's resizing a claim and that claim hasn't been deleted since he started resizing it if (playerData.claimResizing != null && playerData.claimResizing.inDataStore) { From c7151e4808b6282b0e92ad0d5559c671a8b0668e Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 23 Aug 2024 15:14:43 -0400 Subject: [PATCH 09/10] Remove gpblockinfo (#2355) --- .../GriefPrevention/GriefPrevention.java | 14 -------------- src/main/resources/plugin.yml | 7 ------- 2 files changed, 21 deletions(-) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java index f2f49ad..73ae7b7 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -31,7 +31,6 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Chunk; -import org.bukkit.FluidCollisionMode; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; @@ -2089,19 +2088,6 @@ else if (cmd.getName().equalsIgnoreCase("gpreload")) return true; } - //gpblockinfo - else if (cmd.getName().equalsIgnoreCase("gpblockinfo") && player != null) - { - ItemStack inHand = player.getInventory().getItemInMainHand(); - player.sendMessage("In Hand: " + inHand.getType().name()); - - Block inWorld = player.getTargetBlockExact(300, FluidCollisionMode.ALWAYS); - if (inWorld == null) inWorld = player.getEyeLocation().getBlock(); - player.sendMessage("In World: " + inWorld.getType().name()); - - return true; - } - //ignoreplayer else if (cmd.getName().equalsIgnoreCase("ignoreplayer") && player != null) { diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5a0fd0e..9c884ba 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -154,10 +154,6 @@ commands: description: Reloads Grief Prevention's configuration settings. Does NOT totally reload the entire plugin. usage: / permission: griefprevention.reload - gpblockinfo: - description: Allows an administrator to get technical information about blocks in the world and items in hand. - usage: / - permission: griefprevention.gpblockinfo ignoreplayer: description: Ignores another player's chat messages. usage: / @@ -272,9 +268,6 @@ permissions: griefprevention.seeclaimsize: description: Allows a player to see claim size for other players claims when right clicking with investigation tool default: op - griefprevention.gpblockinfo: - description: Grants access to /gpblockinfo. - default: op griefprevention.overrideclaimcountlimit: description: Allows players to create more claims than the limit specified by the config. default: op From 1e5f48ab446f1de03c8b5477dbf3f08923ca0996 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 7 Sep 2024 15:28:01 -0400 Subject: [PATCH 10/10] Use separate file for database configuration (#2356) * Migrate database configuration to separate file * Don't write file if not in use --- .../GriefPrevention/GriefPrevention.java | 66 +++++++++++++++++-- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java index 73ae7b7..7def7c4 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -58,7 +58,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -66,12 +69,14 @@ import java.util.HashSet; import java.util.List; import java.util.Map.Entry; +import java.util.Properties; import java.util.Set; import java.util.UUID; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -670,9 +675,7 @@ else if (world.getEnvironment() == Environment.NORMAL) this.config_pvp_protectPets = config.getBoolean("GriefPrevention.PvP.ProtectPetsOutsideLandClaims", false); //optional database settings - this.databaseUrl = config.getString("GriefPrevention.Database.URL", ""); - this.databaseUserName = config.getString("GriefPrevention.Database.UserName", ""); - this.databasePassword = config.getString("GriefPrevention.Database.Password", ""); + loadDatabaseSettings(config); this.config_advanced_fixNegativeClaimblockAmounts = config.getBoolean("GriefPrevention.Advanced.fixNegativeClaimblockAmounts", true); this.config_advanced_claim_expiration_check_rate = config.getInt("GriefPrevention.Advanced.ClaimExpirationCheckRate", 60); @@ -799,10 +802,6 @@ else if (world.getEnvironment() == Environment.NORMAL) outConfig.set("GriefPrevention.HardModeZombiesBreakDoors", this.config_zombiesBreakDoors); outConfig.set("GriefPrevention.MobProjectilesChangeBlocks", this.config_mobProjectilesChangeBlocks); - outConfig.set("GriefPrevention.Database.URL", this.databaseUrl); - outConfig.set("GriefPrevention.Database.UserName", this.databaseUserName); - outConfig.set("GriefPrevention.Database.Password", this.databasePassword); - outConfig.set("GriefPrevention.UseBanCommand", this.config_ban_useCommand); outConfig.set("GriefPrevention.BanCommandPattern", this.config_ban_commandFormat); @@ -864,6 +863,59 @@ else if (world.getEnvironment() == Environment.NORMAL) } } + private void loadDatabaseSettings(@NotNull FileConfiguration legacyConfig) + { + File databasePropsFile = new File(DataStore.dataLayerFolderPath, "database.properties"); + Properties databaseProps = new Properties(); + + // If properties file exists, use it - old config has already been migrated. + if (databasePropsFile.exists() && databasePropsFile.isFile()) + { + try (FileReader reader = new FileReader(databasePropsFile, StandardCharsets.UTF_8)) + { + // Load properties from file. + databaseProps.load(reader); + + // Set values from loaded properties. + databaseUrl = databaseProps.getProperty("jdbcUrl", ""); + databaseUserName = databaseProps.getProperty("username", ""); + databasePassword = databaseProps.getProperty("password", ""); + } + catch (IOException e) + { + getLogger().log(Level.SEVERE, "Unable to read database.properties", e); + } + + return; + } + + // Otherwise, database details may not have been migrated from legacy configuration. + // Try to load them. + databaseUrl = legacyConfig.getString("GriefPrevention.Database.URL", ""); + databaseUserName = legacyConfig.getString("GriefPrevention.Database.UserName", ""); + databasePassword = legacyConfig.getString("GriefPrevention.Database.Password", ""); + + // If not in use already, database settings are "secret" to discourage adoption until datastore is rewritten. + if (databaseUrl.isBlank()) { + return; + } + + // Set properties to loaded values. + databaseProps.setProperty("jdbcUrl", databaseUrl); + databaseProps.setProperty("username", databaseUserName); + databaseProps.setProperty("password", databasePassword); + + // Write properties file for future usage. + try (FileWriter writer = new FileWriter(databasePropsFile, StandardCharsets.UTF_8)) + { + databaseProps.store(writer, null); + } + catch (IOException e) + { + getLogger().log(Level.SEVERE, "Unable to write database.properties", e); + } + } + private ClaimsMode configStringToClaimsMode(String configSetting) { if (configSetting.equalsIgnoreCase("Survival"))