Total rotation support

This commit is contained in:
Daniel Mills
2020-08-01 08:46:52 -04:00
parent 71c90c6d31
commit f3d87f09d7
77 changed files with 264 additions and 178 deletions

View File

@@ -1,251 +0,0 @@
package com.volmit.iris.generator;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.World;
import com.volmit.iris.Iris;
import com.volmit.iris.layer.GenLayerBiome;
import com.volmit.iris.object.InferredType;
import com.volmit.iris.object.IrisBiome;
import com.volmit.iris.object.IrisBiomeGeneratorLink;
import com.volmit.iris.object.IrisDimension;
import com.volmit.iris.object.IrisGenerator;
import com.volmit.iris.object.IrisRegion;
import com.volmit.iris.util.BiomeResult;
import com.volmit.iris.util.CNG;
import com.volmit.iris.util.ChronoLatch;
import com.volmit.iris.util.ChunkPosition;
import com.volmit.iris.util.IrisInterpolation;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.KMap;
import com.volmit.iris.util.M;
import com.volmit.iris.util.RNG;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class BiomeChunkGenerator extends DimensionChunkGenerator
{
protected ReentrantLock regLock;
private KMap<String, IrisGenerator> generators;
private KMap<String, IrisGenerator> ceilingGenerators;
protected GenLayerBiome glBiome;
protected CNG masterFracture;
private KMap<ChunkPosition, BiomeResult> biomeHitCache;
private KMap<ChunkPosition, BiomeResult> ceilingBiomeHitCache;
protected ChronoLatch cwarn = new ChronoLatch(1000);
private IrisBiome[] biomeCache;
public BiomeChunkGenerator(String dimensionName)
{
super(dimensionName);
generators = new KMap<>();
ceilingGenerators = new KMap<>();
regLock = new ReentrantLock();
biomeHitCache = new KMap<>();
ceilingBiomeHitCache = new KMap<>();
biomeCache = new IrisBiome[256];
}
public void onInit(World world, RNG rng)
{
loadGenerators();
glBiome = new GenLayerBiome(this, masterRandom.nextParallelRNG(1));
masterFracture = CNG.signature(rng.nextParallelRNG(13)).scale(0.12);
}
protected IrisBiome getCachedInternalBiome(int x, int z)
{
return biomeCache[(z << 4) | x];
}
protected void cacheInternalBiome(int x, int z, IrisBiome b)
{
biomeCache[(z << 4) | x] = b;
}
public KMap<ChunkPosition, BiomeResult> getBiomeHitCache()
{
return getDimension().isInverted() ? ceilingBiomeHitCache : biomeHitCache;
}
@Override
public void onHotload()
{
super.onHotload();
biomeHitCache = new KMap<>();
ceilingBiomeHitCache = new KMap<>();
loadGenerators();
}
public void registerGenerator(IrisGenerator g, IrisDimension dim)
{
KMap<String, IrisGenerator> generators = dim.isInverted() ? ceilingGenerators : this.generators;
regLock.lock();
if(g.getLoadKey() == null || generators.containsKey(g.getLoadKey()))
{
regLock.unlock();
return;
}
regLock.unlock();
generators.put(g.getLoadKey(), g);
}
protected KMap<String, IrisGenerator> getGenerators()
{
return getDimension().isInverted() ? ceilingGenerators : generators;
}
protected double getBiomeHeight(double rx, double rz)
{
double h = 0;
for(IrisGenerator i : getGenerators().values())
{
h += interpolateGenerator(rx, rz, i);
}
return h;
}
protected double interpolateGenerator(double rx, double rz, IrisGenerator gen)
{
double hi = IrisInterpolation.getNoise(gen.getInterpolationFunction(), (int) Math.round(rx), (int) Math.round(rz), gen.getInterpolationScale(), (xx, zz) ->
{
IrisBiome b = sampleBiome((int) xx, (int) zz).getBiome();
for(IrisBiomeGeneratorLink i : b.getGenerators())
{
if(i.getGenerator().equals(gen.getLoadKey()))
{
return i.getMax();
}
}
return 0;
});
double lo = IrisInterpolation.getNoise(gen.getInterpolationFunction(), (int) Math.round(rx), (int) Math.round(rz), gen.getInterpolationScale(), (xx, zz) ->
{
IrisBiome b = sampleBiome((int) xx, (int) zz).getBiome();
for(IrisBiomeGeneratorLink i : b.getGenerators())
{
if(i.getGenerator().equals(gen.getLoadKey()))
{
return i.getMin();
}
}
return 0;
});
return M.lerp(lo, hi, gen.getHeight(rx, rz, world.getSeed() + 239945));
}
protected void loadGenerators()
{
generators.clear();
ceilingGenerators.clear();
loadGenerators(((CeilingChunkGenerator) this).getFloorDimension());
loadGenerators(((CeilingChunkGenerator) this).getCeilingDimension());
}
protected void loadGenerators(IrisDimension dim)
{
if(dim == null)
{
return;
}
KList<String> touch = new KList<>();
KList<String> loadQueue = new KList<>();
for(String i : dim.getRegions())
{
IrisRegion r = Iris.data.getRegionLoader().load(i);
if(r != null)
{
loadQueue.addAll(r.getLandBiomes());
loadQueue.addAll(r.getSeaBiomes());
loadQueue.addAll(r.getShoreBiomes());
loadQueue.addAll(r.getRidgeBiomeKeys());
loadQueue.addAll(r.getSpotBiomeKeys());
}
}
while(!loadQueue.isEmpty())
{
String next = loadQueue.pop();
if(!touch.contains(next))
{
touch.add(next);
IrisBiome biome = Iris.data.getBiomeLoader().load(next);
biome.getGenerators().forEach((i) -> registerGenerator(i.getCachedGenerator(), dim));
loadQueue.addAll(biome.getChildren());
}
}
}
public IrisRegion sampleRegion(int x, int z)
{
double wx = getModifiedX(x, z);
double wz = getModifiedZ(x, z);
return glBiome.getRegion(wx, wz);
}
public BiomeResult sampleBiome(int x, int z)
{
if(!getDimension().getFocus().equals(""))
{
IrisBiome biome = Iris.data.getBiomeLoader().load(getDimension().getFocus());
for(String i : getDimension().getRegions())
{
IrisRegion reg = Iris.data.getRegionLoader().load(i);
if(reg.getLandBiomes().contains(biome.getLoadKey()))
{
biome.setInferredType(InferredType.LAND);
break;
}
if(reg.getSeaBiomes().contains(biome.getLoadKey()))
{
biome.setInferredType(InferredType.SEA);
break;
}
if(reg.getShoreBiomes().contains(biome.getLoadKey()))
{
biome.setInferredType(InferredType.SHORE);
break;
}
}
return new BiomeResult(biome, 0);
}
ChunkPosition pos = new ChunkPosition(x, z);
if(getBiomeHitCache().containsKey(pos))
{
return getBiomeHitCache().get(pos);
}
double wx = getModifiedX(x, z);
double wz = getModifiedZ(x, z);
IrisRegion region = glBiome.getRegion(wx, wz);
BiomeResult res = glBiome.generateRegionData(wx, wz, x, z, region);
getBiomeHitCache().put(pos, res);
return res;
}
}

View File

