diff --git a/src/main/java/com/sk89q/worldguard/bukkit/BukkitRegionQueryCache.java b/src/main/java/com/sk89q/worldguard/bukkit/BukkitRegionQueryCache.java new file mode 100644 index 00000000..06a8d9ee --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/bukkit/BukkitRegionQueryCache.java @@ -0,0 +1,99 @@ +// $Id$ +/* + * This file is a part of WorldGuard. + * Copyright (c) sk89q + * Copyright (c) the WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * (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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . +*/ + +package com.sk89q.worldguard.bukkit; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.Event; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.GlobalRegionManager; +import com.sk89q.worldguard.protection.RegionQueryCache; + +/** + * An implementation of {@link RegionQueryCache} for Bukkit. This implementation is + * thread-safe. + */ +public class BukkitRegionQueryCache extends RegionQueryCache { + + private final WorldGuardPlugin plugin; + + /** + * Construct the cache with the given plugin instance. + * + * @param plugin plugin instance + */ + public BukkitRegionQueryCache(WorldGuardPlugin plugin) { + this.plugin = plugin; + } + + /** + * Get an {@link ApplicableRegionSet} for a given location. The result may have been + * temporarily cached for the given event, or null if region protection has + * been disabled for the the world of the given location. + * + * @param event the event to cache against + * @param location the location to check + * @return the set, or null if region protection is disabled for the given location + */ + public ApplicableRegionSet lookup(Event event, Location location) { + World world = location.getWorld(); + Vector vector = BukkitUtil.toVector(location); + + ConfigurationManager config = plugin.getGlobalStateManager(); + WorldConfiguration worldConfig = config.get(world); + GlobalRegionManager regionManager = plugin.getGlobalRegionManager(); + + if (!worldConfig.useRegions) { + return null; + } + + return get(event).lookup(regionManager.get(world), vector); + } + + /** + * Get an {@link ApplicableRegionSet} for a given block. The result may have been + * temporarily cached for the given event, or null if region protection has + * been disabled for the the world of the given block. + * + * @param event the event to cache against + * @param block the block to check + * @return the set, or null if region protection is disabled for the given block + */ + public ApplicableRegionSet lookup(Event event, Block block) { + return lookup(event, block.getLocation()); + } + + /** + * Get an {@link ApplicableRegionSet} for a given entity. The result may have been + * temporarily cached for the given event, or null if region protection has + * been disabled for the the world of the given entity. + * + * @param event the event to cache against + * @param entity the entity to check + * @return the set, or null if region protection is disabled for the given entity + */ + public ApplicableRegionSet lookup(Event event, Entity entity) { + return lookup(event, entity.getLocation()); + } + +} diff --git a/src/main/java/com/sk89q/worldguard/protection/RegionQueryCache.java b/src/main/java/com/sk89q/worldguard/protection/RegionQueryCache.java new file mode 100644 index 00000000..4c826446 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/protection/RegionQueryCache.java @@ -0,0 +1,62 @@ +// $Id$ +/* + * This file is a part of WorldGuard. + * Copyright (c) sk89q + * Copyright (c) the WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * (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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . +*/ + +package com.sk89q.worldguard.protection; + +import java.util.WeakHashMap; + +/** + * To facilitate performing regions-containing-point lookups from multiple stack frames + * but within the same context (the same event), a cache is important in preventing the + * need for redundant lookups made for the same point. This class serves as such a cache. + *

+ * A key needs to be selected to store cache entries against. The best key is one that + * is highly temporal, and would represent a certain "snapshot in time," such as + * an event object. The event objects are indexed in this class using weak references, + * and they will be removed by the garbage collector automatically. Because it + * is a weak reference, the key object needs to be held somewhere with a strong + * reference until the "snapshot" ends. + *

+ * This class is abstract because implementing class should provide methods to check + * against a standard key object. This cache itself is thread-safe. + */ +public abstract class RegionQueryCache { + + private final WeakHashMap cache = + new WeakHashMap(); + + public RegionQueryCache() { + } + + /** + * Get the {@link RegionQueryCacheEntry} object that will cache the + * {@link ApplicableRegionSet}s for this context. + * + * @param key a standard key to store by + * @return an existing QueryCacheEntry or a new one + */ + protected synchronized RegionQueryCacheEntry get(Object key) { + RegionQueryCacheEntry entry = cache.get(key); + if (entry == null) { + entry = new RegionQueryCacheEntry(); + cache.put(key, entry); + } + return entry; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/protection/RegionQueryCacheEntry.java b/src/main/java/com/sk89q/worldguard/protection/RegionQueryCacheEntry.java new file mode 100644 index 00000000..ccf96372 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/protection/RegionQueryCacheEntry.java @@ -0,0 +1,76 @@ +// $Id$ +/* + * This file is a part of WorldGuard. + * Copyright (c) sk89q + * Copyright (c) the WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * (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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . +*/ + +package com.sk89q.worldguard.protection; + +import java.util.HashMap; +import java.util.Map; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; + +/** + * An object to cache a list of {@link ApplicableRegionSet}s. This class is + * thread-safe. + * + * @see RegionQueryCache + */ +public class RegionQueryCacheEntry { + + private final Map cachedPoints = + new HashMap(); + + RegionQueryCacheEntry() { + } + + /** + * Get an {@link ApplicableRegionSet} for a given point. If a lookup already has + * been performed, a cached result will be returned. + * + * @param manager the manager + * @param location the location to lookup + * @return the applicable region set + */ + public synchronized ApplicableRegionSet lookup(RegionManager manager, Vector location) { + BlockVector hashableLocation = location.toBlockVector(); + ApplicableRegionSet set = cachedPoints.get(hashableLocation); + if (set == null) { + set = manager.getApplicableRegions(location); + cachedPoints.put(hashableLocation, set); + } + return set; + } + + /** + * Get an {@link ApplicableRegionSet} for a given region. This method does not yet + * cache results. + * + * @param manager + * the manager + * @param region + * the area to lookup + * @return the applicable region set + */ + public synchronized ApplicableRegionSet lookup(RegionManager manager, + ProtectedRegion region) { + return manager.getApplicableRegions(region); + } + +}