package com.intellectualcrafters.plot.object.worlds; import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.PlotArea; import com.intellectualcrafters.plot.object.RegionWrapper; import com.intellectualcrafters.plot.util.StringMan; import com.intellectualcrafters.plot.util.area.QuadMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; public class DefaultPlotAreaManager implements PlotAreaManager { // All plot areas private PlotArea[] plotAreas = new PlotArea[0]; // All plot areas mapped by world private final HashMap<String, PlotArea[]> plotAreaMap = new HashMap<>(); // All plot areas mapped by position private final HashMap<String, QuadMap<PlotArea>> plotAreaGrid = new HashMap<>(); // Optimization if there are no hash collisions private boolean plotAreaHasCollision = false; private final HashSet<Integer> plotAreaHashCheck = new HashSet<>(); protected final PlotArea[] noPlotAreas = new PlotArea[0]; private String[] worlds = new String[0]; @Override public PlotArea[] getAllPlotAreas() { return plotAreas; } @Override public PlotArea getApplicablePlotArea(Location location) { switch (this.plotAreas.length) { case 0: return null; case 1: return this.plotAreas[0]; case 2: case 3: case 4: case 5: case 6: case 7: case 8: String world = location.getWorld(); int hash = world.hashCode(); for (PlotArea area : this.plotAreas) { if (hash == area.worldhash) { if (area.contains(location.getX(), location.getZ()) && (!this.plotAreaHasCollision || world.equals(area.worldname))) { return area; } } } return null; default: PlotArea[] areas = this.plotAreaMap.get(location.getWorld()); if (areas == null) { return null; } int y; int x; switch (areas.length) { case 1: return areas[0]; case 2: case 3: case 4: case 5: case 6: case 7: case 8: x = location.getX(); y = location.getY(); for (PlotArea area : areas) { if (area.contains(x, y)) { return area; } } return null; default: QuadMap<PlotArea> search = this.plotAreaGrid.get(location.getWorld()); return search.get(location.getX(), location.getZ()); } } } @Override public void addPlotArea(PlotArea plotArea) { HashSet<PlotArea> localAreas = new HashSet<>(Arrays.asList(getPlotAreas(plotArea.worldname, null))); HashSet<PlotArea> globalAreas = new HashSet<>(Arrays.asList(plotAreas)); localAreas.add(plotArea); globalAreas.add(plotArea); this.plotAreas = globalAreas.toArray(new PlotArea[globalAreas.size()]); this.plotAreaMap.put(plotArea.worldname, localAreas.toArray(new PlotArea[localAreas.size()])); QuadMap<PlotArea> map = this.plotAreaGrid.get(plotArea.worldname); if (map == null) { map = new QuadMap<PlotArea>(Integer.MAX_VALUE, 0, 0) { @Override public RegionWrapper getRegion(PlotArea value) { return value.getRegion(); } }; this.plotAreaGrid.put(plotArea.worldname, map); } map.add(plotArea); } @Override public void removePlotArea(PlotArea area) { ArrayList<PlotArea> globalAreas = new ArrayList<PlotArea>(Arrays.asList(plotAreas)); globalAreas.remove(area); this.plotAreas = globalAreas.toArray(new PlotArea[globalAreas.size()]); if (globalAreas.isEmpty()) { this.plotAreaMap.remove(area.worldname); this.plotAreaGrid.remove(area.worldname); } else { this.plotAreaMap.put(area.worldname, globalAreas.toArray(new PlotArea[globalAreas.size()])); this.plotAreaGrid.get(area.worldname).remove(area); } } @Override public PlotArea getPlotArea(String world, String id) { PlotArea[] areas = this.plotAreaMap.get(world); if (areas == null) { return null; } if (areas.length == 1) { return areas[0]; } else if (id == null) { return null; } for (PlotArea area : areas) { if (StringMan.isEqual(id, area.id)) { return area; } } return null; } @Override public PlotArea getPlotArea(Location location) { switch (this.plotAreas.length) { case 0: return null; case 1: PlotArea pa = this.plotAreas[0]; return pa.contains(location) ? pa : null; case 2: case 3: case 4: case 5: case 6: case 7: case 8: String world = location.getWorld(); int hash = world.hashCode(); for (PlotArea area : this.plotAreas) { if (hash == area.worldhash) { if (area.contains(location.getX(), location.getZ()) && (!this.plotAreaHasCollision || world.equals(area.worldname))) { return area; } } } return null; default: PlotArea[] areas = this.plotAreaMap.get(location.getWorld()); if (areas == null) { return null; } int x; int y; switch (areas.length) { case 0: PlotArea a = areas[0]; return a.contains(location.getX(), location.getZ()) ? a : null; case 2: case 3: case 4: case 5: case 6: case 7: case 8: x = location.getX(); y = location.getY(); for (PlotArea area : areas) { if (area.contains(x, y)) { return area; } } return null; default: QuadMap<PlotArea> search = this.plotAreaGrid.get(location.getWorld()); return search.get(location.getX(), location.getZ()); } } } @Override public PlotArea[] getPlotAreas(String world, RegionWrapper region) { if (region == null) { PlotArea[] areas = this.plotAreaMap.get(world); if (areas == null) { return noPlotAreas; } return areas; } QuadMap<PlotArea> areas = this.plotAreaGrid.get(world); if (areas == null) { return noPlotAreas; } else { Set<PlotArea> found = areas.get(region); return found.toArray(new PlotArea[found.size()]); } } @Override public void addWorld(String worldName) { if (!this.plotAreaHasCollision && !this.plotAreaHashCheck.add(worldName.hashCode())) { this.plotAreaHasCollision = true; } Set<String> tmp = new LinkedHashSet<>(); Collections.addAll(tmp, worlds); tmp.add(worldName); worlds = tmp.toArray(new String[tmp.size()]); } @Override public void removeWorld(String worldName) { Set<String> tmp = new LinkedHashSet<>(); Collections.addAll(tmp, worlds); tmp.remove(worldName); worlds = tmp.toArray(new String[tmp.size()]); } @Override public String[] getAllWorlds() { return worlds; } }