@@ -1,154 +0,0 @@
package com.volmit.iris.generator;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.Iris;
import com.volmit.iris.object.IrisDimension;
import com.volmit.iris.util.InvertedBiomeGrid;
import com.volmit.iris.util.RNG;
public abstract class CeilingChunkGenerator extends PostBlockChunkGenerator
{
protected boolean generatingCeiling = false;
protected boolean ceilingCached = false;
protected IrisDimension cacheCeiling = null;
protected IrisDimension cacheFloor = null;
public CeilingChunkGenerator(String dimensionName, int threads)
{
super(dimensionName, threads);
}
@Override
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
{
targetFloor();
generate(random, x, z, data, grid);
if(getFloorDimension().isMirrorCeiling())
{
writeInverted(copy(data), data);
}
else if(getCeilingDimension() != null)
{
ChunkData ceiling = createChunkData(world);
InvertedBiomeGrid ceilingGrid = new InvertedBiomeGrid(grid);
targetCeiling();
generate(random, x, z, ceiling, ceilingGrid);
writeInverted(ceiling, data);
}
}
@Override
public void onHotload()
{
super.onHotload();
ceilingCached = false;
cacheCeiling = null;
cacheFloor = null;
}
private void targetFloor()
{
generatingCeiling = false;
}
private void targetCeiling()
{
generatingCeiling = true;
}
private void generate(RNG random, int x, int z, ChunkData ceiling, BiomeGrid grid)
{
super.onGenerate(random, x, z, ceiling, grid);
}
@Override
public IrisDimension getDimension()
{
return generatingCeiling ? getCeilingDimension() : getFloorDimension();
}
public IrisDimension getFloorDimension()
{
if(cacheFloor != null)
{
return cacheFloor;
}
return cacheFloor = super.getDimension();
}
public IrisDimension getCeilingDimension()
{
if(ceilingCached)
{
return cacheCeiling;
}
if(getFloorDimension().getCeiling().isEmpty())
{
return null;
}
IrisDimension c = Iris.data.getDimensionLoader().load(getFloorDimension().getCeiling());
if(c != null)
{
c.setInverted(true);
}
ceilingCached = true;
cacheCeiling = c;
return c;
}
public void writeInverted(ChunkData data, ChunkData into)
{
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < data.getMaxHeight(); j++)
{
for(int k = 0; k < 16; k++)
{
BlockData b = data.getBlockData(i, j, k);
if(b == null || b.getMaterial().equals(Material.AIR))
{
continue;
}
into.setBlock(i, data.getMaxHeight() - j, k, b);
}
}
}
}
public ChunkData copy(ChunkData d)
{
ChunkData copy = createChunkData(world);
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < d.getMaxHeight(); j++)
{
for(int k = 0; k < 16; k++)
{
BlockData b = d.getBlockData(i, j, k);
if(b == null || b.getMaterial().equals(Material.AIR))
{
continue;
}
copy.setBlock(i, j, k, b);
}
}
}
return copy;
}
}

View File

@@ -1,379 +0,0 @@
package com.volmit.iris.generator;
import java.util.List;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import com.volmit.iris.Iris;
import com.volmit.iris.IrisContext;
import com.volmit.iris.IrisMetrics;
import com.volmit.iris.util.BlockDataTools;
import com.volmit.iris.util.CNG;
import com.volmit.iris.util.ChronoLatch;
import com.volmit.iris.util.J;
import com.volmit.iris.util.PrecisionStopwatch;
import com.volmit.iris.util.RNG;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.api.ChatColor;
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class ContextualChunkGenerator extends ChunkGenerator implements Listener
{
protected boolean failing;
protected int task;
protected boolean dev;
protected boolean initialized;
protected RNG masterRandom;
protected ChronoLatch perSecond;
protected ChronoLatch tickLatch;
protected ChronoLatch pushLatch;
protected IrisMetrics metrics;
protected World world;
protected int generated;
protected int ticks;
private boolean fastPregen = false;
protected boolean pregenDone;
public ContextualChunkGenerator()
{
pushLatch = new ChronoLatch(3000);
tickLatch = new ChronoLatch(650);
perSecond = new ChronoLatch(1000);
CNG.creates = 0;
generated = 0;
ticks = 0;
task = -1;
initialized = false;
failing = false;
pregenDone = false;
dev = false;
}
protected abstract void onGenerate(RNG masterRandom, int x, int z, ChunkData data, BiomeGrid grid);
protected abstract void onInit(World world, RNG masterRandom);
protected abstract void onTick(int ticks);
protected abstract void onClose();
protected abstract void onFailure(Throwable e);
protected abstract void onChunkLoaded(Chunk c);
protected abstract void onChunkUnloaded(Chunk c);
protected abstract void onPlayerJoin(Player p);
protected abstract void onPlayerLeft(Player p);
private void init(World world, RNG rng)
{
if(initialized)
{
return;
}
this.world = world;
this.masterRandom = new RNG(world.getSeed());
metrics = new IrisMetrics(128);
initialized = true;
Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
task = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::tick, 0, 0);
onInit(world, masterRandom);
}
private void tick()
{
if(dev)
{
if(perSecond.flip())
{
if(generated > (fastPregen ? 1950 : 770))
{
pregenDone = true;
}
if(pregenDone)
{
metrics.getPerSecond().put(generated);
generated = 0;
}
}
}
else
{
pregenDone = true;
fastPregen = false;
}
onTick(ticks++);
}
@EventHandler
public void on(PlayerTeleportEvent e)
{
if(e.getFrom().getWorld().equals(world) && !e.getTo().getWorld().equals(world))
{
tick();
onPlayerLeft(e.getPlayer());
}
if(!e.getFrom().getWorld().equals(world) && e.getTo().getWorld().equals(world))
{
tick();
onPlayerJoin(e.getPlayer());
}
}
@EventHandler
public void on(PlayerQuitEvent e)
{
if(e.getPlayer().getWorld().equals(world))
{
tick();
onPlayerLeft(e.getPlayer());
}
}
@EventHandler
public void on(PlayerJoinEvent e)
{
if(e.getPlayer().getWorld().equals(world))
{
tick();
onPlayerJoin(e.getPlayer());
}
}
@EventHandler
public void on(ChunkLoadEvent e)
{
if(e.getWorld().equals(world))
{
tick();
onChunkLoaded(e.getChunk());
}
}
@EventHandler
public void on(ChunkUnloadEvent e)
{
if(e.getWorld().equals(world))
{
tick();
onChunkUnloaded(e.getChunk());
}
}
@EventHandler
public void on(WorldUnloadEvent e)
{
if(world != null && e.getWorld().equals(world))
{
close();
}
}
public void close()
{
HandlerList.unregisterAll(this);
Bukkit.getScheduler().cancelTask(getTask());
onClose();
}
@Override
public boolean canSpawn(World world, int x, int z)
{
return super.canSpawn(world, x, z);
}
protected ChunkData generateChunkDataFailure(World world, Random no, int x, int z, BiomeGrid biomeGrid)
{
ChunkData c = Bukkit.createChunkData(world);
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 16; j++)
{
int h = 0;
if(j == i || j + i == 16)
{
c.setBlock(i, h, j, BlockDataTools.getBlockData("RED_TERRACOTTA"));
}
else
{
c.setBlock(i, h, j, BlockDataTools.getBlockData("BLACK_TERRACOTTA"));
}
}
}
return c;
}
protected ChunkData generateChunkFastPregen(World world, Random no, int x, int z, BiomeGrid biomeGrid)
{
ChunkData c = Bukkit.createChunkData(world);
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 16; j++)
{
int h = 0;
if(j == i || j + i == 16)
{
c.setBlock(i, h, j, BlockDataTools.getBlockData("BLUE_TERRACOTTA"));
}
else
{
c.setBlock(i, h, j, BlockDataTools.getBlockData("WHITE_TERRACOTTA"));
}
}
}
return c;
}
@Override
public ChunkData generateChunkData(World world, Random no, int x, int z, BiomeGrid biomeGrid)
{
if(!dev)
{
pregenDone = true;
fastPregen = false;
}
PrecisionStopwatch sx = PrecisionStopwatch.start();
if(failing)
{
return generateChunkDataFailure(world, no, x, z, biomeGrid);
}
try
{
if(pushLatch.flip())
{
if(this.world == null)
{
this.world = world;
}
Iris.hotloader.check((IrisContext) this);
if(this instanceof IrisContext)
{
IrisContext.pushContext((IrisContext) this);
}
}
PrecisionStopwatch s = PrecisionStopwatch.start();
RNG random = new RNG(world.getSeed());
init(world, random.nextParallelRNG(0));
ChunkData c = Bukkit.createChunkData(world);
if(!pregenDone && fastPregen)
{
c = generateChunkFastPregen(world, no, x, z, biomeGrid);
}
else
{
onGenerate(random, x, z, c, biomeGrid);
}
metrics.getTotal().put(s.getMilliseconds());
generated++;
long hits = CNG.hits;
CNG.hits = 0;
Iris.instance.hit(hits);
metrics.getLoss().put(sx.getMilliseconds() - s.getMilliseconds());
return c;
}
catch(Throwable e)
{
fail(e);
}
return generateChunkDataFailure(world, no, x, z, biomeGrid);
}
public void onHotload()
{
}
protected void fail(Throwable e)
{
if(failing)
{
return;
}
failing = true;
e.printStackTrace();
J.a(() ->
{
J.sleep(1000);
Iris.error("---------------------------------------------------------------------------------------------------------");
e.printStackTrace();
Iris.error("---------------------------------------------------------------------------------------------------------");
Iris.error("ERROR! Failed to generate chunk! Iris has entered a failed state!");
Iris.error("---------------------------------------------------------------------------------------------------------");
for(Player i : world.getPlayers())
{
Iris.instance.imsg(i, ChatColor.DARK_RED + "Iris Generator has entered a failed state!");
Iris.instance.imsg(i, ChatColor.RED + "- Check the console for the error.");
Iris.instance.imsg(i, ChatColor.RED + "- Then simply run /iris dev");
}
});
onFailure(e);
}
@Override
public List<BlockPopulator> getDefaultPopulators(World world)
{
return super.getDefaultPopulators(world);
}
@Override
public Location getFixedSpawnLocation(World world, Random random)
{
return super.getFixedSpawnLocation(world, random);
}
@Override
public boolean isParallelCapable()
{
return true;
}
}

