Performance - Streamlined event handlers.
Lots of changes, all around reducing processing time, especially for very common or very expensive-per-instance events.
This commit is contained in:
parent
99986cc7b2
commit
94fa70c9d9
|
|
@ -166,7 +166,22 @@ public class BlockEventHandler implements Listener
|
|||
public void onBlockBreak(BlockBreakEvent breakEvent)
|
||||
{
|
||||
Player player = breakEvent.getPlayer();
|
||||
Block block = breakEvent.getBlock();
|
||||
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
|
||||
Block block = breakEvent.getBlock();
|
||||
|
||||
//optimization: breaking blocks directly underneath your last successfully broken block is always* safe
|
||||
//*not when the new block was claimed after the last break
|
||||
//*not in siege mode, where some types of claimed blocks may be broken
|
||||
Location blockLocation = block.getLocation();
|
||||
Location lastBreakLocation = playerData.lastSuccessfulBreak;
|
||||
if(lastBreakLocation != null &&
|
||||
!GriefPrevention.instance.siegeEnabledForWorld(block.getWorld()) &&
|
||||
blockLocation.getBlockX() == lastBreakLocation.getBlockX() &&
|
||||
blockLocation.getBlockZ() == lastBreakLocation.getBlockZ() &&
|
||||
blockLocation.getBlockY() <= lastBreakLocation.getBlockY())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//make sure the player is allowed to break at the location
|
||||
String noBuildReason = GriefPrevention.instance.allowBreak(player, block.getLocation());
|
||||
|
|
@ -177,8 +192,8 @@ public class BlockEventHandler implements Listener
|
|||
return;
|
||||
}
|
||||
|
||||
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
|
||||
Claim claim = this.dataStore.getClaimAt(block.getLocation(), true, playerData.lastClaim);
|
||||
//make a note of any successful breaks
|
||||
playerData.lastSuccessfulBreak = block.getLocation();
|
||||
|
||||
//FEATURE: automatically clean up hanging treetops
|
||||
//if it's a log
|
||||
|
|
|
|||
|
|
@ -194,11 +194,18 @@ class CleanupUnusedClaimsTask implements Runnable
|
|||
if(cleanupChunks)
|
||||
{
|
||||
World world = claim.getLesserBoundaryCorner().getWorld();
|
||||
Chunk [] chunks = world.getLoadedChunks();
|
||||
for(int i = 0; i < chunks.length; i++)
|
||||
Chunk lesserChunk = world.getChunkAt(claim.getLesserBoundaryCorner());
|
||||
Chunk greaterChunk = world.getChunkAt(claim.getGreaterBoundaryCorner());
|
||||
for(int x = lesserChunk.getX(); x <= greaterChunk.getX(); x++)
|
||||
{
|
||||
Chunk chunk = chunks[i];
|
||||
chunk.unload(true, true);
|
||||
for(int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++)
|
||||
{
|
||||
Chunk chunk = world.getChunkAt(x, z);
|
||||
if(chunk.isLoaded())
|
||||
{
|
||||
chunk.unload(true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -527,7 +527,12 @@ public abstract class DataStore
|
|||
}
|
||||
|
||||
//saves changes to player data to secondary storage. MUST be called after you're done making changes, otherwise a reload will lose them
|
||||
public abstract void savePlayerData(UUID playerID, PlayerData playerData);
|
||||
public void savePlayerData(UUID playerID, PlayerData playerData)
|
||||
{
|
||||
new SavePlayerDataThread(playerID, playerData).start();
|
||||
}
|
||||
|
||||
public abstract void asyncSavePlayerData(UUID playerID, PlayerData playerData);
|
||||
|
||||
//extends a claim to a new depth
|
||||
//respects the max depth config variable
|
||||
|
|
@ -1116,4 +1121,21 @@ public abstract class DataStore
|
|||
}
|
||||
|
||||
abstract void close();
|
||||
|
||||
private class SavePlayerDataThread extends Thread
|
||||
{
|
||||
private UUID playerID;
|
||||
private PlayerData playerData;
|
||||
|
||||
SavePlayerDataThread(UUID playerID, PlayerData playerData)
|
||||
{
|
||||
this.playerID = playerID;
|
||||
this.playerData = playerData;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
asyncSavePlayerData(this.playerID, this.playerData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -490,7 +490,7 @@ public class DatabaseDataStore extends DataStore
|
|||
|
||||
//saves changes to player data. MUST be called after you're done making changes, otherwise a reload will lose them
|
||||
@Override
|
||||
synchronized public void savePlayerData(UUID playerID, PlayerData playerData)
|
||||
public void asyncSavePlayerData(UUID playerID, PlayerData playerData)
|
||||
{
|
||||
//never save data for the "administrative" account. an empty string for player name indicates administrative account
|
||||
if(playerID == null) return;
|
||||
|
|
@ -574,7 +574,7 @@ public class DatabaseDataStore extends DataStore
|
|||
this.databaseConnection = null;
|
||||
}
|
||||
|
||||
private void refreshDataConnection() throws SQLException
|
||||
private synchronized void refreshDataConnection() throws SQLException
|
||||
{
|
||||
if(this.databaseConnection == null || this.databaseConnection.isClosed())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.bukkit.entity.Creeper;
|
|||
import org.bukkit.entity.Enderman;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Explosive;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Monster;
|
||||
import org.bukkit.entity.Player;
|
||||
|
|
@ -493,6 +494,13 @@ class EntityEventHandler implements Listener
|
|||
{
|
||||
Claim cachedClaim = null;
|
||||
PlayerData playerData = null;
|
||||
|
||||
//if not a player or an explosive, allow
|
||||
if(attacker == null && !(damageSource instanceof Explosive))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(attacker != null)
|
||||
{
|
||||
playerData = this.dataStore.getPlayerData(attacker.getUniqueId());
|
||||
|
|
@ -577,10 +585,17 @@ class EntityEventHandler implements Listener
|
|||
}
|
||||
}
|
||||
|
||||
//if not a player and not an explosion, always allow
|
||||
if(attacker == null && !(damageSource instanceof Explosive))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//NOTE: vehicles can be pushed around.
|
||||
//so unless precautions are taken by the owner, a resourceful thief might find ways to steal anyway
|
||||
Claim cachedClaim = null;
|
||||
PlayerData playerData = null;
|
||||
|
||||
if(attacker != null)
|
||||
{
|
||||
playerData = this.dataStore.getPlayerData(attacker.getUniqueId());
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ public class FlatFileDataStore extends DataStore
|
|||
|
||||
//saves changes to player data. MUST be called after you're done making changes, otherwise a reload will lose them
|
||||
@Override
|
||||
synchronized public void savePlayerData(UUID playerID, PlayerData playerData)
|
||||
public void asyncSavePlayerData(UUID playerID, PlayerData playerData)
|
||||
{
|
||||
//never save data for the "administrative" account. null for claim owner ID indicates administrative account
|
||||
if(playerID == null) return;
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ public class GriefPrevention extends JavaPlugin
|
|||
public static final int NOTIFICATION_SECONDS = 20;
|
||||
|
||||
//adds a server log entry
|
||||
public static void AddLogEntry(String entry)
|
||||
public static synchronized void AddLogEntry(String entry)
|
||||
{
|
||||
log.info("GriefPrevention: " + entry);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ public class PlayerData
|
|||
//the last claim this player was in, that we know of
|
||||
public Claim lastClaim = null;
|
||||
|
||||
//location of the last successfully-broken block, used in a performance optimization
|
||||
Location lastSuccessfulBreak = null;
|
||||
|
||||
//siege
|
||||
public SiegeData siegeData = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -909,12 +909,15 @@ class PlayerEventHandler implements Listener
|
|||
if(!GriefPrevention.instance.config_claims_preventButtonsSwitches) return;
|
||||
|
||||
Player player = bedEvent.getPlayer();
|
||||
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
|
||||
Block block = bedEvent.getBed();
|
||||
|
||||
//if the bed is in a claim
|
||||
Claim claim = this.dataStore.getClaimAt(block.getLocation(), false, null);
|
||||
Claim claim = this.dataStore.getClaimAt(block.getLocation(), false, playerData.lastClaim);
|
||||
if(claim != null)
|
||||
{
|
||||
playerData.lastClaim = claim;
|
||||
|
||||
//if the player doesn't have access in that claim, tell him so and prevent him from sleeping in the bed
|
||||
if(claim.allowAccess(player) != null)
|
||||
{
|
||||
|
|
@ -1006,35 +1009,45 @@ class PlayerEventHandler implements Listener
|
|||
void onPlayerInteract(PlayerInteractEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
|
||||
//determine target block. FEATURE: shovel and string can be used from a distance away
|
||||
Block clickedBlock = null;
|
||||
|
||||
try
|
||||
Block clickedBlock = event.getClickedBlock(); //null returned here means interacting with air
|
||||
Material clickedBlockType = null;
|
||||
if(clickedBlock != null)
|
||||
{
|
||||
clickedBlock = event.getClickedBlock(); //null returned here means interacting with air
|
||||
if(clickedBlock == null || clickedBlock.getType() == Material.SNOW)
|
||||
{
|
||||
//try to find a far away non-air block along line of sight
|
||||
clickedBlock = getTargetBlock(player, 250,
|
||||
Material.AIR,
|
||||
Material.SNOW,
|
||||
Material.LONG_GRASS);
|
||||
}
|
||||
clickedBlockType = clickedBlock.getType();
|
||||
}
|
||||
catch(Exception e) //an exception intermittently comes from getTargetBlock(). when it does, just ignore the event
|
||||
else
|
||||
{
|
||||
return;
|
||||
clickedBlockType = Material.AIR;
|
||||
}
|
||||
|
||||
//apply rule for players trampling tilled soil back to dirt (never allow it)
|
||||
//NOTE: that this event applies only to players. monsters and animals can still trample.
|
||||
if(event.getAction() == Action.PHYSICAL)
|
||||
{
|
||||
if(clickedBlockType == Material.SOIL)
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
//not tracking any other "physical" interaction events right now
|
||||
return;
|
||||
}
|
||||
|
||||
//FEATURE: shovel and stick can be used from a distance away
|
||||
Material itemInHand = player.getItemInHand().getType();
|
||||
if(clickedBlock == null && (itemInHand == Material.STICK || itemInHand == Material.GOLD_SPADE))
|
||||
{
|
||||
//try to find a far away non-air block along line of sight
|
||||
clickedBlock = getTargetBlock(player, 50);
|
||||
clickedBlockType = clickedBlock.getType();
|
||||
}
|
||||
|
||||
//if no block, stop here
|
||||
if(clickedBlock == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Material clickedBlockType = clickedBlock.getType();
|
||||
|
||||
//apply rules for putting out fires (requires build permission)
|
||||
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
|
||||
if(event.getClickedBlock() != null && event.getClickedBlock().getRelative(event.getBlockFace()).getType() == Material.FIRE)
|
||||
|
|
@ -1058,13 +1071,6 @@ class PlayerEventHandler implements Listener
|
|||
if( GriefPrevention.instance.config_claims_preventTheft && (
|
||||
event.getAction() == Action.RIGHT_CLICK_BLOCK && (
|
||||
clickedBlock.getState() instanceof InventoryHolder ||
|
||||
clickedBlockType == Material.WORKBENCH ||
|
||||
clickedBlockType == Material.ENDER_CHEST ||
|
||||
clickedBlockType == Material.DISPENSER ||
|
||||
clickedBlockType == Material.ANVIL ||
|
||||
clickedBlockType == Material.BREWING_STAND ||
|
||||
clickedBlockType == Material.JUKEBOX ||
|
||||
clickedBlockType == Material.ENCHANTMENT_TABLE ||
|
||||
GriefPrevention.instance.config_mods_containerTrustIds.Contains(new MaterialInfo(clickedBlock.getTypeId(), clickedBlock.getData(), null)))))
|
||||
{
|
||||
//block container use while under siege, so players can't hide items from attackers
|
||||
|
|
@ -1145,14 +1151,6 @@ class PlayerEventHandler implements Listener
|
|||
}
|
||||
}
|
||||
|
||||
//apply rule for players trampling tilled soil back to dirt (never allow it)
|
||||
//NOTE: that this event applies only to players. monsters and animals can still trample.
|
||||
else if(event.getAction() == Action.PHYSICAL && clickedBlockType == Material.SOIL)
|
||||
{
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//apply rule for note blocks and repeaters
|
||||
else if(clickedBlockType == Material.NOTE_BLOCK || clickedBlockType == Material.DIODE_BLOCK_ON || clickedBlockType == Material.DIODE_BLOCK_OFF)
|
||||
{
|
||||
|
|
@ -1819,24 +1817,14 @@ class PlayerEventHandler implements Listener
|
|||
}
|
||||
}
|
||||
|
||||
static Block getTargetBlock(Player player, int maxDistance, Material... passthroughMaterials) throws IllegalStateException
|
||||
static Block getTargetBlock(Player player, int maxDistance) throws IllegalStateException
|
||||
{
|
||||
BlockIterator iterator = new BlockIterator(player.getLocation(), player.getEyeHeight(), maxDistance);
|
||||
Block result = player.getLocation().getBlock().getRelative(BlockFace.UP);
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
result = iterator.next();
|
||||
boolean passthrough = false;
|
||||
for(Material passthroughMaterial : passthroughMaterials)
|
||||
{
|
||||
if(result.getType().equals(passthroughMaterial))
|
||||
{
|
||||
passthrough = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!passthrough) return result;
|
||||
if(result.getType() != Material.AIR) return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user