From 8acbee346ec9047fd77ab3515e78c0f17f0029a7 Mon Sep 17 00:00:00 2001 From: ryanhamshire Date: Tue, 11 Nov 2014 21:09:00 -0800 Subject: [PATCH] Perf: Player Interactions and Block Breaks More perf boosts. No more anti-tree-topping, and fires are no longer protected by default (new config option). --- .../GriefPrevention/BlockEventHandler.java | 13 +- .../GriefPrevention/EntityEventHandler.java | 6 - .../GriefPrevention/GriefPrevention.java | 208 +----------------- .../GriefPrevention/PlayerEventHandler.java | 2 +- .../GriefPrevention/TreeCleanupTask.java | 102 --------- 5 files changed, 8 insertions(+), 323 deletions(-) delete mode 100644 src/me/ryanhamshire/GriefPrevention/TreeCleanupTask.java diff --git a/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java b/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java index 37e03b4..f24072d 100644 --- a/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java +++ b/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java @@ -84,25 +84,16 @@ public class BlockEventHandler implements Listener public void onBlockBreak(BlockBreakEvent breakEvent) { Player player = breakEvent.getPlayer(); - PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); - Block block = breakEvent.getBlock(); + Block block = breakEvent.getBlock(); //make sure the player is allowed to break at the location - String noBuildReason = GriefPrevention.instance.allowBreak(player, block.getLocation()); + String noBuildReason = GriefPrevention.instance.allowBreak(player, block, block.getLocation()); if(noBuildReason != null) { GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason); breakEvent.setCancelled(true); return; } - - //FEATURE: automatically clean up hanging treetops - //if it's a log - if(block.getType() == Material.LOG && GriefPrevention.instance.config_trees_removeFloatingTreetops) - { - //run the specialized code for treetop removal (see below) - GriefPrevention.instance.handleLogBroken(block); - } } //when a player places a sign... diff --git a/src/me/ryanhamshire/GriefPrevention/EntityEventHandler.java b/src/me/ryanhamshire/GriefPrevention/EntityEventHandler.java index 5d48bb5..6e56897 100644 --- a/src/me/ryanhamshire/GriefPrevention/EntityEventHandler.java +++ b/src/me/ryanhamshire/GriefPrevention/EntityEventHandler.java @@ -161,12 +161,6 @@ class EntityEventHandler implements Listener { blocks.remove(i--); } - - //if the block is not claimed and is a log, trigger the anti-tree-top code - else if(block.getType() == Material.LOG) - { - GriefPrevention.instance.handleLogBroken(block); - } } } diff --git a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java index 1ec35a4..a6f60da 100644 --- a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -69,6 +69,7 @@ public class GriefPrevention extends JavaPlugin public boolean config_claims_preventTheft; //whether containers and crafting blocks are protectable public boolean config_claims_protectCreatures; //whether claimed animals may be injured by players without permission + public boolean config_claims_protectFires; //whether open flint+steel flames should be protected - optional because it's expensive public boolean config_claims_preventButtonsSwitches; //whether buttons and switches are protectable public boolean config_claims_lockWoodenDoors; //whether wooden doors should be locked by default (require /accesstrust) public boolean config_claims_lockTrapDoors; //whether trap doors should be locked by default (require /accesstrust) @@ -115,9 +116,6 @@ public class GriefPrevention extends JavaPlugin public boolean config_pvp_noCombatInPlayerLandClaims; //whether players may fight in player-owned land claims public boolean config_pvp_noCombatInAdminLandClaims; //whether players may fight in admin-owned land claims - public boolean config_trees_removeFloatingTreetops; //whether to automatically remove partially cut trees - public boolean config_trees_regrowGriefedTrees; //whether to automatically replant partially cut trees - public double config_economy_claimBlocksPurchaseCost; //cost to purchase a claim block. set to zero to disable purchase. public double config_economy_claimBlocksSellValue; //return on a sold claim block. set to zero to disable sale. @@ -455,6 +453,7 @@ public class GriefPrevention extends JavaPlugin this.config_claims_preventTheft = config.getBoolean("GriefPrevention.Claims.PreventTheft", true); this.config_claims_protectCreatures = config.getBoolean("GriefPrevention.Claims.ProtectCreatures", true); + this.config_claims_protectFires = config.getBoolean("GriefPrevention.Claims.ProtectFires", false); this.config_claims_preventButtonsSwitches = config.getBoolean("GriefPrevention.Claims.PreventButtonsSwitches", true); this.config_claims_lockWoodenDoors = config.getBoolean("GriefPrevention.Claims.LockWoodenDoors", false); this.config_claims_lockTrapDoors = config.getBoolean("GriefPrevention.Claims.LockTrapDoors", false); @@ -487,9 +486,6 @@ public class GriefPrevention extends JavaPlugin this.config_pvp_allowCombatItemDrop = config.getBoolean("GriefPrevention.PvP.AllowCombatItemDrop", false); String bannedPvPCommandsList = config.getString("GriefPrevention.PvP.BlockedSlashCommands", "/home;/vanish;/spawn;/tpa"); - this.config_trees_removeFloatingTreetops = config.getBoolean("GriefPrevention.Trees.RemoveFloatingTreetops", true); - this.config_trees_regrowGriefedTrees = config.getBoolean("GriefPrevention.Trees.RegrowGriefedTrees", true); - this.config_economy_claimBlocksPurchaseCost = config.getDouble("GriefPrevention.Economy.ClaimBlocksPurchaseCost", 0); this.config_economy_claimBlocksSellValue = config.getDouble("GriefPrevention.Economy.ClaimBlocksSellValue", 0); @@ -704,6 +700,7 @@ public class GriefPrevention extends JavaPlugin outConfig.set("GriefPrevention.Claims.LockTrapDoors", this.config_claims_lockTrapDoors); outConfig.set("GriefPrevention.Claims.LockFenceGates", this.config_claims_lockFenceGates); outConfig.set("GriefPrevention.Claims.EnderPearlsRequireAccessTrust", this.config_claims_enderPearlsRequireAccessTrust); + outConfig.set("GriefPrevention.Claims.ProtectFires", this.config_claims_protectFires); outConfig.set("GriefPrevention.Claims.InitialBlocks", this.config_claims_initialBlocks); outConfig.set("GriefPrevention.Claims.BlocksAccruedPerHour", this.config_claims_blocksAccruedPerHour); outConfig.set("GriefPrevention.Claims.MaxAccruedBlocks", this.config_claims_maxAccruedBlocks); @@ -737,9 +734,6 @@ public class GriefPrevention extends JavaPlugin outConfig.set("GriefPrevention.PvP.ProtectPlayersInLandClaims.PlayerOwnedClaims", this.config_pvp_noCombatInPlayerLandClaims); outConfig.set("GriefPrevention.PvP.ProtectPlayersInLandClaims.AdministrativeClaims", this.config_pvp_noCombatInAdminLandClaims); - outConfig.set("GriefPrevention.Trees.RemoveFloatingTreetops", this.config_trees_removeFloatingTreetops); - outConfig.set("GriefPrevention.Trees.RegrowGriefedTrees", this.config_trees_regrowGriefedTrees); - outConfig.set("GriefPrevention.Economy.ClaimBlocksPurchaseCost", this.config_economy_claimBlocksPurchaseCost); outConfig.set("GriefPrevention.Economy.ClaimBlocksSellValue", this.config_economy_claimBlocksSellValue); @@ -2360,198 +2354,6 @@ public class GriefPrevention extends JavaPlugin return this.config_siege_enabledWorlds.contains(world); } - //processes broken log blocks to automatically remove floating treetops - void handleLogBroken(Block block) - { - //find the lowest log in the tree trunk including this log - Block rootBlock = this.getRootBlock(block); - - //null indicates this block isn't part of a tree trunk - if(rootBlock == null) return; - - //next step: scan for other log blocks and leaves in this tree - - //set boundaries for the scan - int min_x = rootBlock.getX() - GriefPrevention.TREE_RADIUS; - int max_x = rootBlock.getX() + GriefPrevention.TREE_RADIUS; - int min_z = rootBlock.getZ() - GriefPrevention.TREE_RADIUS; - int max_z = rootBlock.getZ() + GriefPrevention.TREE_RADIUS; - int max_y = rootBlock.getWorld().getMaxHeight() - 1; - - //keep track of all the examined blocks, and all the log blocks found - ArrayList examinedBlocks = new ArrayList(); - ArrayList treeBlocks = new ArrayList(); - - //queue the first block, which is the block immediately above the player-chopped block - ConcurrentLinkedQueue blocksToExamine = new ConcurrentLinkedQueue(); - blocksToExamine.add(rootBlock); - examinedBlocks.add(rootBlock); - - boolean hasLeaves = false; - - while(!blocksToExamine.isEmpty()) - { - //pop a block from the queue - Block currentBlock = blocksToExamine.remove(); - - //if this is a log block, determine whether it should be chopped - if(currentBlock.getType() == Material.LOG) - { - boolean partOfTree = false; - - //if it's stacked with the original chopped block, the answer is always yes - if(currentBlock.getX() == block.getX() && currentBlock.getZ() == block.getZ()) - { - partOfTree = true; - } - - //otherwise find the block underneath this stack of logs - else - { - Block downBlock = currentBlock.getRelative(BlockFace.DOWN); - while(downBlock.getType() == Material.LOG) - { - downBlock = downBlock.getRelative(BlockFace.DOWN); - } - - //if it's air or leaves, it's okay to chop this block - //this avoids accidentally chopping neighboring trees which are close enough to touch their leaves to ours - if(downBlock.getType() == Material.AIR || downBlock.getType() == Material.LEAVES) - { - partOfTree = true; - } - - //otherwise this is a stack of logs which touches a solid surface - //if it's close to the original block's stack, don't clean up this tree (just stop here) - else - { - if(Math.abs(downBlock.getX() - block.getX()) <= 1 && Math.abs(downBlock.getZ() - block.getZ()) <= 1) return; - } - } - - if(partOfTree) - { - treeBlocks.add(currentBlock); - } - } - - //if this block is a log OR a leaf block, also check its neighbors - if(currentBlock.getType() == Material.LOG || currentBlock.getType() == Material.LEAVES) - { - if(currentBlock.getType() == Material.LEAVES) - { - hasLeaves = true; - } - - Block [] neighboringBlocks = new Block [] - { - currentBlock.getRelative(BlockFace.EAST), - currentBlock.getRelative(BlockFace.WEST), - currentBlock.getRelative(BlockFace.NORTH), - currentBlock.getRelative(BlockFace.SOUTH), - currentBlock.getRelative(BlockFace.UP), - currentBlock.getRelative(BlockFace.DOWN) - }; - - for(int i = 0; i < neighboringBlocks.length; i++) - { - Block neighboringBlock = neighboringBlocks[i]; - - //if the neighboringBlock is out of bounds, skip it - if(neighboringBlock.getX() < min_x || neighboringBlock.getX() > max_x || neighboringBlock.getZ() < min_z || neighboringBlock.getZ() > max_z || neighboringBlock.getY() > max_y) continue; - - //if we already saw this block, skip it - if(examinedBlocks.contains(neighboringBlock)) continue; - - //mark the block as examined - examinedBlocks.add(neighboringBlock); - - //if the neighboringBlock is a leaf or log, put it in the queue to be examined later - if(neighboringBlock.getType() == Material.LOG || neighboringBlock.getType() == Material.LEAVES) - { - blocksToExamine.add(neighboringBlock); - } - - //if we encounter any player-placed block type, bail out (don't automatically remove parts of this tree, it might support a treehouse!) - else if(this.isPlayerBlock(neighboringBlock)) - { - return; - } - } - } - } - - //if it doesn't have leaves, it's not a tree, so don't clean it up - if(hasLeaves) - { - //schedule a cleanup task for later, in case the player leaves part of this tree hanging in the air - TreeCleanupTask cleanupTask = new TreeCleanupTask(block, rootBlock, treeBlocks, rootBlock.getData()); - - //20L ~ 1 second, so 2 mins = 120 seconds ~ 2400L - GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, cleanupTask, 2400L); - } - } - - //helper for above, finds the "root" of a stack of logs - //will return null if the stack is determined to not be a natural tree - private Block getRootBlock(Block logBlock) - { - if(logBlock.getType() != Material.LOG) return null; - - //run down through log blocks until finding a non-log block - Block underBlock = logBlock.getRelative(BlockFace.DOWN); - while(underBlock.getType() == Material.LOG) - { - underBlock = underBlock.getRelative(BlockFace.DOWN); - } - - //if this is a standard tree, that block MUST be dirt - if(underBlock.getType() != Material.DIRT) return null; - - //run up through log blocks until finding a non-log block - Block aboveBlock = logBlock.getRelative(BlockFace.UP); - while(aboveBlock.getType() == Material.LOG) - { - aboveBlock = aboveBlock.getRelative(BlockFace.UP); - } - - //if this is a standard tree, that block MUST be air or leaves - if(aboveBlock.getType() != Material.AIR && aboveBlock.getType() != Material.LEAVES) return null; - - return underBlock.getRelative(BlockFace.UP); - } - - //for sake of identifying trees ONLY, a cheap but not 100% reliable method for identifying player-placed blocks - private boolean isPlayerBlock(Block block) - { - Material material = block.getType(); - - //list of natural blocks which are OK to have next to a log block in a natural tree setting - if( material == Material.AIR || - material == Material.LEAVES || - material == Material.LOG || - material == Material.DIRT || - material == Material.GRASS || - material == Material.STATIONARY_WATER || - material == Material.BROWN_MUSHROOM || - material == Material.RED_MUSHROOM || - material == Material.RED_ROSE || - material == Material.LONG_GRASS || - material == Material.SNOW || - material == Material.STONE || - material == Material.VINE || - material == Material.WATER_LILY || - material == Material.YELLOW_FLOWER || - material == Material.CLAY) - { - return false; - } - else - { - return true; - } - } - //moves a player from the claim he's in to a nearby wilderness location public Location ejectPlayer(Player player) { @@ -2677,7 +2479,7 @@ public class GriefPrevention extends JavaPlugin } } - public String allowBreak(Player player, Location location) + public String allowBreak(Player player, Block block, Location location) { PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim); @@ -2709,7 +2511,7 @@ public class GriefPrevention extends JavaPlugin playerData.lastClaim = claim; //if not in the wilderness, then apply claim rules (permissions, etc) - return claim.allowBreak(player, location.getBlock().getType()); + return claim.allowBreak(player, block.getType()); } } diff --git a/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index 0bbd6ea..50f7c9a 100644 --- a/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -1122,7 +1122,7 @@ class PlayerEventHandler implements Listener if(!this.onLeftClickWatchList(clickedBlockType) && !GriefPrevention.instance.config_mods_accessTrustIds.Contains(new MaterialInfo(clickedBlock.getTypeId(), clickedBlock.getData(), null))) { //and an exception for putting our fires - if(clickedBlockType == Material.NETHERRACK && event.getClickedBlock() != null && event.getClickedBlock().getRelative(event.getBlockFace()).getType() == Material.FIRE) + if(GriefPrevention.instance.config_claims_protectFires && event.getClickedBlock() != null && event.getClickedBlock().getRelative(event.getBlockFace()).getType() == Material.FIRE) { if(playerData == null) playerData = this.dataStore.getPlayerData(player.getUniqueId()); Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim); diff --git a/src/me/ryanhamshire/GriefPrevention/TreeCleanupTask.java b/src/me/ryanhamshire/GriefPrevention/TreeCleanupTask.java deleted file mode 100644 index 3beff33..0000000 --- a/src/me/ryanhamshire/GriefPrevention/TreeCleanupTask.java +++ /dev/null @@ -1,102 +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 java.util.ArrayList; - -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; - -//FEATURE: treetops left unnaturally hanging will be automatically cleaned up - -//this main thread task revisits the location of a partially chopped tree from several minutes ago -//if any part of the tree is still there and nothing else has been built in its place, remove the remaining parts -class TreeCleanupTask implements Runnable -{ - private Block originalChoppedBlock; //first block chopped in the tree - private Block originalRootBlock; //where the root of the tree used to be - private byte originalRootBlockData; //data value of that root block (TYPE of log) - private ArrayList originalTreeBlocks; //a list of other log blocks determined to be part of this tree - - public TreeCleanupTask(Block originalChoppedBlock, Block originalRootBlock, ArrayList originalTreeBlocks, byte originalRootBlockData) - { - this.originalChoppedBlock = originalChoppedBlock; - this.originalRootBlock = originalRootBlock; - this.originalTreeBlocks = originalTreeBlocks; - this.originalRootBlockData = originalRootBlockData; - } - - @Override - public void run() - { - //if this chunk is no longer loaded, load it and come back in a few seconds - Chunk chunk = this.originalChoppedBlock.getWorld().getChunkAt(this.originalChoppedBlock); - if(!chunk.isLoaded()) - { - chunk.load(); - GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, this, 100L); - return; - } - - //if the block originally chopped has been replaced with anything but air, something has been built (or has grown here) - //in that case, don't do any cleanup - if(this.originalChoppedBlock.getWorld().getBlockAt(this.originalChoppedBlock.getLocation()).getType() != Material.AIR) return; - - //scan the original tree block locations to see if any of them have been replaced - for(int i = 0; i < this.originalTreeBlocks.size(); i++) - { - Location location = this.originalTreeBlocks.get(i).getLocation(); - Block currentBlock = location.getBlock(); - - //if the block has been replaced, stop here, we won't do any cleanup - if(currentBlock.getType() != Material.LOG && currentBlock.getType() != Material.AIR) - { - return; - } - } - - //otherwise scan again, this time removing any remaining log blocks - boolean logsRemaining = false; - for(int i = 0; i < this.originalTreeBlocks.size(); i++) - { - Location location = this.originalTreeBlocks.get(i).getLocation(); - Block currentBlock = location.getBlock(); - if(currentBlock.getType() == Material.LOG) - { - logsRemaining = true; - currentBlock.setType(Material.AIR); - } - } - - //if any were actually removed and we're set to automatically replant griefed trees, place a sapling where the root block was previously - if(logsRemaining && GriefPrevention.instance.config_trees_regrowGriefedTrees) - { - Block currentBlock = this.originalRootBlock.getLocation().getBlock(); - //make sure there's grass or dirt underneath - if(currentBlock.getType() == Material.AIR && (currentBlock.getRelative(BlockFace.DOWN).getType() == Material.DIRT || currentBlock.getRelative(BlockFace.DOWN).getType() == Material.GRASS)) - { - currentBlock.setType(Material.SAPLING); - currentBlock.setData(this.originalRootBlockData); //makes the sapling type match the original tree type - } - } - } -}