View File

@@ -1,96 +0,0 @@
package com.volmit.iris.generator;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.Iris;
import com.volmit.iris.object.InferredType;
import com.volmit.iris.object.IrisBiome;
import com.volmit.iris.object.IrisDimension;
import com.volmit.iris.object.IrisRegion;
import com.volmit.iris.util.BiomeResult;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class DimensionChunkGenerator extends ContextualChunkGenerator
{
protected final String dimensionName;
protected static final BlockData AIR = Material.AIR.createBlockData();
protected static final BlockData CAVE_AIR = Material.CAVE_AIR.createBlockData();
protected static final BlockData BEDROCK = Material.BEDROCK.createBlockData();
public DimensionChunkGenerator(String dimensionName)
{
super();
this.dimensionName = dimensionName;
}
public IrisDimension getDimension()
{
IrisDimension d = Iris.data.getDimensionLoader().load(dimensionName);
if(d == null)
{
Iris.error("Can't find dimension: " + dimensionName);
}
return d;
}
protected BiomeResult focus()
{
IrisBiome biome = Iris.data.getBiomeLoader().load(getDimension().getFocus());
for(String i : getDimension().getRegions())
{
IrisRegion reg = Iris.data.getRegionLoader().load(i);
if(reg.getLandBiomes().contains(biome.getLoadKey()))
{
biome.setInferredType(InferredType.LAND);
break;
}
if(reg.getSeaBiomes().contains(biome.getLoadKey()))
{
biome.setInferredType(InferredType.SEA);
break;
}
if(reg.getShoreBiomes().contains(biome.getLoadKey()))
{
biome.setInferredType(InferredType.SHORE);
break;
}
}
return new BiomeResult(biome, 0);
}
public double getModifiedX(int rx, int rz)
{
return (getDimension().cosRotate() * rx) + (-getDimension().sinRotate() * rz) +
getDimension().getCoordFracture(masterRandom, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
}
public double getModifiedZ(int rx, int rz)
{
return (getDimension().sinRotate() * rx) + (getDimension().cosRotate() * rz) +
getDimension().getCoordFracture(masterRandom, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
}
public double getZoomed(double modified)
{
return (double) (modified) / getDimension().getTerrainZoom();
}
public double getUnzoomed(double modified)
{
return (double) (modified) * getDimension().getTerrainZoom();
}
}

View File

@@ -1,195 +0,0 @@
package com.volmit.iris.generator;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.entity.Player;
import com.volmit.iris.Iris;
import com.volmit.iris.IrisContext;
import com.volmit.iris.object.IrisBiome;
import com.volmit.iris.object.IrisRegion;
import com.volmit.iris.object.atomics.AtomicRegionData;
import com.volmit.iris.util.BiomeResult;
import com.volmit.iris.util.CNG;
import com.volmit.iris.util.KMap;
import com.volmit.iris.util.RNG;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class IrisChunkGenerator extends CeilingChunkGenerator implements IrisContext
{
private Method initLighting;
private ReentrantLock lock;
private KMap<Player, IrisBiome> b = new KMap<>();
public IrisChunkGenerator(String dimensionName, int threads)
{
super(dimensionName, threads);
lock = new ReentrantLock();
}
@Override
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
{
lock.lock();
super.onGenerate(random, x, z, data, grid);
lock.unlock();
}
public void onInit(World world, RNG rng)
{
try
{
super.onInit(world, rng);
}
catch(Throwable e)
{
fail(e);
}
}
@Override
public BiomeResult getBiome(int x, int z)
{
return sampleBiome(x, z);
}
@Override
public IrisRegion getRegion(int x, int z)
{
return sampleRegion(x, z);
}
@Override
public int getHeight(int x, int z)
{
return sampleHeight(x, z);
}
@Override
protected void onTick(int ticks)
{
super.onTick(ticks);
}
@Override
protected void onClose()
{
super.onClose();
try
{
parallaxMap.saveAll();
ceilingParallaxMap.saveAll();
parallaxMap.getLoadedChunks().clear();
parallaxMap.getLoadedRegions().clear();
ceilingParallaxMap.getLoadedChunks().clear();
ceilingParallaxMap.getLoadedRegions().clear();
}
catch(IOException e)
{
e.printStackTrace();
}
setBiomeCache(null);
setAvailableFilters(null);
setBiomeHitCache(null);
setCacheTrueBiome(null);
setCacheHeightMap(null);
setCeilingSliverCache(null);
setSliverCache(null);
Iris.info("Closing Iris Dimension " + getWorld().getName());
}
@Override
protected void onFailure(Throwable e)
{
}
@Override
protected void onChunkLoaded(Chunk c)
{
}
@Override
protected void onChunkUnloaded(Chunk c)
{
}
@Override
protected void onPlayerJoin(Player p)
{
}
@Override
protected void onPlayerLeft(Player p)
{
}
@Override
public void onHotloaded()
{
CNG.creates = 0;
onHotload();
}
public long guessMemoryUsage()
{
long bytes = 1024 * 1024 * (8 + (getThreads() / 4));
for(AtomicRegionData i : parallaxMap.getLoadedRegions().values())
{
bytes += i.guessMemoryUsage();
}
for(AtomicRegionData i : ceilingParallaxMap.getLoadedRegions().values())
{
bytes += i.guessMemoryUsage();
}
bytes += parallaxMap.getLoadedChunks().size() * 256 * 4 * 460;
bytes += ceilingParallaxMap.getLoadedChunks().size() * 256 * 4 * 460;
bytes += getSliverBuffer() * 220;
bytes += 752 * Iris.data.getObjectLoader().getTotalStorage();
return bytes;
}
@Override
public boolean shouldGenerateCaves()
{
return false;
}
@Override
public boolean shouldGenerateDecorations()
{
return false;
}
@Override
public boolean shouldGenerateMobs()
{
return true;
}
@Override
public boolean shouldGenerateStructures()
{
return true;
}
}

View File

@@ -1,401 +0,0 @@
package com.volmit.iris.generator;
import java.io.IOException;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.Iris;
import com.volmit.iris.object.IrisBiome;
import com.volmit.iris.object.IrisBiomeMutation;
import com.volmit.iris.object.IrisObjectPlacement;
import com.volmit.iris.object.atomics.AtomicSliver;
import com.volmit.iris.object.atomics.AtomicSliverMap;
import com.volmit.iris.object.atomics.AtomicWorldData;
import com.volmit.iris.object.atomics.MasterLock;
import com.volmit.iris.util.BiomeMap;
import com.volmit.iris.util.CaveResult;
import com.volmit.iris.util.ChunkPosition;
import com.volmit.iris.util.HeightMap;
import com.volmit.iris.util.IObjectPlacer;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.KMap;
import com.volmit.iris.util.NastyRunnable;
import com.volmit.iris.util.PrecisionStopwatch;
import com.volmit.iris.util.RNG;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator implements IObjectPlacer
{
protected KMap<ChunkPosition, AtomicSliver> sliverCache;
protected AtomicWorldData parallaxMap;
protected KMap<ChunkPosition, AtomicSliver> ceilingSliverCache;
protected AtomicWorldData ceilingParallaxMap;
private MasterLock masterLock;
private ReentrantLock lock = new ReentrantLock();
private ReentrantLock lockq = new ReentrantLock();
private int sliverBuffer;
public ParallaxChunkGenerator(String dimensionName, int threads)
{
super(dimensionName, threads);
sliverCache = new KMap<>();
ceilingSliverCache = new KMap<>();
sliverBuffer = 0;
masterLock = new MasterLock();
}
public void onInit(World world, RNG rng)
{
super.onInit(world, rng);
parallaxMap = new AtomicWorldData(world, "floor");
ceilingParallaxMap = new AtomicWorldData(world, "ceiling");
}
protected KMap<ChunkPosition, AtomicSliver> getSliverCache()
{
return getDimension().isInverted() ? ceilingSliverCache : sliverCache;
}
protected void onClose()
{
super.onClose();
try
{
parallaxMap.unloadAll(true);
ceilingParallaxMap.unloadAll(true);
}
catch(IOException e)
{
e.printStackTrace();
}
}
@Override
public int getHighest(int x, int z)
{
return getHighest(x, z, false);
}
@Override
public int getHighest(int x, int z, boolean ignoreFluid)
{
int h = (int) Math.round(ignoreFluid ? getTerrainHeight(x, z) : getTerrainWaterHeight(x, z));
if(getDimension().isCarving() && h >= getDimension().getCarvingMin())
{
while(getGlCarve().isCarved(x, h, z))
{
h--;
}
return h;
}
return h;
}
@Override
public void set(int x, int y, int z, BlockData d)
{
getMasterLock().lock((x >> 4) + "." + (z >> 4));
getParallaxSliver(x, z).set(y, d);
getMasterLock().unlock((x >> 4) + "." + (z >> 4));
}
@Override
public BlockData get(int x, int y, int z)
{
BlockData b = sampleSliver(x, z).getBlock().get(y);
return b == null ? AIR : b;
}
@Override
public boolean isSolid(int x, int y, int z)
{
return get(x, y, z).getMaterial().isSolid();
}
public AtomicSliver getParallaxSliver(int wx, int wz)
{
getMasterLock().lock("gpc");
getMasterLock().lock((wx >> 4) + "." + (wz >> 4));
AtomicSliverMap map = getParallaxChunk(wx >> 4, wz >> 4);
getMasterLock().unlock("gpc");
AtomicSliver sliver = map.getSliver(wx & 15, wz & 15);
getMasterLock().unlock((wx >> 4) + "." + (wz >> 4));
return sliver;
}
public boolean isParallaxGenerated(int x, int z)
{
return getParallaxChunk(x, z).isParallaxGenerated();
}
public boolean isWorldGenerated(int x, int z)
{
return getParallaxChunk(x, z).isWorldGenerated();
}
public AtomicWorldData getParallaxMap()
{
return getDimension().isInverted() ? ceilingParallaxMap : parallaxMap;
}
public AtomicSliverMap getParallaxChunk(int x, int z)
{
try
{
return getParallaxMap().loadChunk(x, z);
}
catch(IOException e)
{
fail(e);
}
return new AtomicSliverMap();
}
@Override
protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
{
if(getSliverCache().size() > 20000)
{
getSliverCache().clear();
}
super.onPostGenerate(random, x, z, data, grid, height, biomeMap);
PrecisionStopwatch p = PrecisionStopwatch.start();
getBiomeHitCache().clear();
if(getDimension().isPlaceObjects())
{
onGenerateParallax(random, x, z);
injectBiomeSky(x, z, grid);
getParallaxChunk(x, z).inject(data);
setSliverBuffer(getSliverCache().size());
getParallaxChunk(x, z).setWorldGenerated(true);
getMasterLock().clear();
}
p.end();
getMetrics().getParallax().put(p.getMilliseconds());
super.onPostParallaxPostGenerate(random, x, z, data, grid, height, biomeMap);
}
protected void injectBiomeSky(int x, int z, BiomeGrid grid)
{
if(getDimension().isInverted())
{
return;
}
int rx;
int rz;
for(int i = 0; i < 16; i++)
{
rx = (x * 16) + i;
for(int j = 0; j < 16; j++)
{
rz = (z * 16) + j;
int min = sampleSliver(rx, rz).getHighestBiome();
int max = getParallaxSliver(rx, rz).getHighestBlock();
if(min < max)
{
IrisBiome biome = getCachedInternalBiome(i, j);
for(int g = min; g <= max; g++)
{
grid.setBiome(i, g, j, biome.getSkyBiome(masterRandom, rz, g, rx));
}
}
}
}
}
protected void onGenerateParallax(RNG random, int x, int z)
{
String key = "par." + x + "." + "z";
ChunkPosition rad = getDimension().getParallaxSize();
KList<NastyRunnable> q = new KList<>();
for(int ii = x - (rad.getX() / 2); ii <= x + (rad.getX() / 2); ii++)
{
int i = ii;
for(int jj = z - (rad.getZ() / 2); jj <= z + (rad.getZ() / 2); jj++)
{
int j = jj;
if(isParallaxGenerated(ii, jj))
{
continue;
}
if(isWorldGenerated(ii, jj))
{
continue;
}
getAccelerant().queue(key, () ->
{
IrisBiome b = sampleTrueBiome((i * 16) + 7, (j * 16) + 7).getBiome();
RNG ro = random.nextParallelRNG(496888 + i + j);
int g = 1;
searching: for(IrisBiomeMutation k : getDimension().getMutations())
{
for(int l = 0; l < k.getChecks(); l++)
{
IrisBiome sa = sampleTrueBiome(((i * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()), ((j * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius())).getBiome();
IrisBiome sb = sampleTrueBiome(((i * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()), ((j * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius())).getBiome();
if(sa.getLoadKey().equals(sb.getLoadKey()))
{
continue;
}
if(k.getRealSideA().contains(sa.getLoadKey()) && k.getRealSideB().contains(sb.getLoadKey()))
{
for(IrisObjectPlacement m : k.getObjects())
{
int gg = g++;
lockq.lock();
q.add(() ->
{
placeObject(m, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 1569962));
});
lockq.unlock();
}
continue searching;
}
}
}
for(IrisObjectPlacement k : b.getObjects())
{
int gg = g++;
lockq.lock();
q.add(() ->
{
placeObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 3569222));
});
lockq.unlock();
}
if(getDimension().isCaves())
{
int bx = (i * 16) + ro.nextInt(16);
int bz = (j * 16) + ro.nextInt(16);
IrisBiome biome = sampleCaveBiome(bx, bz).getBiome();
if(biome == null)
{
return;
}
if(biome.getObjects().isEmpty())
{
return;
}
for(IrisObjectPlacement k : biome.getObjects())
{
int gg = g++;
lockq.lock();
q.add(() ->
{
placeCaveObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 1869322));
});
lockq.unlock();
}
}
});
getParallaxChunk(ii, jj).setParallaxGenerated(true);
}
}
getAccelerant().waitFor(key);
lockq.lock();
for(NastyRunnable i : q)
{
getAccelerant().queue(key + "-obj", i);
}
lockq.unlock();
getAccelerant().waitFor(key + "-obj");
}
public void placeObject(IrisObjectPlacement o, int x, int z, RNG rng)
{
for(int i = 0; i < o.getTriesForChunk(rng); i++)
{
rng = rng.nextParallelRNG((i * 3 + 8) - 23040);
o.getSchematic(rng).place((x * 16) + rng.nextInt(16), (z * 16) + rng.nextInt(16), this, o, rng);
}
}
public void placeCaveObject(IrisObjectPlacement o, int x, int z, RNG rng)
{
for(int i = 0; i < o.getTriesForChunk(rng); i++)
{
rng = rng.nextParallelRNG((i * 3 + 8) - 23040);
int xx = (x * 16) + rng.nextInt(16);
int zz = (z * 16) + rng.nextInt(16);
KList<CaveResult> res = getCaves(xx, zz);
if(res.isEmpty())
{
continue;
}
o.getSchematic(rng).place(xx, res.get(rng.nextParallelRNG(29345 * (i + 234)).nextInt(res.size())).getFloor() + 2, zz, this, o, rng);
}
}
@Override
protected void onTick(int ticks)
{
getParallaxMap().clean(ticks);
Iris.data.getObjectLoader().clean();
}
public AtomicSliver sampleSliver(int x, int z)
{
ChunkPosition key = new ChunkPosition(x, z);
if(getSliverCache().containsKey(key))
{
return getSliverCache().get(key);
}
AtomicSliver s = new AtomicSliver(x & 15, z & 15);
onGenerateColumn(x >> 4, z >> 4, x, z, x & 15, z & 15, s, null);
getSliverCache().put(key, s);
return s;
}
@Override
public boolean isPreventingDecay()
{
return getDimension().isPreventLeafDecay();
}
}

View File

@@ -1,134 +0,0 @@
package com.volmit.iris.generator;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.World;
import com.volmit.iris.Iris;
import com.volmit.iris.object.atomics.AtomicSliver;
import com.volmit.iris.object.atomics.AtomicSliverMap;
import com.volmit.iris.util.BiomeMap;
import com.volmit.iris.util.GroupedExecutor;
import com.volmit.iris.util.HeightMap;
import com.volmit.iris.util.PrecisionStopwatch;
import com.volmit.iris.util.RNG;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class ParallelChunkGenerator extends BiomeChunkGenerator
{
private GroupedExecutor accelerant;
private int threads;
protected boolean unsafe;
protected int cacheX;
protected int cacheZ;
private ReentrantLock genlock;
protected boolean cachingAllowed;
public ParallelChunkGenerator(String dimensionName, int threads)
{
super(dimensionName);
unsafe = false;
cacheX = 0;
cacheZ = 0;
this.threads = threads;
genlock = new ReentrantLock();
}
public void changeThreadCount(int tc)
{
threads = tc;
GroupedExecutor e = accelerant;
accelerant = new GroupedExecutor(threads, Thread.NORM_PRIORITY, "Iris Generator - " + world.getName());
Iris.executors.add(accelerant);
if(e != null)
{
e.close();
}
}
protected abstract void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap, int onlyY);
protected void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap)
{
onGenerateColumn(cx, cz, wx, wz, x, z, sliver, biomeMap, -1);
}
protected abstract int onSampleColumnHeight(int cx, int cz, int wx, int wz, int x, int z);
protected abstract void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap);
protected int sampleHeight(int x, int z)
{
return onSampleColumnHeight(x >> 4, z >> 4, x, z, x & 15, z & 15);
}
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
{
genlock.lock();
cacheX = x;
cacheZ = z;
PrecisionStopwatch p = PrecisionStopwatch.start();
AtomicSliverMap map = new AtomicSliverMap();
HeightMap height = new HeightMap();
String key = "c" + x + "," + z;
BiomeMap biomeMap = new BiomeMap();
int ii, jj;
for(ii = 0; ii < 16; ii++)
{
int i = ii;
int wx = (x * 16) + i;
for(jj = 0; jj < 16; jj++)
{
int j = jj;
int wz = (z * 16) + j;
AtomicSliver sliver = map.getSliver(i, j);
accelerant.queue(key, () ->
{
onGenerateColumn(x, z, wx, wz, i, j, sliver, biomeMap);
});
}
}
setCachingAllowed(true);
setUnsafe(true);
accelerant.waitFor(key);
setUnsafe(false);
setCachingAllowed(false);
map.write(data, grid, height);
getMetrics().getTerrain().put(p.getMilliseconds());
p = PrecisionStopwatch.start();
onPostGenerate(random, x, z, data, grid, height, biomeMap);
genlock.unlock();
}
protected void onClose()
{
accelerant.close();
Iris.executors.remove(accelerant);
}
public void onInit(World world, RNG rng)
{
super.onInit(world, rng);
changeThreadCount(threads);
}
public boolean isSafe()
{
return !unsafe;
}
@Override
public boolean isParallelCapable()
{
return false;
}
}

