Performance: Claim Lookup
Major perf improvement for claim search.
This commit is contained in:
parent
195afef302
commit
04d628b01e
|
|
@ -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<Chunk> 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<Chunk> getChunks()
|
||||
{
|
||||
ArrayList<Chunk> chunks = new ArrayList<Chunk>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public abstract class DataStore
|
|||
|
||||
//in-memory cache for claim data
|
||||
ArrayList<Claim> claims = new ArrayList<Claim>();
|
||||
ConcurrentHashMap<String, ArrayList<Claim>> chunksToClaimsMap = new ConcurrentHashMap<String, ArrayList<Claim>>();
|
||||
|
||||
//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<Chunk> chunks = newClaim.getChunks();
|
||||
for(Chunk chunk : chunks)
|
||||
{
|
||||
String chunkID = this.getChunkString(chunk);
|
||||
ArrayList<Claim> claimsInChunk = this.chunksToClaimsMap.get(chunkID);
|
||||
if(claimsInChunk == null)
|
||||
{
|
||||
claimsInChunk = new ArrayList<Claim>();
|
||||
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<Chunk> chunks = claim.getChunks();
|
||||
for(Chunk chunk : chunks)
|
||||
{
|
||||
String chunkID = this.getChunkString(chunk);
|
||||
ArrayList<Claim> 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<Claim> 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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<Chunk> 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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user