package com.bioxx.jmapgen.graph; import java.util.*; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import com.bioxx.jmapgen.BiomeType; import com.bioxx.jmapgen.IslandMap; import com.bioxx.jmapgen.Point; import com.bioxx.jmapgen.attributes.Attribute; import com.bioxx.jmapgen.attributes.RiverAttribute; import com.bioxx.tfc2.api.types.Moisture; public class Center { public int index; public Point point; // location private EnumSet<Marker> flags = EnumSet.noneOf(Marker.class); public BiomeType biome; public double elevation = 0; // 0.0-1.0 private float moisture = 0; // 0.0-1.0 public Center downslope; // pointer to adjacent center most downhill public Vector<Center> neighbors; public Vector<Edge> borders; public Vector<Corner> corners; public HashMap<UUID, Attribute> attribMap; private NBTTagCompound customNBT; public Center() { index = 0; neighbors = new Vector<Center>(); borders = new Vector<Edge>(); corners = new Vector<Corner>(); attribMap = new HashMap<UUID, Attribute>(); customNBT = new NBTTagCompound(); } public Center(int i) { this(); index = i; } public float getMoistureRaw() { return this.moisture; } public void setMoistureRaw(double d) { this.moisture = (float)d; } public void setMoistureRaw(float d) { this.moisture = d; } public double getElevation() { return this.elevation; } public void setElevation(double d) { this.elevation = d; } public void setMarkers(Marker... m) { for(Marker mk : m) flags.add(mk); } public boolean hasMarker(Marker m) { return flags.contains(m); } public boolean hasAnyMarkersOf(Marker... m) { for(Marker mk : m) if(flags.contains(mk)) return true; return false; } public void removeMarkers(Marker... m) { for(Marker mk : m) flags.remove(mk); } public void resetMarkers() { flags.clear(); } public Attribute getAttribute(UUID id) { return attribMap.get(id); } public boolean hasAttribute(UUID id) { return attribMap.containsKey(id); } public boolean addAttribute(Attribute a) { if(attribMap.containsKey(a.id)) return false; attribMap.put(a.id, a); return true; } public double getAverageElevation() { double sum = elevation; int total = 1; for(Center n : neighbors) { total++; sum += n.getElevation(); } sum/=total; return sum; } public Center getClosestNeighbor(Point p) { double angle = (Math.atan2((p.y - point.y) , (p.x - point.x)) * 180 / Math.PI) - 30; if((angle >= 330 || angle < 30) && neighbors.size() > 0) return neighbors.get(0); if(angle < 90 && neighbors.size() > 1) return neighbors.get(1); if(angle < 150 && neighbors.size() > 2) return neighbors.get(2); if(angle < 210 && neighbors.size() > 3) return neighbors.get(3); if(angle < 270 && neighbors.size() > 4) return neighbors.get(4); if(angle < 330 && neighbors.size() >= 5) return neighbors.get(5); return this; } public Center getNeighbor(HexDirection dir) { switch(dir) { case North: return neighbors.size() > 1 ? neighbors.get(1) : null; case NorthEast: return neighbors.size() > 2 ? neighbors.get(2) : null; case SouthEast: return neighbors.size() > 3 ? neighbors.get(3) : null; case South: return neighbors.size() > 4 ? neighbors.get(4) : null; case SouthWest: return neighbors.size() > 5 ? neighbors.get(5) : null; case NorthWest: return neighbors.size() > 0 ? neighbors.get(0) : null; default: return neighbors.get(0); } } public HexDirection getDirection(Center c) { for(HexDirection n : HexDirection.values()) { if(getNeighbor(n) == c) return n; } return null; } public Center getRandomNeighbor(Random r) { return neighbors.get(r.nextInt(neighbors.size())); } public Center getRandomNeighborExcept(Random r, Center c) { Center out = getRandomNeighbor(r); while(out == c) out = getRandomNeighbor(r); return out; } public Center getHighestNeighbor() { Center highest = this; for(Iterator<Center> centerIter2 = neighbors.iterator(); centerIter2.hasNext();) { Center center2 = (Center)centerIter2.next(); if(highest == null || center2.elevation > highest.elevation) highest = center2; } RiverAttribute attrib = ((RiverAttribute)getAttribute(Attribute.River)); if(attrib != null && attrib.upriver != null) { highest = getHighestFromGroup(attrib.upriver); } return highest; } public Center getLowestNeighbor() { Center lowest = this; for(Iterator<Center> centerIter2 = neighbors.iterator(); centerIter2.hasNext();) { Center center2 = (Center)centerIter2.next(); if(lowest == null || center2.elevation < lowest.elevation) lowest = center2; } RiverAttribute attrib = ((RiverAttribute)getAttribute(Attribute.River)); if(attrib != null && attrib.getDownRiver() != null) lowest = attrib.getDownRiver(); return lowest; } public Center getLowestFromGroup(Vector<Center> group) { Center lowest = group.get(0); for(Iterator<Center> centerIter2 = group.iterator(); centerIter2.hasNext();) { Center center2 = (Center)centerIter2.next(); if(lowest == null || center2.elevation < lowest.elevation) lowest = center2; } return lowest; } public Center getHighestFromGroup(Vector<Center> group) { Center highest = group.get(0); for(Iterator<Center> centerIter2 = group.iterator(); centerIter2.hasNext();) { Center center2 = (Center)centerIter2.next(); if(highest == null || center2.elevation > highest.elevation) highest = center2; } return highest; } public Center getRandomFromGroup(Random r, Vector<Center> centers) { if(centers.size() == 0) return null; return centers.get(r.nextInt(centers.size())); } public Vector<Center> getOnlyHigherCenters() { Vector<Center> out = new Vector<Center>(); for(Center c : neighbors) if(c.getElevation() > getElevation()) out.add(c); return out; } public Corner getClosestCorner(Point p) { Corner closest = corners.get(0); double distance = p.distanceSq(corners.get(0).point); for (int i = 1; i < corners.size(); i++) { double newDist = p.distanceSq(corners.get(i).point); if(newDist < distance) { distance = newDist; closest = corners.get(i); } } return closest; } /** * Returns an edge shared between two centers. May return null if neighbors are not supplied. */ public Edge getSharedEdge(Center c) { for(Edge e : borders) { if(e.dCenter0 == this && e.dCenter1 == c) return e; if(e.dCenter1 == this && e.dCenter0 == c) return e; } return null; } public Moisture getMoisture() { return Moisture.fromVal(moisture); } public void writeToNBT(NBTTagCompound nbt) { nbt.setInteger("index", index); nbt.setInteger("biome", biome.ordinal()); nbt.setDouble("xCoord", point.x); nbt.setDouble("yCoord", point.y); long f = 0; for(Marker ff : flags) { f += ff.getFlag(); } nbt.setLong("flags", f); nbt.setDouble("elevation", elevation); nbt.setFloat("moisture", moisture); if(downslope != null) nbt.setInteger("downslope", downslope.index); int[] nArray = new int[neighbors.size()]; for(int i = 0; i < nArray.length; i++) { nArray[i] = neighbors.get(i).index; } nbt.setIntArray("neighbors", nArray); nArray = new int[corners.size()]; for(int i = 0; i < nArray.length; i++) { nArray[i] = corners.get(i).index; } nbt.setIntArray("corners", nArray); nArray = new int[borders.size()]; for(int i = 0; i < nArray.length; i++) { nArray[i] = borders.get(i).index; } nbt.setIntArray("borders", nArray); Iterator<Attribute> iter = attribMap.values().iterator(); NBTTagList attribList = new NBTTagList(); while(iter.hasNext()) { Attribute a = iter.next(); NBTTagCompound attribNBT = new NBTTagCompound(); attribNBT.setString("class", a.getClass().getName()); a.writeToNBT(attribNBT); attribList.appendTag(attribNBT); } nbt.setTag("attribMap", attribList); nbt.setTag("CustomData", this.customNBT); } public void readFromNBT(NBTTagCompound nbt, IslandMap m) { try { biome = BiomeType.values()[nbt.getInteger("biome")]; point = new Point(nbt.getDouble("xCoord"), nbt.getDouble("yCoord")); setMarkers(nbt.getLong("flags")); elevation = nbt.getDouble("elevation"); moisture = nbt.getFloat("moisture"); if(nbt.hasKey("downslope")) downslope = m.centers.get(nbt.getInteger("downslope")); int[] nArray = nbt.getIntArray("neighbors"); for(int i = 0; i < nArray.length; i++) { this.neighbors.add(m.centers.get(nArray[i])); } nArray = nbt.getIntArray("corners"); for(int i = 0; i < nArray.length; i++) { this.corners.add(m.corners.get(nArray[i])); } nArray = nbt.getIntArray("borders"); for(int i = 0; i < nArray.length; i++) { this.borders.add(m.edges.get(nArray[i])); } if(nbt.hasKey("attribMap")) { NBTTagList list = nbt.getTagList("attribMap", 10); for(int i = 0; i < list.tagCount(); i++) { NBTTagCompound aNBT = list.getCompoundTagAt(i); Object o = Class.forName(aNBT.getString("class")).newInstance(); ((Attribute)o).readFromNBT(aNBT, m); this.attribMap.put(((Attribute)o).id, (Attribute)o); } } this.customNBT = nbt.getCompoundTag("CustomData"); } catch (Exception e) { e.printStackTrace(); } } /** * @return Access to an nbt tag used specifically for saving custom data to a hex. */ public NBTTagCompound getCustomNBT() { return this.customNBT; } /** * Used for reading stored nbt information */ private void setMarkers(long i) { for(Marker f : Marker.values()) { if((i & f.getFlag()) > 0) { flags.add(f); } } } public enum Marker { Water(1), Ocean(2), Coast(3), CoastWater(4), Border(5), Lava(6), Valley(7), SmallCrater(8), Pond(9), Spire(10), Volcano(11); long flag; Marker(int f) { //Sets it to a bit flag flag = 1 << f; } public long getFlag() { return flag; } } public enum HexDirection { NorthWest(0), North(1), NorthEast(2), SouthEast(3), South(4), SouthWest(5); int order; HexDirection (int o) { order = o; } public HexDirection getOpposite() { switch(this) { case North: return South; case South: return North; case NorthEast: return SouthWest; case NorthWest: return SouthEast; case SouthEast: return NorthWest; case SouthWest: return NorthEast; default: return North; } } public HexDirection getNextClockwise() { if( order == 5) return values()[0]; else return values()[order+1]; } public HexDirection getNextCounterClockwise() { if( order == 0) return values()[5]; else return values()[order-1]; } public HexDirection getRandomTurnSmall(Random r, boolean mid) { int rand = mid ? 5 : 4; switch(r.nextInt(rand)) { case 0: return getNextClockwise(); case 1: return getNextCounterClockwise(); default: return this; } } public HexDirection getRandomTurnSmall(Random r) { return getRandomTurnSmall(r, true); } public HexDirection getRandomTurnBig(Random r, boolean mid) { int rand = mid ? 5 : 4; switch(r.nextInt(rand)) { case 0: return getNextClockwise(); case 1: return getNextCounterClockwise(); case 2: return getNextClockwise().getNextClockwise(); case 3: return getNextCounterClockwise().getNextCounterClockwise(); default: return this; } } public HexDirection getRandomTurnBig(Random r) { return getRandomTurnBig(r, true); } public int getOrder() { return order; } } }