mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-27 19:19:07 +00:00
Reorganize
This commit is contained in:
6
src/main/java/com/volmit/iris/object/Blueprint.java
Normal file
6
src/main/java/com/volmit/iris/object/Blueprint.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public class Blueprint
|
||||
{
|
||||
|
||||
}
|
||||
8
src/main/java/com/volmit/iris/object/DecorationPart.java
Normal file
8
src/main/java/com/volmit/iris/object/DecorationPart.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum DecorationPart
|
||||
{
|
||||
NONE,
|
||||
SHORE_LINE,
|
||||
SEA_SURFACE
|
||||
}
|
||||
7
src/main/java/com/volmit/iris/object/Dispersion.java
Normal file
7
src/main/java/com/volmit/iris/object/Dispersion.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum Dispersion
|
||||
{
|
||||
SCATTER,
|
||||
WISPY,
|
||||
}
|
||||
8
src/main/java/com/volmit/iris/object/Envelope.java
Normal file
8
src/main/java/com/volmit/iris/object/Envelope.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum Envelope
|
||||
{
|
||||
EVERYWHERE,
|
||||
CELLS,
|
||||
VEINS,
|
||||
}
|
||||
10
src/main/java/com/volmit/iris/object/InferredType.java
Normal file
10
src/main/java/com/volmit/iris/object/InferredType.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum InferredType
|
||||
{
|
||||
SHORE,
|
||||
LAND,
|
||||
SEA,
|
||||
CAVE,
|
||||
DEFER;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
public enum InterpolationMethod
|
||||
{
|
||||
NONE,
|
||||
BILINEAR,
|
||||
BICUBIC,
|
||||
HERMITE
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
|
||||
@Desc("Represents a rotation axis with intervals and maxes")
|
||||
@Data
|
||||
public class IrisAxisRotationClamp
|
||||
{
|
||||
@Desc("Should this axis be rotated at all?")
|
||||
private boolean enabled = false;
|
||||
|
||||
@Desc("The minimum angle (from) or set this and max to zero for any angle degrees")
|
||||
private double min = 0;
|
||||
|
||||
@Desc("The maximum angle (to) or set this and min to zero for any angle degrees")
|
||||
private double max = 0;
|
||||
|
||||
@Desc("Iris spins the axis but not freely. For example an interval of 90 would mean 4 possible angles (right angles) degrees")
|
||||
private double interval = 0;
|
||||
|
||||
public IrisAxisRotationClamp()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IrisAxisRotationClamp(boolean enabled, double min, double max, double interval)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public boolean isUnlimited()
|
||||
{
|
||||
return min == max;
|
||||
}
|
||||
|
||||
public double getRadians(int rng)
|
||||
{
|
||||
if(isUnlimited())
|
||||
{
|
||||
return Math.toRadians((rng * interval) % 360D);
|
||||
}
|
||||
|
||||
double deg = min + (rng * interval) % (Math.abs(max - min) / 360D);
|
||||
return Math.toRadians(deg);
|
||||
}
|
||||
}
|
||||
386
src/main/java/com/volmit/iris/object/IrisBiome.java
Normal file
386
src/main/java/com/volmit/iris/object/IrisBiome.java
Normal file
@@ -0,0 +1,386 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.logging.L;
|
||||
|
||||
@Desc("Represents a biome in iris.")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisBiome extends IrisRegistrant
|
||||
{
|
||||
@Desc("This is the human readable name for this biome. This can and should be different than the file name. This is not used for loading biomes in other objects.")
|
||||
private String name = "A Biome";
|
||||
|
||||
@Desc("This changes the dispersion of the biome colors if multiple derivatives are chosen")
|
||||
private Dispersion biomeDispersion = Dispersion.SCATTER;
|
||||
|
||||
@Desc("This zooms in the biome colors if multiple derivatives are chosen")
|
||||
private double biomeZoom = 1;
|
||||
|
||||
@Desc("Layers no longer descend from the surface block, they descend from the max possible height the biome can produce (constant) creating mesa like layers.")
|
||||
private boolean lockLayers = false;
|
||||
|
||||
@Desc("The rarity of this biome (integer)")
|
||||
private int rarity = 1;
|
||||
|
||||
@Desc("The raw derivative of this biome. This is required or the terrain will not properly generate. Use any vanilla biome type. Look in examples/biome-list.txt")
|
||||
private Biome derivative = Biome.THE_VOID;
|
||||
|
||||
@Desc("You can instead specify multiple biome derivatives to randomly scatter colors in this biome")
|
||||
private KList<Biome> biomeScatter = new KList<>();
|
||||
|
||||
@Desc("Since 1.13 supports 3D biomes, you can add different derivative colors for anything above the terrain. (Think swampy tree leaves with a desert looking grass surface)")
|
||||
private KList<Biome> biomeSkyScatter = new KList<>();
|
||||
|
||||
@Desc("If this biome has children biomes, and the gen layer chooses one of this biomes children, how much smaller will it be (inside of this biome). Higher values means a smaller biome relative to this biome's size. Set higher than 1.0 and below 3.0 for best results.")
|
||||
private double childShrinkFactor = 1.5;
|
||||
|
||||
@Desc("List any biome names (file names without.json) here as children. Portions of this biome can sometimes morph into their children. Iris supports cyclic relationships such as A > B > A > B. Iris will stop checking 9 biomes down the tree.")
|
||||
private KList<String> children = new KList<>();
|
||||
|
||||
@Desc("The default slab if iris decides to place a slab in this biome. Default is no slab.")
|
||||
private IrisBiomePaletteLayer slab = new IrisBiomePaletteLayer().zero();
|
||||
|
||||
@Desc("The default wall if iris decides to place a wall higher than 2 blocks (steep hills or possibly cliffs)")
|
||||
private IrisBiomePaletteLayer wall = new IrisBiomePaletteLayer().zero();
|
||||
|
||||
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
|
||||
private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
|
||||
|
||||
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
|
||||
private KList<IrisBiomePaletteLayer> seaLayers = new KList<IrisBiomePaletteLayer>();
|
||||
|
||||
@Desc("Decorators are used for things like tall grass, bisected flowers, and even kelp or cactus (random heights)")
|
||||
private KList<IrisBiomeDecorator> decorators = new KList<IrisBiomeDecorator>();
|
||||
|
||||
@Desc("Objects define what schematics (iob files) iris will place in this biome")
|
||||
private KList<IrisObjectPlacement> objects = new KList<IrisObjectPlacement>();
|
||||
|
||||
@Desc("Generators for this biome. Multiple generators with different interpolation sizes will mix with other biomes how you would expect. This defines your biome height relative to the fluid height. Use negative for oceans.")
|
||||
private KList<IrisBiomeGeneratorLink> generators = new KList<IrisBiomeGeneratorLink>().qadd(new IrisBiomeGeneratorLink());
|
||||
|
||||
@Desc("Define biome deposit generators that add onto the existing regional and global deposit generators")
|
||||
private KList<IrisDepositGenerator> deposits = new KList<>();
|
||||
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient CellGenerator childrenCell;
|
||||
private transient InferredType inferredType;
|
||||
private transient CNG biomeGenerator;
|
||||
private transient int maxHeight = Integer.MIN_VALUE;
|
||||
private transient KList<BlockData> fullLayerSpec;
|
||||
private transient KList<CNG> layerHeightGenerators;
|
||||
private transient KList<CNG> layerSeaHeightGenerators;
|
||||
private transient KList<CNG> layerSurfaceGenerators;
|
||||
private transient KList<CNG> layerSeaSurfaceGenerators;
|
||||
|
||||
public IrisBiome()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public double getHeight(double x, double z, long seed)
|
||||
{
|
||||
double height = 0;
|
||||
|
||||
for(IrisBiomeGeneratorLink i : generators)
|
||||
{
|
||||
height += i.getHeight(x, z, seed);
|
||||
}
|
||||
|
||||
return Math.max(0, Math.min(height, 255));
|
||||
}
|
||||
|
||||
public CNG getBiomeGenerator(RNG random)
|
||||
{
|
||||
if(biomeGenerator == null)
|
||||
{
|
||||
biomeGenerator = CNG.signature(random.nextParallelRNG(213949 + hashCode())).scale(biomeDispersion.equals(Dispersion.SCATTER) ? 1000D : 0.1D);
|
||||
}
|
||||
|
||||
return biomeGenerator;
|
||||
}
|
||||
|
||||
public CellGenerator getChildrenGenerator(RNG random, int sig, double scale)
|
||||
{
|
||||
if(childrenCell == null)
|
||||
{
|
||||
childrenCell = new CellGenerator(random.nextParallelRNG(sig * 213));
|
||||
childrenCell.setCellScale(scale);
|
||||
}
|
||||
|
||||
return childrenCell;
|
||||
}
|
||||
|
||||
public KList<BlockData> generateLayers(double wx, double wz, RNG random, int maxDepth, int height)
|
||||
{
|
||||
if(isLockLayers())
|
||||
{
|
||||
return generateLockedLayers(wx, wz, random, maxDepth, height);
|
||||
}
|
||||
|
||||
KList<BlockData> data = new KList<>();
|
||||
|
||||
if(maxDepth <= 0)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
for(int i = 0; i < layers.size(); i++)
|
||||
{
|
||||
CNG hgen = getLayerHeightGenerators(random).get(i);
|
||||
int d = hgen.fit(layers.get(i).getMinHeight(), layers.get(i).getMaxHeight(), wx / layers.get(i).getTerrainZoom(), wz / layers.get(i).getTerrainZoom());
|
||||
|
||||
if(d < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < d; j++)
|
||||
{
|
||||
if(data.size() >= maxDepth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data.add(getLayers().get(i).get(random.nextParallelRNG(i + j), (wx + j) / layers.get(i).getTerrainZoom(), j, (wz - j) / layers.get(i).getTerrainZoom()));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
L.ex(e);
|
||||
}
|
||||
}
|
||||
|
||||
if(data.size() >= maxDepth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public KList<BlockData> generateLockedLayers(double wx, double wz, RNG random, int maxDepth, int height)
|
||||
{
|
||||
KList<BlockData> data = new KList<>();
|
||||
KList<BlockData> real = new KList<>();
|
||||
|
||||
if(maxDepth <= 0)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
for(int i = 0; i < layers.size(); i++)
|
||||
{
|
||||
CNG hgen = getLayerHeightGenerators(random).get(i);
|
||||
int d = hgen.fit(layers.get(i).getMinHeight(), layers.get(i).getMaxHeight(), wx / layers.get(i).getTerrainZoom(), wz / layers.get(i).getTerrainZoom());
|
||||
|
||||
if(d < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < d; j++)
|
||||
{
|
||||
try
|
||||
{
|
||||
data.add(getLayers().get(i).get(random.nextParallelRNG(i + j), (wx + j) / layers.get(i).getTerrainZoom(), j, (wz - j) / layers.get(i).getTerrainZoom()));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
L.ex(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(data.isEmpty())
|
||||
{
|
||||
return real;
|
||||
}
|
||||
|
||||
for(int i = 0; i < maxDepth; i++)
|
||||
{
|
||||
int offset = (getMaxHeight() - height) - i;
|
||||
int index = offset % data.size();
|
||||
real.add(data.get(index < 0 ? 0 : index));
|
||||
}
|
||||
|
||||
return real;
|
||||
}
|
||||
|
||||
private int getMaxHeight()
|
||||
{
|
||||
if(maxHeight == Integer.MIN_VALUE)
|
||||
{
|
||||
lock.lock();
|
||||
|
||||
maxHeight = 0;
|
||||
|
||||
for(IrisBiomeGeneratorLink i : getGenerators())
|
||||
{
|
||||
maxHeight += i.getMax();
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
public IrisBiome infer(InferredType t, InferredType type)
|
||||
{
|
||||
setInferredType(t.equals(InferredType.DEFER) ? type : t);
|
||||
return this;
|
||||
}
|
||||
|
||||
public KList<BlockData> generateSeaLayers(double wx, double wz, RNG random, int maxDepth)
|
||||
{
|
||||
KList<BlockData> data = new KList<>();
|
||||
|
||||
for(int i = 0; i < seaLayers.size(); i++)
|
||||
{
|
||||
CNG hgen = getLayerSeaHeightGenerators(random).get(i);
|
||||
int d = hgen.fit(seaLayers.get(i).getMinHeight(), seaLayers.get(i).getMaxHeight(), wx / seaLayers.get(i).getTerrainZoom(), wz / seaLayers.get(i).getTerrainZoom());
|
||||
|
||||
if(d < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < d; j++)
|
||||
{
|
||||
if(data.size() >= maxDepth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
data.add(getSeaLayers().get(i).get(random.nextParallelRNG(i + j), (wx + j) / seaLayers.get(i).getTerrainZoom(), j, (wz - j) / seaLayers.get(i).getTerrainZoom()));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
L.ex(e);
|
||||
}
|
||||
}
|
||||
|
||||
if(data.size() >= maxDepth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public KList<CNG> getLayerHeightGenerators(RNG rng)
|
||||
{
|
||||
lock.lock();
|
||||
if(layerHeightGenerators == null)
|
||||
{
|
||||
layerHeightGenerators = new KList<>();
|
||||
|
||||
int m = 7235;
|
||||
|
||||
for(IrisBiomePaletteLayer i : getLayers())
|
||||
{
|
||||
layerHeightGenerators.add(i.getHeightGenerator(rng.nextParallelRNG((m++) * m * m * m)));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return layerHeightGenerators;
|
||||
}
|
||||
|
||||
public KList<CNG> getLayerSeaHeightGenerators(RNG rng)
|
||||
{
|
||||
lock.lock();
|
||||
if(layerSeaHeightGenerators == null)
|
||||
{
|
||||
layerSeaHeightGenerators = new KList<>();
|
||||
|
||||
int m = 7735;
|
||||
|
||||
for(IrisBiomePaletteLayer i : getSeaLayers())
|
||||
{
|
||||
layerSeaHeightGenerators.add(i.getHeightGenerator(rng.nextParallelRNG((m++) * m * m * m)));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return layerSeaHeightGenerators;
|
||||
}
|
||||
|
||||
public boolean isLand()
|
||||
{
|
||||
if(inferredType == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return inferredType.equals(InferredType.LAND);
|
||||
}
|
||||
|
||||
public boolean isSea()
|
||||
{
|
||||
if(inferredType == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return inferredType.equals(InferredType.SEA);
|
||||
}
|
||||
|
||||
public boolean isShore()
|
||||
{
|
||||
if(inferredType == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return inferredType.equals(InferredType.SHORE);
|
||||
}
|
||||
|
||||
public Biome getSkyBiome(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(biomeSkyScatter.size() == 1)
|
||||
{
|
||||
return biomeSkyScatter.get(0);
|
||||
}
|
||||
|
||||
if(biomeSkyScatter.isEmpty())
|
||||
{
|
||||
return getGroundBiome(rng, x, y, z);
|
||||
}
|
||||
|
||||
return biomeSkyScatter.get(getBiomeGenerator(rng).fit(0, biomeSkyScatter.size() - 1, x, y, z));
|
||||
}
|
||||
|
||||
public Biome getGroundBiome(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(biomeSkyScatter.isEmpty())
|
||||
{
|
||||
return getDerivative();
|
||||
}
|
||||
|
||||
if(biomeScatter.size() == 1)
|
||||
{
|
||||
return biomeScatter.get(0);
|
||||
}
|
||||
|
||||
return biomeScatter.get(getBiomeGenerator(rng).fit(0, biomeScatter.size() - 1, x, y, z));
|
||||
}
|
||||
}
|
||||
153
src/main/java/com/volmit/iris/object/IrisBiomeDecorator.java
Normal file
153
src/main/java/com/volmit/iris/object/IrisBiomeDecorator.java
Normal file
@@ -0,0 +1,153 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Desc("A biome decorator is used for placing flowers, grass, cacti and so on")
|
||||
@Data
|
||||
public class IrisBiomeDecorator
|
||||
{
|
||||
@Desc("The varience dispersion is used when multiple blocks are put in the palette. Scatter scrambles them, Wispy shows streak-looking varience")
|
||||
private Dispersion variance = Dispersion.SCATTER;
|
||||
|
||||
@Desc("Dispersion is used to pick places to spawn. Scatter randomly places them (vanilla) or Wispy for a streak like patch system.")
|
||||
private Dispersion dispersion = Dispersion.SCATTER;
|
||||
|
||||
@Desc("If this decorator has a height more than 1 this changes how it picks the height between your maxes. Scatter = random, Wispy = wavy heights")
|
||||
private Dispersion verticalVariance = Dispersion.SCATTER;
|
||||
|
||||
@Desc("Tells iris where this decoration is a part of. I.e. SHORE_LINE or SEA_SURFACE")
|
||||
private DecorationPart partOf = DecorationPart.NONE;
|
||||
|
||||
@Desc("The minimum repeat stack height (setting to 3 would stack 3 of <block> on top of each other")
|
||||
private int stackMin = 1;
|
||||
|
||||
@Desc("The maximum repeat stack height")
|
||||
private int stackMax = 1;
|
||||
|
||||
@Desc("The zoom is for zooming in or out wispy dispersions. Makes patches bigger the higher this zoom value is/")
|
||||
private double zoom = 1;
|
||||
|
||||
@Desc("The vertical zoom is for wispy stack heights. Zooming this in makes stack heights more slowly change over a distance")
|
||||
private double verticalZoom = 1;
|
||||
|
||||
@Desc("The chance for this decorator to decorate at a given X,Y coordinate. This is hit 256 times per chunk (per surface block)")
|
||||
private double chance = 0.1;
|
||||
|
||||
@Desc("The palette of blocks to pick from when this decorator needs to place.")
|
||||
private KList<String> palette = new KList<String>().qadd("GRASS");
|
||||
|
||||
private transient KMap<Long, CNG> layerGenerators;
|
||||
private transient CNG heightGenerator;
|
||||
private transient KList<BlockData> blockData;
|
||||
private transient RNG nrng;
|
||||
|
||||
public int getHeight(RNG rng, double x, double z)
|
||||
{
|
||||
if(stackMin == stackMax)
|
||||
{
|
||||
return stackMin;
|
||||
}
|
||||
|
||||
return getGenerator(rng).fit(stackMin, stackMax, x * (verticalVariance.equals(Dispersion.SCATTER) ? 1000D : 1D), z * (verticalVariance.equals(Dispersion.SCATTER) ? 1000D : 1D));
|
||||
}
|
||||
|
||||
public CNG getHeightGenerator(RNG rng)
|
||||
{
|
||||
if(heightGenerator == null)
|
||||
{
|
||||
heightGenerator = CNG.signature(rng.nextParallelRNG(getBlockData().size() + stackMax + stackMin)).scale(1D / verticalZoom);
|
||||
}
|
||||
|
||||
return heightGenerator;
|
||||
}
|
||||
|
||||
public CNG getGenerator(RNG rng)
|
||||
{
|
||||
long key = rng.nextParallelRNG(1).nextLong();
|
||||
|
||||
if(layerGenerators == null)
|
||||
{
|
||||
layerGenerators = new KMap<>();
|
||||
}
|
||||
|
||||
if(!layerGenerators.containsKey(key))
|
||||
{
|
||||
layerGenerators.put(key, CNG.signature(rng.nextParallelRNG(getBlockData().size())).scale(1D / zoom));
|
||||
}
|
||||
|
||||
return layerGenerators.get(key);
|
||||
}
|
||||
|
||||
public KList<String> add(String b)
|
||||
{
|
||||
palette.add(b);
|
||||
return palette;
|
||||
}
|
||||
|
||||
public BlockData getBlockData(RNG rng, double x, double z)
|
||||
{
|
||||
if(getGenerator(rng) == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(getBlockData() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(getBlockData().isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(nrng == null)
|
||||
{
|
||||
nrng = rng.nextParallelRNG(2398552 + hashCode());
|
||||
}
|
||||
|
||||
double xx = dispersion.equals(Dispersion.SCATTER) ? nrng.i(-100000, 100000) : x;
|
||||
double zz = dispersion.equals(Dispersion.SCATTER) ? nrng.i(-100000, 100000) : z;
|
||||
|
||||
if(getGenerator(rng).fitDoubleD(0D, 1D, xx, zz) <= chance)
|
||||
{
|
||||
try
|
||||
{
|
||||
return getBlockData().get(getGenerator(rng.nextParallelRNG(53)).fit(0, getBlockData().size() - 1, xx, zz));
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public KList<BlockData> getBlockData()
|
||||
{
|
||||
if(blockData == null)
|
||||
{
|
||||
blockData = new KList<>();
|
||||
for(String i : palette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(i);
|
||||
if(bx != null)
|
||||
{
|
||||
blockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blockData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||
|
||||
@Desc("This represents a link to a generator for a biome")
|
||||
@Data
|
||||
public class IrisBiomeGeneratorLink
|
||||
{
|
||||
@Desc("The generator id")
|
||||
private String generator = "default";
|
||||
|
||||
@Desc("The min block value (value + fluidHeight)")
|
||||
private int min = 0;
|
||||
|
||||
@Desc("The max block value (value + fluidHeight)")
|
||||
private int max = 0;
|
||||
|
||||
private transient IrisGenerator gen;
|
||||
|
||||
public IrisBiomeGeneratorLink()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IrisGenerator getCachedGenerator()
|
||||
{
|
||||
if(gen == null)
|
||||
{
|
||||
gen = Iris.data.getGeneratorLoader().load(getGenerator());
|
||||
|
||||
if(gen == null)
|
||||
{
|
||||
gen = new IrisGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
return gen;
|
||||
}
|
||||
|
||||
public double getHeight(double x, double z, long seed)
|
||||
{
|
||||
double g = getCachedGenerator().getHeight(x, z, seed);
|
||||
g = g < 0 ? 0 : g;
|
||||
g = g > 1 ? 1 : g;
|
||||
|
||||
return IrisInterpolation.lerp(min, max, g);
|
||||
}
|
||||
}
|
||||
123
src/main/java/com/volmit/iris/object/IrisBiomePaletteLayer.java
Normal file
123
src/main/java/com/volmit/iris/object/IrisBiomePaletteLayer.java
Normal file
@@ -0,0 +1,123 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Desc("A layer of surface / subsurface material in biomes")
|
||||
@Data
|
||||
public class IrisBiomePaletteLayer
|
||||
{
|
||||
@Desc("The dispersion of materials from the palette")
|
||||
private Dispersion dispersion = Dispersion.SCATTER;
|
||||
|
||||
@Desc("The min thickness of this layer")
|
||||
private int minHeight = 1;
|
||||
|
||||
@Desc("The max thickness of this layer")
|
||||
private int maxHeight = 1;
|
||||
|
||||
@Desc("The terrain zoom mostly for zooming in on a wispy palette")
|
||||
private double terrainZoom = 5;
|
||||
|
||||
@Desc("The palette of blocks to be used in this layer")
|
||||
private KList<String> palette = new KList<String>().qadd("GRASS_BLOCK");
|
||||
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient KList<BlockData> blockData;
|
||||
private transient CNG layerGenerator;
|
||||
private transient CNG heightGenerator;
|
||||
|
||||
public CNG getHeightGenerator(RNG rng)
|
||||
{
|
||||
if(heightGenerator == null)
|
||||
{
|
||||
heightGenerator = CNG.signature(rng.nextParallelRNG(minHeight * maxHeight + getBlockData().size()));
|
||||
}
|
||||
|
||||
return heightGenerator;
|
||||
}
|
||||
|
||||
public BlockData get(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(layerGenerator == null)
|
||||
{
|
||||
cacheGenerator(rng);
|
||||
}
|
||||
|
||||
if(layerGenerator != null)
|
||||
{
|
||||
if(dispersion.equals(Dispersion.SCATTER))
|
||||
{
|
||||
return getBlockData().get(layerGenerator.fit(0, 30000000, x, y, z) % getBlockData().size());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return getBlockData().get(layerGenerator.fit(0, getBlockData().size() - 1, x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
if(getBlockData().isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return getBlockData().get(0);
|
||||
}
|
||||
|
||||
public void cacheGenerator(RNG rng)
|
||||
{
|
||||
RNG rngx = rng.nextParallelRNG(minHeight + maxHeight + getBlockData().size());
|
||||
|
||||
switch(dispersion)
|
||||
{
|
||||
case SCATTER:
|
||||
layerGenerator = CNG.signature(rngx).freq(1000000);
|
||||
break;
|
||||
case WISPY:
|
||||
layerGenerator = CNG.signature(rngx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public KList<String> add(String b)
|
||||
{
|
||||
palette.add(b);
|
||||
|
||||
return palette;
|
||||
}
|
||||
|
||||
public KList<BlockData> getBlockData()
|
||||
{
|
||||
lock.lock();
|
||||
if(blockData == null)
|
||||
{
|
||||
blockData = new KList<>();
|
||||
for(String ix : palette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
if(bx != null)
|
||||
{
|
||||
blockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return blockData;
|
||||
}
|
||||
|
||||
public IrisBiomePaletteLayer zero()
|
||||
{
|
||||
palette.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
172
src/main/java/com/volmit/iris/object/IrisDepositGenerator.java
Normal file
172
src/main/java/com/volmit/iris/object/IrisDepositGenerator.java
Normal file
@@ -0,0 +1,172 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.generator.ParallaxChunkGenerator;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Data
|
||||
public class IrisDepositGenerator
|
||||
{
|
||||
@Desc("The minimum height this deposit can generate at")
|
||||
private int minHeight = 7;
|
||||
|
||||
@Desc("The maximum height this deposit can generate at")
|
||||
private int maxHeight = 55;
|
||||
|
||||
@Desc("The minimum amount of deposit blocks per clump")
|
||||
private int minSize = 3;
|
||||
|
||||
@Desc("The maximum amount of deposit blocks per clump")
|
||||
private int maxSize = 5;
|
||||
|
||||
@Desc("The maximum amount of clumps per chunk")
|
||||
private int maxPerChunk = 3;
|
||||
|
||||
@Desc("The minimum amount of clumps per chunk")
|
||||
private int minPerChunk = 1;
|
||||
|
||||
@Desc("The palette of blocks to be used in this deposit generator")
|
||||
private KList<String> palette = new KList<String>();
|
||||
|
||||
@Desc("Ore varience is how many different objects clumps iris will create")
|
||||
private int varience = 8;
|
||||
|
||||
private transient IrisObjectPlacement config = createDepositConfig();
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient KList<IrisObject> objects;
|
||||
private transient KList<BlockData> blockData;
|
||||
|
||||
public IrisObject getClump(RNG rng)
|
||||
{
|
||||
lock.lock();
|
||||
|
||||
if(objects == null)
|
||||
{
|
||||
RNG rngv = rng.nextParallelRNG(3957778);
|
||||
objects = new KList<>();
|
||||
|
||||
for(int i = 0; i < varience; i++)
|
||||
{
|
||||
objects.add(generateClumpObject(rngv.nextParallelRNG(2349 * i + 3598)));
|
||||
}
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
return objects.get(rng.i(0, objects.size() - 1));
|
||||
}
|
||||
|
||||
private IrisObjectPlacement createDepositConfig()
|
||||
{
|
||||
IrisObjectPlacement p = new IrisObjectPlacement();
|
||||
IrisObjectRotation rot = new IrisObjectRotation();
|
||||
rot.setEnabled(true);
|
||||
IrisAxisRotationClamp xc = new IrisAxisRotationClamp();
|
||||
IrisAxisRotationClamp yc = new IrisAxisRotationClamp();
|
||||
IrisAxisRotationClamp zc = new IrisAxisRotationClamp();
|
||||
xc.setEnabled(true);
|
||||
xc.setInterval(45);
|
||||
yc.setEnabled(true);
|
||||
yc.setInterval(45);
|
||||
zc.setEnabled(true);
|
||||
zc.setInterval(45);
|
||||
rot.setXAxis(xc);
|
||||
rot.setYAxis(yc);
|
||||
rot.setZAxis(zc);
|
||||
p.setRotation(rot);
|
||||
p.setUnderwater(true);
|
||||
p.setMeld(true);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
private IrisObject generateClumpObject(RNG rngv)
|
||||
{
|
||||
int s = rngv.i(minSize, maxSize);
|
||||
int dim = (int) Math.round(Math.pow(s, 1D / 3D));
|
||||
int w = dim / 2;
|
||||
IrisObject o = new IrisObject(dim, dim, dim);
|
||||
|
||||
if(s == 1)
|
||||
{
|
||||
o.getBlocks().put(o.getCenter(), nextBlock(rngv));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
while(s > 0)
|
||||
{
|
||||
s--;
|
||||
BlockVector ang = new BlockVector(rngv.i(-w, w), rngv.i(-w, w), rngv.i(-w, w));
|
||||
BlockVector pos = o.getCenter().clone().add(ang).toBlockVector();
|
||||
o.getBlocks().put(pos, nextBlock(rngv));
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private BlockData nextBlock(RNG rngv)
|
||||
{
|
||||
return getBlockData().get(rngv.i(0, getBlockData().size() - 1));
|
||||
}
|
||||
|
||||
public KList<BlockData> getBlockData()
|
||||
{
|
||||
lock.lock();
|
||||
|
||||
if(blockData == null)
|
||||
{
|
||||
blockData = new KList<>();
|
||||
|
||||
for(String ix : palette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
|
||||
if(bx != null)
|
||||
{
|
||||
blockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
return blockData;
|
||||
}
|
||||
|
||||
public void generate(int x, int z, RNG rng, ParallaxChunkGenerator g)
|
||||
{
|
||||
IrisObject clump = getClump(rng);
|
||||
int height = (int) (Math.round(g.getTerrainHeight(x, z))) - 5;
|
||||
|
||||
if(height < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int i = Math.max(0, minHeight);
|
||||
int a = Math.min(height, Math.min(256, maxHeight));
|
||||
|
||||
if(i >= a)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int h = rng.i(i, a);
|
||||
|
||||
if(h > maxHeight || h < minHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
clump.place(x, h, z, g, config, rng);
|
||||
}
|
||||
}
|
||||
311
src/main/java/com/volmit/iris/object/IrisDimension.java
Normal file
311
src/main/java/com/volmit/iris/object/IrisDimension.java
Normal file
@@ -0,0 +1,311 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Desc("Represents a dimension")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisDimension extends IrisRegistrant
|
||||
{
|
||||
@Desc("The human readable name of this dimension")
|
||||
private String name = "A Dimension";
|
||||
|
||||
@Desc("The interpolation function for splicing noise maxes together")
|
||||
private InterpolationMethod interpolationFunction = InterpolationMethod.BICUBIC;
|
||||
|
||||
@Desc("The interpolation distance scale. Increase = more smooth, less detail")
|
||||
private double interpolationScale = 63;
|
||||
|
||||
@Desc("The Thickness scale of cave veins")
|
||||
private double caveThickness = 1D;
|
||||
|
||||
@Desc("The cave web scale. Smaller values means scaled up vein networks.")
|
||||
private double caveScale = 1D;
|
||||
|
||||
@Desc("Shift the Y value of the cave networks up or down.")
|
||||
private double caveShift = 0D;
|
||||
|
||||
@Desc("Generate caves or not.")
|
||||
private boolean caves = true;
|
||||
|
||||
@Desc("Carve terrain or not")
|
||||
private boolean carving = true;
|
||||
|
||||
@Desc("Generate decorations or not")
|
||||
private boolean decorate = true;
|
||||
|
||||
@Desc("Use post processing features. Usually for production only as there is a gen speed cost.")
|
||||
private boolean postProcess = true;
|
||||
|
||||
@Desc("The ceiling dimension. Leave blank for normal sky.")
|
||||
private String ceiling = "";
|
||||
|
||||
@Desc("Mirrors the generator floor into the ceiling. Think nether but worse...")
|
||||
private boolean mirrorCeiling = false;
|
||||
|
||||
@Desc("The world environment")
|
||||
private Environment environment = Environment.NORMAL;
|
||||
|
||||
@Desc("Define all of the regions to include in this dimension. Dimensions -> Regions -> Biomes -> Objects etc")
|
||||
private KList<String> regions = new KList<>();
|
||||
|
||||
@Desc("The fluid height for this dimension")
|
||||
private int fluidHeight = 63;
|
||||
|
||||
@Desc("Keep this either undefined or empty. Setting any biome name into this will force iris to only generate the specified biome. Great for testing.")
|
||||
private String focus = "";
|
||||
|
||||
@Desc("Zoom in or out the biome size. Higher = bigger biomes")
|
||||
private double biomeZoom = 5D;
|
||||
|
||||
@Desc("Zoom in or out the terrain. This stretches the terrain. Due to performance improvements, Higher than 2.0 may cause weird rounding artifacts. Lower = more terrain changes per block. Its a true zoom-out.")
|
||||
private double terrainZoom = 2D;
|
||||
|
||||
@Desc("You can rotate the input coordinates by an angle. This can make terrain appear more natural (less sharp corners and lines). This literally rotates the entire dimension by an angle. Hint: Try 12 degrees or something not on a 90 or 45 degree angle.")
|
||||
private double dimensionAngleDeg = 0;
|
||||
|
||||
@Desc("Iris adds a few roughness filters to noise. Increasing this smooths it out. Decreasing this makes it bumpier/scratchy")
|
||||
private double roughnessZoom = 2D;
|
||||
|
||||
@Desc("The height of the roughness filters")
|
||||
private int roughnessHeight = 3;
|
||||
|
||||
@Desc("Coordinate fracturing applies noise to the input coordinates. This creates the 'iris swirls' and wavy features. The distance pushes these waves further into places they shouldnt be. This is a block value multiplier.")
|
||||
private double coordFractureDistance = 20;
|
||||
|
||||
@Desc("Coordinate fracturing zoom. Higher = less frequent warping, Lower = more frequent and rapid warping / swirls.")
|
||||
private double coordFractureZoom = 8;
|
||||
|
||||
@Desc("This zooms in the land space")
|
||||
private double landZoom = 1;
|
||||
|
||||
@Desc("This zooms in the cave biome space")
|
||||
private double caveBiomeZoom = 1;
|
||||
|
||||
@Desc("This can zoom the shores")
|
||||
private double shoreZoom = 1;
|
||||
|
||||
@Desc("This zooms oceanic biomes")
|
||||
private double seaZoom = 1;
|
||||
|
||||
@Desc("Zoom in continents")
|
||||
private double continentZoom = 1;
|
||||
|
||||
@Desc("Change the size of regions")
|
||||
private double regionZoom = 1;
|
||||
|
||||
@Desc("Disable this to stop placing schematics in biomes")
|
||||
private boolean placeObjects = true;
|
||||
|
||||
@Desc("Prevent Leaf decay as if placed in creative mode")
|
||||
private boolean preventLeafDecay = false;
|
||||
|
||||
@Desc("Define global deposit generators")
|
||||
private KList<IrisDepositGenerator> deposits = new KList<>();
|
||||
|
||||
@Desc("The dispersion of materials for the rock palette")
|
||||
private Dispersion dispersion = Dispersion.SCATTER;
|
||||
|
||||
@Desc("The rock zoom mostly for zooming in on a wispy palette")
|
||||
private double rockZoom = 5;
|
||||
|
||||
@Desc("The palette of blocks for 'stone'")
|
||||
private KList<String> rockPalette = new KList<String>().qadd("STONE");
|
||||
|
||||
@Desc("The palette of blocks for 'water'")
|
||||
private KList<String> fluidPalette = new KList<String>().qadd("WATER");
|
||||
|
||||
private transient ReentrantLock rockLock = new ReentrantLock();
|
||||
private transient ReentrantLock fluidLock = new ReentrantLock();
|
||||
private transient KList<BlockData> rockData;
|
||||
private transient KList<BlockData> fluidData;
|
||||
private transient CNG rockLayerGenerator;
|
||||
private transient CNG fluidLayerGenerator;
|
||||
private transient CNG coordFracture;
|
||||
private transient Double sinr;
|
||||
private transient Double cosr;
|
||||
private transient Double rad;
|
||||
private transient boolean inverted;
|
||||
|
||||
public CNG getCoordFracture(RNG rng, int signature)
|
||||
{
|
||||
if(coordFracture == null)
|
||||
{
|
||||
coordFracture = CNG.signature(rng.nextParallelRNG(signature));
|
||||
coordFracture.scale(0.012 / coordFractureZoom);
|
||||
}
|
||||
|
||||
return coordFracture;
|
||||
}
|
||||
|
||||
public BlockData getRock(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(getRockData().size() == 1)
|
||||
{
|
||||
return getRockData().get(0);
|
||||
}
|
||||
|
||||
if(rockLayerGenerator == null)
|
||||
{
|
||||
cacheRockGenerator(rng);
|
||||
}
|
||||
|
||||
if(rockLayerGenerator != null)
|
||||
{
|
||||
if(dispersion.equals(Dispersion.SCATTER))
|
||||
{
|
||||
return getRockData().get(rockLayerGenerator.fit(0, 30000000, x, y, z) % getRockData().size());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return getRockData().get(rockLayerGenerator.fit(0, getRockData().size() - 1, x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
return getRockData().get(0);
|
||||
}
|
||||
|
||||
public void cacheRockGenerator(RNG rng)
|
||||
{
|
||||
RNG rngx = rng.nextParallelRNG(getRockData().size() * hashCode());
|
||||
|
||||
switch(dispersion)
|
||||
{
|
||||
case SCATTER:
|
||||
rockLayerGenerator = CNG.signature(rngx).freq(1000000);
|
||||
break;
|
||||
case WISPY:
|
||||
rockLayerGenerator = CNG.signature(rngx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public KList<BlockData> getRockData()
|
||||
{
|
||||
rockLock.lock();
|
||||
|
||||
if(rockData == null)
|
||||
{
|
||||
rockData = new KList<>();
|
||||
for(String ix : rockPalette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
if(bx != null)
|
||||
{
|
||||
rockData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rockLock.unlock();
|
||||
|
||||
return rockData;
|
||||
}
|
||||
|
||||
public BlockData getFluid(RNG rng, double x, double y, double z)
|
||||
{
|
||||
if(getFluidData().size() == 1)
|
||||
{
|
||||
return getFluidData().get(0);
|
||||
}
|
||||
|
||||
if(fluidLayerGenerator == null)
|
||||
{
|
||||
cacheFluidGenerator(rng);
|
||||
}
|
||||
|
||||
if(fluidLayerGenerator != null)
|
||||
{
|
||||
if(dispersion.equals(Dispersion.SCATTER))
|
||||
{
|
||||
return getFluidData().get(fluidLayerGenerator.fit(0, 30000000, x, y, z) % getFluidData().size());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return getFluidData().get(fluidLayerGenerator.fit(0, getFluidData().size() - 1, x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
return getFluidData().get(0);
|
||||
}
|
||||
|
||||
public void cacheFluidGenerator(RNG rng)
|
||||
{
|
||||
RNG rngx = rng.nextParallelRNG(getFluidData().size() * hashCode());
|
||||
|
||||
switch(dispersion)
|
||||
{
|
||||
case SCATTER:
|
||||
fluidLayerGenerator = CNG.signature(rngx).freq(1000000);
|
||||
break;
|
||||
case WISPY:
|
||||
fluidLayerGenerator = CNG.signature(rngx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public KList<BlockData> getFluidData()
|
||||
{
|
||||
fluidLock.lock();
|
||||
|
||||
if(fluidData == null)
|
||||
{
|
||||
fluidData = new KList<>();
|
||||
for(String ix : fluidPalette)
|
||||
{
|
||||
BlockData bx = BlockDataTools.getBlockData(ix);
|
||||
if(bx != null)
|
||||
{
|
||||
fluidData.add(bx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fluidLock.unlock();
|
||||
|
||||
return fluidData;
|
||||
}
|
||||
|
||||
public double getDimensionAngle()
|
||||
{
|
||||
if(rad == null)
|
||||
{
|
||||
rad = Math.toRadians(dimensionAngleDeg);
|
||||
}
|
||||
|
||||
return rad;
|
||||
}
|
||||
|
||||
public double sinRotate()
|
||||
{
|
||||
if(sinr == null)
|
||||
{
|
||||
sinr = Math.sin(getDimensionAngle());
|
||||
}
|
||||
|
||||
return sinr;
|
||||
}
|
||||
|
||||
public double cosRotate()
|
||||
{
|
||||
if(cosr == null)
|
||||
{
|
||||
cosr = Math.cos(getDimensionAngle());
|
||||
}
|
||||
|
||||
return cosr;
|
||||
}
|
||||
}
|
||||
98
src/main/java/com/volmit/iris/object/IrisGenerator.java
Normal file
98
src/main/java/com/volmit/iris/object/IrisGenerator.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Desc("Represents a composite generator of noise gens")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisGenerator extends IrisRegistrant
|
||||
{
|
||||
@Desc("The zoom or frequency.")
|
||||
private double zoom = 1;
|
||||
|
||||
@Desc("The opacity, essentially a multiplier on the output.")
|
||||
private double opacity = 1;
|
||||
|
||||
@Desc("The offset to shift this noise x")
|
||||
private double offsetX = 0;
|
||||
|
||||
@Desc("The offset to shift this noise z")
|
||||
private double offsetZ = 0;
|
||||
|
||||
@Desc("The seed for this generator")
|
||||
private long seed = 1;
|
||||
|
||||
@Desc("The interpolation method when two biomes use different heights but this same generator")
|
||||
private InterpolationMethod interpolationFunction = InterpolationMethod.BICUBIC;
|
||||
|
||||
@Desc("The interpolation distance scale (blocks) when two biomes use different heights but this same generator")
|
||||
private double interpolationScale = 7;
|
||||
|
||||
@Desc("Cliff Height Max. Disable with 0 for min and max")
|
||||
private double cliffHeightMax = 0;
|
||||
|
||||
@Desc("Cliff Height Min. Disable with 0 for min and max")
|
||||
private double cliffHeightMin = 0;
|
||||
|
||||
@Desc("The list of noise gens this gen contains.")
|
||||
private KList<IrisNoiseGenerator> composite = new KList<IrisNoiseGenerator>();
|
||||
|
||||
@Desc("The noise gen for cliff height.")
|
||||
private IrisNoiseGenerator cliffHeightGenerator = new IrisNoiseGenerator();
|
||||
|
||||
public double getMax()
|
||||
{
|
||||
return opacity;
|
||||
}
|
||||
|
||||
public boolean hasCliffs()
|
||||
{
|
||||
return cliffHeightMax > 0;
|
||||
}
|
||||
|
||||
public double getHeight(double rx, double rz, long superSeed)
|
||||
{
|
||||
if(composite.isEmpty())
|
||||
{
|
||||
Iris.warn("Useless Generator: Composite is empty in " + getLoadKey());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hc = hashCode();
|
||||
double h = 0;
|
||||
double tp = 0;
|
||||
|
||||
for(IrisNoiseGenerator i : composite)
|
||||
{
|
||||
tp += i.getOpacity();
|
||||
h += i.getNoise(seed + superSeed + hc, (rx + offsetX) / zoom, (rz + offsetZ) / zoom);
|
||||
}
|
||||
|
||||
double v = (h / tp) * opacity;
|
||||
|
||||
if(Double.isNaN(v))
|
||||
{
|
||||
Iris.warn("Nan value on gen: " + getLoadKey() + ": H = " + h + " TP = " + tp + " OPACITY = " + opacity + " ZOOM = " + zoom);
|
||||
}
|
||||
|
||||
return hasCliffs() ? cliff(rx, rz, v, superSeed + 294596) : v;
|
||||
}
|
||||
|
||||
public double getCliffHeight(double rx, double rz, double superSeed)
|
||||
{
|
||||
int hc = hashCode();
|
||||
double h = cliffHeightGenerator.getNoise((long) (seed + superSeed + hc), (rx + offsetX) / zoom, (rz + offsetZ) / zoom);
|
||||
return IrisInterpolation.lerp(cliffHeightMin, cliffHeightMax, h);
|
||||
}
|
||||
|
||||
public double cliff(double rx, double rz, double v, double superSeed)
|
||||
{
|
||||
double cliffHeight = getCliffHeight(rx, rz, superSeed - 34857);
|
||||
return (Math.round((v * 255D) / cliffHeight) * cliffHeight) / 255D;
|
||||
}
|
||||
}
|
||||
117
src/main/java/com/volmit/iris/object/IrisNoiseGenerator.java
Normal file
117
src/main/java/com/volmit/iris/object/IrisNoiseGenerator.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Desc("A noise generator")
|
||||
@Data
|
||||
public class IrisNoiseGenerator
|
||||
{
|
||||
@Desc("The coordinate input zoom")
|
||||
private double zoom = 1;
|
||||
|
||||
@Desc("The output multiplier")
|
||||
private double opacity = 1;
|
||||
|
||||
@Desc("Coordinate offset x")
|
||||
private double offsetX = 0;
|
||||
|
||||
@Desc("Height output offset y")
|
||||
private double offsetY = 0;
|
||||
|
||||
@Desc("Coordinate offset z")
|
||||
private double offsetZ = 0;
|
||||
|
||||
@Desc("The seed")
|
||||
private long seed = 0;
|
||||
|
||||
@Desc("Apply a parametric curve on the output")
|
||||
private boolean parametric = false;
|
||||
@Desc("Apply a bezier curve on the output")
|
||||
private boolean bezier = false;
|
||||
|
||||
@Desc("Apply a sin-center curve on the output (0, and 1 = 0 and 0.5 = 1.0 using a sinoid shape.)")
|
||||
private boolean sinCentered = false;
|
||||
|
||||
@Desc("The exponent noise^EXPONENT")
|
||||
private double exponent = 1;
|
||||
|
||||
@Desc("Enable / disable. Outputs offsetY if disabled")
|
||||
private boolean enabled = true;
|
||||
|
||||
@Desc("If this generator uses the default iris swirly/wispy noise generator. Set to false for pure simplex.")
|
||||
private boolean irisBased = true;
|
||||
|
||||
@Desc("Multiple octaves for multple generators of changing zooms added together")
|
||||
private int octaves = 1;
|
||||
|
||||
@Desc("Apply a child noise generator to fracture the input coordinates of this generator")
|
||||
private KList<IrisNoiseGenerator> fracture = new KList<>();
|
||||
|
||||
private transient ReentrantLock lock;
|
||||
private transient CNG generator;
|
||||
|
||||
public IrisNoiseGenerator()
|
||||
{
|
||||
lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
public IrisNoiseGenerator(boolean enabled)
|
||||
{
|
||||
this();
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
protected CNG getGenerator(long superSeed)
|
||||
{
|
||||
if(generator == null)
|
||||
{
|
||||
lock.lock();
|
||||
generator = irisBased ? CNG.signature(new RNG(superSeed + 33955677 - seed)) : new CNG(new RNG(superSeed + 33955677 - seed), 1D, octaves);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
public double getMax()
|
||||
{
|
||||
return getOffsetY() + opacity;
|
||||
}
|
||||
|
||||
public double getNoise(long superSeed, double xv, double zv)
|
||||
{
|
||||
if(!enabled)
|
||||
{
|
||||
return offsetY;
|
||||
}
|
||||
|
||||
double x = xv;
|
||||
double z = zv;
|
||||
int g = 33;
|
||||
|
||||
for(IrisNoiseGenerator i : fracture)
|
||||
{
|
||||
if(i.isEnabled())
|
||||
{
|
||||
x += i.getNoise(superSeed + seed + g, xv, zv);
|
||||
z -= i.getNoise(superSeed + seed + g, zv, xv);
|
||||
}
|
||||
g += 819;
|
||||
}
|
||||
|
||||
double n = getGenerator(superSeed).fitDoubleD(0, opacity, (x / zoom) + offsetX, (z / zoom) + offsetZ);
|
||||
n = (exponent != 1 ? n < 0 ? -Math.pow(-n, exponent) : Math.pow(n, exponent) : n) + offsetY;
|
||||
n = parametric ? IrisInterpolation.parametric(n, 1) : n;
|
||||
n = bezier ? IrisInterpolation.bezier(n) : n;
|
||||
n = sinCentered ? IrisInterpolation.sinCenter(n) : n;
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
||||
221
src/main/java/com/volmit/iris/object/IrisObject.java
Normal file
221
src/main/java/com/volmit/iris/object/IrisObject.java
Normal file
@@ -0,0 +1,221 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Leaves;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
import ninja.bytecode.iris.util.IObjectPlacer;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisObject extends IrisRegistrant
|
||||
{
|
||||
private static final Material SNOW = Material.SNOW;
|
||||
private static final BlockData[] SNOW_LAYERS = new BlockData[] {BlockDataTools.getBlockData("minecraft:snow[layers=1]"), BlockDataTools.getBlockData("minecraft:snow[layers=2]"), BlockDataTools.getBlockData("minecraft:snow[layers=3]"), BlockDataTools.getBlockData("minecraft:snow[layers=4]"), BlockDataTools.getBlockData("minecraft:snow[layers=5]"), BlockDataTools.getBlockData("minecraft:snow[layers=6]"), BlockDataTools.getBlockData("minecraft:snow[layers=7]"), BlockDataTools.getBlockData("minecraft:snow[layers=8]")};
|
||||
private KMap<BlockVector, BlockData> blocks;
|
||||
private int w;
|
||||
private int d;
|
||||
private int h;
|
||||
private transient BlockVector center;
|
||||
|
||||
public IrisObject(int w, int h, int d)
|
||||
{
|
||||
blocks = new KMap<>();
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.d = d;
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
}
|
||||
|
||||
public static BlockVector sampleSize(File file) throws IOException
|
||||
{
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
BlockVector bv = new BlockVector(din.readInt(), din.readInt(), din.readInt());
|
||||
din.close();
|
||||
return bv;
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws IOException
|
||||
{
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
this.w = din.readInt();
|
||||
this.h = din.readInt();
|
||||
this.d = din.readInt();
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
int s = din.readInt();
|
||||
|
||||
for(int i = 0; i < s; i++)
|
||||
{
|
||||
blocks.put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), BlockDataTools.getBlockData(din.readUTF()));
|
||||
}
|
||||
}
|
||||
|
||||
public void read(File file) throws IOException
|
||||
{
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
read(fin);
|
||||
fin.close();
|
||||
}
|
||||
|
||||
public void write(File file) throws IOException
|
||||
{
|
||||
file.getParentFile().mkdirs();
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
write(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
public void write(OutputStream o) throws IOException
|
||||
{
|
||||
DataOutputStream dos = new DataOutputStream(o);
|
||||
dos.writeInt(w);
|
||||
dos.writeInt(h);
|
||||
dos.writeInt(d);
|
||||
dos.writeInt(blocks.size());
|
||||
for(BlockVector i : blocks.k())
|
||||
{
|
||||
dos.writeShort(i.getBlockX());
|
||||
dos.writeShort(i.getBlockY());
|
||||
dos.writeShort(i.getBlockZ());
|
||||
dos.writeUTF(blocks.get(i).getAsString(true));
|
||||
}
|
||||
}
|
||||
|
||||
public void setUnsigned(int x, int y, int z, BlockData block)
|
||||
{
|
||||
if(x >= w || y >= h || z >= d)
|
||||
{
|
||||
throw new RuntimeException(x + " " + y + " " + z + " exceeds limit of " + w + " " + h + " " + d);
|
||||
}
|
||||
|
||||
BlockVector v = new BlockVector(x, y, z).subtract(center).toBlockVector();
|
||||
|
||||
if(block == null)
|
||||
{
|
||||
blocks.remove(v);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
blocks.put(v, block);
|
||||
}
|
||||
}
|
||||
|
||||
public void place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng)
|
||||
{
|
||||
place(x, -1, z, placer, config, rng);
|
||||
}
|
||||
|
||||
public void place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng)
|
||||
{
|
||||
boolean yf = rng.nextBoolean();
|
||||
boolean xf = rng.nextBoolean();
|
||||
int spinx = rng.imax() / 1000;
|
||||
int spiny = rng.imax() / 1000;
|
||||
int spinz = rng.imax() / 1000;
|
||||
int y = yv < 0 ? placer.getHighest(x, z, config.isUnderwater()) + config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), yf, xf, spinx, spiny, spinz).getBlockY() : yv;
|
||||
KMap<ChunkPosition, Integer> heightmap = config.getSnow() > 0 ? new KMap<>() : null;
|
||||
|
||||
if(!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(BlockVector g : blocks.k())
|
||||
{
|
||||
BlockVector i = g.clone();
|
||||
i = config.getRotation().rotate(i.clone(), yf, xf, spinx, spiny, spinz).clone();
|
||||
i = config.getTranslate().translate(i.clone()).clone();
|
||||
BlockData data = blocks.get(g);
|
||||
|
||||
if(placer.isPreventingDecay() && data instanceof Leaves && !((Leaves) data).isPersistent())
|
||||
{
|
||||
((Leaves) data).setPersistent(true);
|
||||
}
|
||||
|
||||
for(IrisObjectReplace j : config.getEdit())
|
||||
{
|
||||
if(j.getFind().matches(data))
|
||||
{
|
||||
data = j.getReplace();
|
||||
}
|
||||
}
|
||||
|
||||
int xx = x + (int) Math.round(i.getX());
|
||||
int yy = y + (int) Math.round(i.getY());
|
||||
int zz = z + (int) Math.round(i.getZ());
|
||||
|
||||
if(heightmap != null)
|
||||
{
|
||||
ChunkPosition pos = new ChunkPosition(xx, zz);
|
||||
|
||||
if(!heightmap.containsKey(pos))
|
||||
{
|
||||
heightmap.put(pos, yy);
|
||||
}
|
||||
|
||||
if(heightmap.get(pos) < yy)
|
||||
{
|
||||
heightmap.put(pos, yy);
|
||||
}
|
||||
}
|
||||
|
||||
if(config.isMeld() && !placer.isSolid(xx, yy, zz))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
placer.set(xx, yy, zz, data);
|
||||
}
|
||||
|
||||
if(heightmap != null)
|
||||
{
|
||||
RNG rngx = rng.nextParallelRNG(3468854);
|
||||
|
||||
for(ChunkPosition i : heightmap.k())
|
||||
{
|
||||
int vx = i.getX();
|
||||
int vy = heightmap.get(i);
|
||||
int vz = i.getZ();
|
||||
|
||||
if(config.getSnow() > 0)
|
||||
{
|
||||
BlockData bd = placer.get(vx, vy, vz);
|
||||
if(bd != null && bd.getMaterial().equals(SNOW))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int height = rngx.i(0, (int) (config.getSnow() * 7));
|
||||
placer.set(vx, vy + 1, vz, SNOW_LAYERS[Math.max(Math.min(height, 7), 0)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void place(Location at)
|
||||
{
|
||||
for(BlockVector i : blocks.k())
|
||||
{
|
||||
at.clone().add(0, getCenter().getY(), 0).add(i).getBlock().setBlockData(blocks.get(i), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
|
||||
@Data
|
||||
public class IrisObjectPlacement
|
||||
{
|
||||
@Desc("List of objects to place")
|
||||
private KList<String> place = new KList<>();
|
||||
|
||||
@Desc("Find and replace blocks")
|
||||
private KList<IrisObjectReplace> edit = new KList<>();
|
||||
|
||||
@Desc("Translate this object's placement")
|
||||
private IrisObjectTranslate translate = new IrisObjectTranslate();
|
||||
|
||||
@Desc("Rotate this objects placement")
|
||||
private IrisObjectRotation rotation = new IrisObjectRotation();
|
||||
|
||||
@Desc("The maximum layer level of a snow filter overtop of this placement. Set to 0 to disable. Max of 1.")
|
||||
private double snow = 0;
|
||||
|
||||
@Desc("The chance for this to place in a chunk. If you need multiple per chunk, set this to 1 and use density.")
|
||||
private double chance = 1;
|
||||
|
||||
@Desc("If the chance check passes, place this many in a single chunk")
|
||||
private int density = 1;
|
||||
|
||||
@Desc("If set to true, objects will place on the terrain height, ignoring the water surface.")
|
||||
private boolean underwater = false;
|
||||
|
||||
@Desc("If set to true, objects will place on the fluid height level Such as boats.")
|
||||
private boolean onwater = false;
|
||||
|
||||
@Desc("If set to true, this object will only place parts of itself where blocks already exist.")
|
||||
private boolean meld = false;
|
||||
|
||||
public IrisObjectPlacement()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IrisObject getSchematic(RNG random)
|
||||
{
|
||||
if(place.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Iris.data.getObjectLoader().load(place.get(random.nextInt(place.size())));
|
||||
}
|
||||
|
||||
public int getTriesForChunk(RNG random)
|
||||
{
|
||||
if(chance <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(chance >= 1 || random.nextDouble() < chance)
|
||||
{
|
||||
return density;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
46
src/main/java/com/volmit/iris/object/IrisObjectReplace.java
Normal file
46
src/main/java/com/volmit/iris/object/IrisObjectReplace.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
|
||||
@Desc("Find and replace object materials")
|
||||
@Data
|
||||
public class IrisObjectReplace
|
||||
{
|
||||
private String find;
|
||||
private String replace;
|
||||
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
private transient BlockData findData;
|
||||
private transient BlockData replaceData;
|
||||
|
||||
public IrisObjectReplace()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BlockData getFind()
|
||||
{
|
||||
if(findData == null)
|
||||
{
|
||||
findData = BlockDataTools.getBlockData(find);
|
||||
}
|
||||
|
||||
return findData;
|
||||
}
|
||||
|
||||
public BlockData getReplace()
|
||||
{
|
||||
if(replaceData == null)
|
||||
{
|
||||
replaceData = BlockDataTools.getBlockData(replace);
|
||||
}
|
||||
|
||||
return replaceData;
|
||||
}
|
||||
}
|
||||
112
src/main/java/com/volmit/iris/object/IrisObjectRotation.java
Normal file
112
src/main/java/com/volmit/iris/object/IrisObjectRotation.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
|
||||
@Desc("Configures rotation for iris")
|
||||
@Data
|
||||
public class IrisObjectRotation
|
||||
{
|
||||
@Desc("If this rotator is enabled or not")
|
||||
private boolean enabled = true;
|
||||
@Desc("The x axis rotation")
|
||||
private IrisAxisRotationClamp xAxis = new IrisAxisRotationClamp();
|
||||
@Desc("The y axis rotation")
|
||||
private IrisAxisRotationClamp yAxis = new IrisAxisRotationClamp(true, 0, 0, 90);
|
||||
@Desc("The z axis rotation")
|
||||
private IrisAxisRotationClamp zAxis = new IrisAxisRotationClamp();
|
||||
|
||||
public IrisObjectRotation()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public double getYRotation(int spin)
|
||||
{
|
||||
return getRotation(spin, yAxis);
|
||||
}
|
||||
|
||||
public double getXRotation(int spin)
|
||||
{
|
||||
return getRotation(spin, xAxis);
|
||||
}
|
||||
|
||||
public double getZRotation(int spin)
|
||||
{
|
||||
return getRotation(spin, zAxis);
|
||||
}
|
||||
|
||||
public double getRotation(int spin, IrisAxisRotationClamp clamp)
|
||||
{
|
||||
if(!enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!clamp.isEnabled())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clamp.getRadians(spin);
|
||||
}
|
||||
|
||||
public BlockVector rotate(BlockVector b, boolean yf, boolean xf, int spinx, int spiny, int spinz)
|
||||
{
|
||||
if(!canRotate())
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
BlockVector v = b.clone();
|
||||
|
||||
if(yf && canRotateY())
|
||||
{
|
||||
v.rotateAroundY(getYRotation(spiny));
|
||||
}
|
||||
|
||||
if(xf && canRotateX())
|
||||
{
|
||||
v.rotateAroundX(getXRotation(spinx));
|
||||
}
|
||||
|
||||
if(canRotateZ())
|
||||
{
|
||||
v.rotateAroundZ(getZRotation(spinz));
|
||||
}
|
||||
|
||||
if(!xf && canRotateX())
|
||||
{
|
||||
v.rotateAroundX(getXRotation(spinx));
|
||||
}
|
||||
|
||||
if(!yf && canRotateY())
|
||||
{
|
||||
v.rotateAroundY(getYRotation(spiny));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public boolean canRotateX()
|
||||
{
|
||||
return enabled && xAxis.isEnabled();
|
||||
}
|
||||
|
||||
public boolean canRotateY()
|
||||
{
|
||||
return enabled && yAxis.isEnabled();
|
||||
}
|
||||
|
||||
public boolean canRotateZ()
|
||||
{
|
||||
return enabled && zAxis.isEnabled();
|
||||
}
|
||||
|
||||
public boolean canRotate()
|
||||
{
|
||||
return canRotateX() || canRotateY() || canRotateZ();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
|
||||
@Desc("Translate objects")
|
||||
@Data
|
||||
public class IrisObjectTranslate
|
||||
{
|
||||
@Desc("The x shift in blocks")
|
||||
private int x;
|
||||
|
||||
@Desc("The x shift in blocks")
|
||||
private int y;
|
||||
|
||||
@Desc("The x shift in blocks")
|
||||
private int z;
|
||||
|
||||
public IrisObjectTranslate()
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
}
|
||||
|
||||
public boolean canTranslate()
|
||||
{
|
||||
return x != 0 || y != 0 || z != 0;
|
||||
}
|
||||
|
||||
public BlockVector translate(BlockVector i)
|
||||
{
|
||||
if(canTranslate())
|
||||
{
|
||||
return (BlockVector) i.clone().add(new BlockVector(x, y, z));
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
127
src/main/java/com/volmit/iris/object/IrisRegion.java
Normal file
127
src/main/java/com/volmit/iris/object/IrisRegion.java
Normal file
@@ -0,0 +1,127 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.CNG;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
import ninja.bytecode.shuriken.collections.KList;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.collections.KSet;
|
||||
|
||||
@Desc("Represents an iris region")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class IrisRegion extends IrisRegistrant
|
||||
{
|
||||
@Desc("The name of the region")
|
||||
private String name = "A Region";
|
||||
@Desc("The shore ration (How much percent of land should be a shore)")
|
||||
private double shoreRatio = 0.13;
|
||||
|
||||
@Desc("The min shore height")
|
||||
private double shoreHeightMin = 1.2;
|
||||
|
||||
@Desc("The the max shore height")
|
||||
private double shoreHeightMax = 3.2;
|
||||
|
||||
@Desc("The varience of the shore height")
|
||||
private double shoreHeightZoom = 3.14;
|
||||
|
||||
@Desc("The biome implosion ratio, how much to implode biomes into children (chance)")
|
||||
private double biomeImplosionRatio = 0.4;
|
||||
|
||||
@Desc("A list of root-level biomes in this region. Don't specify child biomes of other biomes here. Just the root parents.")
|
||||
private KList<String> landBiomes = new KList<>();
|
||||
|
||||
@Desc("A list of root-level biomes in this region. Don't specify child biomes of other biomes here. Just the root parents.")
|
||||
private KList<String> seaBiomes = new KList<>();
|
||||
|
||||
@Desc("A list of root-level biomes in this region. Don't specify child biomes of other biomes here. Just the root parents.")
|
||||
private KList<String> shoreBiomes = new KList<>();
|
||||
|
||||
@Desc("Ridge biomes create a vein-like network like rivers through this region")
|
||||
private KList<IrisRegionRidge> ridgeBiomes = new KList<>();
|
||||
|
||||
@Desc("Spot biomes splotch themselves across this region like lakes")
|
||||
private KList<IrisRegionSpot> spotBiomes = new KList<>();
|
||||
|
||||
@Desc("Define regional deposit generators that add onto the global deposit generators")
|
||||
private KList<IrisDepositGenerator> deposits = new KList<>();
|
||||
|
||||
private transient KList<String> cacheRidge;
|
||||
private transient KList<String> cacheSpot;
|
||||
private transient CNG shoreHeightGenerator;
|
||||
private transient ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
public KList<String> getRidgeBiomeKeys()
|
||||
{
|
||||
lock.lock();
|
||||
if(cacheRidge == null)
|
||||
{
|
||||
cacheRidge = new KList<String>();
|
||||
ridgeBiomes.forEach((i) -> cacheRidge.add(i.getBiome()));
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return cacheRidge;
|
||||
}
|
||||
|
||||
public KList<String> getSpotBiomeKeys()
|
||||
{
|
||||
lock.lock();
|
||||
if(cacheSpot == null)
|
||||
{
|
||||
cacheSpot = new KList<String>();
|
||||
spotBiomes.forEach((i) -> cacheSpot.add(i.getBiome()));
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
return cacheSpot;
|
||||
}
|
||||
|
||||
public double getShoreHeight(double x, double z)
|
||||
{
|
||||
if(shoreHeightGenerator == null)
|
||||
{
|
||||
lock.lock();
|
||||
shoreHeightGenerator = CNG.signature(new RNG(hashCode()));
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return shoreHeightGenerator.fitDoubleD(shoreHeightMin, shoreHeightMax, x / shoreHeightZoom, z / shoreHeightZoom);
|
||||
}
|
||||
|
||||
public KList<IrisBiome> getAllBiomes()
|
||||
{
|
||||
KMap<String, IrisBiome> b = new KMap<>();
|
||||
KSet<String> names = new KSet<>();
|
||||
names.addAll(landBiomes);
|
||||
names.addAll(seaBiomes);
|
||||
names.addAll(shoreBiomes);
|
||||
spotBiomes.forEach((i) -> names.add(i.getBiome()));
|
||||
ridgeBiomes.forEach((i) -> names.add(i.getBiome()));
|
||||
|
||||
while(!names.isEmpty())
|
||||
{
|
||||
for(String i : new KList<>(names))
|
||||
{
|
||||
if(b.containsKey(i))
|
||||
{
|
||||
names.remove(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
IrisBiome biome = Iris.data.getBiomeLoader().load(i);
|
||||
b.put(biome.getLoadKey(), biome);
|
||||
names.remove(i);
|
||||
names.addAll(biome.getChildren());
|
||||
}
|
||||
}
|
||||
|
||||
return b.v();
|
||||
}
|
||||
}
|
||||
69
src/main/java/com/volmit/iris/object/IrisRegionRidge.java
Normal file
69
src/main/java/com/volmit/iris/object/IrisRegionRidge.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
|
||||
@Desc("A ridge config")
|
||||
@Data
|
||||
public class IrisRegionRidge
|
||||
{
|
||||
@Desc("The biome name")
|
||||
private String biome;
|
||||
@Desc("The type this biome should override (land sea or shore)")
|
||||
private InferredType type = InferredType.LAND;
|
||||
@Desc("What type this spot is (i.e. target SEA but as LAND) like an island. Default matches the target type")
|
||||
private InferredType as = InferredType.DEFER;
|
||||
@Desc("The chance this biome will be placed in a given spot")
|
||||
private double chance = 0.75;
|
||||
@Desc("The scale of the biome ridge. Higher values = wider veins & bigger connected cells")
|
||||
private double scale = 5;
|
||||
@Desc("The chance scale (cell chances)")
|
||||
private double chanceScale = 4;
|
||||
@Desc("The shuffle, how 'natural' this looks. Compared to pure polygons")
|
||||
private double shuffle = 16;
|
||||
@Desc("The chance shuffle (polygon cell chances)")
|
||||
private double chanceShuffle = 128;
|
||||
@Desc("The thickness of the vein")
|
||||
private double thickness = 0.125;
|
||||
private transient CellGenerator spot;
|
||||
private transient CellGenerator ridge;
|
||||
|
||||
public IrisRegionRidge()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public boolean isRidge(RNG rng, double x, double z)
|
||||
{
|
||||
if(ridge == null)
|
||||
{
|
||||
ridge = new CellGenerator(rng.nextParallelRNG(165583 * hashCode()));
|
||||
ridge.setCellScale(scale);
|
||||
ridge.setShuffle(shuffle);
|
||||
}
|
||||
|
||||
if(spot == null)
|
||||
{
|
||||
spot = new CellGenerator(rng.nextParallelRNG(168523 * hashCode()));
|
||||
spot.setCellScale(chanceScale);
|
||||
spot.setShuffle(shuffle);
|
||||
}
|
||||
|
||||
if(chance < 1)
|
||||
{
|
||||
if(spot.getIndex(x, z, 1000) > chance * 1000)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(ridge.getDistance(x, z) <= thickness)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/volmit/iris/object/IrisRegionSpot.java
Normal file
48
src/main/java/com/volmit/iris/object/IrisRegionSpot.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.CellGenerator;
|
||||
import ninja.bytecode.iris.util.Desc;
|
||||
import ninja.bytecode.iris.util.RNG;
|
||||
|
||||
@Desc("A spot config")
|
||||
@Data
|
||||
public class IrisRegionSpot
|
||||
{
|
||||
@Desc("The biome to be placed")
|
||||
private String biome;
|
||||
@Desc("Where this spot overrides. Land sea or shore")
|
||||
private InferredType type = InferredType.LAND;
|
||||
@Desc("What type this spot is (i.e. target SEA but as LAND) like an island. Default matches the target type")
|
||||
private InferredType as = InferredType.DEFER;
|
||||
@Desc("The scale of splotches")
|
||||
private double scale = 1;
|
||||
@Desc("Rarity is how often this splotch appears. higher = less often")
|
||||
private double rarity = 1;
|
||||
@Desc("The shuffle or how natural the splotch looks like (anti-polygon)")
|
||||
private double shuffle = 128;
|
||||
|
||||
private transient CellGenerator spot;
|
||||
|
||||
public IrisRegionSpot()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public boolean isSpot(RNG rng, double x, double z)
|
||||
{
|
||||
if(spot == null)
|
||||
{
|
||||
spot = new CellGenerator(rng.nextParallelRNG(168583 * hashCode()));
|
||||
spot.setCellScale(scale);
|
||||
spot.setShuffle(shuffle);
|
||||
}
|
||||
|
||||
if(spot.getIndex(x, z, (int) (Math.round(rarity) + 8)) == (int) ((Math.round(rarity) + 8) / 2))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
9
src/main/java/com/volmit/iris/object/IrisRegistrant.java
Normal file
9
src/main/java/com/volmit/iris/object/IrisRegistrant.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package ninja.bytecode.iris.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class IrisRegistrant
|
||||
{
|
||||
private String loadKey;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import ninja.bytecode.iris.util.ByteArrayTag;
|
||||
import ninja.bytecode.iris.util.CompoundTag;
|
||||
import ninja.bytecode.iris.util.NBTInputStream;
|
||||
import ninja.bytecode.iris.util.NBTOutputStream;
|
||||
import ninja.bytecode.iris.util.Tag;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class AtomicRegionData
|
||||
{
|
||||
private final World world;
|
||||
private KMap<String, Tag> tag;
|
||||
|
||||
public AtomicRegionData(World world)
|
||||
{
|
||||
this.world = world;
|
||||
tag = new KMap<>();
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws IOException
|
||||
{
|
||||
NBTInputStream nin = new NBTInputStream(in);
|
||||
tag = new KMap<>();
|
||||
tag.putAll(((CompoundTag) nin.readTag()).getValue());
|
||||
nin.close();
|
||||
}
|
||||
|
||||
public void write(OutputStream out) throws IOException
|
||||
{
|
||||
NBTOutputStream nos = new NBTOutputStream(out);
|
||||
nos.writeTag(new CompoundTag("imca", tag));
|
||||
nos.close();
|
||||
}
|
||||
|
||||
public boolean contains(int rx, int rz)
|
||||
{
|
||||
return tag.containsKey(rx + "." + rz);
|
||||
}
|
||||
|
||||
public void delete(int rx, int rz)
|
||||
{
|
||||
tag.remove(rx + "." + rz);
|
||||
}
|
||||
|
||||
public void set(int rx, int rz, AtomicSliverMap data) throws IOException
|
||||
{
|
||||
if(data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream boas = new ByteArrayOutputStream();
|
||||
data.write(boas);
|
||||
tag.put(rx + "." + rz, new ByteArrayTag(rx + "." + rz, boas.toByteArray()));
|
||||
}
|
||||
|
||||
public AtomicSliverMap get(int rx, int rz) throws IOException
|
||||
{
|
||||
AtomicSliverMap data = new AtomicSliverMap();
|
||||
|
||||
if(!contains(rx, rz))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
ByteArrayTag btag = (ByteArrayTag) tag.get(rx + "." + rz);
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(btag.getValue());
|
||||
data.read(in);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public World getWorld()
|
||||
{
|
||||
return world;
|
||||
}
|
||||
}
|
||||
169
src/main/java/com/volmit/iris/object/atomics/AtomicSliver.java
Normal file
169
src/main/java/com/volmit/iris/object/atomics/AtomicSliver.java
Normal file
@@ -0,0 +1,169 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.BlockDataTools;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
@Data
|
||||
public class AtomicSliver
|
||||
{
|
||||
public static final BlockData AIR = BlockDataTools.getBlockData("AIR");
|
||||
private KMap<Integer, BlockData> block;
|
||||
private KMap<Integer, Biome> biome;
|
||||
private int highestBlock = 0;
|
||||
private int highestBiome = 0;
|
||||
private int x;
|
||||
private int z;
|
||||
|
||||
public AtomicSliver(int x, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.block = new KMap<>();
|
||||
this.biome = new KMap<>();
|
||||
}
|
||||
|
||||
public Material getType(int h)
|
||||
{
|
||||
return get(h).getMaterial();
|
||||
}
|
||||
|
||||
public BlockData get(int h)
|
||||
{
|
||||
BlockData b = block.get(h);
|
||||
|
||||
if(b == null)
|
||||
{
|
||||
return AIR;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public void set(int h, BlockData d)
|
||||
{
|
||||
if(d == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block.put(h, d);
|
||||
highestBlock = h > highestBlock ? h : highestBlock;
|
||||
}
|
||||
|
||||
public void setSilently(int h, BlockData d)
|
||||
{
|
||||
if(d == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block.put(h, d);
|
||||
}
|
||||
|
||||
public boolean isSolid(int h)
|
||||
{
|
||||
return getType(h).isSolid();
|
||||
}
|
||||
|
||||
public void set(int h, Biome d)
|
||||
{
|
||||
biome.put(h, d);
|
||||
highestBiome = h > highestBiome ? h : highestBiome;
|
||||
}
|
||||
|
||||
public void write(ChunkData d)
|
||||
{
|
||||
for(int i = 0; i <= highestBlock; i++)
|
||||
{
|
||||
if(block.get(i) == null)
|
||||
{
|
||||
d.setBlock(x, i, z, AIR);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
d.setBlock(x, i, z, block.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(BiomeGrid d)
|
||||
{
|
||||
for(int i = 0; i <= highestBiome; i++)
|
||||
{
|
||||
if(biome.get(i) != null)
|
||||
{
|
||||
d.setBiome(x, i, z, biome.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(HeightMap height)
|
||||
{
|
||||
height.setHeight(x, z, highestBlock);
|
||||
}
|
||||
|
||||
public void read(DataInputStream din) throws IOException
|
||||
{
|
||||
this.block = new KMap<Integer, BlockData>();
|
||||
int h = din.readByte() - Byte.MIN_VALUE;
|
||||
highestBlock = h;
|
||||
|
||||
for(int i = 0; i <= h; i++)
|
||||
{
|
||||
block.put(i, BlockDataTools.getBlockData(din.readUTF()));
|
||||
}
|
||||
}
|
||||
|
||||
public void write(DataOutputStream dos) throws IOException
|
||||
{
|
||||
dos.writeByte(highestBlock + Byte.MIN_VALUE);
|
||||
|
||||
for(int i = 0; i <= highestBlock; i++)
|
||||
{
|
||||
BlockData dat = block.get(i);
|
||||
dos.writeUTF((dat == null ? AIR : dat).getAsString(true));
|
||||
}
|
||||
}
|
||||
|
||||
public void insert(AtomicSliver atomicSliver)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
if(block.get(i) == null || block.get(i).equals(AIR))
|
||||
{
|
||||
BlockData b = atomicSliver.block.get(i);
|
||||
if(b == null || b.equals(AIR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
block.put(i, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void inject(ChunkData currentData)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
if(block.get(i) != null && !block.get(i).equals(AIR))
|
||||
{
|
||||
BlockData b = block.get(i);
|
||||
currentData.setBlock(x, i, z, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
import lombok.Data;
|
||||
import ninja.bytecode.iris.util.HeightMap;
|
||||
|
||||
@Data
|
||||
public class AtomicSliverMap
|
||||
{
|
||||
private final AtomicSliver[] slivers;
|
||||
private boolean parallaxGenerated;
|
||||
private boolean worldGenerated;
|
||||
|
||||
public AtomicSliverMap()
|
||||
{
|
||||
parallaxGenerated = false;
|
||||
worldGenerated = false;
|
||||
slivers = new AtomicSliver[256];
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
for(int j = 0; j < 16; j++)
|
||||
{
|
||||
slivers[i * 16 + j] = new AtomicSliver(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void insert(AtomicSliverMap map)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
slivers[i].insert(map.slivers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(OutputStream out) throws IOException
|
||||
{
|
||||
DataOutputStream dos = new DataOutputStream(out);
|
||||
dos.writeBoolean(isParallaxGenerated());
|
||||
dos.writeBoolean(isWorldGenerated());
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
slivers[i].write(dos);
|
||||
}
|
||||
|
||||
dos.flush();
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws IOException
|
||||
{
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
parallaxGenerated = din.readBoolean();
|
||||
worldGenerated = din.readBoolean();
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
slivers[i].read(din);
|
||||
}
|
||||
}
|
||||
|
||||
public AtomicSliver getSliver(int x, int z)
|
||||
{
|
||||
return slivers[x * 16 + z];
|
||||
}
|
||||
|
||||
public void write(ChunkData data, BiomeGrid grid, HeightMap height)
|
||||
{
|
||||
for(AtomicSliver i : slivers)
|
||||
{
|
||||
if(i != null)
|
||||
{
|
||||
i.write(data);
|
||||
i.write(grid);
|
||||
i.write(height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void inject(ChunkData currentData)
|
||||
{
|
||||
for(AtomicSliver i : slivers)
|
||||
{
|
||||
i.inject(currentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import ninja.bytecode.iris.Iris;
|
||||
import ninja.bytecode.iris.util.ChronoLatch;
|
||||
import ninja.bytecode.iris.util.ChunkPosition;
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
import ninja.bytecode.shuriken.math.M;
|
||||
|
||||
public class AtomicWorldData
|
||||
{
|
||||
private World world;
|
||||
private KMap<ChunkPosition, AtomicSliverMap> loadedChunks;
|
||||
private KMap<ChunkPosition, AtomicRegionData> loadedSections;
|
||||
private KMap<ChunkPosition, Long> lastRegion;
|
||||
private KMap<ChunkPosition, Long> lastChunk;
|
||||
private String prefix;
|
||||
private ChronoLatch cl = new ChronoLatch(15000);
|
||||
|
||||
public AtomicWorldData(World world, String prefix)
|
||||
{
|
||||
this.world = world;
|
||||
loadedSections = new KMap<>();
|
||||
loadedChunks = new KMap<>();
|
||||
lastRegion = new KMap<>();
|
||||
lastChunk = new KMap<>();
|
||||
this.prefix = prefix;
|
||||
getSubregionFolder().mkdirs();
|
||||
}
|
||||
|
||||
public KMap<ChunkPosition, AtomicRegionData> getLoadedRegions()
|
||||
{
|
||||
return loadedSections;
|
||||
}
|
||||
|
||||
public AtomicRegionData getSubregion(int x, int z) throws IOException
|
||||
{
|
||||
lastRegion.put(new ChunkPosition(x, z), M.ms());
|
||||
|
||||
if(!isSectionLoaded(x, z))
|
||||
{
|
||||
loadedSections.put(new ChunkPosition(x, z), loadSection(x, z));
|
||||
}
|
||||
|
||||
AtomicRegionData f = loadedSections.get(new ChunkPosition(x, z));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public void saveAll() throws IOException
|
||||
{
|
||||
saveChunks();
|
||||
|
||||
for(ChunkPosition i : loadedSections.keySet())
|
||||
{
|
||||
saveSection(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadAll(boolean save) throws IOException
|
||||
{
|
||||
saveChunks();
|
||||
|
||||
for(ChunkPosition i : loadedSections.keySet())
|
||||
{
|
||||
unloadSection(i, save);
|
||||
}
|
||||
|
||||
loadedSections.clear();
|
||||
loadedChunks.clear();
|
||||
lastRegion.clear();
|
||||
}
|
||||
|
||||
public void deleteSection(int x, int z) throws IOException
|
||||
{
|
||||
unloadSection(x, z, false);
|
||||
getSubregionFile(x, z).delete();
|
||||
}
|
||||
|
||||
public boolean isSectionLoaded(int x, int z)
|
||||
{
|
||||
return isSectionLoaded(new ChunkPosition(x, z));
|
||||
}
|
||||
|
||||
public boolean isSectionLoaded(ChunkPosition s)
|
||||
{
|
||||
return loadedSections.containsKey(s);
|
||||
}
|
||||
|
||||
public boolean unloadSection(int x, int z, boolean save) throws IOException
|
||||
{
|
||||
return unloadSection(new ChunkPosition(x, z), save);
|
||||
}
|
||||
|
||||
public boolean unloadSection(ChunkPosition s, boolean save) throws IOException
|
||||
{
|
||||
if(!isSectionLoaded(s))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(save)
|
||||
{
|
||||
saveSection(s);
|
||||
}
|
||||
|
||||
loadedSections.remove(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean saveSection(int x, int z) throws IOException
|
||||
{
|
||||
return saveSection(new ChunkPosition(x, z));
|
||||
}
|
||||
|
||||
public boolean saveSection(ChunkPosition s) throws IOException
|
||||
{
|
||||
if(!isSectionLoaded(s.getX(), s.getZ()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
saveChunks(s);
|
||||
AtomicRegionData data = loadedSections.get(s);
|
||||
FileOutputStream fos = new FileOutputStream(getSubregionFile(s.getX(), s.getZ()));
|
||||
data.write(fos);
|
||||
fos.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void saveChunks() throws IOException
|
||||
{
|
||||
for(ChunkPosition i : loadedChunks.k())
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChunks(ChunkPosition reg) throws IOException
|
||||
{
|
||||
for(ChunkPosition i : loadedChunks.k())
|
||||
{
|
||||
int x = i.getX();
|
||||
int z = i.getZ();
|
||||
|
||||
if(x >> 5 == reg.getX() && z >> 5 == reg.getZ())
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChunk(ChunkPosition i) throws IOException
|
||||
{
|
||||
int x = i.getX();
|
||||
int z = i.getZ();
|
||||
AtomicRegionData dat = loadSection(x >> 5, z >> 5);
|
||||
dat.set(x & 31, z & 31, loadedChunks.get(i));
|
||||
loadedChunks.remove(i);
|
||||
}
|
||||
|
||||
public AtomicSliverMap loadChunk(int x, int z) throws IOException
|
||||
{
|
||||
ChunkPosition pos = new ChunkPosition(x, z);
|
||||
lastChunk.put(pos, M.ms());
|
||||
if(loadedChunks.containsKey(pos))
|
||||
{
|
||||
return loadedChunks.get(pos);
|
||||
}
|
||||
|
||||
AtomicRegionData dat = loadSection(x >> 5, z >> 5);
|
||||
AtomicSliverMap m = dat.get(x & 31, z & 31);
|
||||
loadedChunks.put(pos, m);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public boolean hasChunk(int x, int z) throws IOException
|
||||
{
|
||||
return loadSection(x >> 5, z >> 5).contains(x & 31, z & 31);
|
||||
}
|
||||
|
||||
public AtomicRegionData loadSection(int x, int z) throws IOException
|
||||
{
|
||||
ChunkPosition pos = new ChunkPosition(x, z);
|
||||
lastRegion.put(pos, M.ms());
|
||||
|
||||
if(isSectionLoaded(x, z))
|
||||
{
|
||||
return loadedSections.get(pos);
|
||||
}
|
||||
|
||||
File file = getSubregionFile(x, z);
|
||||
|
||||
if(!file.exists())
|
||||
{
|
||||
AtomicRegionData dat = createSection(x, z);
|
||||
loadedSections.put(pos, dat);
|
||||
return dat;
|
||||
}
|
||||
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
AtomicRegionData data = new AtomicRegionData(world);
|
||||
data.read(fin);
|
||||
fin.close();
|
||||
loadedSections.put(pos, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public AtomicRegionData createSection(int x, int z)
|
||||
{
|
||||
if(isSectionLoaded(x, z))
|
||||
{
|
||||
return loadedSections.get(new ChunkPosition(x, z));
|
||||
}
|
||||
|
||||
AtomicRegionData data = new AtomicRegionData(world);
|
||||
loadedSections.put(new ChunkPosition(x, z), data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public File getSubregionFile(int x, int z)
|
||||
{
|
||||
return new File(getSubregionFolder(), "sr." + x + "." + z + ".smca");
|
||||
}
|
||||
|
||||
public File getSubregionFolder()
|
||||
{
|
||||
return new File(world.getWorldFolder(), "subregion-" + prefix);
|
||||
}
|
||||
|
||||
public KMap<ChunkPosition, AtomicSliverMap> getLoadedChunks()
|
||||
{
|
||||
return loadedChunks;
|
||||
}
|
||||
|
||||
public void clean(int j)
|
||||
{
|
||||
if(!cl.flip())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(ChunkPosition i : lastRegion.k())
|
||||
{
|
||||
if(M.ms() - lastRegion.get(i) > 60000)
|
||||
{
|
||||
lastRegion.remove(i);
|
||||
|
||||
try
|
||||
{
|
||||
unloadSection(i, true);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(ChunkPosition i : lastChunk.k())
|
||||
{
|
||||
if(M.ms() - lastChunk.get(i) > 60000)
|
||||
{
|
||||
try
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
Iris.warn("Failed to save chunk");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/volmit/iris/object/atomics/MasterLock.java
Normal file
48
src/main/java/com/volmit/iris/object/atomics/MasterLock.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package ninja.bytecode.iris.object.atomics;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import ninja.bytecode.shuriken.collections.KMap;
|
||||
|
||||
public class MasterLock
|
||||
{
|
||||
private KMap<String, ReentrantLock> locks;
|
||||
private ReentrantLock lock;
|
||||
|
||||
public MasterLock()
|
||||
{
|
||||
locks = new KMap<>();
|
||||
lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
locks.clear();
|
||||
}
|
||||
|
||||
public void lock(String key)
|
||||
{
|
||||
lock.lock();
|
||||
if(!locks.containsKey(key))
|
||||
{
|
||||
locks.put(key, new ReentrantLock());
|
||||
}
|
||||
|
||||
ReentrantLock l = locks.get(key);
|
||||
lock.unlock();
|
||||
l.lock();
|
||||
}
|
||||
|
||||
public void unlock(String key)
|
||||
{
|
||||
lock.lock();
|
||||
if(!locks.containsKey(key))
|
||||
{
|
||||
locks.put(key, new ReentrantLock());
|
||||
}
|
||||
|
||||
ReentrantLock l = locks.get(key);
|
||||
lock.unlock();
|
||||
l.unlock();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user