View File

@@ -1,203 +0,0 @@
package com.volmit.iris.generator;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.Iris;
import com.volmit.iris.object.IrisDimension;
import com.volmit.iris.util.CaveResult;
import com.volmit.iris.util.IPostBlockAccess;
import com.volmit.iris.util.IrisPostBlockFilter;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.PrecisionStopwatch;
import com.volmit.iris.util.RNG;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class PostBlockChunkGenerator extends ParallaxChunkGenerator implements IPostBlockAccess
{
protected boolean generatingCeiling = false;
protected boolean ceilingCached = false;
protected IrisDimension cacheCeiling = null;
protected IrisDimension cacheFloor = null;
private int currentPostX;
private int currentPostZ;
private ChunkData currentData;
private KList<IrisPostBlockFilter> availableFilters;
private String postKey;
private ReentrantLock lock;
private int minPhase;
private int maxPhase;
public PostBlockChunkGenerator(String dimensionName, int threads)
{
super(dimensionName, threads);
availableFilters = new KList<>();
postKey = "post-" + dimensionName;
lock = new ReentrantLock();
}
public void onInit(World world, RNG rng)
{
super.onInit(world, rng);
for(Class<? extends IrisPostBlockFilter> i : Iris.postProcessors)
{
try
{
availableFilters.add(i.getConstructor(PostBlockChunkGenerator.class).newInstance(this));
}
catch(Throwable e)
{
Iris.error("Failed to initialize post processor: " + i.getCanonicalName());
fail(e);
}
}
}
@Override
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
{
super.onGenerate(random, x, z, data, grid);
if(!getDimension().isPostProcessing())
{
return;
}
KList<IrisPostBlockFilter> filters = getDimension().getPostBlockProcessors(this);
currentData = data;
currentPostX = x;
currentPostZ = z;
int rx, i, j;
PrecisionStopwatch p = PrecisionStopwatch.start();
for(int h = getMinPhase(); h <= getMaxPhase(); h++)
{
for(i = 0; i < 16; i++)
{
rx = (x << 4) + i;
for(j = 0; j < 16; j++)
{
int rxx = rx;
int rzz = (z << 4) + j;
for(IrisPostBlockFilter f : filters)
{
if(f.getPhase() == h)
{
f.onPost(rxx, rzz);
}
}
}
}
for(IrisPostBlockFilter f : filters)
{
if(f.getPhase() == h)
{
while(f.getQueue().size() > 0)
{
f.getQueue().pop().run();
}
}
}
}
p.end();
getMetrics().getPost().put(p.getMilliseconds());
}
public IrisPostBlockFilter createProcessor(String processor, int phase)
{
for(IrisPostBlockFilter i : availableFilters)
{
if(i.getKey().equals(processor))
{
try
{
return i.getClass().getConstructor(PostBlockChunkGenerator.class, int.class).newInstance(this, phase);
}
catch(Throwable e)
{
Iris.error("Failed initialize find post processor: " + processor);
fail(e);
}
}
}
Iris.error("Failed to find post processor: " + processor);
fail(new RuntimeException("Failed to find post processor: " + processor));
return null;
}
@Override
public void updateHeight(int x, int z, int h)
{
if(x >> 4 == currentPostX && z >> 4 == currentPostZ)
{
getCacheHeightMap()[((z & 15) << 4) | (x & 15)] = h;
}
else
{
Iris.error("Invalid Heightmap set! Chunk Currently at " + currentPostX + "," + currentPostZ + ". Attempted to place at " + (x >> 4) + " " + (z >> 4) + " which is bad.");
}
}
@Override
public BlockData getPostBlock(int x, int y, int z)
{
if(x >> 4 == currentPostX && z >> 4 == currentPostZ)
{
lock.lock();
BlockData d = currentData.getBlockData(x & 15, y, z & 15);
lock.unlock();
return d == null ? AIR : d;
}
return sampleSliver(x, z).get(y);
}
@Override
public void setPostBlock(int x, int y, int z, BlockData d)
{
if(x >> 4 == currentPostX && z >> 4 == currentPostZ)
{
lock.lock();
currentData.setBlock(x & 15, y, z & 15, d);
lock.unlock();
}
else
{
Iris.warn("Post Block Overdraw: " + currentPostX + "," + currentPostZ + " into " + (x >> 4) + ", " + (z >> 4));
}
}
@Override
public int highestTerrainOrFluidBlock(int x, int z)
{
return getHighest(x, z, false);
}
@Override
public int highestTerrainBlock(int x, int z)
{
return getHighest(x, z, true);
}
@Override
public KList<CaveResult> caveFloors(int x, int z)
{
return getCaves(x, z);
}
}

