123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- package me.km.plots;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.EOFException;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- import java.util.UUID;
- import java.util.function.Predicate;
- import java.util.stream.Collectors;
- public class PlotMap {
- public static class Plot {
- private Plot previous = null;
- private Plot next = null;
- private final int id;
- private final int minX;
- private final int minY;
- private final int minZ;
- private final int maxX;
- private final int maxY;
- private final int maxZ;
- private final ArrayList<UUID> owners = new ArrayList<>(1);
- private int flags = 0;
- private String name = "";
- public Plot(int id, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
- minX = Math.min(32000, Math.max(-32000, minX));
- minY = Math.min(32000, Math.max(-32000, minY));
- minZ = Math.min(32000, Math.max(-32000, minZ));
- maxX = Math.min(32000, Math.max(-32000, maxX));
- maxY = Math.min(32000, Math.max(-32000, maxY));
- maxZ = Math.min(32000, Math.max(-32000, maxZ));
- this.id = id;
- if(minX < maxX) {
- this.minX = minX;
- this.maxX = maxX;
- } else {
- this.minX = maxX;
- this.maxX = minX;
- }
- if(minY < maxY) {
- this.minY = minY;
- this.maxY = maxY;
- } else {
- this.minY = maxY;
- this.maxY = minY;
- }
- if(minZ < maxZ) {
- this.minZ = minZ;
- this.maxZ = maxZ;
- } else {
- this.minZ = maxZ;
- this.maxZ = minZ;
- }
- }
- private boolean isInside(int x, int y, int z) {
- return minX <= x && x <= maxX && minY <= y && y <= maxY && minZ <= z && z <= maxZ;
- }
- public int getMinX() {
- return minX;
- }
- public int getMinY() {
- return minY;
- }
- public int getMinZ() {
- return minZ;
- }
- public int getMaxX() {
- return maxX;
- }
- public int getMaxY() {
- return maxY;
- }
- public int getMaxZ() {
- return maxZ;
- }
- public int getFlags() {
- return flags;
- }
- public boolean hasFlags(int flags) {
- return (flags & this.flags) == flags;
- }
- public void setFlag(int flags, boolean b) {
- if(b) {
- this.flags |= flags;
- } else {
- this.flags &= ~flags;
- }
- }
- public ArrayList<UUID> getOwners() {
- return owners;
- }
- public void setName(String s) {
- name = s;
- }
- public String getName() {
- return name;
- }
- public int getId() {
- return id;
- }
- @Override
- public String toString() {
- return String.format("Plot(%d, %d, %d, %d, %d, %d)", minX, minY, minZ, maxX, maxY,
- maxZ);
- }
- }
- private static int idCounter = 0;
- private static final int SIZE_FACTOR = 64;
- private final static int[] PRIMES = {17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911,
- 43853, 87719, 175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671,
- 44917381, 89834777, 179669557, 359339171, 718678369};
- private int primeIndex = 0;
- private int size = 0;
- @SuppressWarnings("unchecked")
- private ArrayList<Plot>[] plots = new ArrayList[PRIMES[primeIndex]];
- private Plot last = null;
- public PlotMap() {}
- private int hash(int x, int z, int arrayLength) {
- int h = (x + z * 12195263) % arrayLength;
- if(h < 0) {
- return h + arrayLength;
- }
- return h;
- }
- private void rehash() {
- // load factor 0.75
- if(size < (plots.length * 3 / 4) || primeIndex + 1 >= PRIMES.length) {
- return;
- }
- primeIndex++;
- @SuppressWarnings("unchecked")
- ArrayList<Plot>[] newPlots = new ArrayList[PRIMES[primeIndex]];
- Plot p = last;
- while(p != null) {
- addIntern(newPlots, p, newPlots.length);
- p = p.previous;
- }
- plots = newPlots;
- }
- private void addIntern(ArrayList<Plot>[] data, Plot p, int arrayLength) {
- int startX = Math.floorDiv(p.minX, SIZE_FACTOR);
- int startZ = Math.floorDiv(p.minZ, SIZE_FACTOR);
- int endX = Math.floorDiv(p.maxX, SIZE_FACTOR);
- int endZ = Math.floorDiv(p.maxZ, SIZE_FACTOR);
- for(int x = startX; x <= endX; x++) {
- for(int z = startZ; z <= endZ; z++) {
- int hash = hash(x, z, arrayLength);
- if(data[hash] == null) {
- data[hash] = new ArrayList<>();
- }
- if(!data[hash].contains(p)) {
- data[hash].add(p);
- }
- }
- }
- }
- public Plot add(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, int id) {
- if(id >= idCounter) {
- idCounter = id + 1;
- }
- Plot p = new Plot(id, minX, minY, minZ, maxX, maxY, maxZ);
- if(last == null) {
- last = p;
- } else {
- last.next = p;
- p.previous = last;
- last = p;
- }
- size++;
- rehash();
- addIntern(plots, p, plots.length);
- return p;
- }
- public Plot add(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
- return add(minX, minY, minZ, maxX, maxY, maxZ, idCounter);
- }
- public List<Plot> getPlotAt(int x, int y, int z) {
- ArrayList<Plot> list = plots[hash(Math.floorDiv(x, SIZE_FACTOR),
- Math.floorDiv(z, SIZE_FACTOR), plots.length)];
- if(list == null) {
- return new ArrayList<>();
- }
- return list.stream().filter(p -> p.isInside(x, y, z)).collect(Collectors.toList());
- }
- public boolean anyPlotMatches(int x, int y, int z, boolean empty, Predicate<Plot> pred) {
- ArrayList<Plot> list = plots[hash(Math.floorDiv(x, SIZE_FACTOR),
- Math.floorDiv(z, SIZE_FACTOR), plots.length)];
- if(list == null) {
- return empty;
- }
- boolean r = empty;
- for(Plot p : list) {
- if(p.isInside(x, y, z)) {
- if(pred.test(p)) {
- return true;
- }
- r = false;
- }
- }
- return r;
- }
- public void remove(Plot p) {
- if(last == p) {
- last = last.previous;
- if(last != null) {
- last.next = null;
- }
- } else {
- if(p.previous != null) {
- p.previous.next = p.next;
- }
- if(p.next != null) {
- p.next.previous = p.previous;
- }
- }
- int startX = Math.floorDiv(p.minX, SIZE_FACTOR);
- int startZ = Math.floorDiv(p.minZ, SIZE_FACTOR);
- int endX = Math.floorDiv(p.maxX, SIZE_FACTOR);
- int endZ = Math.floorDiv(p.maxZ, SIZE_FACTOR);
- for(int x = startX; x <= endX; x++) {
- for(int z = startZ; z <= endZ; z++) {
- int hash = hash(x, z, plots.length);
- if(plots[hash] == null) {
- throw new NullPointerException("plot without list at location");
- }
- plots[hash].remove(p);
- }
- }
- }
- public Iterator<Plot> getIterator() {
- return new Iterator<PlotMap.Plot>() {
- private Plot current = last;
- @Override
- public boolean hasNext() {
- return current != null;
- }
- @Override
- public Plot next() {
- Plot p = current;
- current = current.previous;
- return p;
- }
- };
- }
- public Iterator<Plot> getIterator(UUID uuid) {
- return new Iterator<PlotMap.Plot>() {
- private Plot current = last;
- private boolean gotoNext() {
- if(current == null) {
- return false;
- }
- if(current.getOwners().contains(uuid)) {
- return true;
- }
- while(current.previous != null) {
- current = current.previous;
- if(current.getOwners().contains(uuid)) {
- return true;
- }
- }
- return false;
- }
- @Override
- public boolean hasNext() {
- return gotoNext();
- }
- @Override
- public Plot next() {
- if(!gotoNext()) {
- throw new IllegalStateException("next without a next element");
- }
- Plot p = current;
- current = current.previous;
- return p;
- }
- };
- }
- public void save(String path) {
- File f = new File(path);
- try(DataOutputStream out = new DataOutputStream(new FileOutputStream(f))) {
- Iterator<Plot> iter = getIterator();
- while(iter.hasNext()) {
- Plot p = iter.next();
- out.writeInt(p.id);
- out.writeShort(p.minX);
- out.writeShort(p.minY);
- out.writeShort(p.minZ);
- out.writeShort(p.maxX);
- out.writeShort(p.maxY);
- out.writeShort(p.maxZ);
- int owners = Math.min(127, p.owners.size());
- out.writeByte(owners);
- for(int i = 0; i < owners; i++) {
- out.writeLong(p.owners.get(i).getLeastSignificantBits());
- out.writeLong(p.owners.get(i).getMostSignificantBits());
- }
- out.writeInt(p.flags);
- out.writeUTF(p.name);
- }
- } catch(IOException ex) {
- ex.printStackTrace();
- }
- }
- public void read(File f) {
- if(!f.exists()) {
- return;
- }
- try(DataInputStream in = new DataInputStream(new FileInputStream(f))) {
- while(true) {
- int id = in.readInt();
- int minX = in.readShort();
- int minY = in.readShort();
- int minZ = in.readShort();
- int maxX = in.readShort();
- int maxY = in.readShort();
- int maxZ = in.readShort();
- Plot p = add(minX, minY, minZ, maxX, maxY, maxZ, id);
- int owners = in.readByte();
- for(int i = 0; i < owners; i++) {
- long lsb = in.readLong();
- long msb = in.readLong();
- p.owners.add(new UUID(msb, lsb));
- }
- p.flags = in.readInt();
- p.name = in.readUTF();
- }
- } catch(EOFException ex) {
- } catch(IOException ex) {
- ex.printStackTrace();
- }
- }
- public ArrayList<Plot> getIntersectingPlots(int minX, int minY, int minZ, int maxX, int maxY,
- int maxZ) {
- if(minX > maxX) {
- int tmp = minX;
- minX = maxX;
- maxX = tmp;
- }
- if(minY > maxY) {
- int tmp = minY;
- minY = maxY;
- maxY = tmp;
- }
- if(minZ > maxZ) {
- int tmp = minZ;
- minZ = maxZ;
- maxZ = tmp;
- }
- ArrayList<Plot> list = new ArrayList<>();
- Plot p = last;
- while(p != null) {
- if(maxX > p.minX && p.maxX > minX && maxY > p.minY && p.maxY > minY && maxZ > p.minZ
- && p.maxZ > minZ) {
- list.add(p);
- }
- p = p.previous;
- }
- return list;
- }
- }
|