diff --git a/plugin.yml b/plugin.yml index dd37294..fd0e5cc 100644 --- a/plugin.yml +++ b/plugin.yml @@ -92,6 +92,16 @@ commands: usage: /BasicClaims aliases: bc permission: griefprevention.claims + extendclaim: + description: Resizes the land claim you're standing in by pushing or pulling its boundary in the direction you're facing. + usage: /ExtendClaim + aliases: [expandclaim, resizeclaim] + permission: griefprevention.claims + claim: + description: Creates a land claim centered at your current location. + usage: /Claim + aliases: [createclaim, makeclaim, newclaim] + permission: griefprevention.claims buyclaimblocks: description: Purchases additional claim blocks with server money. Doesn't work on servers without a Vault-compatible economy plugin. usage: /BuyClaimBlocks diff --git a/src/me/ryanhamshire/GriefPrevention/DataStore.java b/src/me/ryanhamshire/GriefPrevention/DataStore.java index 11f355b..bac36c5 100644 --- a/src/me/ryanhamshire/GriefPrevention/DataStore.java +++ b/src/me/ryanhamshire/GriefPrevention/DataStore.java @@ -1193,6 +1193,164 @@ public abstract class DataStore return result; } + void resizeClaimWithChecks(Player player, PlayerData playerData, int newx1, int newx2, int newy1, int newy2, int newz1, int newz2) + { + //for top level claims, apply size rules and claim blocks requirement + if(playerData.claimResizing.parent == null) + { + //measure new claim, apply size rules + int newWidth = (Math.abs(newx1 - newx2) + 1); + int newHeight = (Math.abs(newz1 - newz2) + 1); + boolean smaller = newWidth < playerData.claimResizing.getWidth() || newHeight < playerData.claimResizing.getHeight(); + + if(!player.hasPermission("griefprevention.adminclaims") && !playerData.claimResizing.isAdminClaim() && smaller) + { + if(newWidth < GriefPrevention.instance.config_claims_minWidth || newHeight < GriefPrevention.instance.config_claims_minWidth) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeClaimTooNarrow, String.valueOf(GriefPrevention.instance.config_claims_minWidth)); + return; + } + + int newArea = newWidth * newHeight; + if(newArea < GriefPrevention.instance.config_claims_minArea) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeClaimInsufficientArea, String.valueOf(GriefPrevention.instance.config_claims_minArea)); + return; + } + } + + //make sure player has enough blocks to make up the difference + if(!playerData.claimResizing.isAdminClaim() && player.getName().equals(playerData.claimResizing.getOwnerName())) + { + int newArea = newWidth * newHeight; + int blocksRemainingAfter = playerData.getRemainingClaimBlocks() + playerData.claimResizing.getArea() - newArea; + + if(blocksRemainingAfter < 0) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeNeedMoreBlocks, String.valueOf(Math.abs(blocksRemainingAfter))); + this.tryAdvertiseAdminAlternatives(player); + 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 + Claim oldClaim = playerData.claimResizing; + boolean smaller = false; + if(oldClaim.parent == null) + { + //temporary claim instance, just for checking contains() + Claim newClaim = new Claim( + new Location(oldClaim.getLesserBoundaryCorner().getWorld(), newx1, newy1, newz1), + new Location(oldClaim.getLesserBoundaryCorner().getWorld(), newx2, newy2, newz2), + null, new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), 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, newx1, newx2, newy1, newy2, newz1, newz2, player); + + if(result.succeeded) + { + //decide how many claim blocks are available for more resizing + int claimBlocksRemaining = 0; + if(!playerData.claimResizing.isAdminClaim()) + { + UUID ownerID = playerData.claimResizing.ownerID; + if(playerData.claimResizing.parent != null) + { + ownerID = playerData.claimResizing.parent.ownerID; + } + if(ownerID == player.getUniqueId()) + { + claimBlocksRemaining = playerData.getRemainingClaimBlocks(); + } + else + { + PlayerData ownerData = this.getPlayerData(ownerID); + claimBlocksRemaining = ownerData.getRemainingClaimBlocks(); + OfflinePlayer owner = GriefPrevention.instance.getServer().getOfflinePlayer(ownerID); + if(!owner.isOnline()) + { + this.clearCachedPlayerData(ownerID); + } + } + } + + //inform about success, visualize, communicate remaining blocks available + GriefPrevention.sendMessage(player, TextMode.Success, Messages.ClaimResizeSuccess, String.valueOf(claimBlocksRemaining)); + Visualization visualization = Visualization.FromClaim(result.claim, player.getEyeLocation().getBlockY(), VisualizationType.Claim, player.getLocation()); + Visualization.Apply(player, visualization); + + //if resizing someone else's claim, make a log entry + if(!player.getUniqueId().equals(playerData.claimResizing.ownerID) && playerData.claimResizing.parent == null) + { + GriefPrevention.AddLogEntry(player.getName() + " resized " + playerData.claimResizing.getOwnerName() + "'s claim at " + GriefPrevention.getfriendlyLocationString(playerData.claimResizing.lesserBoundaryCorner) + "."); + } + + //if increased to a sufficiently large size and no subdivisions yet, send subdivision instructions + if(oldClaim.getArea() < 1000 && result.claim.getArea() >= 1000 && result.claim.children.size() == 0 && !player.hasPermission("griefprevention.adminclaims")) + { + GriefPrevention.sendMessage(player, TextMode.Info, Messages.BecomeMayor, 200L); + 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; + } + else + { + if(result.claim != null) + { + //inform player + GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeFailOverlap); + + //show the player the conflicting claim + Visualization visualization = Visualization.FromClaim(result.claim, player.getEyeLocation().getBlockY(), VisualizationType.ErrorClaim, player.getLocation()); + Visualization.Apply(player, visualization); + } + else + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeFailOverlapRegion); + } + } + } + + //educates a player about /adminclaims and /acb, if he can use them + void tryAdvertiseAdminAlternatives(Player player) + { + if(player.hasPermission("griefprevention.adminclaims") && player.hasPermission("griefprevention.adjustclaimblocks")) + { + GriefPrevention.sendMessage(player, TextMode.Info, Messages.AdvertiseACandACB); + } + else if(player.hasPermission("griefprevention.adminclaims")) + { + GriefPrevention.sendMessage(player, TextMode.Info, Messages.AdvertiseAdminClaims); + } + else if(player.hasPermission("griefprevention.adjustclaimblocks")) + { + GriefPrevention.sendMessage(player, TextMode.Info, Messages.AdvertiseACB); + } + } + private void loadMessages() { Messages [] messageIDs = Messages.values(); @@ -1406,6 +1564,10 @@ public abstract class DataStore 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.BookAuthor, "BigScary", null); this.addDefault(defaults, Messages.BookTitle, "How to Claim Land", null); @@ -1561,7 +1723,7 @@ public abstract class DataStore { for(Claim claim : claimsInChunk) { - if(claim.getLesserBoundaryCorner().getWorld().equals(location.getWorld())) + if(claim.inDataStore && claim.getLesserBoundaryCorner().getWorld().equals(location.getWorld())) { claims.add(claim); } diff --git a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java index 21143db..2a15b5d 100644 --- a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -40,6 +40,7 @@ import org.bukkit.BanList; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; @@ -924,6 +925,227 @@ public class GriefPrevention extends JavaPlugin player = (Player) sender; } + //claim + if(cmd.getName().equalsIgnoreCase("claim") && player != null) + { + if(!GriefPrevention.instance.claimsEnabledForWorld(player.getWorld())) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.ClaimsDisabledWorld); + return true; + } + + //if player already has a land claim, this requires the claim modification tool to be in hand + PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); + int radius = GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius; + if(radius < 0) radius = 0; + if(playerData.getClaims().size() > 0) + { + if(player.getGameMode() != GameMode.CREATIVE && player.getItemInHand().getType() != GriefPrevention.instance.config_claims_modificationTool) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.MustHoldModificationToolForThat); + return true; + } + radius = (int)Math.ceil(Math.sqrt(GriefPrevention.instance.config_claims_minArea) / 2); + } + + Location lc = player.getLocation().add(-radius, 0, -radius); + Location gc = player.getLocation().add(radius, 0, radius); + + //player must have sufficient unused claim blocks + if(playerData.getClaims().size() > 0) + { + int area = Math.abs((gc.getBlockX() - lc.getBlockX() + 1) * (gc.getBlockZ() - lc.getBlockZ() + 1)); + int remaining = playerData.getRemainingClaimBlocks(); + if(remaining < area) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimInsufficientBlocks, String.valueOf(area - remaining)); + GriefPrevention.instance.dataStore.tryAdvertiseAdminAlternatives(player); + return true; + } + } + + CreateClaimResult result = this.dataStore.createClaim(lc.getWorld(), + lc.getBlockX(), gc.getBlockX(), + lc.getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance - 1, + gc.getWorld().getHighestBlockYAt(gc) - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance - 1, + lc.getBlockZ(), gc.getBlockZ(), + player.getUniqueId(), null, null, player); + if(!result.succeeded) + { + if(result.claim != null) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapShort); + + Visualization visualization = Visualization.FromClaim(result.claim, player.getEyeLocation().getBlockY(), VisualizationType.ErrorClaim, player.getLocation()); + Visualization.Apply(player, visualization); + } + else + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapRegion); + } + } + else + { + GriefPrevention.sendMessage(player, TextMode.Success, Messages.CreateClaimSuccess); + + //link to a video demo of land claiming, based on world type + if(GriefPrevention.instance.creativeRulesApply(player.getLocation())) + { + GriefPrevention.sendMessage(player, TextMode.Instr, Messages.CreativeBasicsVideo2, DataStore.CREATIVE_VIDEO_URL); + } + else if(GriefPrevention.instance.claimsEnabledForWorld(player.getLocation().getWorld())) + { + GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SurvivalBasicsVideo2, DataStore.SURVIVAL_VIDEO_URL); + } + Visualization visualization = Visualization.FromClaim(result.claim, player.getEyeLocation().getBlockY(), VisualizationType.Claim, player.getLocation()); + Visualization.Apply(player, visualization); + playerData.lastShovelLocation = null; + + this.autoExtendClaim(result.claim); + } + + return true; + } + + //extendclaim + if(cmd.getName().equalsIgnoreCase("extendclaim") && player != null) + { + if(args.length < 1) + { + //link to a video demo of land claiming, based on world type + if(GriefPrevention.instance.creativeRulesApply(player.getLocation())) + { + GriefPrevention.sendMessage(player, TextMode.Instr, Messages.CreativeBasicsVideo2, DataStore.CREATIVE_VIDEO_URL); + } + else if(GriefPrevention.instance.claimsEnabledForWorld(player.getLocation().getWorld())) + { + GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SurvivalBasicsVideo2, DataStore.SURVIVAL_VIDEO_URL); + } + return false; + } + + int amount; + try + { + amount = Integer.parseInt(args[0]); + } + catch(NumberFormatException e) + { + //link to a video demo of land claiming, based on world type + if(GriefPrevention.instance.creativeRulesApply(player.getLocation())) + { + GriefPrevention.sendMessage(player, TextMode.Instr, Messages.CreativeBasicsVideo2, DataStore.CREATIVE_VIDEO_URL); + } + else if(GriefPrevention.instance.claimsEnabledForWorld(player.getLocation().getWorld())) + { + GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SurvivalBasicsVideo2, DataStore.SURVIVAL_VIDEO_URL); + } + return false; + } + + //requires claim modification tool in hand + if(player.getGameMode() != GameMode.CREATIVE && player.getItemInHand().getType() != GriefPrevention.instance.config_claims_modificationTool) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.MustHoldModificationToolForThat); + return true; + } + + //must be standing in a land claim + PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); + Claim claim = this.dataStore.getClaimAt(player.getLocation(), true, playerData.lastClaim); + if(claim == null) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.StandInClaimToResize); + return true; + } + + //must have permission to edit the land claim you're in + String errorMessage = claim.allowEdit(player); + if(errorMessage != null) + { + GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotYourClaim); + return true; + } + + //determine new corner coordinates + org.bukkit.util.Vector direction = player.getLocation().getDirection(); +GriefPrevention.AddLogEntry(direction.toString()); + if(direction.getY() > .75) + { + GriefPrevention.sendMessage(player, TextMode.Info, Messages.ClaimsExtendToSky); + return true; + } + + if(direction.getY() < -.75) + { + GriefPrevention.sendMessage(player, TextMode.Info, Messages.ClaimsAutoExtendDownward); + return true; + } + + Location lc = claim.getLesserBoundaryCorner(); + Location gc = claim.getGreaterBoundaryCorner(); + int newx1 = lc.getBlockX(); + int newx2 = gc.getBlockX(); + int newy1 = lc.getBlockY(); + int newy2 = gc.getBlockY(); + int newz1 = lc.getBlockZ(); + int newz2 = gc.getBlockZ(); + + //if changing Z only + if(Math.abs(direction.getX()) < .3) + { + if(direction.getZ() > 0) + { + newz2 += amount; //north + } + else + { + newz1 -= amount; //south + } + } + + //if changing X only + else if(Math.abs(direction.getZ()) < .3) + { + if(direction.getX() > 0) + { + newx2 += amount; //east + } + else + { + newx1 -= amount; //west + } + } + + //diagonals + else + { + if(direction.getX() > 0) + { + newx2 += amount; + } + else + { + newx1 -= amount; + } + + if(direction.getZ() > 0) + { + newz2 += amount; + } + else + { + newz1 -= amount; + } + } + + //attempt resize + playerData.claimResizing = claim; + this.dataStore.resizeClaimWithChecks(player, playerData, newx1, newx2, newy1, newy2, newz1, newz2); + + return true; + } + //abandonclaim if(cmd.getName().equalsIgnoreCase("abandonclaim") && player != null) { @@ -3061,6 +3283,27 @@ public class GriefPrevention extends JavaPlugin return false; } + + void autoExtendClaim(Claim newClaim) + { + //auto-extend it downward to cover anything already built underground + Location lesserCorner = newClaim.getLesserBoundaryCorner(); + Location greaterCorner = newClaim.getGreaterBoundaryCorner(); + World world = lesserCorner.getWorld(); + ArrayList snapshots = new ArrayList(); + for(int chunkx = lesserCorner.getBlockX() / 16; chunkx <= greaterCorner.getBlockX() / 16; chunkx++) + { + for(int chunkz = lesserCorner.getBlockZ() / 16; chunkz <= greaterCorner.getBlockZ() / 16; chunkz++) + { + if(world.isChunkLoaded(chunkx, chunkz)) + { + snapshots.add(world.getChunkAt(chunkx, chunkz).getChunkSnapshot(true, true, true)); + } + } + } + + Bukkit.getScheduler().runTaskAsynchronously(GriefPrevention.instance, new AutoExtendClaimTask(newClaim, snapshots, world.getEnvironment())); + } public boolean pvpRulesApply(World world) { diff --git a/src/me/ryanhamshire/GriefPrevention/Messages.java b/src/me/ryanhamshire/GriefPrevention/Messages.java index d59a7f4..ff04723 100644 --- a/src/me/ryanhamshire/GriefPrevention/Messages.java +++ b/src/me/ryanhamshire/GriefPrevention/Messages.java @@ -20,5 +20,5 @@ package me.ryanhamshire.GriefPrevention; public enum Messages { - RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound2, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionVideo2, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsVideo2, SurvivalBasicsVideo2, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooNarrow, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, HowToClaimRegex, NoBuildOutsideClaims, PlayerOfflineTime, BuildingOutsideClaims, TrappedWontWorkHere, CommandBannedInPvP, UnclaimCleanupWarning, BuySellNotConfigured, NoTeleportPvPCombat, NoTNTDamageAboveSeaLevel, NoTNTDamageClaims, IgnoreClaimsAdvertisement, NoPermissionForCommand, ClaimsListNoPermission, ExplosivesDisabled, ExplosivesEnabled, ClaimExplosivesAdvertisement, PlayerInPvPSafeZone, NoPistonsOutsideClaims, SoftMuted, UnSoftMuted, DropUnlockAdvertisement, PickupBlockedExplanation, DropUnlockConfirmation, AdvertiseACandACB, AdvertiseAdminClaims, AdvertiseACB, NotYourPet, PetGiveawayConfirmation, PetTransferCancellation, ReadyToTransferPet, AvoidGriefClaimLand, BecomeMayor, ClaimCreationFailedOverClaimCountLimit, CreateClaimFailOverlapRegion, ResizeFailOverlapRegion, NoBuildPortalPermission, ShowNearbyClaims, NoChatUntilMove, SiegeImmune, SetClaimBlocksSuccess, IgnoreConfirmation, NotIgnoringPlayer, UnIgnoreConfirmation, SeparateConfirmation, UnSeparateConfirmation, NotIgnoringAnyone, TrustListHeader, Manage, Build, Containers, Access, StartBlockMath, ClaimsListHeader, ContinueBlockMath, EndBlockMath, NoClaimDuringPvP, UntrustAllOwnerOnly, ManagersDontUntrustManagers, BookAuthor, BookTitle, BookIntro, BookDisabledChestClaims, BookUsefulCommands, BookLink, BookTools, ResizeClaimTooNarrow, ResizeClaimInsufficientArea, NoProfanity, PlayerNotIgnorable, NoEnoughBlocksForChestClaim, IsIgnoringYou + RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound2, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionVideo2, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsVideo2, SurvivalBasicsVideo2, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooNarrow, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, HowToClaimRegex, NoBuildOutsideClaims, PlayerOfflineTime, BuildingOutsideClaims, TrappedWontWorkHere, CommandBannedInPvP, UnclaimCleanupWarning, BuySellNotConfigured, NoTeleportPvPCombat, NoTNTDamageAboveSeaLevel, NoTNTDamageClaims, IgnoreClaimsAdvertisement, NoPermissionForCommand, ClaimsListNoPermission, ExplosivesDisabled, ExplosivesEnabled, ClaimExplosivesAdvertisement, PlayerInPvPSafeZone, NoPistonsOutsideClaims, SoftMuted, UnSoftMuted, DropUnlockAdvertisement, PickupBlockedExplanation, DropUnlockConfirmation, AdvertiseACandACB, AdvertiseAdminClaims, AdvertiseACB, NotYourPet, PetGiveawayConfirmation, PetTransferCancellation, ReadyToTransferPet, AvoidGriefClaimLand, BecomeMayor, ClaimCreationFailedOverClaimCountLimit, CreateClaimFailOverlapRegion, ResizeFailOverlapRegion, NoBuildPortalPermission, ShowNearbyClaims, NoChatUntilMove, SiegeImmune, SetClaimBlocksSuccess, IgnoreConfirmation, NotIgnoringPlayer, UnIgnoreConfirmation, SeparateConfirmation, UnSeparateConfirmation, NotIgnoringAnyone, TrustListHeader, Manage, Build, Containers, Access, StartBlockMath, ClaimsListHeader, ContinueBlockMath, EndBlockMath, NoClaimDuringPvP, UntrustAllOwnerOnly, ManagersDontUntrustManagers, BookAuthor, BookTitle, BookIntro, BookDisabledChestClaims, BookUsefulCommands, BookLink, BookTools, ResizeClaimTooNarrow, ResizeClaimInsufficientArea, NoProfanity, PlayerNotIgnorable, NoEnoughBlocksForChestClaim, IsIgnoringYou, MustHoldModificationToolForThat, StandInClaimToResize, ClaimsExtendToSky, ClaimsAutoExtendDownward } diff --git a/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index c45cb49..67de154 100644 --- a/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -2211,143 +2211,7 @@ class PlayerEventHandler implements Listener newy1 = playerData.claimResizing.getLesserBoundaryCorner().getBlockY(); newy2 = clickedBlock.getY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance; - //for top level claims, apply size rules and claim blocks requirement - if(playerData.claimResizing.parent == null) - { - //measure new claim, apply size rules - int newWidth = (Math.abs(newx1 - newx2) + 1); - int newHeight = (Math.abs(newz1 - newz2) + 1); - boolean smaller = newWidth < playerData.claimResizing.getWidth() || newHeight < playerData.claimResizing.getHeight(); - - if(!player.hasPermission("griefprevention.adminclaims") && !playerData.claimResizing.isAdminClaim() && smaller) - { - if(newWidth < GriefPrevention.instance.config_claims_minWidth || newHeight < GriefPrevention.instance.config_claims_minWidth) - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeClaimTooNarrow, String.valueOf(GriefPrevention.instance.config_claims_minWidth)); - return; - } - - int newArea = newWidth * newHeight; - if(newArea < GriefPrevention.instance.config_claims_minArea) - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeClaimInsufficientArea, String.valueOf(GriefPrevention.instance.config_claims_minArea)); - return; - } - } - - //make sure player has enough blocks to make up the difference - if(!playerData.claimResizing.isAdminClaim() && player.getName().equals(playerData.claimResizing.getOwnerName())) - { - int newArea = newWidth * newHeight; - int blocksRemainingAfter = playerData.getRemainingClaimBlocks() + playerData.claimResizing.getArea() - newArea; - - if(blocksRemainingAfter < 0) - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeNeedMoreBlocks, String.valueOf(Math.abs(blocksRemainingAfter))); - this.tryAdvertiseAdminAlternatives(player); - 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 - Claim oldClaim = playerData.claimResizing; - boolean smaller = false; - if(oldClaim.parent == null) - { - //temporary claim instance, just for checking contains() - Claim newClaim = new Claim( - new Location(oldClaim.getLesserBoundaryCorner().getWorld(), newx1, newy1, newz1), - new Location(oldClaim.getLesserBoundaryCorner().getWorld(), newx2, newy2, newz2), - null, new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), 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, newx1, newx2, newy1, newy2, newz1, newz2, player); - - if(result.succeeded) - { - //decide how many claim blocks are available for more resizing - int claimBlocksRemaining = 0; - if(!playerData.claimResizing.isAdminClaim()) - { - UUID ownerID = playerData.claimResizing.ownerID; - if(playerData.claimResizing.parent != null) - { - ownerID = playerData.claimResizing.parent.ownerID; - } - if(ownerID == player.getUniqueId()) - { - claimBlocksRemaining = playerData.getRemainingClaimBlocks(); - } - else - { - PlayerData ownerData = this.dataStore.getPlayerData(ownerID); - claimBlocksRemaining = ownerData.getRemainingClaimBlocks(); - OfflinePlayer owner = GriefPrevention.instance.getServer().getOfflinePlayer(ownerID); - if(!owner.isOnline()) - { - this.dataStore.clearCachedPlayerData(ownerID); - } - } - } - - //inform about success, visualize, communicate remaining blocks available - GriefPrevention.sendMessage(player, TextMode.Success, Messages.ClaimResizeSuccess, String.valueOf(claimBlocksRemaining)); - Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim, player.getLocation()); - Visualization.Apply(player, visualization); - - //if resizing someone else's claim, make a log entry - if(!playerID.equals(playerData.claimResizing.ownerID) && playerData.claimResizing.parent == null) - { - GriefPrevention.AddLogEntry(player.getName() + " resized " + playerData.claimResizing.getOwnerName() + "'s claim at " + GriefPrevention.getfriendlyLocationString(playerData.claimResizing.lesserBoundaryCorner) + "."); - } - - //if increased to a sufficiently large size and no subdivisions yet, send subdivision instructions - if(oldClaim.getArea() < 1000 && result.claim.getArea() >= 1000 && result.claim.children.size() == 0 && !player.hasPermission("griefprevention.adminclaims")) - { - GriefPrevention.sendMessage(player, TextMode.Info, Messages.BecomeMayor, 200L); - 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; - } - else - { - if(result.claim != null) - { - //inform player - GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeFailOverlap); - - //show the player the conflicting claim - Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim, player.getLocation()); - Visualization.Apply(player, visualization); - } - else - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeFailOverlapRegion); - } - } + this.dataStore.resizeClaimWithChecks(player, playerData, newx1, newx2, newy1, newy2, newz1, newz2); return; } @@ -2541,7 +2405,7 @@ class PlayerEventHandler implements Listener if(newClaimArea > remainingBlocks) { GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimInsufficientBlocks, String.valueOf(newClaimArea - remainingBlocks)); - this.tryAdvertiseAdminAlternatives(player); + GriefPrevention.instance.dataStore.tryAdvertiseAdminAlternatives(player); return; } } @@ -2593,46 +2457,12 @@ class PlayerEventHandler implements Listener GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SubdivisionVideo2, 201L, DataStore.SUBDIVISION_VIDEO_URL); } - //auto-extend it downward to cover anything already built underground - Claim newClaim = result.claim; - Location lesserCorner = newClaim.getLesserBoundaryCorner(); - Location greaterCorner = newClaim.getGreaterBoundaryCorner(); - World world = lesserCorner.getWorld(); - ArrayList snapshots = new ArrayList(); - for(int chunkx = lesserCorner.getBlockX() / 16; chunkx <= greaterCorner.getBlockX() / 16; chunkx++) - { - for(int chunkz = lesserCorner.getBlockZ() / 16; chunkz <= greaterCorner.getBlockZ() / 16; chunkz++) - { - if(world.isChunkLoaded(chunkx, chunkz)) - { - snapshots.add(world.getChunkAt(chunkx, chunkz).getChunkSnapshot(true, true, true)); - } - } - } - - Bukkit.getScheduler().runTaskAsynchronously(GriefPrevention.instance, new AutoExtendClaimTask(newClaim, snapshots, world.getEnvironment())); + GriefPrevention.instance.autoExtendClaim(result.claim); } } } } - //educates a player about /adminclaims and /acb, if he can use them - private void tryAdvertiseAdminAlternatives(Player player) - { - if(player.hasPermission("griefprevention.adminclaims") && player.hasPermission("griefprevention.adjustclaimblocks")) - { - GriefPrevention.sendMessage(player, TextMode.Info, Messages.AdvertiseACandACB); - } - else if(player.hasPermission("griefprevention.adminclaims")) - { - GriefPrevention.sendMessage(player, TextMode.Info, Messages.AdvertiseAdminClaims); - } - else if(player.hasPermission("griefprevention.adjustclaimblocks")) - { - GriefPrevention.sendMessage(player, TextMode.Info, Messages.AdvertiseACB); - } - } - //determines whether a block type is an inventory holder. uses a caching strategy to save cpu time private ConcurrentHashMap inventoryHolderCache = new ConcurrentHashMap(); private boolean isInventoryHolder(Block clickedBlock) diff --git a/src/me/ryanhamshire/GriefPrevention/WelcomeTask.java b/src/me/ryanhamshire/GriefPrevention/WelcomeTask.java index 0616f5e..aa91ff2 100644 --- a/src/me/ryanhamshire/GriefPrevention/WelcomeTask.java +++ b/src/me/ryanhamshire/GriefPrevention/WelcomeTask.java @@ -55,7 +55,8 @@ public class WelcomeTask implements Runnable page2.append("/Trust /UnTrust /TrustList\n"); page2.append("/ClaimsList\n"); page2.append("/AbandonClaim\n\n"); - + page2.append("/Claim /ExtendClaim\n"); + page2.append("/IgnorePlayer\n\n"); page2.append("/SubdivideClaims\n");