diff --git a/src/me/ryanhamshire/GriefPrevention/Claim.java b/src/me/ryanhamshire/GriefPrevention/Claim.java index 23891ef..aae4aaf 100644 --- a/src/me/ryanhamshire/GriefPrevention/Claim.java +++ b/src/me/ryanhamshire/GriefPrevention/Claim.java @@ -18,13 +18,6 @@ package me.ryanhamshire.GriefPrevention; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; import java.util.*; import org.bukkit.*; @@ -735,25 +728,21 @@ public class Claim if(maxEntities == 0) return GriefPrevention.instance.dataStore.getMessage(Messages.ClaimTooSmallForEntities); //count current entities (ignoring players) - Chunk lesserChunk = this.getLesserBoundaryCorner().getChunk(); - Chunk greaterChunk = this.getGreaterBoundaryCorner().getChunk(); - int totalEntities = 0; - for(int x = lesserChunk.getX(); x <= greaterChunk.getX(); x++) - for(int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++) + ArrayList chunks = this.getChunks(); + for(Chunk chunk : chunks) + { + Entity [] entities = chunk.getEntities(); + for(int i = 0; i < entities.length; i++) { - Chunk chunk = lesserChunk.getWorld().getChunkAt(x, z); - Entity [] entities = chunk.getEntities(); - for(int i = 0; i < entities.length; i++) + Entity entity = entities[i]; + if(!(entity instanceof Player) && this.contains(entity.getLocation(), false, false)) { - Entity entity = entities[i]; - if(!(entity instanceof Player) && this.contains(entity.getLocation(), false, false)) - { - totalEntities++; - if(totalEntities > maxEntities) entity.remove(); - } + totalEntities++; + if(totalEntities > maxEntities) entity.remove(); } } + } if(totalEntities > maxEntities) return GriefPrevention.instance.dataStore.getMessage(Messages.TooManyEntitiesInClaim); @@ -833,4 +822,23 @@ public class Claim return (long)score; } + + public ArrayList getChunks() + { + ArrayList chunks = new ArrayList(); + + World world = this.getLesserBoundaryCorner().getWorld(); + Chunk lesserChunk = this.getLesserBoundaryCorner().getChunk(); + Chunk greaterChunk = this.getGreaterBoundaryCorner().getChunk(); + + for(int x = lesserChunk.getX(); x <= greaterChunk.getX(); x++) + { + for(int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++) + { + chunks.add(world.getChunkAt(x, z)); + } + } + + return chunks; + } } diff --git a/src/me/ryanhamshire/GriefPrevention/DataStore.java b/src/me/ryanhamshire/GriefPrevention/DataStore.java index eb32779..b9f83b4 100644 --- a/src/me/ryanhamshire/GriefPrevention/DataStore.java +++ b/src/me/ryanhamshire/GriefPrevention/DataStore.java @@ -40,6 +40,7 @@ public abstract class DataStore //in-memory cache for claim data ArrayList claims = new ArrayList(); + ConcurrentHashMap> chunksToClaimsMap = new ConcurrentHashMap>(); //in-memory cache for messages private String [] messages; @@ -197,7 +198,7 @@ public abstract class DataStore } //adds a claim to the datastore, making it an effective claim - synchronized void addClaim(Claim newClaim) + synchronized void addClaim(Claim newClaim, boolean writeToStorage) { //subdivisions are easy if(newClaim.parent != null) @@ -209,12 +210,21 @@ public abstract class DataStore } //add it and mark it as added - int j = 0; - while(j < this.claims.size() && !this.claims.get(j).greaterThan(newClaim)) j++; - if(j < this.claims.size()) - this.claims.add(j, newClaim); - else - this.claims.add(this.claims.size(), newClaim); + this.claims.add(newClaim); + ArrayList chunks = newClaim.getChunks(); + for(Chunk chunk : chunks) + { + String chunkID = this.getChunkString(chunk); + ArrayList claimsInChunk = this.chunksToClaimsMap.get(chunkID); + if(claimsInChunk == null) + { + claimsInChunk = new ArrayList(); + this.chunksToClaimsMap.put(chunkID, claimsInChunk); + } + + claimsInChunk.add(newClaim); + } + newClaim.inDataStore = true; //except for administrative claims (which have no owner), update the owner's playerData with the new claim @@ -226,7 +236,10 @@ public abstract class DataStore } //make sure the claim is saved to disk - this.saveClaim(newClaim); + if(writeToStorage) + { + this.saveClaim(newClaim); + } } //turns a location into a string, useful in data storage @@ -360,6 +373,21 @@ public abstract class DataStore } break; } + + ArrayList chunks = claim.getChunks(); + for(Chunk chunk : chunks) + { + String chunkID = this.getChunkString(chunk); + ArrayList claimsInChunk = this.chunksToClaimsMap.get(chunkID); + for(int j = 0; j < claimsInChunk.size(); j++) + { + if(claimsInChunk.get(j).id.equals(claim.id)) + { + claimsInChunk.remove(j); + break; + } + } + } } //remove from secondary storage @@ -391,40 +419,41 @@ public abstract class DataStore //check cachedClaim guess first. if it's in the datastore and the location is inside it, we're done if(cachedClaim != null && cachedClaim.inDataStore && cachedClaim.contains(location, ignoreHeight, true)) return cachedClaim; - //the claims list is ordered by greater boundary corner - //create a temporary "fake" claim in memory for comparison purposes - Claim tempClaim = new Claim(); - tempClaim.lesserBoundaryCorner = location; + //find a top level claim + String chunkID = this.getChunkString(location.getChunk()); + ArrayList claimsInChunk = this.chunksToClaimsMap.get(chunkID); + if(claimsInChunk == null) return null; - //otherwise, search all existing claims until we find the right claim - for(int i = 0; i < this.claims.size(); i++) + for(Claim claim : claimsInChunk) { - Claim claim = this.claims.get(i); - - //if we reach a claim which is greater than the temp claim created above, there's definitely no claim - //in the collection which includes our location - if(claim.greaterThan(tempClaim)) return null; - - //find a top level claim - if(claim.contains(location, ignoreHeight, false)) - { - //when we find a top level claim, if the location is in one of its subdivisions, - //return the SUBDIVISION, not the top level claim - for(int j = 0; j < claim.children.size(); j++) - { - Claim subdivision = claim.children.get(j); - if(subdivision.contains(location, ignoreHeight, false)) return subdivision; - } - - return claim; - } + if(claim.contains(location, ignoreHeight, false)) + { + //when we find a top level claim, if the location is in one of its subdivisions, + //return the SUBDIVISION, not the top level claim + for(int j = 0; j < claim.children.size(); j++) + { + Claim subdivision = claim.children.get(j); + if(subdivision.contains(location, ignoreHeight, false)) return subdivision; + } + + return claim; + } } //if no claim found, return null return null; } - //creates a claim. + //gets a unique, persistent identifier string for a chunk + private String getChunkString(Chunk chunk) + { + return String.format("%s;%d;%d", + chunk.getWorld().getName(), + chunk.getX(), + chunk.getZ()); + } + + //creates a claim. //if the new claim would overlap an existing claim, returns a failure along with a reference to the existing claim //otherwise, returns a success along with a reference to the new claim //use ownerName == "" for administrative claims @@ -518,7 +547,7 @@ public abstract class DataStore } //otherwise add this new claim to the data store to make it effective - this.addClaim(newClaim); + this.addClaim(newClaim, true); //then return success along with reference to new claim result.succeeded = true; @@ -557,7 +586,7 @@ public abstract class DataStore } //save changes - this.addClaim(claim); + this.addClaim(claim, true); } //starts a siege on a claim @@ -833,7 +862,7 @@ public abstract class DataStore else { //put original claim back - this.addClaim(claim); + this.addClaim(claim, true); } return result; diff --git a/src/me/ryanhamshire/GriefPrevention/DatabaseDataStore.java b/src/me/ryanhamshire/GriefPrevention/DatabaseDataStore.java index ba64c36..5779807 100644 --- a/src/me/ryanhamshire/GriefPrevention/DatabaseDataStore.java +++ b/src/me/ryanhamshire/GriefPrevention/DatabaseDataStore.java @@ -212,13 +212,7 @@ public class DatabaseDataStore extends DataStore //otherwise, add this claim to the claims collection else { - int j = 0; - while(j < this.claims.size() && !this.claims.get(j).greaterThan(topLevelClaim)) j++; - if(j < this.claims.size()) - this.claims.add(j, topLevelClaim); - else - this.claims.add(this.claims.size(), topLevelClaim); - topLevelClaim.inDataStore = true; + this.addClaim(topLevelClaim, false); } //look for any subdivisions for this claim diff --git a/src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java b/src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java index 96c9cc7..3e8a0ef 100644 --- a/src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java +++ b/src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java @@ -265,13 +265,7 @@ public class FlatFileDataStore extends DataStore else { topLevelClaim.modifiedDate = new Date(files[i].lastModified()); - int j = 0; - while(j < this.claims.size() && !this.claims.get(j).greaterThan(topLevelClaim)) j++; - if(j < this.claims.size()) - this.claims.add(j, topLevelClaim); - else - this.claims.add(this.claims.size(), topLevelClaim); - topLevelClaim.inDataStore = true; + this.addClaim(topLevelClaim, false); } } @@ -662,7 +656,7 @@ public class FlatFileDataStore extends DataStore for(int i = 0; i < this.claims.size(); i++) { Claim claim = this.claims.get(i); - databaseStore.addClaim(claim); + databaseStore.addClaim(claim, true); } //migrate groups diff --git a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java index ac6c0a3..8c293e6 100644 --- a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -2660,15 +2660,11 @@ public class GriefPrevention extends JavaPlugin //it's too expensive to do this for huge claims if(claim.getArea() > 10000) return; - Chunk lesserChunk = claim.getLesserBoundaryCorner().getChunk(); - Chunk greaterChunk = claim.getGreaterBoundaryCorner().getChunk(); - - for(int x = lesserChunk.getX(); x <= greaterChunk.getX(); x++) - for(int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++) - { - Chunk chunk = lesserChunk.getWorld().getChunkAt(x, z); - this.restoreChunk(chunk, this.getSeaLevel(chunk.getWorld()) - 15, false, delayInTicks, null); - } + 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) diff --git a/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index c6b1039..893cd25 100644 --- a/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -1071,6 +1071,7 @@ class PlayerEventHandler implements Listener if( GriefPrevention.instance.config_claims_preventTheft && ( event.getAction() == Action.RIGHT_CLICK_BLOCK && ( clickedBlock.getState() instanceof InventoryHolder || + clickedBlock.getType() == Material.ANVIL || 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 diff --git a/src/me/ryanhamshire/GriefPrevention/Visualization.java b/src/me/ryanhamshire/GriefPrevention/Visualization.java index 6e307be..28c70ce 100644 --- a/src/me/ryanhamshire/GriefPrevention/Visualization.java +++ b/src/me/ryanhamshire/GriefPrevention/Visualization.java @@ -48,7 +48,7 @@ public class Visualization //if he's online, create a task to send him the visualization in about half a second if(player.isOnline()) { - GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, new VisualizationApplicationTask(player, playerData, visualization), 10L); + GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, new VisualizationApplicationTask(player, playerData, visualization), 1L); } } @@ -215,13 +215,7 @@ public class Visualization private static boolean isTransparent(Block block) { return ( block.getType() == Material.AIR || - block.getType() == Material.LONG_GRASS || block.getType() == Material.FENCE || - block.getType() == Material.LEAVES || - block.getType() == Material.RED_ROSE || - block.getType() == Material.CHEST || - block.getType() == Material.TORCH || - block.getType() == Material.VINE || - block.getType() == Material.YELLOW_FLOWER ); + block.getType().isTransparent()); } }