mirror of
https://github.com/EngineHub/WorldGuard.git
synced 2024-11-03 01:19:42 +01:00
Add a hash table index for regions that hashes on chunk coordinates.
This commit is contained in:
parent
eb23e28c16
commit
38587a1c61
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.sk89q.worldguard.bukkit.listener;
|
package com.sk89q.worldguard.bukkit.listener;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||||
import com.sk89q.worldguard.bukkit.event.block.BreakBlockEvent;
|
import com.sk89q.worldguard.bukkit.event.block.BreakBlockEvent;
|
||||||
import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
|
import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
|
||||||
@ -30,13 +31,19 @@
|
|||||||
import com.sk89q.worldguard.bukkit.util.Materials;
|
import com.sk89q.worldguard.bukkit.util.Materials;
|
||||||
import com.sk89q.worldguard.bukkit.util.RegionQuery;
|
import com.sk89q.worldguard.bukkit.util.RegionQuery;
|
||||||
import com.sk89q.worldguard.protection.flags.DefaultFlag;
|
import com.sk89q.worldguard.protection.flags.DefaultFlag;
|
||||||
|
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.world.ChunkLoadEvent;
|
||||||
|
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||||
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
|
import org.bukkit.event.world.WorldUnloadEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle events that need to be processed by region protection.
|
* Handle events that need to be processed by region protection.
|
||||||
@ -56,6 +63,34 @@ private void tellErrorMessage(CommandSender sender, Object subject) {
|
|||||||
sender.sendMessage(ChatColor.DARK_RED + "You don't have permission for this area.");
|
sender.sendMessage(ChatColor.DARK_RED + "You don't have permission for this area.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onWorldLoad(WorldLoadEvent event) {
|
||||||
|
getPlugin().getGlobalRegionManager().load(event.getWorld());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onWorldUnload(WorldUnloadEvent event) {
|
||||||
|
getPlugin().getGlobalRegionManager().unload(event.getWorld());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onChunkLoad(ChunkLoadEvent event) {
|
||||||
|
RegionManager manager = getPlugin().getGlobalRegionManager().get(event.getWorld());
|
||||||
|
if (manager != null) {
|
||||||
|
Chunk chunk = event.getChunk();
|
||||||
|
manager.loadChunk(new Vector2D(chunk.getX(), chunk.getZ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onChunkUnload(ChunkUnloadEvent event) {
|
||||||
|
RegionManager manager = getPlugin().getGlobalRegionManager().get(event.getWorld());
|
||||||
|
if (manager != null) {
|
||||||
|
Chunk chunk = event.getChunk();
|
||||||
|
manager.unloadChunk(new Vector2D(chunk.getX(), chunk.getZ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onPlaceBlock(PlaceBlockEvent event) {
|
public void onPlaceBlock(PlaceBlockEvent event) {
|
||||||
Player player = event.getCause().getPlayerRootCause();
|
Player player = event.getCause().getPlayerRootCause();
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.sk89q.worldguard.protection;
|
package com.sk89q.worldguard.protection;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
import com.sk89q.worldguard.LocalPlayer;
|
import com.sk89q.worldguard.LocalPlayer;
|
||||||
import com.sk89q.worldguard.bukkit.BukkitUtil;
|
import com.sk89q.worldguard.bukkit.BukkitUtil;
|
||||||
import com.sk89q.worldguard.bukkit.ConfigurationManager;
|
import com.sk89q.worldguard.bukkit.ConfigurationManager;
|
||||||
@ -26,14 +27,17 @@
|
|||||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||||
import com.sk89q.worldguard.protection.flags.StateFlag;
|
import com.sk89q.worldguard.protection.flags.StateFlag;
|
||||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.sk89q.worldguard.bukkit.BukkitUtil.toVector;
|
import static com.sk89q.worldguard.bukkit.BukkitUtil.toVector;
|
||||||
|
|
||||||
public class GlobalRegionManager {
|
public class GlobalRegionManager {
|
||||||
@ -50,7 +54,16 @@ public GlobalRegionManager(WorldGuardPlugin plugin) {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public RegionManager load(World world) {
|
public RegionManager load(World world) {
|
||||||
return container.load(world.getName());
|
checkNotNull(world);
|
||||||
|
RegionManager manager = container.load(world.getName());
|
||||||
|
if (manager != null) {
|
||||||
|
List<Vector2D> positions = new ArrayList<Vector2D>();
|
||||||
|
for (Chunk chunk : world.getLoadedChunks()) {
|
||||||
|
positions.add(new Vector2D(chunk.getX(), chunk.getZ()));
|
||||||
|
}
|
||||||
|
manager.loadChunks(positions);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void preload() {
|
public void preload() {
|
||||||
@ -59,6 +72,10 @@ public void preload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unload(World world) {
|
||||||
|
unload(world.getName());
|
||||||
|
}
|
||||||
|
|
||||||
public void unload(String name) {
|
public void unload(String name) {
|
||||||
container.unload(name);
|
container.unload(name);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.sk89q.worldguard.bukkit.ConfigurationManager;
|
import com.sk89q.worldguard.bukkit.ConfigurationManager;
|
||||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||||
|
import com.sk89q.worldguard.protection.managers.index.ChunkHashTable;
|
||||||
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
|
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
|
||||||
import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
|
import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
|
||||||
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
|
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
|
||||||
@ -57,7 +58,7 @@ class ManagerContainer {
|
|||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
private final EnumMap<DriverType, RegionStoreDriver> drivers = new EnumMap<DriverType, RegionStoreDriver>(DriverType.class);
|
private final EnumMap<DriverType, RegionStoreDriver> drivers = new EnumMap<DriverType, RegionStoreDriver>(DriverType.class);
|
||||||
private final RegionStoreDriver defaultDriver;
|
private final RegionStoreDriver defaultDriver;
|
||||||
private final Supplier<? extends ConcurrentRegionIndex> indexFactory = new PriorityRTreeIndex.Factory();
|
private final Supplier<? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
|
||||||
private final Timer timer = new Timer();
|
private final Timer timer = new Timer();
|
||||||
|
|
||||||
ManagerContainer(ConfigurationManager config) {
|
ManagerContainer(ConfigurationManager config) {
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
import com.sk89q.worldguard.LocalPlayer;
|
import com.sk89q.worldguard.LocalPlayer;
|
||||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||||
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
|
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
|
||||||
@ -29,6 +30,7 @@
|
|||||||
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
|
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
|
||||||
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
|
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
|
||||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||||
|
import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
|
||||||
import com.sk89q.worldguard.util.Normal;
|
import com.sk89q.worldguard.util.Normal;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -113,6 +115,33 @@ public void saveChanges() throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the regions for a chunk.
|
||||||
|
*
|
||||||
|
* @param position the position
|
||||||
|
*/
|
||||||
|
public void loadChunk(Vector2D position) {
|
||||||
|
index.bias(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the regions for a chunk.
|
||||||
|
*
|
||||||
|
* @param positions a collection of positions
|
||||||
|
*/
|
||||||
|
public void loadChunks(Collection<Vector2D> positions) {
|
||||||
|
index.biasAll(positions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload the regions for a chunk.
|
||||||
|
*
|
||||||
|
* @param position the position
|
||||||
|
*/
|
||||||
|
public void unloadChunk(Vector2D position) {
|
||||||
|
index.forget(position);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an unmodifiable map of regions containing the state of the
|
* Get an unmodifiable map of regions containing the state of the
|
||||||
* index at the time of call.
|
* index at the time of call.
|
||||||
|
@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
* WorldGuard, a suite of tools for Minecraft
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) 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 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 Lesser 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldguard.protection.managers.index;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import com.sk89q.odeum.concurrent.EvenMoreExecutors;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
|
import com.sk89q.worldguard.protection.managers.RegionDifference;
|
||||||
|
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
|
||||||
|
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||||
|
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||||
|
import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
|
||||||
|
import com.sk89q.worldguard.util.collect.LongHashTable;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maintains a hash table for each chunk containing a list of regions that
|
||||||
|
* are contained within that chunk, allowing for fast spatial lookup.
|
||||||
|
*/
|
||||||
|
public class ChunkHashTable implements ConcurrentRegionIndex {
|
||||||
|
|
||||||
|
private ListeningExecutorService executor = createExecutor();
|
||||||
|
private LongHashTable<ChunkState> states = new LongHashTable<ChunkState>();
|
||||||
|
private final RegionIndex index;
|
||||||
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
*
|
||||||
|
* @param index the index
|
||||||
|
*/
|
||||||
|
public ChunkHashTable(RegionIndex index) {
|
||||||
|
checkNotNull(index);
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an executor.
|
||||||
|
*
|
||||||
|
* @return an executor service
|
||||||
|
*/
|
||||||
|
private ListeningExecutorService createExecutor() {
|
||||||
|
return MoreExecutors.listeningDecorator(
|
||||||
|
EvenMoreExecutors.newBoundedCachedThreadPool(0, 4, Integer.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a state object at the given position.
|
||||||
|
*
|
||||||
|
* @param position the position
|
||||||
|
* @param create true to create an entry if one does not exist
|
||||||
|
* @return a chunk state object, or {@code null} (only if {@code create} is false)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private ChunkState get(Vector2D position, boolean create) {
|
||||||
|
ChunkState state;
|
||||||
|
synchronized (lock) {
|
||||||
|
state = states.get(position.getBlockX(), position.getBlockZ());
|
||||||
|
if (state == null && create) {
|
||||||
|
state = new ChunkState(position);
|
||||||
|
states.put(position.getBlockX(), position.getBlockZ(), state);
|
||||||
|
executor.submit(new EnumerateRegions(position));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a state at the given position or create a new entry if one does
|
||||||
|
* not exist.
|
||||||
|
*
|
||||||
|
* @param position the position
|
||||||
|
* @return a state
|
||||||
|
*/
|
||||||
|
private ChunkState getOrCreate(Vector2D position) {
|
||||||
|
return get(position, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the current hash table and rebuild it in the background.
|
||||||
|
*/
|
||||||
|
private void rebuild() {
|
||||||
|
synchronized (lock) {
|
||||||
|
ListeningExecutorService previousExecutor = executor;
|
||||||
|
LongHashTable<ChunkState> previousStates = states;
|
||||||
|
|
||||||
|
previousExecutor.shutdownNow();
|
||||||
|
states = new LongHashTable<ChunkState>();
|
||||||
|
executor = createExecutor();
|
||||||
|
|
||||||
|
List<Vector2D> positions = new ArrayList<Vector2D>();
|
||||||
|
for (ChunkState state : previousStates.values()) {
|
||||||
|
Vector2D position = state.getPosition();
|
||||||
|
positions.add(position);
|
||||||
|
states.put(position.getBlockX(), position.getBlockZ(), new ChunkState(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!positions.isEmpty()) {
|
||||||
|
executor.submit(new EnumerateRegions(positions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bias(Vector2D chunkPosition) {
|
||||||
|
checkNotNull(chunkPosition);
|
||||||
|
getOrCreate(chunkPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void biasAll(Collection<Vector2D> chunkPositions) {
|
||||||
|
synchronized (lock) {
|
||||||
|
for (Vector2D position : chunkPositions) {
|
||||||
|
bias(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forget(Vector2D chunkPosition) {
|
||||||
|
checkNotNull(chunkPosition);
|
||||||
|
synchronized (lock) {
|
||||||
|
states.remove(chunkPosition.getBlockX(), chunkPosition.getBlockZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forgetAll() {
|
||||||
|
synchronized (lock) {
|
||||||
|
executor.shutdownNow();
|
||||||
|
states = new LongHashTable<ChunkState>();
|
||||||
|
executor = createExecutor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(ProtectedRegion region) {
|
||||||
|
index.add(region);
|
||||||
|
rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAll(Collection<ProtectedRegion> regions) {
|
||||||
|
index.addAll(regions);
|
||||||
|
rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<ProtectedRegion> remove(String id, RemovalStrategy strategy) {
|
||||||
|
Set<ProtectedRegion> removed = index.remove(id, strategy);
|
||||||
|
rebuild();
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(String id) {
|
||||||
|
return index.contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public ProtectedRegion get(String id) {
|
||||||
|
return index.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(Predicate<ProtectedRegion> consumer) {
|
||||||
|
index.apply(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyContaining(Vector position, Predicate<ProtectedRegion> consumer) {
|
||||||
|
checkNotNull(position);
|
||||||
|
checkNotNull(consumer);
|
||||||
|
|
||||||
|
ChunkState state = get(new Vector2D(position.getBlockX() >> 4, position.getBlockZ() >> 4), false);
|
||||||
|
if (state != null && state.isLoaded()) {
|
||||||
|
for (ProtectedRegion region : state.getRegions()) {
|
||||||
|
if (region.contains(position)) {
|
||||||
|
consumer.apply(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index.applyContaining(position, consumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyIntersecting(ProtectedRegion region, Predicate<ProtectedRegion> consumer) {
|
||||||
|
index.applyIntersecting(region, consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return index.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RegionDifference getAndClearDifference() {
|
||||||
|
return index.getAndClearDifference();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ProtectedRegion> values() {
|
||||||
|
return index.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDirty() {
|
||||||
|
return index.isDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDirty(boolean dirty) {
|
||||||
|
index.setDirty(dirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task to enumerate the regions for a list of provided chunks.
|
||||||
|
*/
|
||||||
|
private class EnumerateRegions implements Runnable {
|
||||||
|
private final List<Vector2D> positions;
|
||||||
|
|
||||||
|
private EnumerateRegions(Vector2D position) {
|
||||||
|
this(Arrays.asList(checkNotNull(position)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnumerateRegions(List<Vector2D> positions) {
|
||||||
|
checkNotNull(positions);
|
||||||
|
checkArgument(!positions.isEmpty(), "List of positions can't be empty");
|
||||||
|
this.positions = positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (Vector2D position : positions) {
|
||||||
|
ChunkState state = get(position, false);
|
||||||
|
|
||||||
|
if (state != null) {
|
||||||
|
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();
|
||||||
|
ProtectedRegion chunkRegion = new ProtectedCuboidRegion(
|
||||||
|
"_",
|
||||||
|
position.toVector(0).toBlockVector(),
|
||||||
|
position.add(16, 16).toVector(Integer.MAX_VALUE).toBlockVector());
|
||||||
|
index.applyIntersecting(chunkRegion, new RegionCollectionConsumer(regions, false));
|
||||||
|
|
||||||
|
state.setRegions(Collections.unmodifiableList(regions));
|
||||||
|
|
||||||
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a cache of region data for a chunk.
|
||||||
|
*/
|
||||||
|
private class ChunkState {
|
||||||
|
private final Vector2D position;
|
||||||
|
private boolean loaded = false;
|
||||||
|
private List<ProtectedRegion> regions = Collections.emptyList();
|
||||||
|
|
||||||
|
private ChunkState(Vector2D position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2D getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProtectedRegion> getRegions() {
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegions(List<ProtectedRegion> regions) {
|
||||||
|
this.regions = regions;
|
||||||
|
this.loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoaded() {
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory for instances of {@code ChunkHashCache}.
|
||||||
|
*/
|
||||||
|
public static class Factory implements Supplier<ChunkHashTable> {
|
||||||
|
private final Supplier<? extends ConcurrentRegionIndex> supplier;
|
||||||
|
|
||||||
|
public Factory(Supplier<? extends ConcurrentRegionIndex> supplier) {
|
||||||
|
checkNotNull(supplier);
|
||||||
|
this.supplier = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkHashTable get() {
|
||||||
|
return new ChunkHashTable(supplier.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,6 +22,7 @@
|
|||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
import com.sk89q.worldguard.protection.managers.RegionDifference;
|
import com.sk89q.worldguard.protection.managers.RegionDifference;
|
||||||
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
|
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
|
||||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||||
@ -102,6 +103,26 @@ public void addAll(Collection<ProtectedRegion> regions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bias(Vector2D chunkPosition) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void biasAll(Collection<Vector2D> chunkPositions) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forget(Vector2D chunkPosition) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forgetAll() {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(ProtectedRegion region) {
|
public void add(ProtectedRegion region) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
import com.sk89q.worldguard.protection.managers.RegionDifference;
|
import com.sk89q.worldguard.protection.managers.RegionDifference;
|
||||||
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
|
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
|
||||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||||
@ -39,6 +40,37 @@
|
|||||||
*/
|
*/
|
||||||
public interface RegionIndex extends ChangeTracked {
|
public interface RegionIndex extends ChangeTracked {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bias the given chunk for faster lookups (put it in a hash table, etc.).
|
||||||
|
*
|
||||||
|
* <p>Implementations may choose to do nothing.</p>
|
||||||
|
*
|
||||||
|
* @param chunkPosition the chunk position
|
||||||
|
*/
|
||||||
|
void bias(Vector2D chunkPosition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bias the given chunk for faster lookups (put it in a hash table, etc.).
|
||||||
|
*
|
||||||
|
* <p>Implementations may choose to do nothing.</p>
|
||||||
|
*
|
||||||
|
* @param chunkPosition the chunk position
|
||||||
|
*/
|
||||||
|
void biasAll(Collection<Vector2D> chunkPosition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No longer bias the given chunk for faster lookup.
|
||||||
|
*
|
||||||
|
* @param chunkPosition the chunk position
|
||||||
|
*/
|
||||||
|
void forget(Vector2D chunkPosition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clearly all extra cache data created by any calls to
|
||||||
|
* {@link #bias(Vector2D)}.
|
||||||
|
*/
|
||||||
|
void forgetAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a region to this index, replacing any existing one with the same
|
* Add a region to this index, replacing any existing one with the same
|
||||||
* name (equality determined using {@link Normal}).
|
* name (equality determined using {@link Normal}).
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.sk89q.worldguard.protection.managers;
|
package com.sk89q.worldguard.protection.util;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||||
@ -33,7 +33,7 @@
|
|||||||
* to the collection, although it may result in duplicates in the collection
|
* to the collection, although it may result in duplicates in the collection
|
||||||
* if the collection is not a set.</p>
|
* if the collection is not a set.</p>
|
||||||
*/
|
*/
|
||||||
class RegionCollectionConsumer implements Predicate<ProtectedRegion> {
|
public class RegionCollectionConsumer implements Predicate<ProtectedRegion> {
|
||||||
|
|
||||||
private final Collection<ProtectedRegion> collection;
|
private final Collection<ProtectedRegion> collection;
|
||||||
private final boolean addParents;
|
private final boolean addParents;
|
||||||
@ -44,7 +44,7 @@ class RegionCollectionConsumer implements Predicate<ProtectedRegion> {
|
|||||||
* @param collection the collection to add regions to
|
* @param collection the collection to add regions to
|
||||||
* @param addParents true to also add the parents to the collection
|
* @param addParents true to also add the parents to the collection
|
||||||
*/
|
*/
|
||||||
RegionCollectionConsumer(Collection<ProtectedRegion> collection, boolean addParents) {
|
public RegionCollectionConsumer(Collection<ProtectedRegion> collection, boolean addParents) {
|
||||||
checkNotNull(collection);
|
checkNotNull(collection);
|
||||||
|
|
||||||
this.collection = collection;
|
this.collection = collection;
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* WorldGuard, a suite of tools for Minecraft
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) 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 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 Lesser 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldguard.util.collect;
|
||||||
|
|
||||||
|
public class EntryBase {
|
||||||
|
|
||||||
|
protected long key;
|
||||||
|
|
||||||
|
public EntryBase(long key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* WorldGuard, a suite of tools for Minecraft
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) 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 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 Lesser 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldguard.util.collect;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class LongBaseHashTable extends LongHash {
|
||||||
|
|
||||||
|
EntryBase[][][] values = new EntryBase[256][][];
|
||||||
|
EntryBase cache = null;
|
||||||
|
|
||||||
|
public void put(int msw, int lsw, EntryBase entry) {
|
||||||
|
put(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntryBase getEntry(int msw, int lsw) {
|
||||||
|
return getEntry(toLong(msw, lsw));
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void put(EntryBase entry) {
|
||||||
|
int mainIdx = (int) (entry.key & 255);
|
||||||
|
EntryBase[][] outer = this.values[mainIdx];
|
||||||
|
if (outer == null) this.values[mainIdx] = outer = new EntryBase[256][];
|
||||||
|
|
||||||
|
int outerIdx = (int) ((entry.key >> 32) & 255);
|
||||||
|
EntryBase[] inner = outer[outerIdx];
|
||||||
|
|
||||||
|
if (inner == null) {
|
||||||
|
outer[outerIdx] = inner = new EntryBase[5];
|
||||||
|
inner[0] = this.cache = entry;
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < inner.length; i++) {
|
||||||
|
if (inner[i] == null || inner[i].key == entry.key) {
|
||||||
|
inner[i] = this.cache = entry;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outer[outerIdx] = inner = Arrays.copyOf(inner, i + i);
|
||||||
|
inner[i] = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized EntryBase getEntry(long key) {
|
||||||
|
return containsKey(key) ? cache : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean containsKey(long key) {
|
||||||
|
if (this.cache != null && cache.key == key) return true;
|
||||||
|
|
||||||
|
int outerIdx = (int) ((key >> 32) & 255);
|
||||||
|
EntryBase[][] outer = this.values[(int) (key & 255)];
|
||||||
|
if (outer == null) return false;
|
||||||
|
|
||||||
|
EntryBase[] inner = outer[outerIdx];
|
||||||
|
if (inner == null) return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < inner.length; i++) {
|
||||||
|
EntryBase e = inner[i];
|
||||||
|
if (e == null) {
|
||||||
|
return false;
|
||||||
|
} else if (e.key == key) {
|
||||||
|
this.cache = e;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void remove(long key) {
|
||||||
|
EntryBase[][] outer = this.values[(int) (key & 255)];
|
||||||
|
if (outer == null) return;
|
||||||
|
|
||||||
|
EntryBase[] inner = outer[(int) ((key >> 32) & 255)];
|
||||||
|
if (inner == null) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < inner.length; i++) {
|
||||||
|
if (inner[i] == null) continue;
|
||||||
|
|
||||||
|
if (inner[i].key == key) {
|
||||||
|
for (i++; i < inner.length; i++) {
|
||||||
|
if (inner[i] == null) break;
|
||||||
|
inner[i - 1] = inner[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
inner[i-1] = null;
|
||||||
|
this.cache = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized ArrayList<EntryBase> entries() {
|
||||||
|
ArrayList<EntryBase> ret = new ArrayList<EntryBase>();
|
||||||
|
|
||||||
|
for (EntryBase[][] outer : this.values) {
|
||||||
|
if (outer == null) continue;
|
||||||
|
|
||||||
|
for (EntryBase[] inner : outer) {
|
||||||
|
if (inner == null) continue;
|
||||||
|
|
||||||
|
for (EntryBase entry : inner) {
|
||||||
|
if (entry == null) break;
|
||||||
|
|
||||||
|
ret.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* WorldGuard, a suite of tools for Minecraft
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) 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 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 Lesser 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldguard.util.collect;
|
||||||
|
|
||||||
|
public abstract class LongHash {
|
||||||
|
|
||||||
|
public static long toLong(int msw, int lsw) {
|
||||||
|
return ((long) msw << 32) + lsw - Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int msw(long l) {
|
||||||
|
return (int) (l >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int lsw(long l) {
|
||||||
|
return (int) (l & 0xFFFFFFFF) + Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsKey(int msw, int lsw) {
|
||||||
|
return containsKey(toLong(msw, lsw));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(int msw, int lsw) {
|
||||||
|
remove(toLong(msw, lsw));
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean containsKey(long key);
|
||||||
|
|
||||||
|
public abstract void remove(long key);
|
||||||
|
|
||||||
|
}
|
199
src/main/java/com/sk89q/worldguard/util/collect/LongHashSet.java
Normal file
199
src/main/java/com/sk89q/worldguard/util/collect/LongHashSet.java
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* WorldGuard, a suite of tools for Minecraft
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) 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 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 Lesser 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldguard.util.collect;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||||
|
|
||||||
|
public class LongHashSet extends LongHash {
|
||||||
|
|
||||||
|
protected long[][][] values = new long[256][][];
|
||||||
|
protected int count = 0;
|
||||||
|
protected ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||||
|
protected ReadLock rl = rwl.readLock();
|
||||||
|
protected WriteLock wl = rwl.writeLock();
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
rl.lock();
|
||||||
|
try {
|
||||||
|
return this.count == 0;
|
||||||
|
} finally {
|
||||||
|
rl.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(int msw, int lsw) {
|
||||||
|
add(toLong(msw, lsw));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(long key) {
|
||||||
|
wl.lock();
|
||||||
|
try {
|
||||||
|
int mainIdx = (int) (key & 255);
|
||||||
|
long outer[][] = this.values[mainIdx];
|
||||||
|
if (outer == null) this.values[mainIdx] = outer = new long[256][];
|
||||||
|
|
||||||
|
int outerIdx = (int) ((key >> 32) & 255);
|
||||||
|
long inner[] = outer[outerIdx];
|
||||||
|
|
||||||
|
if (inner == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
outer[outerIdx] = inner = new long[1];
|
||||||
|
inner[0] = key;
|
||||||
|
this.count++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < inner.length; i++) {
|
||||||
|
if (inner[i] == key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inner = Arrays.copyOf(inner, i + 1);
|
||||||
|
outer[outerIdx] = inner;
|
||||||
|
inner[i] = key;
|
||||||
|
this.count++;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
wl.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsKey(long key) {
|
||||||
|
rl.lock();
|
||||||
|
try {
|
||||||
|
long[][] outer = this.values[(int) (key & 255)];
|
||||||
|
if (outer == null) return false;
|
||||||
|
|
||||||
|
long[] inner = outer[(int) ((key >> 32) & 255)];
|
||||||
|
if (inner == null) return false;
|
||||||
|
|
||||||
|
for (long entry : inner) {
|
||||||
|
if (entry == key) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
rl.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(long key) {
|
||||||
|
wl.lock();
|
||||||
|
try {
|
||||||
|
long[][] outer = this.values[(int) (key & 255)];
|
||||||
|
if (outer == null) return;
|
||||||
|
|
||||||
|
long[] inner = outer[(int) ((key >> 32) & 255)];
|
||||||
|
if (inner == null) return;
|
||||||
|
|
||||||
|
int max = inner.length - 1;
|
||||||
|
for (int i = 0; i <= max; i++) {
|
||||||
|
if (inner[i] == key) {
|
||||||
|
this.count--;
|
||||||
|
if (i != max) {
|
||||||
|
inner[i] = inner[max];
|
||||||
|
}
|
||||||
|
|
||||||
|
outer[(int) ((key >> 32) & 255)] = (max == 0 ? null : Arrays.copyOf(inner, max));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
wl.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long popFirst() {
|
||||||
|
wl.lock();
|
||||||
|
try {
|
||||||
|
for (long[][] outer: this.values) {
|
||||||
|
if (outer == null) continue;
|
||||||
|
|
||||||
|
for (int i = 0; i < outer.length; i++) {
|
||||||
|
long[] inner = outer[i];
|
||||||
|
if (inner == null || inner.length == 0) continue;
|
||||||
|
|
||||||
|
this.count--;
|
||||||
|
long ret = inner[inner.length - 1];
|
||||||
|
outer[i] = Arrays.copyOf(inner, inner.length - 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
wl.unlock();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long[] popAll() {
|
||||||
|
int index = 0;
|
||||||
|
wl.lock();
|
||||||
|
try {
|
||||||
|
long[] ret = new long[this.count];
|
||||||
|
for (long[][] outer : this.values) {
|
||||||
|
if (outer == null) continue;
|
||||||
|
|
||||||
|
for (int oIdx = outer.length - 1; oIdx >= 0; oIdx--) {
|
||||||
|
long[] inner = outer[oIdx];
|
||||||
|
if (inner == null) continue;
|
||||||
|
|
||||||
|
for (long entry: inner) {
|
||||||
|
ret[index++] = entry;
|
||||||
|
}
|
||||||
|
outer[oIdx] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
return ret;
|
||||||
|
} finally {
|
||||||
|
wl.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long[] keys() {
|
||||||
|
int index = 0;
|
||||||
|
rl.lock();
|
||||||
|
try {
|
||||||
|
long[] ret = new long[this.count];
|
||||||
|
for (long[][] outer : this.values) {
|
||||||
|
if (outer == null) continue;
|
||||||
|
|
||||||
|
for (long[] inner : outer) {
|
||||||
|
if (inner == null) continue;
|
||||||
|
|
||||||
|
for (long entry : inner) {
|
||||||
|
ret[index++] = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} finally {
|
||||||
|
rl.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* WorldGuard, a suite of tools for Minecraft
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) 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 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 Lesser 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldguard.util.collect;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class LongHashTable<V> extends LongBaseHashTable {
|
||||||
|
|
||||||
|
public void put(int msw, int lsw, V value) {
|
||||||
|
put(toLong(msw, lsw), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V get(int msw, int lsw) {
|
||||||
|
return get(toLong(msw, lsw));
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void put(long key, V value) {
|
||||||
|
put(new Entry(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public synchronized V get(long key) {
|
||||||
|
Entry entry = ((Entry) getEntry(key));
|
||||||
|
return entry != null ? entry.value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public synchronized ArrayList<V> values() {
|
||||||
|
ArrayList<V> ret = new ArrayList<V>();
|
||||||
|
|
||||||
|
ArrayList<EntryBase> entries = entries();
|
||||||
|
|
||||||
|
for (EntryBase entry : entries) {
|
||||||
|
ret.add(((Entry) entry).value);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Entry extends EntryBase {
|
||||||
|
V value;
|
||||||
|
|
||||||
|
Entry(long k, V v) {
|
||||||
|
super(k);
|
||||||
|
this.value = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user