View File

@@ -1,651 +0,0 @@
package com.volmit.iris.generator;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.Bisected.Half;
import org.bukkit.block.data.BlockData;
import com.volmit.iris.Iris;
import com.volmit.iris.layer.GenLayerCarve;
import com.volmit.iris.layer.GenLayerCave;
import com.volmit.iris.object.DecorationPart;
import com.volmit.iris.object.InferredType;
import com.volmit.iris.object.IrisBiome;
import com.volmit.iris.object.IrisBiomeDecorator;
import com.volmit.iris.object.IrisDepositGenerator;
import com.volmit.iris.object.IrisRegion;
import com.volmit.iris.object.atomics.AtomicSliver;
import com.volmit.iris.util.BiomeMap;
import com.volmit.iris.util.BiomeResult;
import com.volmit.iris.util.BlockDataTools;
import com.volmit.iris.util.CaveResult;
import com.volmit.iris.util.HeightMap;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.M;
import com.volmit.iris.util.RNG;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
{
private long lastUpdateRequest = M.ms();
private long lastChunkLoad = M.ms();
private GenLayerCave glCave;
private GenLayerCarve glCarve;
private RNG rockRandom;
private int[] cacheHeightMap;
private IrisBiome[] cacheTrueBiome;
private ReentrantLock cacheLock;
public TerrainChunkGenerator(String dimensionName, int threads)
{
super(dimensionName, threads);
cacheHeightMap = new int[256];
cacheTrueBiome = new IrisBiome[256];
cachingAllowed = true;
cacheLock = new ReentrantLock();
}
public void onInit(World world, RNG rng)
{
super.onInit(world, rng);
rockRandom = getMasterRandom().nextParallelRNG(2858678);
glCave = new GenLayerCave(this, rng.nextParallelRNG(238948));
glCarve = new GenLayerCarve(this, rng.nextParallelRNG(968346576));
}
public KList<CaveResult> getCaves(int x, int z)
{
return glCave.genCaves(x, z, x & 15, z & 15, null);
}
@Override
protected void onGenerateColumn(int cx, int cz, int rx, int rz, int x, int z, AtomicSliver sliver, BiomeMap biomeMap, int onlyY)
{
if(x > 15 || x < 0 || z > 15 || z < 0)
{
throw new RuntimeException("Invalid OnGenerate call: x:" + x + " z:" + z);
}
try
{
int highestPlaced = 0;
BlockData block;
int fluidHeight = getDimension().getFluidHeight();
double ox = getModifiedX(rx, rz);
double oz = getModifiedZ(rx, rz);
double wx = getZoomed(ox);
double wz = getZoomed(oz);
int depth = 0;
double noise = getNoiseHeight(rx, rz);
int height = (int) Math.round(noise) + fluidHeight;
boolean carvable = getDimension().isCarving() && height > getDimension().getCarvingMin();
IrisRegion region = sampleRegion(rx, rz);
IrisBiome biome = sampleTrueBiome(rx, rz).getBiome();
if(biome == null)
{
throw new RuntimeException("Null Biome!");
}
if(cachingAllowed)
{
try
{
cacheTrueBiome[(z << 4) | x] = biome;
cacheHeightMap[(z << 4) | x] = height;
}
catch(Throwable e)
{
Iris.error("Failed to write cache at " + x + " " + z + " in chunk " + cx + " " + cz);
}
}
KList<BlockData> layers = biome.generateLayers(wx, wz, masterRandom, height, height - getFluidHeight());
KList<BlockData> seaLayers = biome.isSea() ? biome.generateSeaLayers(wx, wz, masterRandom, fluidHeight - height) : new KList<>();
cacheInternalBiome(x, z, biome);
boolean caverning = false;
KList<Integer> cavernHeights = new KList<>();
int lastCavernHeight = -1;
for(int k = Math.max(height, fluidHeight); k < Math.max(height, fluidHeight) + 3; k++)
{
if(k < Math.max(height, fluidHeight) + 3)
{
if(biomeMap != null)
{
sliver.set(k, biome.getGroundBiome(masterRandom, rz, k, rx));
}
}
}
for(int k = Math.max(height, fluidHeight); k >= 0; k--)
{
boolean cavernSurface = false;
if(k == 0)
{
if(biomeMap != null)
{
sliver.set(k, biome.getDerivative());
biomeMap.setBiome(x, z, biome);
}
sliver.set(k, BEDROCK);
continue;
}
if(carvable && glCarve.isCarved(rx, k, rz))
{
if(biomeMap != null)
{
sliver.set(k, biome.getDerivative());
biomeMap.setBiome(x, z, biome);
}
sliver.set(k, CAVE_AIR);
caverning = true;
continue;
}
else if(carvable && caverning)
{
lastCavernHeight = k;
cavernSurface = true;
cavernHeights.add(k);
caverning = false;
}
boolean underwater = k > height && k <= fluidHeight;
if(biomeMap != null)
{
sliver.set(k, biome.getGroundBiome(masterRandom, rz, k, rx));
biomeMap.setBiome(x, z, biome);
}
if(underwater)
{
block = seaLayers.hasIndex(fluidHeight - k) ? layers.get(depth) : getDimension().getFluid(rockRandom, wx, k, wz);
}
else if(layers.hasIndex(lastCavernHeight - k))
{
block = layers.get(lastCavernHeight - k);
}
else
{
block = layers.hasIndex(depth) ? layers.get(depth) : getDimension().getRock(rockRandom, wx, k, wz);
depth++;
}
sliver.set(k, block);
highestPlaced = Math.max(highestPlaced, k);
if(!cavernSurface && (k == height && block.getMaterial().isSolid() && k < fluidHeight))
{
decorateUnderwater(biome, sliver, wx, k, wz, rx, rz, block);
}
if((carvable && cavernSurface) || (k == Math.max(height, fluidHeight) && block.getMaterial().isSolid() && k < 255 && k > fluidHeight))
{
decorateLand(biome, sliver, wx, k, wz, rx, rz, block);
}
}
KList<CaveResult> caveResults = glCave.genCaves(rx, rz, x, z, sliver);
IrisBiome caveBiome = glBiome.generateData(InferredType.CAVE, wx, wz, rx, rz, region).getBiome();
if(caveBiome != null)
{
for(CaveResult i : caveResults)
{
for(int j = i.getFloor(); j <= i.getCeiling(); j++)
{
sliver.set(j, caveBiome);
sliver.set(j, caveBiome.getGroundBiome(masterRandom, rz, j, rx));
}
KList<BlockData> floor = caveBiome.generateLayers(wx, wz, rockRandom, i.getFloor() - 2, i.getFloor() - 2);
KList<BlockData> ceiling = caveBiome.generateLayers(wx + 256, wz + 256, rockRandom, height - i.getCeiling() - 2, height - i.getCeiling() - 2);
BlockData blockc = null;
for(int j = 0; j < floor.size(); j++)
{
if(j == 0)
{
blockc = floor.get(j);
}
sliver.set(i.getFloor() - j, floor.get(j));
}
for(int j = ceiling.size() - 1; j > 0; j--)
{
sliver.set(i.getCeiling() + j, ceiling.get(j));
}
if(blockc != null && !sliver.isSolid(i.getFloor() + 1))
{
decorateCave(caveBiome, sliver, wx, i.getFloor(), wz, rx, rz, blockc);
}
}
}
if(cachingAllowed && highestPlaced < height)
{
cacheHeightMap[(z << 4) | x] = highestPlaced;
}
}
catch(Throwable e)
{
fail(e);
}
}
@Override
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
{
super.onGenerate(random, x, z, data, grid);
RNG ro = random.nextParallelRNG((x * x * x) - z);
IrisRegion region = sampleRegion((x * 16) + 7, (z * 16) + 7);
IrisBiome biome = sampleTrueBiome((x * 16) + 7, (z * 16) + 7).getBiome();
for(IrisDepositGenerator k : getDimension().getDeposits())
{
k.generate(data, ro, this);
}
for(IrisDepositGenerator k : region.getDeposits())
{
for(int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++)
{
k.generate(data, ro, this);
}
}
for(IrisDepositGenerator k : biome.getDeposits())
{
for(int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++)
{
k.generate(data, ro, this);
}
}
}
protected boolean canPlace(Material mat, Material onto)
{
if(onto.equals(Material.GRASS_BLOCK) && mat.equals(Material.DEAD_BUSH))
{
return false;
}
if(onto.equals(Material.GRASS_PATH))
{
if(!mat.isSolid())
{
return false;
}
}
if(onto.equals(Material.STONE) || onto.equals(Material.GRAVEL) || onto.equals(Material.GRAVEL) || onto.equals(Material.ANDESITE) || onto.equals(Material.GRANITE) || onto.equals(Material.DIORITE) || onto.equals(Material.BLACKSTONE) || onto.equals(Material.BASALT))
{
if(mat.equals(Material.POPPY) || mat.equals(Material.DANDELION) || mat.equals(Material.CORNFLOWER) || mat.equals(Material.ORANGE_TULIP) || mat.equals(Material.PINK_TULIP) || mat.equals(Material.RED_TULIP) || mat.equals(Material.WHITE_TULIP) || mat.equals(Material.FERN) || mat.equals(Material.LARGE_FERN) || mat.equals(Material.GRASS) || mat.equals(Material.TALL_GRASS))
{
return false;
}
}
if(onto.equals(Material.ACACIA_LEAVES) || onto.equals(Material.BIRCH_LEAVES) || onto.equals(Material.DARK_OAK_LEAVES) || onto.equals(Material.JUNGLE_LEAVES) || onto.equals(Material.OAK_LEAVES) || onto.equals(Material.SPRUCE_LEAVES))
{
if(!mat.isSolid())
{
return false;
}
}
return true;
}
private void decorateLand(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, BlockData block)
{
if(!getDimension().isDecorate())
{
return;
}
int j = 0;
for(IrisBiomeDecorator i : biome.getDecorators())
{
if(i.getPartOf().equals(DecorationPart.SHORE_LINE) && !touchesSea(rx, rz))
{
continue;
}
BlockData d = i.getBlockData(getMasterRandom().nextParallelRNG((int) (38888 + biome.getRarity() + biome.getName().length() + j++)), wx, wz);
if(d != null)
{
if(!canPlace(d.getMaterial(), block.getMaterial()))
{
continue;
}
if(d.getMaterial().equals(Material.CACTUS))
{
if(!block.getMaterial().equals(Material.SAND) && !block.getMaterial().equals(Material.RED_SAND))
{
sliver.set(k, BlockDataTools.getBlockData("RED_SAND"));
}
}
if(d instanceof Bisected && k < 254)
{
Bisected t = ((Bisected) d.clone());
t.setHalf(Half.TOP);
Bisected b = ((Bisected) d.clone());
b.setHalf(Half.BOTTOM);
sliver.set(k + 1, b);
sliver.set(k + 2, t);
}
else
{
int stack = i.getHeight(getMasterRandom().nextParallelRNG((int) (39456 + (10000 * i.getChance()) + i.getStackMax() + i.getStackMin() + i.getZoom())), wx, wz);
if(stack == 1)
{
sliver.set(k + 1, d);
}
else if(k < 255 - stack)
{
for(int l = 0; l < stack; l++)
{
sliver.set(k + l + 1, d);
}
}
}
break;
}
}
}
private void decorateCave(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, BlockData block)
{
if(!getDimension().isDecorate())
{
return;
}
int j = 0;
for(IrisBiomeDecorator i : biome.getDecorators())
{
BlockData d = i.getBlockData(getMasterRandom().nextParallelRNG(2333877 + biome.getRarity() + biome.getName().length() + +j++), wx, wz);
if(d != null)
{
if(!canPlace(d.getMaterial(), block.getMaterial()))
{
continue;
}
if(d.getMaterial().equals(Material.CACTUS))
{
if(!block.getMaterial().equals(Material.SAND) && !block.getMaterial().equals(Material.RED_SAND))
{
sliver.set(k, BlockDataTools.getBlockData("SAND"));
}
}
if(d instanceof Bisected && k < 254)
{
Bisected t = ((Bisected) d.clone());
t.setHalf(Half.TOP);
Bisected b = ((Bisected) d.clone());
b.setHalf(Half.BOTTOM);
sliver.set(k + 1, b);
sliver.set(k + 2, t);
}
else
{
int stack = i.getHeight(getMasterRandom().nextParallelRNG((int) (39456 + (1000 * i.getChance()) + i.getZoom() * 10)), wx, wz);
if(stack == 1)
{
sliver.set(k + 1, d);
}
else if(k < 255 - stack)
{
for(int l = 0; l < stack; l++)
{
if(sliver.isSolid(k + l + 1))
{
break;
}
sliver.set(k + l + 1, d);
}
}
}
break;
}
}
}
private void decorateUnderwater(IrisBiome biome, AtomicSliver sliver, double wx, int y, double wz, int rx, int rz, BlockData block)
{
if(!getDimension().isDecorate())
{
return;
}
int j = 0;
for(IrisBiomeDecorator i : biome.getDecorators())
{
if(biome.getInferredType().equals(InferredType.SHORE))
{
continue;
}
BlockData d = i.getBlockData(getMasterRandom().nextParallelRNG(2555 + biome.getRarity() + biome.getName().length() + j++), wx, wz);
if(d != null)
{
int stack = i.getHeight(getMasterRandom().nextParallelRNG((int) (239456 + i.getStackMax() + i.getStackMin() + i.getVerticalZoom() + i.getZoom() + i.getBlockData().size() + j)), wx, wz);
if(stack == 1)
{
sliver.set(i.getPartOf().equals(DecorationPart.SEA_SURFACE) ? (getFluidHeight() + 1) : (y + 1), d);
}
else if(y < getFluidHeight() - stack)
{
for(int l = 0; l < stack; l++)
{
sliver.set(i.getPartOf().equals(DecorationPart.SEA_SURFACE) ? (getFluidHeight() + 1 + l) : (y + l + 1), d);
}
}
break;
}
}
}
@Override
protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
{
onPreParallaxPostGenerate(random, x, z, data, grid, height, biomeMap);
}
protected void onPreParallaxPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
{
}
protected void onPostParallaxPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap)
{
}
protected double getNoiseHeight(int rx, int rz)
{
double wx = getZoomed(rx);
double wz = getZoomed(rz);
return getBiomeHeight(wx, wz);
}
public BiomeResult sampleTrueBiomeBase(int x, int z)
{
if(!getDimension().getFocus().equals(""))
{
return focus();
}
double wx = getModifiedX(x, z);
double wz = getModifiedZ(x, z);
IrisRegion region = sampleRegion(x, z);
int height = (int) Math.round(getTerrainHeight(x, z));
double sh = region.getShoreHeight(wx, wz);
IrisBiome current = sampleBiome(x, z).getBiome();
if(current.isShore() && height > sh)
{
return glBiome.generateData(InferredType.LAND, wx, wz, x, z, region);
}
if(current.isShore() || current.isLand() && height <= getDimension().getFluidHeight())
{
return glBiome.generateData(InferredType.SEA, wx, wz, x, z, region);
}
if(current.isSea() && height > getDimension().getFluidHeight())
{
return glBiome.generateData(InferredType.LAND, wx, wz, x, z, region);
}
if(height <= getDimension().getFluidHeight())
{
return glBiome.generateData(InferredType.SEA, wx, wz, x, z, region);
}
if(height <= getDimension().getFluidHeight() + sh)
{
return glBiome.generateData(InferredType.SHORE, wx, wz, x, z, region);
}
return glBiome.generateRegionData(wx, wz, x, z, region);
}
public BiomeResult sampleCaveBiome(int x, int z)
{
double wx = getModifiedX(x, z);
double wz = getModifiedZ(x, z);
return glBiome.generateData(InferredType.CAVE, wx, wz, x, z, sampleRegion(x, z));
}
public BiomeResult sampleTrueBiome(int x, int y, int z)
{
if(y < getTerrainHeight(x, z))
{
double wx = getModifiedX(x, z);
double wz = getModifiedZ(x, z);
BiomeResult r = glBiome.generateData(InferredType.CAVE, wx, wz, x, z, sampleRegion(x, z));
if(r.getBiome() != null)
{
return r;
}
}
return sampleTrueBiome(x, z);
}
public BiomeResult sampleTrueBiome(int x, int z)
{
if(!getDimension().getFocus().equals(""))
{
return focus();
}
if(isSafe() && x >> 4 == cacheX && z >> 4 == cacheZ)
{
return new BiomeResult(cacheTrueBiome[((z & 15) << 4) | (x & 15)], 0);
}
double wx = getModifiedX(x, z);
double wz = getModifiedZ(x, z);
IrisRegion region = sampleRegion(x, z);
int height = sampleHeight(x, z);
double sh = region.getShoreHeight(wx, wz);
BiomeResult res = sampleTrueBiomeBase(x, z);
IrisBiome current = res.getBiome();
if(current.isSea() && height > getDimension().getFluidHeight() - sh)
{
return glBiome.generateData(InferredType.SHORE, wx, wz, x, z, region);
}
return res;
}
@Override
protected int onSampleColumnHeight(int cx, int cz, int rx, int rz, int x, int z)
{
int fluidHeight = getDimension().getFluidHeight();
double noise = getNoiseHeight(rx, rz);
return (int) Math.round(noise) + fluidHeight;
}
private boolean touchesSea(int rx, int rz)
{
return isFluidAtHeight(rx + 1, rz) || isFluidAtHeight(rx - 1, rz) || isFluidAtHeight(rx, rz - 1) || isFluidAtHeight(rx, rz + 1);
}
public boolean isUnderwater(int x, int z)
{
return isFluidAtHeight(x, z);
}
public boolean isFluidAtHeight(int x, int z)
{
return Math.round(getTerrainHeight(x, z)) < getFluidHeight();
}
public int getFluidHeight()
{
return getDimension().getFluidHeight();
}
public double getTerrainHeight(int x, int z)
{
if(isSafe() && x >> 4 == cacheX && z >> 4 == cacheZ)
{
return cacheHeightMap[((z & 15) << 4) | (x & 15)];
}
return getNoiseHeight(x, z) + getFluidHeight();
}
public double getTerrainWaterHeight(int x, int z)
{
return Math.max(getTerrainHeight(x, z), getFluidHeight());
}
}