mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-30 12:29:20 +00:00
Total rotation support
This commit is contained in:
251
src/main/java/com/volmit/iris/gen/BiomeChunkGenerator.java
Normal file
251
src/main/java/com/volmit/iris/gen/BiomeChunkGenerator.java
Normal file
@@ -0,0 +1,251 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
154
src/main/java/com/volmit/iris/gen/CeilingChunkGenerator.java
Normal file
154
src/main/java/com/volmit/iris/gen/CeilingChunkGenerator.java
Normal file
@@ -0,0 +1,154 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
379
src/main/java/com/volmit/iris/gen/ContextualChunkGenerator.java
Normal file
379
src/main/java/com/volmit/iris/gen/ContextualChunkGenerator.java
Normal file
@@ -0,0 +1,379 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
195
src/main/java/com/volmit/iris/gen/IrisChunkGenerator.java
Normal file
195
src/main/java/com/volmit/iris/gen/IrisChunkGenerator.java
Normal file
@@ -0,0 +1,195 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
401
src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java
Normal file
401
src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java
Normal file
@@ -0,0 +1,401 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
134
src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java
Normal file
134
src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java
Normal file
@@ -0,0 +1,134 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
203
src/main/java/com/volmit/iris/gen/PostBlockChunkGenerator.java
Normal file
203
src/main/java/com/volmit/iris/gen/PostBlockChunkGenerator.java
Normal file
@@ -0,0 +1,203 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
651
src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java
Normal file
651
src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java
Normal file
@@ -0,0 +1,651 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
162
src/main/java/com/volmit/iris/gen/atomics/AtomicRegionData.java
Normal file
162
src/main/java/com/volmit/iris/gen/atomics/AtomicRegionData.java
Normal file
@@ -0,0 +1,162 @@
|
||||
package com.volmit.iris.object.atomics;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.volmit.iris.IrisSettings;
|
||||
import com.volmit.iris.util.ByteArrayTag;
|
||||
import com.volmit.iris.util.CompoundTag;
|
||||
import com.volmit.iris.util.CustomOutputStream;
|
||||
import com.volmit.iris.util.KMap;
|
||||
import com.volmit.iris.util.NBTInputStream;
|
||||
import com.volmit.iris.util.NBTOutputStream;
|
||||
import com.volmit.iris.util.Tag;
|
||||
|
||||
public class AtomicRegionData
|
||||
{
|
||||
private final World world;
|
||||
private Tag[] tag;
|
||||
|
||||
public AtomicRegionData(World world)
|
||||
{
|
||||
this.world = world;
|
||||
tag = new Tag[1024];
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return tag.length;
|
||||
}
|
||||
|
||||
public void read(InputStream in) throws IOException
|
||||
{
|
||||
NBTInputStream nin = new NBTInputStream(in);
|
||||
KMap<String, Tag> tags = new KMap<>();
|
||||
tags.putAll(((CompoundTag) nin.readTag()).getValue());
|
||||
|
||||
for(String i : tags.keySet())
|
||||
{
|
||||
int x = Integer.valueOf(i.split("\\Q.\\E")[0]);
|
||||
int z = Integer.valueOf(i.split("\\Q.\\E")[1]);
|
||||
tag[(z << 5) | x] = tags.get(i);
|
||||
}
|
||||
|
||||
nin.close();
|
||||
}
|
||||
|
||||
public void write(OutputStream out) throws IOException
|
||||
{
|
||||
NBTOutputStream nos = new NBTOutputStream(out);
|
||||
|
||||
KMap<String, Tag> tags = new KMap<>();
|
||||
|
||||
for(int i = 0; i < 32; i++)
|
||||
{
|
||||
for(int j = 0; j < 32; j++)
|
||||
{
|
||||
if(tag[(j << 5) | i] != null)
|
||||
{
|
||||
tags.put(i + "." + j, tag[(j << 5) | i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nos.writeTag(new CompoundTag("imca", tags));
|
||||
nos.close();
|
||||
}
|
||||
|
||||
public boolean contains(int rx, int rz)
|
||||
{
|
||||
return tag[(rz << 5) | rx] != null;
|
||||
}
|
||||
|
||||
public void delete(int rx, int rz)
|
||||
{
|
||||
tag[(rz << 5) | rx] = null;
|
||||
}
|
||||
|
||||
public void set(int rx, int rz, AtomicSliverMap data) throws IOException
|
||||
{
|
||||
if(data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OutputStream out;
|
||||
ByteArrayOutputStream boas = new ByteArrayOutputStream();
|
||||
out = boas;
|
||||
|
||||
if(IrisSettings.get().parallaxCompression)
|
||||
{
|
||||
out = new CustomOutputStream(boas, IrisSettings.get().parallaxCompressionLevel);
|
||||
}
|
||||
|
||||
data.write(out);
|
||||
out.flush();
|
||||
out.close();
|
||||
tag[(rz << 5) | rx] = 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;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ByteArrayTag btag = (ByteArrayTag) tag[(rz << 5) | rx];
|
||||
|
||||
InputStream in;
|
||||
|
||||
if(IrisSettings.get().parallaxCompression)
|
||||
{
|
||||
in = new GZIPInputStream(new ByteArrayInputStream(btag.getValue()));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
in = new ByteArrayInputStream(btag.getValue());
|
||||
}
|
||||
|
||||
data.read(in);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public World getWorld()
|
||||
{
|
||||
return world;
|
||||
}
|
||||
|
||||
public long guessMemoryUsage()
|
||||
{
|
||||
long bytes = 0;
|
||||
|
||||
for(int i = 0; i < 1024; i++)
|
||||
{
|
||||
if(tag[i] != null && tag[i] instanceof ByteArrayTag)
|
||||
{
|
||||
bytes += 122;
|
||||
bytes += ((ByteArrayTag) tag[i]).getValue().length;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
243
src/main/java/com/volmit/iris/gen/atomics/AtomicSliver.java
Normal file
243
src/main/java/com/volmit/iris/gen/atomics/AtomicSliver.java
Normal file
@@ -0,0 +1,243 @@
|
||||
package com.volmit.iris.object.atomics;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
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 com.volmit.iris.object.IrisBiome;
|
||||
import com.volmit.iris.util.BlockDataTools;
|
||||
import com.volmit.iris.util.HeightMap;
|
||||
import com.volmit.iris.util.KMap;
|
||||
import com.volmit.iris.util.M;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AtomicSliver
|
||||
{
|
||||
public static final BlockData AIR = BlockDataTools.getBlockData("AIR");
|
||||
private KMap<Integer, BlockData> block;
|
||||
private KMap<Integer, IrisBiome> truebiome;
|
||||
private KMap<Integer, Biome> biome;
|
||||
private ReentrantLock lock = new ReentrantLock();
|
||||
private int highestBlock = 0;
|
||||
private int highestBiome = 0;
|
||||
private long last = M.ms();
|
||||
private int x;
|
||||
private int z;
|
||||
boolean modified = false;
|
||||
|
||||
public AtomicSliver(int x, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.block = new KMap<>();
|
||||
this.biome = new KMap<>();
|
||||
this.truebiome = new KMap<>();
|
||||
}
|
||||
|
||||
public Material getType(int h)
|
||||
{
|
||||
return get(h).getMaterial();
|
||||
}
|
||||
|
||||
public BlockData get(int h)
|
||||
{
|
||||
BlockData b = block.get(h);
|
||||
last = M.ms();
|
||||
|
||||
if(b == null)
|
||||
{
|
||||
return AIR;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public void set(int h, BlockData d)
|
||||
{
|
||||
if(d == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
block.put(h, d);
|
||||
modified = true;
|
||||
|
||||
if(d.getMaterial().equals(Material.AIR) || d.getMaterial().equals(Material.CAVE_AIR))
|
||||
{
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
highestBlock = h > highestBlock ? h : highestBlock;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void setSilently(int h, BlockData d)
|
||||
{
|
||||
if(d == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
modified = true;
|
||||
block.put(h, d);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public boolean isSolid(int h)
|
||||
{
|
||||
return getType(h).isSolid();
|
||||
}
|
||||
|
||||
public Biome getBiome(int h)
|
||||
{
|
||||
last = M.ms();
|
||||
return biome.containsKey(h) ? biome.get(h) : Biome.THE_VOID;
|
||||
}
|
||||
|
||||
public IrisBiome getTrueBiome(int h)
|
||||
{
|
||||
last = M.ms();
|
||||
return truebiome.get(h);
|
||||
}
|
||||
|
||||
public void set(int h, Biome d)
|
||||
{
|
||||
lock.lock();
|
||||
biome.put(h, d);
|
||||
modified = true;
|
||||
highestBiome = h > highestBiome ? h : highestBiome;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void set(int h, IrisBiome d)
|
||||
{
|
||||
lock.lock();
|
||||
modified = true;
|
||||
truebiome.put(h, d);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void write(ChunkData d)
|
||||
{
|
||||
lock.lock();
|
||||
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));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void write(BiomeGrid d)
|
||||
{
|
||||
lock.lock();
|
||||
for(int i = 0; i <= highestBiome; i++)
|
||||
{
|
||||
if(biome.get(i) != null)
|
||||
{
|
||||
d.setBiome(x, i, z, biome.get(i));
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void write(HeightMap height)
|
||||
{
|
||||
lock.lock();
|
||||
height.setHeight(x, z, highestBlock);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void read(DataInputStream din) throws IOException
|
||||
{
|
||||
lock.lock();
|
||||
this.block = new KMap<Integer, BlockData>();
|
||||
int h = din.readByte() - Byte.MIN_VALUE;
|
||||
highestBlock = h;
|
||||
|
||||
for(int i = 0; i <= h; i++)
|
||||
{
|
||||
BlockData v = BlockDataTools.getBlockData(din.readUTF());
|
||||
|
||||
if(v == null)
|
||||
{
|
||||
block.put(i, AIR);
|
||||
continue;
|
||||
}
|
||||
|
||||
block.put(i, v);
|
||||
}
|
||||
modified = false;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void write(DataOutputStream dos) throws IOException
|
||||
{
|
||||
lock.lock();
|
||||
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));
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void insert(AtomicSliver atomicSliver)
|
||||
{
|
||||
lock.lock();
|
||||
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);
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void inject(ChunkData currentData)
|
||||
{
|
||||
lock.lock();
|
||||
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);
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public boolean isOlderThan(long m)
|
||||
{
|
||||
return M.ms() - last > m;
|
||||
}
|
||||
}
|
||||
117
src/main/java/com/volmit/iris/gen/atomics/AtomicSliverMap.java
Normal file
117
src/main/java/com/volmit/iris/gen/atomics/AtomicSliverMap.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package com.volmit.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 com.volmit.iris.util.HeightMap;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@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++)
|
||||
{
|
||||
try
|
||||
{
|
||||
slivers[i].read(din);
|
||||
}
|
||||
|
||||
catch(Throwable e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isModified()
|
||||
{
|
||||
for(AtomicSliver i : slivers)
|
||||
{
|
||||
if(i.isModified())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
348
src/main/java/com/volmit/iris/gen/atomics/AtomicWorldData.java
Normal file
348
src/main/java/com/volmit/iris/gen/atomics/AtomicWorldData.java
Normal file
@@ -0,0 +1,348 @@
|
||||
package com.volmit.iris.object.atomics;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.ChunkPosition;
|
||||
import com.volmit.iris.util.KList;
|
||||
import com.volmit.iris.util.KMap;
|
||||
import com.volmit.iris.util.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 KList<ChunkPosition> unloadRegions;
|
||||
private KList<ChunkPosition> unloadChunks;
|
||||
private long last = M.ms();
|
||||
private String prefix;
|
||||
|
||||
public AtomicWorldData(World world, String prefix)
|
||||
{
|
||||
this.world = world;
|
||||
loadedSections = new KMap<>();
|
||||
loadedChunks = new KMap<>();
|
||||
lastRegion = new KMap<>();
|
||||
lastChunk = new KMap<>();
|
||||
unloadRegions = new KList<>();
|
||||
unloadChunks = new KList<>();
|
||||
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))
|
||||
{
|
||||
Iris.warn("Cant unload because section isnt loaded?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(save)
|
||||
{
|
||||
saveSection(s);
|
||||
}
|
||||
|
||||
loadedSections.remove(s);
|
||||
lastRegion.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()))
|
||||
{
|
||||
Iris.warn("Cant save section " + s.getX() + " " + s.getZ() + " because section isnt loaded?");
|
||||
|
||||
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
|
||||
{
|
||||
AtomicSliverMap m = loadedChunks.get(i);
|
||||
|
||||
if(m.isModified())
|
||||
{
|
||||
int x = i.getX();
|
||||
int z = i.getZ();
|
||||
AtomicRegionData dat = loadSection(x >> 5, z >> 5, true);
|
||||
dat.set(x & 31, z & 31, m);
|
||||
}
|
||||
|
||||
loadedChunks.remove(i);
|
||||
lastChunk.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, boolean anonymous) throws IOException
|
||||
{
|
||||
ChunkPosition pos = new ChunkPosition(x, z);
|
||||
if(!anonymous)
|
||||
{
|
||||
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 loadSection(int x, int z) throws IOException
|
||||
{
|
||||
return loadSection(x, z, false);
|
||||
}
|
||||
|
||||
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(M.ms() - last < getUnloadBatchSpeed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int m = 0;
|
||||
|
||||
for(ChunkPosition i : lastRegion.keySet())
|
||||
{
|
||||
if(m > 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(M.ms() - lastRegion.get(i) > 60000)
|
||||
{
|
||||
unloadRegions.add(i);
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
m = 0;
|
||||
|
||||
for(ChunkPosition i : unloadRegions)
|
||||
{
|
||||
lastRegion.remove(i);
|
||||
|
||||
try
|
||||
{
|
||||
unloadSection(i, true);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
unloadRegions.clear();
|
||||
|
||||
for(ChunkPosition i : lastChunk.keySet())
|
||||
{
|
||||
if(m > getUnloadBatchSize())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(M.ms() - lastChunk.get(i) > 15000)
|
||||
{
|
||||
m++;
|
||||
unloadChunks.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
for(ChunkPosition i : unloadChunks)
|
||||
{
|
||||
try
|
||||
{
|
||||
saveChunk(i);
|
||||
}
|
||||
|
||||
catch(IOException e)
|
||||
{
|
||||
Iris.warn("Failed to save chunk");
|
||||
}
|
||||
}
|
||||
|
||||
unloadChunks.clear();
|
||||
}
|
||||
|
||||
private int getUnloadBatchSize()
|
||||
{
|
||||
return Math.max(3, getLoadedRegions().size() / 125);
|
||||
}
|
||||
|
||||
private int getUnloadBatchSpeed()
|
||||
{
|
||||
return Math.max(250, 2000 - getLoadedRegions().size());
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/volmit/iris/gen/atomics/MasterLock.java
Normal file
48
src/main/java/com/volmit/iris/gen/atomics/MasterLock.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package com.volmit.iris.object.atomics;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.volmit.iris.util.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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.volmit.iris.layer;
|
||||
|
||||
import com.volmit.iris.object.InferredType;
|
||||
import com.volmit.iris.object.IrisRegion;
|
||||
import com.volmit.iris.util.BiomeRarityCellGenerator;
|
||||
import com.volmit.iris.util.BiomeResult;
|
||||
import com.volmit.iris.util.RNG;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BiomeDataProvider
|
||||
{
|
||||
private InferredType type;
|
||||
private BiomeRarityCellGenerator generator;
|
||||
private GenLayerBiome layer;
|
||||
|
||||
public BiomeDataProvider(GenLayerBiome layer, InferredType type, RNG rng)
|
||||
{
|
||||
this.type = type;
|
||||
this.layer = layer;
|
||||
generator = new BiomeRarityCellGenerator(rng.nextParallelRNG(4645079 + (type.ordinal() * 23845)));
|
||||
}
|
||||
|
||||
public BiomeResult generatePureData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
getGenerator().setShuffle(12);
|
||||
double zoom = (layer.getIris().getDimension().getBiomeZoom() * regionData.getBiomeZoom(getType())) * 3.15;
|
||||
getGenerator().setCellScale(1D / zoom);
|
||||
return layer.generateBiomeData(bx, bz, regionData, getGenerator(), regionData.getBiomes(getType()), getType());
|
||||
}
|
||||
|
||||
public BiomeResult generateData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
return layer.generateImpureData(rawX, rawZ, getType(), regionData, generatePureData(bx, bz, rawX, rawZ, regionData));
|
||||
}
|
||||
}
|
||||
202
src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java
Normal file
202
src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java
Normal file
@@ -0,0 +1,202 @@
|
||||
package com.volmit.iris.layer;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.generator.DimensionChunkGenerator;
|
||||
import com.volmit.iris.object.InferredType;
|
||||
import com.volmit.iris.object.IrisBiome;
|
||||
import com.volmit.iris.object.IrisRegion;
|
||||
import com.volmit.iris.object.IrisRegionRidge;
|
||||
import com.volmit.iris.object.IrisRegionSpot;
|
||||
import com.volmit.iris.util.BiomeRarityCellGenerator;
|
||||
import com.volmit.iris.util.BiomeResult;
|
||||
import com.volmit.iris.util.CellGenerator;
|
||||
import com.volmit.iris.util.GenLayer;
|
||||
import com.volmit.iris.util.KList;
|
||||
import com.volmit.iris.util.RNG;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class GenLayerBiome extends GenLayer
|
||||
{
|
||||
private CellGenerator regionGenerator;
|
||||
private CellGenerator bridgeGenerator;
|
||||
private BiomeDataProvider seaProvider;
|
||||
private BiomeDataProvider landProvider;
|
||||
private BiomeDataProvider shoreProvider;
|
||||
private BiomeDataProvider caveProvider;
|
||||
private BiomeDataProvider islandProvider;
|
||||
private BiomeDataProvider skylandProvider;
|
||||
private DimensionChunkGenerator iris;
|
||||
|
||||
public GenLayerBiome(DimensionChunkGenerator iris, RNG rng)
|
||||
{
|
||||
super(iris, rng);
|
||||
this.iris = iris;
|
||||
seaProvider = new BiomeDataProvider(this, InferredType.SEA, rng);
|
||||
landProvider = new BiomeDataProvider(this, InferredType.LAND, rng);
|
||||
shoreProvider = new BiomeDataProvider(this, InferredType.SHORE, rng);
|
||||
caveProvider = new BiomeDataProvider(this, InferredType.CAVE, rng);
|
||||
islandProvider = new BiomeDataProvider(this, InferredType.ISLAND, rng);
|
||||
skylandProvider = new BiomeDataProvider(this, InferredType.SKYLAND, rng);
|
||||
regionGenerator = new CellGenerator(rng.nextParallelRNG(1188519));
|
||||
bridgeGenerator = new CellGenerator(rng.nextParallelRNG(1541462));
|
||||
}
|
||||
|
||||
public IrisRegion getRegion(double bx, double bz)
|
||||
{
|
||||
if(iris.getDimension().getRegions().isEmpty())
|
||||
{
|
||||
Iris.error("NO REGIONS!");
|
||||
return null;
|
||||
}
|
||||
|
||||
regionGenerator.setShuffle(8);
|
||||
regionGenerator.setCellScale(0.33 / iris.getDimension().getRegionZoom());
|
||||
double x = bx / iris.getDimension().getBiomeZoom();
|
||||
double z = bz / iris.getDimension().getBiomeZoom();
|
||||
String regionId = iris.getDimension().getRegions().get(regionGenerator.getIndex(x, z, iris.getDimension().getRegions().size()));
|
||||
|
||||
return Iris.data.getRegionLoader().load(regionId);
|
||||
}
|
||||
|
||||
public BiomeResult generateData(double bx, double bz, int rawX, int rawZ)
|
||||
{
|
||||
return generateRegionData(bx, bz, rawX, rawZ, getRegion(bx, bz));
|
||||
}
|
||||
|
||||
public BiomeResult generateData(InferredType type, double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
return getProvider(type).generateData(bx, bz, rawX, rawZ, regionData);
|
||||
}
|
||||
|
||||
public BiomeDataProvider getProvider(InferredType type)
|
||||
{
|
||||
if(type.equals(InferredType.SEA))
|
||||
{
|
||||
return seaProvider;
|
||||
}
|
||||
|
||||
else if(type.equals(InferredType.LAND))
|
||||
{
|
||||
return landProvider;
|
||||
}
|
||||
|
||||
else if(type.equals(InferredType.SHORE))
|
||||
{
|
||||
return shoreProvider;
|
||||
}
|
||||
|
||||
else if(type.equals(InferredType.CAVE))
|
||||
{
|
||||
return caveProvider;
|
||||
}
|
||||
|
||||
else if(type.equals(InferredType.ISLAND))
|
||||
{
|
||||
return islandProvider;
|
||||
}
|
||||
|
||||
else if(type.equals(InferredType.SKYLAND))
|
||||
{
|
||||
return skylandProvider;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Iris.error("Cannot find a BiomeDataProvider for type " + type.name());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public BiomeResult generateRegionData(double bx, double bz, int rawX, int rawZ, IrisRegion regionData)
|
||||
{
|
||||
return generateData(getType(bx, bz, regionData), bx, bz, rawX, rawZ, regionData);
|
||||
}
|
||||
|
||||
public InferredType getType(double bx, double bz, IrisRegion regionData)
|
||||
{
|
||||
bridgeGenerator.setShuffle(0);
|
||||
bridgeGenerator.setCellScale(0.33 / iris.getDimension().getContinentZoom());
|
||||
double x = bx / iris.getDimension().getBiomeZoom();
|
||||
double z = bz / iris.getDimension().getBiomeZoom();
|
||||
return bridgeGenerator.getIndex(x, z, 5) == 1 ? InferredType.SEA : InferredType.LAND;
|
||||
}
|
||||
|
||||
public BiomeResult generateBiomeData(double bx, double bz, IrisRegion regionData, BiomeRarityCellGenerator cell, KList<IrisBiome> biomes, InferredType inferredType)
|
||||
{
|
||||
if(biomes.isEmpty())
|
||||
{
|
||||
return new BiomeResult(null, 0);
|
||||
}
|
||||
|
||||
double x = bx / iris.getDimension().getBiomeZoom();
|
||||
double z = bz / iris.getDimension().getBiomeZoom();
|
||||
IrisBiome biome = cell.get(x, z, biomes);
|
||||
biome.setInferredType(inferredType);
|
||||
|
||||
return implode(bx, bz, regionData, cell, new BiomeResult(biome, cell.getDistance(x, z)));
|
||||
}
|
||||
|
||||
public BiomeResult generateImpureData(int rawX, int rawZ, InferredType type, IrisRegion regionData, BiomeResult pureResult)
|
||||
{
|
||||
for(IrisRegionRidge i : regionData.getRidgeBiomes())
|
||||
{
|
||||
if(i.getType().equals(type) && i.isRidge(rng, rawX, rawZ))
|
||||
{
|
||||
return new BiomeResult(Iris.data.getBiomeLoader().load(i.getBiome()).infer(i.getAs(), type), 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
for(IrisRegionSpot i : regionData.getSpotBiomes())
|
||||
{
|
||||
if(i.getType().equals(type) && i.isSpot(rng, rawX, rawZ))
|
||||
{
|
||||
return new BiomeResult(Iris.data.getBiomeLoader().load(i.getBiome()).infer(i.getAs(), type), 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
return pureResult;
|
||||
}
|
||||
|
||||
public BiomeResult implode(double bx, double bz, IrisRegion regionData, BiomeRarityCellGenerator parentCell, BiomeResult parent)
|
||||
{
|
||||
return implode(bx, bz, regionData, parentCell, parent, 1);
|
||||
}
|
||||
|
||||
public BiomeResult implode(double bx, double bz, IrisRegion regionData, BiomeRarityCellGenerator parentCell, BiomeResult parent, int hits)
|
||||
{
|
||||
if(hits > 9)
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
double x = bx / iris.getDimension().getBiomeZoom();
|
||||
double z = bz / iris.getDimension().getBiomeZoom();
|
||||
|
||||
if(parent.getDistance() > regionData.getBiomeImplosionRatio())
|
||||
{
|
||||
if(!parent.getBiome().getRealChildren().isEmpty())
|
||||
{
|
||||
BiomeRarityCellGenerator childCell = parent.getBiome().getChildrenGenerator(rng, 123, parentCell.getCellScale() * parent.getBiome().getChildShrinkFactor());
|
||||
KList<IrisBiome> chx = parent.getBiome().getRealChildren().copy();
|
||||
chx.add(parent.getBiome());
|
||||
IrisBiome biome = childCell.get(x, z, chx);
|
||||
biome.setInferredType(parent.getBiome().getInferredType());
|
||||
|
||||
return implode(bx, bz, regionData, childCell, new BiomeResult(biome, childCell.getDistance(x, z)), hits + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x, double z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
45
src/main/java/com/volmit/iris/gen/layer/GenLayerCarve.java
Normal file
45
src/main/java/com/volmit/iris/gen/layer/GenLayerCarve.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package com.volmit.iris.layer;
|
||||
|
||||
import com.volmit.iris.generator.DimensionChunkGenerator;
|
||||
import com.volmit.iris.util.CellGenerator;
|
||||
import com.volmit.iris.util.GenLayer;
|
||||
import com.volmit.iris.util.IrisInterpolation;
|
||||
import com.volmit.iris.util.M;
|
||||
import com.volmit.iris.util.RNG;
|
||||
|
||||
public class GenLayerCarve extends GenLayer
|
||||
{
|
||||
private CellGenerator cell;
|
||||
|
||||
public GenLayerCarve(DimensionChunkGenerator iris, RNG rng)
|
||||
{
|
||||
super(iris, rng);
|
||||
cell = new CellGenerator(rng.nextParallelRNG(-135486678));
|
||||
}
|
||||
|
||||
public boolean isCarved(int xc, int y, int zc)
|
||||
{
|
||||
if(y > iris.getDimension().getCarvingMax() || y < iris.getDimension().getCarvingMin())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
double x = ((double) xc / iris.getDimension().getCarvingZoom());
|
||||
double z = ((double) zc / iris.getDimension().getCarvingZoom());
|
||||
|
||||
double opacity = Math.pow(IrisInterpolation.sinCenter(M.lerpInverse(iris.getDimension().getCarvingMin(), iris.getDimension().getCarvingMax(), y)), 4);
|
||||
|
||||
if(cell.getDistance(x - (Math.cos(y / iris.getDimension().getCarvingRippleThickness()) + 0.5D) / 2D, y / iris.getDimension().getCarvingSliverThickness(), z + (Math.sin(y / iris.getDimension().getCarvingRippleThickness()) + 0.5D) / 2D) < opacity * iris.getDimension().getCarvingEnvelope())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x, double z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
187
src/main/java/com/volmit/iris/gen/layer/GenLayerCave.java
Normal file
187
src/main/java/com/volmit/iris/gen/layer/GenLayerCave.java
Normal file
@@ -0,0 +1,187 @@
|
||||
package com.volmit.iris.layer;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import com.volmit.iris.generator.DimensionChunkGenerator;
|
||||
import com.volmit.iris.object.atomics.AtomicSliver;
|
||||
import com.volmit.iris.util.BlockDataTools;
|
||||
import com.volmit.iris.util.CNG;
|
||||
import com.volmit.iris.util.CaveResult;
|
||||
import com.volmit.iris.util.FastNoise;
|
||||
import com.volmit.iris.util.GenLayer;
|
||||
import com.volmit.iris.util.KList;
|
||||
import com.volmit.iris.util.RNG;
|
||||
import com.volmit.iris.util.FastNoise.CellularDistanceFunction;
|
||||
import com.volmit.iris.util.FastNoise.CellularReturnType;
|
||||
import com.volmit.iris.util.FastNoise.NoiseType;
|
||||
|
||||
public class GenLayerCave extends GenLayer
|
||||
{
|
||||
public static final BlockData CAVE_AIR = BlockDataTools.getBlockData("CAVE_AIR");
|
||||
public static final BlockData AIR = BlockDataTools.getBlockData("AIR");
|
||||
private static final KList<CaveResult> EMPTY = new KList<>();
|
||||
private CNG gincline;
|
||||
private CNG shuffle;
|
||||
private FastNoise gg;
|
||||
|
||||
public GenLayerCave(DimensionChunkGenerator iris, RNG rng)
|
||||
{
|
||||
//@builder
|
||||
super(iris, rng);
|
||||
shuffle = CNG.signature(rng.nextParallelRNG(1348566));
|
||||
gincline = new CNG(rng.nextParallelRNG(26512), 1D, 3).scale(0.00452);
|
||||
gg = new FastNoise(324895 * rng.nextParallelRNG(49678).imax());
|
||||
//@done
|
||||
}
|
||||
|
||||
public KList<CaveResult> genCaves(double wxx, double wzz, int x, int z, AtomicSliver data)
|
||||
{
|
||||
if(!iris.getDimension().isCaves())
|
||||
{
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
int surface = data.getHighestBlock();
|
||||
KList<CaveResult> result = new KList<>();
|
||||
shuffle.scale(0.01);
|
||||
double shuffleDistance = 72;
|
||||
gg.SetNoiseType(NoiseType.Cellular);
|
||||
gg.SetCellularReturnType(CellularReturnType.Distance2Sub);
|
||||
gg.SetCellularDistanceFunction(CellularDistanceFunction.Natural);
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
double wx = wxx + (shuffle.noise(wxx, wzz) * shuffleDistance);
|
||||
double wz = wzz + (shuffle.noise(wzz, wxx) * shuffleDistance);
|
||||
double incline = 157;
|
||||
double baseWidth = (14 * iris.getDimension().getCaveScale());
|
||||
double distanceCheck = 0.0132 * baseWidth;
|
||||
double distanceTake = 0.0022 * baseWidth;
|
||||
double drop = (-i * 17) + 44 + iris.getDimension().getCaveShift();
|
||||
double caveHeightNoise = incline * gincline.noise((wx + (10000 * i)), (wz - (10000 * i)));
|
||||
caveHeightNoise += shuffle.fitDoubleD(-1, 1, wxx - caveHeightNoise, wzz + caveHeightNoise) * 3;
|
||||
|
||||
int ceiling = -256;
|
||||
int floor = 512;
|
||||
|
||||
for(double tunnelHeight = 1; tunnelHeight <= baseWidth; tunnelHeight++)
|
||||
{
|
||||
double distance = (gg.GetCellular((float) wx + (10000 * i), (float) wz - (10000 * i)) + 1D) / 2D;
|
||||
if(distance < distanceCheck - (tunnelHeight * distanceTake))
|
||||
{
|
||||
int caveHeight = (int) Math.round(caveHeightNoise - drop);
|
||||
int pu = (int) (caveHeight + tunnelHeight);
|
||||
int pd = (int) (caveHeight - tunnelHeight);
|
||||
|
||||
if(pd > surface + 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if((pu > 255 && pd > 255) || (pu < 0 && pd < 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(data == null)
|
||||
{
|
||||
ceiling = pu > ceiling ? pu : ceiling;
|
||||
floor = pu < floor ? pu : floor;
|
||||
ceiling = pd > ceiling ? pd : ceiling;
|
||||
floor = pd < floor ? pd : floor;
|
||||
|
||||
if(tunnelHeight == 1)
|
||||
{
|
||||
ceiling = caveHeight > ceiling ? caveHeight : ceiling;
|
||||
floor = caveHeight < floor ? caveHeight : floor;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if(dig(x, pu, z, data))
|
||||
{
|
||||
ceiling = pu > ceiling ? pu : ceiling;
|
||||
floor = pu < floor ? pu : floor;
|
||||
|
||||
if(pu > surface - 2)
|
||||
{
|
||||
if(dig(x, pu + 1, z, data))
|
||||
{
|
||||
ceiling = pu + 1 > ceiling ? pu + 1 : ceiling;
|
||||
floor = pu + 1 < floor ? pu + 1 : floor;
|
||||
|
||||
if(dig(x, pu + 2, z, data))
|
||||
{
|
||||
ceiling = pu + 2 > ceiling ? pu + 2 : ceiling;
|
||||
floor = pu + 2 < floor ? pu + 2 : floor;
|
||||
|
||||
if(dig(x, pu + 3, z, data))
|
||||
{
|
||||
ceiling = pu + 3 > ceiling ? pu + 3 : ceiling;
|
||||
floor = pu + 3 < floor ? pu + 3 : floor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dig(x, pd, z, data))
|
||||
{
|
||||
ceiling = pd > ceiling ? pd : ceiling;
|
||||
floor = pd < floor ? pd : floor;
|
||||
}
|
||||
|
||||
if(tunnelHeight == 1)
|
||||
{
|
||||
if(dig(x, (int) (caveHeight), z, data))
|
||||
{
|
||||
ceiling = caveHeight > ceiling ? caveHeight : ceiling;
|
||||
floor = caveHeight < floor ? caveHeight : floor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(floor >= 0 && ceiling <= 255)
|
||||
{
|
||||
result.add(new CaveResult(floor, ceiling));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean dig(int x, int y, int z, AtomicSliver data)
|
||||
{
|
||||
Material a = data.getType(y);
|
||||
Material c = data.getType(y + 1);
|
||||
Material f = data.getType(y - 1);
|
||||
|
||||
if(can(a) && canAir(c) && canAir(f))
|
||||
{
|
||||
data.set(y, CAVE_AIR);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canAir(Material m)
|
||||
{
|
||||
return (m.isSolid() || m.equals(Material.AIR) || m.equals(Material.CAVE_AIR)) && !m.equals(Material.BEDROCK);
|
||||
}
|
||||
|
||||
public boolean can(Material m)
|
||||
{
|
||||
return m.isSolid() && !m.equals(Material.BEDROCK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x, double z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
14
src/main/java/com/volmit/iris/gen/post/Post.java
Normal file
14
src/main/java/com/volmit/iris/gen/post/Post.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.volmit.iris.layer.post;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@Target(TYPE)
|
||||
public @interface Post
|
||||
{
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.volmit.iris.layer.post;
|
||||
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import com.volmit.iris.generator.PostBlockChunkGenerator;
|
||||
import com.volmit.iris.util.BlockDataTools;
|
||||
import com.volmit.iris.util.IrisPostBlockFilter;
|
||||
|
||||
@Post("floating-block-remover")
|
||||
public class PostFloatingNibDeleter extends IrisPostBlockFilter
|
||||
{
|
||||
private static final BlockData AIR = BlockDataTools.getBlockData("AIR");
|
||||
|
||||
public PostFloatingNibDeleter(PostBlockChunkGenerator gen, int phase)
|
||||
{
|
||||
super(gen, phase);
|
||||
}
|
||||
|
||||
public PostFloatingNibDeleter(PostBlockChunkGenerator gen)
|
||||
{
|
||||
this(gen, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
int g = 0;
|
||||
int h = highestTerrainBlock(x, z);
|
||||
|
||||
if(h < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int ha = highestTerrainBlock(x + 1, z);
|
||||
int hb = highestTerrainBlock(x, z + 1);
|
||||
int hc = highestTerrainBlock(x - 1, z);
|
||||
int hd = highestTerrainBlock(x, z - 1);
|
||||
g += ha < h - 1 ? 1 : 0;
|
||||
g += hb < h - 1 ? 1 : 0;
|
||||
g += hc < h - 1 ? 1 : 0;
|
||||
g += hd < h - 1 ? 1 : 0;
|
||||
|
||||
if(g == 4 && isAir(x, h - 1, z))
|
||||
{
|
||||
setPostBlock(x, h, z, AIR);
|
||||
|
||||
for(int i = h - 1; i > 0; i--)
|
||||
{
|
||||
if(!isAir(x, i, z))
|
||||
{
|
||||
updateHeight(x, z, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/main/java/com/volmit/iris/gen/post/PostNibSmoother.java
Normal file
49
src/main/java/com/volmit/iris/gen/post/PostNibSmoother.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package com.volmit.iris.layer.post;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import com.volmit.iris.generator.PostBlockChunkGenerator;
|
||||
import com.volmit.iris.util.IrisPostBlockFilter;
|
||||
|
||||
@Post("nib-smoother")
|
||||
public class PostNibSmoother extends IrisPostBlockFilter
|
||||
{
|
||||
public PostNibSmoother(PostBlockChunkGenerator gen, int phase)
|
||||
{
|
||||
super(gen, phase);
|
||||
}
|
||||
|
||||
public PostNibSmoother(PostBlockChunkGenerator gen)
|
||||
{
|
||||
this(gen, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
int g = 0;
|
||||
int h = highestTerrainBlock(x, z);
|
||||
int ha = highestTerrainBlock(x + 1, z);
|
||||
int hb = highestTerrainBlock(x, z + 1);
|
||||
int hc = highestTerrainBlock(x - 1, z);
|
||||
int hd = highestTerrainBlock(x, z - 1);
|
||||
g += ha == h - 1 ? 1 : 0;
|
||||
g += hb == h - 1 ? 1 : 0;
|
||||
g += hc == h - 1 ? 1 : 0;
|
||||
g += hd == h - 1 ? 1 : 0;
|
||||
|
||||
if(g >= 3)
|
||||
{
|
||||
BlockData bc = getPostBlock(x, h, z);
|
||||
BlockData b = getPostBlock(x, h + 1, z);
|
||||
Material m = bc.getMaterial();
|
||||
|
||||
if(m.isSolid())
|
||||
{
|
||||
setPostBlock(x, h, z, b);
|
||||
updateHeight(x, z, h - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.volmit.iris.layer.post;
|
||||
|
||||
import com.volmit.iris.generator.PostBlockChunkGenerator;
|
||||
import com.volmit.iris.util.IrisPostBlockFilter;
|
||||
|
||||
@Post("pothole-filler")
|
||||
public class PostPotholeFiller extends IrisPostBlockFilter
|
||||
{
|
||||
public PostPotholeFiller(PostBlockChunkGenerator gen, int phase)
|
||||
{
|
||||
super(gen, phase);
|
||||
}
|
||||
|
||||
public PostPotholeFiller(PostBlockChunkGenerator gen)
|
||||
{
|
||||
this(gen, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
int g = 0;
|
||||
int h = highestTerrainBlock(x, z);
|
||||
int ha = highestTerrainBlock(x + 1, z);
|
||||
int hb = highestTerrainBlock(x, z + 1);
|
||||
int hc = highestTerrainBlock(x - 1, z);
|
||||
int hd = highestTerrainBlock(x, z - 1);
|
||||
g += ha == h + 1 ? 1 : 0;
|
||||
g += hb == h + 1 ? 1 : 0;
|
||||
g += hc == h + 1 ? 1 : 0;
|
||||
g += hd == h + 1 ? 1 : 0;
|
||||
|
||||
if(g >= 3)
|
||||
{
|
||||
setPostBlock(x, h + 1, z, getPostBlock(x, h, z));
|
||||
updateHeight(x, z, h + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/main/java/com/volmit/iris/gen/post/PostSlabber.java
Normal file
69
src/main/java/com/volmit/iris/gen/post/PostSlabber.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package com.volmit.iris.layer.post;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import com.volmit.iris.generator.PostBlockChunkGenerator;
|
||||
import com.volmit.iris.util.IrisPostBlockFilter;
|
||||
import com.volmit.iris.util.RNG;
|
||||
|
||||
@Post("slabber")
|
||||
public class PostSlabber extends IrisPostBlockFilter
|
||||
{
|
||||
public static final Material AIR = Material.AIR;
|
||||
public static final Material WATER = Material.WATER;
|
||||
private RNG rng;
|
||||
|
||||
public PostSlabber(PostBlockChunkGenerator gen, int phase)
|
||||
{
|
||||
super(gen, phase);
|
||||
rng = gen.getMasterRandom().nextParallelRNG(166456);
|
||||
}
|
||||
|
||||
public PostSlabber(PostBlockChunkGenerator gen)
|
||||
{
|
||||
this(gen, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
int h = highestTerrainBlock(x, z);
|
||||
int ha = highestTerrainBlock(x + 1, z);
|
||||
int hb = highestTerrainBlock(x, z + 1);
|
||||
int hc = highestTerrainBlock(x - 1, z);
|
||||
int hd = highestTerrainBlock(x, z - 1);
|
||||
|
||||
if((ha == h + 1 && isSolid(x + 1, ha, z)) || (hb == h + 1 && isSolid(x, hb, z + 1)) || (hc == h + 1 && isSolid(x - 1, hc, z)) || (hd == h + 1 && isSolid(x, hd, z - 1)))
|
||||
{
|
||||
BlockData d = gen.sampleTrueBiome(x, z).getBiome().getSlab().get(rng, x, h, z);
|
||||
|
||||
if(d != null)
|
||||
{
|
||||
if(d.getMaterial().equals(AIR))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(d.getMaterial().equals(Material.SNOW) && h + 1 <= gen.getFluidHeight())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(isSnowLayer(x, h, z))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(isAirOrWater(x, h + 2, z))
|
||||
{
|
||||
queue(() ->
|
||||
{
|
||||
setPostBlock(x, h + 1, z, d);
|
||||
updateHeight(x, z, h + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
src/main/java/com/volmit/iris/gen/post/PostWallPatcher.java
Normal file
78
src/main/java/com/volmit/iris/gen/post/PostWallPatcher.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.volmit.iris.layer.post;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import com.volmit.iris.generator.PostBlockChunkGenerator;
|
||||
import com.volmit.iris.object.IrisBiome;
|
||||
import com.volmit.iris.util.IrisPostBlockFilter;
|
||||
import com.volmit.iris.util.RNG;
|
||||
|
||||
@Post("wall-painter")
|
||||
public class PostWallPatcher extends IrisPostBlockFilter
|
||||
{
|
||||
public static final Material AIR = Material.AIR;
|
||||
private RNG rng;
|
||||
|
||||
public PostWallPatcher(PostBlockChunkGenerator gen, int phase)
|
||||
{
|
||||
super(gen, phase);
|
||||
rng = gen.getMasterRandom().nextParallelRNG(1239456);
|
||||
}
|
||||
|
||||
public PostWallPatcher(PostBlockChunkGenerator gen)
|
||||
{
|
||||
this(gen, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
IrisBiome biome = gen.sampleTrueBiome(x, z).getBiome();
|
||||
int h, ha, hb, hc, hd;
|
||||
|
||||
if(!biome.getWall().getPalette().isEmpty())
|
||||
{
|
||||
h = highestTerrainBlock(x, z);
|
||||
ha = highestTerrainBlock(x + 1, z);
|
||||
hb = highestTerrainBlock(x, z + 1);
|
||||
hc = highestTerrainBlock(x - 1, z);
|
||||
hd = highestTerrainBlock(x, z - 1);
|
||||
|
||||
if(ha < h - 2 || hb < h - 2 || hc < h - 2 || hd < h - 2)
|
||||
{
|
||||
int max = Math.abs(Math.max(h - ha, Math.max(h - hb, Math.max(h - hc, h - hd))));
|
||||
BlockData s = gen.sampleTrueBiome(x, z).getBiome().getSlab().get(rng, x, h, z);
|
||||
|
||||
if(s != null)
|
||||
{
|
||||
if(!s.getMaterial().equals(AIR))
|
||||
{
|
||||
setPostBlock(x, h + 1, z, s);
|
||||
updateHeight(x, z, h + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = h; i > h - max; i--)
|
||||
{
|
||||
BlockData d = biome.getWall().get(rng, x + i, i + h, z + i);
|
||||
|
||||
if(d != null)
|
||||
{
|
||||
if(d.getMaterial().equals(AIR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isAirOrWater(x, i, z))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
setPostBlock(x, i, z, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
src/main/java/com/volmit/iris/gen/post/PostWaterlogger.java
Normal file
62
src/main/java/com/volmit/iris/gen/post/PostWaterlogger.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package com.volmit.iris.layer.post;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
|
||||
import com.volmit.iris.generator.PostBlockChunkGenerator;
|
||||
import com.volmit.iris.util.BlockDataTools;
|
||||
import com.volmit.iris.util.IrisPostBlockFilter;
|
||||
|
||||
@Post("waterlogger")
|
||||
public class PostWaterlogger extends IrisPostBlockFilter
|
||||
{
|
||||
private static final BlockData WATER = BlockDataTools.getBlockData("WATER");
|
||||
|
||||
public PostWaterlogger(PostBlockChunkGenerator gen, int phase)
|
||||
{
|
||||
super(gen, phase);
|
||||
}
|
||||
|
||||
public PostWaterlogger(PostBlockChunkGenerator gen)
|
||||
{
|
||||
super(gen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPost(int x, int z)
|
||||
{
|
||||
int h = highestTerrainBlock(x, z);
|
||||
BlockData b = getPostBlock(x, h, z);
|
||||
|
||||
if(b instanceof Waterlogged)
|
||||
{
|
||||
Waterlogged ww = (Waterlogged) b;
|
||||
|
||||
if(ww.isWaterlogged())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(isWaterOrWaterlogged(x, h + 1, z) && !ww.isWaterlogged())
|
||||
{
|
||||
ww.setWaterlogged(true);
|
||||
setPostBlock(x, h, z, ww);
|
||||
}
|
||||
|
||||
else if(!ww.isWaterlogged() && (isWaterOrWaterlogged(x + 1, h, z) || isWaterOrWaterlogged(x - 1, h, z) || isWaterOrWaterlogged(x, h, z + 1) || isWaterOrWaterlogged(x, h, z - 1)))
|
||||
{
|
||||
ww.setWaterlogged(true);
|
||||
setPostBlock(x, h, z, ww);
|
||||
}
|
||||
}
|
||||
|
||||
else if(b.getMaterial().equals(Material.AIR) && h <= gen.getFluidHeight())
|
||||
{
|
||||
if((isWaterOrWaterlogged(x + 1, h, z) || isWaterOrWaterlogged(x - 1, h, z) || isWaterOrWaterlogged(x, h, z + 1) || isWaterOrWaterlogged(x, h, z - 1)))
|
||||
{
|
||||
setPostBlock(x, h, z, WATER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user