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).
This commit is contained in:
parent
02fba83551
commit
8acbee346e
|
|
@ -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();
|
||||
|
||||
//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...
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Block> examinedBlocks = new ArrayList<Block>();
|
||||
ArrayList<Block> treeBlocks = new ArrayList<Block>();
|
||||
|
||||
//queue the first block, which is the block immediately above the player-chopped block
|
||||
ConcurrentLinkedQueue<Block> blocksToExamine = new ConcurrentLinkedQueue<Block>();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Block> originalTreeBlocks; //a list of other log blocks determined to be part of this tree
|
||||
|
||||
public TreeCleanupTask(Block originalChoppedBlock, Block originalRootBlock, ArrayList<Block> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user