mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-18 18:23:06 +00:00
Cleanup
This commit is contained in:
parent
eca3174214
commit
17df8f23c5
@ -17,6 +17,7 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import ninja.bytecode.iris.generator.IrisGenerator;
|
||||||
import ninja.bytecode.iris.object.IrisBiome;
|
import ninja.bytecode.iris.object.IrisBiome;
|
||||||
import ninja.bytecode.iris.object.IrisDimension;
|
import ninja.bytecode.iris.object.IrisDimension;
|
||||||
import ninja.bytecode.iris.util.BiomeResult;
|
import ninja.bytecode.iris.util.BiomeResult;
|
||||||
@ -154,7 +155,7 @@ public class Iris extends JavaPlugin implements BoardProvider
|
|||||||
imsg(i, "Creating Iris " + dimm + "...");
|
imsg(i, "Creating Iris " + dimm + "...");
|
||||||
}
|
}
|
||||||
|
|
||||||
IrisGenerator gx = new IrisGenerator("overworld");
|
IrisGenerator gx = new IrisGenerator("overworld", 16);
|
||||||
|
|
||||||
O<Boolean> done = new O<Boolean>();
|
O<Boolean> done = new O<Boolean>();
|
||||||
done.set(false);
|
done.set(false);
|
||||||
@ -207,7 +208,7 @@ public class Iris extends JavaPlugin implements BoardProvider
|
|||||||
@Override
|
@Override
|
||||||
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id)
|
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id)
|
||||||
{
|
{
|
||||||
return new IrisGenerator("overworld");
|
return new IrisGenerator("overworld", 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void msg(String string)
|
public static void msg(String string)
|
||||||
|
@ -2,6 +2,8 @@ package ninja.bytecode.iris;
|
|||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import ninja.bytecode.iris.object.IrisDimension;
|
||||||
|
import ninja.bytecode.iris.object.IrisRegion;
|
||||||
import ninja.bytecode.iris.util.BiomeResult;
|
import ninja.bytecode.iris.util.BiomeResult;
|
||||||
import ninja.bytecode.shuriken.collections.KMap;
|
import ninja.bytecode.shuriken.collections.KMap;
|
||||||
|
|
||||||
@ -21,7 +23,13 @@ public interface IrisContext
|
|||||||
|
|
||||||
public BiomeResult getBiome(int x, int z);
|
public BiomeResult getBiome(int x, int z);
|
||||||
|
|
||||||
|
public IrisDimension getDimension();
|
||||||
|
|
||||||
|
public IrisRegion getRegion(int x, int z);
|
||||||
|
|
||||||
public IrisMetrics getMetrics();
|
public IrisMetrics getMetrics();
|
||||||
|
|
||||||
|
public int getHeight(int x, int z);
|
||||||
|
|
||||||
public World getWorld();
|
public World getWorld();
|
||||||
}
|
}
|
||||||
|
@ -1,373 +0,0 @@
|
|||||||
package ninja.bytecode.iris;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.block.data.BlockData;
|
|
||||||
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.PlayerTeleportEvent;
|
|
||||||
import org.bukkit.event.world.WorldUnloadEvent;
|
|
||||||
import org.bukkit.generator.BlockPopulator;
|
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import ninja.bytecode.iris.layer.GenLayerBiome;
|
|
||||||
import ninja.bytecode.iris.object.IrisBiome;
|
|
||||||
import ninja.bytecode.iris.object.IrisDimension;
|
|
||||||
import ninja.bytecode.iris.object.IrisRegion;
|
|
||||||
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
|
||||||
import ninja.bytecode.iris.util.BiomeResult;
|
|
||||||
import ninja.bytecode.iris.util.BlockDataTools;
|
|
||||||
import ninja.bytecode.iris.util.CNG;
|
|
||||||
import ninja.bytecode.iris.util.ChronoLatch;
|
|
||||||
import ninja.bytecode.iris.util.GroupedExecutor;
|
|
||||||
import ninja.bytecode.iris.util.IrisInterpolation;
|
|
||||||
import ninja.bytecode.iris.util.RNG;
|
|
||||||
import ninja.bytecode.shuriken.bench.PrecisionStopwatch;
|
|
||||||
import ninja.bytecode.shuriken.collections.KList;
|
|
||||||
import ninja.bytecode.shuriken.format.Form;
|
|
||||||
import ninja.bytecode.shuriken.logging.L;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = false)
|
|
||||||
public class IrisGenerator extends ChunkGenerator implements IrisContext, Listener
|
|
||||||
{
|
|
||||||
private String dimensionName;
|
|
||||||
private IrisMetrics metrics;
|
|
||||||
private World world;
|
|
||||||
private ChronoLatch perSecond;
|
|
||||||
private ChronoLatch pushLatch;
|
|
||||||
private BlockData STONE = Material.STONE.createBlockData();
|
|
||||||
private BlockData WATER = Material.WATER.createBlockData();
|
|
||||||
private GenLayerBiome glBiome;
|
|
||||||
private CNG terrainNoise;
|
|
||||||
private RNG masterRandom;
|
|
||||||
private GroupedExecutor tx;
|
|
||||||
private boolean failing = false;
|
|
||||||
private boolean initialized = false;
|
|
||||||
private int generated = 0;
|
|
||||||
private boolean pregenDone = false;
|
|
||||||
private int task = -1;
|
|
||||||
|
|
||||||
public IrisGenerator(String dimensionName)
|
|
||||||
{
|
|
||||||
this.dimensionName = dimensionName;
|
|
||||||
pushLatch = new ChronoLatch(3000);
|
|
||||||
perSecond = new ChronoLatch(1000);
|
|
||||||
CNG.creates = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IrisDimension getDimension()
|
|
||||||
{
|
|
||||||
IrisDimension d = Iris.data.getDimensionLoader().load(dimensionName);
|
|
||||||
|
|
||||||
if(d == null)
|
|
||||||
{
|
|
||||||
Iris.error("Can't find dimension: " + dimensionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onInit(World world, RNG rng)
|
|
||||||
{
|
|
||||||
if(initialized)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.world = world;
|
|
||||||
this.masterRandom = new RNG(world.getSeed());
|
|
||||||
glBiome = new GenLayerBiome(this, masterRandom.nextParallelRNG(1));
|
|
||||||
terrainNoise = CNG.signature(masterRandom.nextParallelRNG(2));
|
|
||||||
metrics = new IrisMetrics(128);
|
|
||||||
initialized = true;
|
|
||||||
tx = new GroupedExecutor(16, Thread.MIN_PRIORITY, "Iris Generator");
|
|
||||||
Iris.executors.add(tx);
|
|
||||||
Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
|
|
||||||
task = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::tick, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void tick()
|
|
||||||
{
|
|
||||||
if(perSecond.flip())
|
|
||||||
{
|
|
||||||
if(generated > 770)
|
|
||||||
{
|
|
||||||
pregenDone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pregenDone)
|
|
||||||
{
|
|
||||||
metrics.getPerSecond().put(generated);
|
|
||||||
generated = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void on(PlayerTeleportEvent e)
|
|
||||||
{
|
|
||||||
if(e.getFrom().getWorld().equals(world) && !e.getTo().getWorld().equals(world))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!e.getFrom().getWorld().equals(world) && e.getTo().getWorld().equals(world))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void on(WorldUnloadEvent e)
|
|
||||||
{
|
|
||||||
if(world != null && e.getWorld().equals(world))
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
HandlerList.unregisterAll(this);
|
|
||||||
Bukkit.getScheduler().cancelTask(getTask());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canSpawn(World world, int x, int z)
|
|
||||||
{
|
|
||||||
return super.canSpawn(world, x, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChunkData generateChunkData(World world, Random no, int x, int z, BiomeGrid biomeGrid)
|
|
||||||
{
|
|
||||||
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.pushContext(this);
|
|
||||||
if(metrics != null)
|
|
||||||
{
|
|
||||||
Iris.info("Generating " + Form.f(1000D / metrics.getTotal().getAverage(), 0) + "/s (" + Form.duration(metrics.getTotal().getAverage(), 2) + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String key = "c" + x + "," + z;
|
|
||||||
PrecisionStopwatch s = PrecisionStopwatch.start();
|
|
||||||
RNG random = new RNG(world.getSeed());
|
|
||||||
onInit(world, random.nextParallelRNG(0));
|
|
||||||
ChunkData c = Bukkit.createChunkData(world);
|
|
||||||
int ii, jj;
|
|
||||||
int fluidHeight = getDimension().getFluidHeight();
|
|
||||||
KList<Runnable> collapse = new KList<>();
|
|
||||||
ReentrantLock l = new ReentrantLock();
|
|
||||||
|
|
||||||
for(ii = 0; ii < 16; ii++)
|
|
||||||
{
|
|
||||||
int i = ii;
|
|
||||||
for(jj = 0; jj < 16; jj++)
|
|
||||||
{
|
|
||||||
int j = jj;
|
|
||||||
tx.queue(key, () ->
|
|
||||||
{
|
|
||||||
BlockData block;
|
|
||||||
int rx = (x * 16) + i;
|
|
||||||
int rz = (z * 16) + j;
|
|
||||||
AtomicSliver sliver = new AtomicSliver(i, j);
|
|
||||||
double ox = (getDimension().cosRotate() * rx) + (-getDimension().sinRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
|
||||||
double oz = (getDimension().sinRotate() * rx) + (getDimension().cosRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
|
||||||
double wx = (double) (ox) / getDimension().getTerrainZoom();
|
|
||||||
double wz = (double) (oz) / getDimension().getTerrainZoom();
|
|
||||||
int depth = 0;
|
|
||||||
IrisRegion region = glBiome.getRegion(wx, wz);
|
|
||||||
BiomeResult biomeResult = glBiome.generateRegionData(wx, wz, region);
|
|
||||||
IrisBiome biome = biomeResult.getBiome();
|
|
||||||
double lo = interpolateHeight(ox, oz, (b) -> b.getLowHeight());
|
|
||||||
double hi = interpolateSurface(ox, oz, (b) -> b.getHighHeight());
|
|
||||||
double noise = lo + (terrainNoise.fitDoubleD(0, hi - lo, wx, wz));
|
|
||||||
int height = (int) Math.round(noise) + fluidHeight;
|
|
||||||
|
|
||||||
// Remove Land biome surfaces from underwater
|
|
||||||
if(height < fluidHeight + 1)
|
|
||||||
{
|
|
||||||
if(biome.isLand())
|
|
||||||
{
|
|
||||||
biome = glBiome.generateShoreData(wx, wz, region).getBiome();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KList<BlockData> layers = biome.generateLayers(wx, wz, random, height);
|
|
||||||
|
|
||||||
for(int k = Math.max(height, fluidHeight); k >= 0; k--)
|
|
||||||
{
|
|
||||||
boolean underwater = k > height && k <= fluidHeight;
|
|
||||||
sliver.set(k, biome.getDerivative());
|
|
||||||
// biomeGrid.setBiome(i, k, j, biome.getDerivative());
|
|
||||||
|
|
||||||
if(underwater)
|
|
||||||
{
|
|
||||||
block = WATER;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
block = layers.hasIndex(depth) ? layers.get(depth) : STONE;
|
|
||||||
depth++;
|
|
||||||
}
|
|
||||||
|
|
||||||
sliver.set(k, block);
|
|
||||||
// c.setBlock(i, k, j, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
l.lock();
|
|
||||||
collapse.add(() ->
|
|
||||||
{
|
|
||||||
sliver.write(c);
|
|
||||||
sliver.write(biomeGrid);
|
|
||||||
});
|
|
||||||
l.unlock();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.waitFor(key);
|
|
||||||
collapse.forEach((i) -> i.run());
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
failing = true;
|
|
||||||
Iris.error("ERROR! Failed to generate chunk! Iris has entered a failed state!");
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
L.ex(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return generateChunkDataFailure(world, no, x, z, biomeGrid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double interpolateHeight(double rx, double rz, Function<IrisBiome, Double> property)
|
|
||||||
{
|
|
||||||
return IrisInterpolation.getNoise(getDimension().getInterpolationFunction(), (int) Math.round(rx), (int) Math.round(rz), getDimension().getInterpolationScale(), (xx, zz) ->
|
|
||||||
{
|
|
||||||
BiomeResult neighborResult = glBiome.generateData(xx / getDimension().getTerrainZoom(), zz / getDimension().getTerrainZoom());
|
|
||||||
return property.apply(neighborResult.getBiome());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public double interpolateSurface(double rx, double rz, Function<IrisBiome, Double> property)
|
|
||||||
{
|
|
||||||
return IrisInterpolation.getNoise(getDimension().getInterpolationSurfaceFunction(), (int) Math.round(rx), (int) Math.round(rz), getDimension().getInterpolationSurfaceScale(), (xx, zz) ->
|
|
||||||
{
|
|
||||||
BiomeResult neighborResult = glBiome.generateData(xx / getDimension().getTerrainZoom(), zz / getDimension().getTerrainZoom());
|
|
||||||
return property.apply(neighborResult.getBiome());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisMetrics getMetrics()
|
|
||||||
{
|
|
||||||
return metrics;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public World getWorld()
|
|
||||||
{
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BiomeResult getBiome(int rx, int rz)
|
|
||||||
{
|
|
||||||
RNG random = new RNG(world.getSeed());
|
|
||||||
double ox = (getDimension().cosRotate() * rx) + (-getDimension().sinRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
|
||||||
double oz = (getDimension().sinRotate() * rx) + (getDimension().cosRotate() * rz) + getDimension().getCoordFracture(random, 39392).fitDoubleD(-getDimension().getCoordFractureDistance() / 2, getDimension().getCoordFractureDistance() / 2, rx, rz);
|
|
||||||
double wx = (double) (ox) / getDimension().getTerrainZoom();
|
|
||||||
double wz = (double) (oz) / getDimension().getTerrainZoom();
|
|
||||||
IrisRegion region = glBiome.getRegion(wx, wz);
|
|
||||||
return glBiome.generateRegionData(wx, wz, region);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,64 @@
|
|||||||
|
package ninja.bytecode.iris.generator;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import ninja.bytecode.iris.layer.GenLayerBiome;
|
||||||
|
import ninja.bytecode.iris.object.IrisBiome;
|
||||||
|
import ninja.bytecode.iris.object.IrisRegion;
|
||||||
|
import ninja.bytecode.iris.util.BiomeResult;
|
||||||
|
import ninja.bytecode.iris.util.IrisInterpolation;
|
||||||
|
import ninja.bytecode.iris.util.RNG;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public abstract class BiomeChunkGenerator extends DimensionChunkGenerator
|
||||||
|
{
|
||||||
|
protected GenLayerBiome glBiome;
|
||||||
|
|
||||||
|
public BiomeChunkGenerator(String dimensionName)
|
||||||
|
{
|
||||||
|
super(dimensionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onInit(World world, RNG rng)
|
||||||
|
{
|
||||||
|
glBiome = new GenLayerBiome(this, masterRandom.nextParallelRNG(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrisRegion sampleRegion(int x, int z)
|
||||||
|
{
|
||||||
|
double wx = getZoomed(getModifiedX(x, z));
|
||||||
|
double wz = getZoomed(getModifiedZ(x, z));
|
||||||
|
return glBiome.getRegion(wx, wz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BiomeResult sampleBiome(int x, int z)
|
||||||
|
{
|
||||||
|
double wx = getZoomed(getModifiedX(x, z));
|
||||||
|
double wz = getZoomed(getModifiedZ(x, z));
|
||||||
|
IrisRegion region = glBiome.getRegion(wx, wz);
|
||||||
|
return glBiome.generateRegionData(wx, wz, region);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected double interpolateHeight(double rx, double rz, Function<IrisBiome, Double> property)
|
||||||
|
{
|
||||||
|
return IrisInterpolation.getNoise(getDimension().getInterpolationFunction(), (int) Math.round(rx), (int) Math.round(rz), getDimension().getInterpolationScale(), (xx, zz) ->
|
||||||
|
{
|
||||||
|
BiomeResult neighborResult = glBiome.generateData(xx / getDimension().getTerrainZoom(), zz / getDimension().getTerrainZoom());
|
||||||
|
return property.apply(neighborResult.getBiome());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected double interpolateSurface(double rx, double rz, Function<IrisBiome, Double> property)
|
||||||
|
{
|
||||||
|
return IrisInterpolation.getNoise(getDimension().getInterpolationSurfaceFunction(), (int) Math.round(rx), (int) Math.round(rz), getDimension().getInterpolationSurfaceScale(), (xx, zz) ->
|
||||||
|
{
|
||||||
|
BiomeResult neighborResult = glBiome.generateData(xx / getDimension().getTerrainZoom(), zz / getDimension().getTerrainZoom());
|
||||||
|
return property.apply(neighborResult.getBiome());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,293 @@
|
|||||||
|
package ninja.bytecode.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 lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import ninja.bytecode.iris.Iris;
|
||||||
|
import ninja.bytecode.iris.IrisContext;
|
||||||
|
import ninja.bytecode.iris.IrisMetrics;
|
||||||
|
import ninja.bytecode.iris.util.BlockDataTools;
|
||||||
|
import ninja.bytecode.iris.util.CNG;
|
||||||
|
import ninja.bytecode.iris.util.ChronoLatch;
|
||||||
|
import ninja.bytecode.iris.util.RNG;
|
||||||
|
import ninja.bytecode.shuriken.bench.PrecisionStopwatch;
|
||||||
|
import ninja.bytecode.shuriken.logging.L;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public abstract class ContextualChunkGenerator extends ChunkGenerator implements Listener
|
||||||
|
{
|
||||||
|
protected boolean failing;
|
||||||
|
protected int task;
|
||||||
|
protected boolean initialized;
|
||||||
|
protected RNG masterRandom;
|
||||||
|
protected ChronoLatch perSecond;
|
||||||
|
protected ChronoLatch pushLatch;
|
||||||
|
protected IrisMetrics metrics;
|
||||||
|
protected World world;
|
||||||
|
protected int generated;
|
||||||
|
protected int ticks;
|
||||||
|
protected boolean pregenDone;
|
||||||
|
|
||||||
|
public ContextualChunkGenerator()
|
||||||
|
{
|
||||||
|
pushLatch = new ChronoLatch(3000);
|
||||||
|
perSecond = new ChronoLatch(1000);
|
||||||
|
CNG.creates = 0;
|
||||||
|
generated = 0;
|
||||||
|
ticks = 0;
|
||||||
|
task = -1;
|
||||||
|
initialized = false;
|
||||||
|
failing = false;
|
||||||
|
pregenDone = 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(perSecond.flip())
|
||||||
|
{
|
||||||
|
if(generated > 770)
|
||||||
|
{
|
||||||
|
pregenDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pregenDone)
|
||||||
|
{
|
||||||
|
metrics.getPerSecond().put(generated);
|
||||||
|
generated = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTick(ticks++);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void on(PlayerTeleportEvent e)
|
||||||
|
{
|
||||||
|
if(e.getFrom().getWorld().equals(world) && !e.getTo().getWorld().equals(world))
|
||||||
|
{
|
||||||
|
onPlayerLeft(e.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!e.getFrom().getWorld().equals(world) && e.getTo().getWorld().equals(world))
|
||||||
|
{
|
||||||
|
onPlayerJoin(e.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void on(PlayerQuitEvent e)
|
||||||
|
{
|
||||||
|
if(e.getPlayer().getWorld().equals(world))
|
||||||
|
{
|
||||||
|
onPlayerLeft(e.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void on(PlayerJoinEvent e)
|
||||||
|
{
|
||||||
|
if(e.getPlayer().getWorld().equals(world))
|
||||||
|
{
|
||||||
|
onPlayerJoin(e.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void on(ChunkLoadEvent e)
|
||||||
|
{
|
||||||
|
if(e.getWorld().equals(world))
|
||||||
|
{
|
||||||
|
onChunkLoaded(e.getChunk());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void on(ChunkUnloadEvent e)
|
||||||
|
{
|
||||||
|
if(e.getWorld().equals(world))
|
||||||
|
{
|
||||||
|
onChunkUnloaded(e.getChunk());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void on(WorldUnloadEvent e)
|
||||||
|
{
|
||||||
|
if(world != null && e.getWorld().equals(world))
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkData generateChunkData(World world, Random no, int x, int z, BiomeGrid biomeGrid)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
|
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);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
failing = true;
|
||||||
|
Iris.error("ERROR! Failed to generate chunk! Iris has entered a failed state!");
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
L.ex(e);
|
||||||
|
onFailure(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateChunkDataFailure(world, no, x, z, biomeGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,46 @@
|
|||||||
|
package ninja.bytecode.iris.generator;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import ninja.bytecode.iris.Iris;
|
||||||
|
import ninja.bytecode.iris.object.IrisDimension;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public abstract class DimensionChunkGenerator extends ContextualChunkGenerator
|
||||||
|
{
|
||||||
|
protected final String dimensionName;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package ninja.bytecode.iris.generator;
|
||||||
|
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import ninja.bytecode.iris.IrisContext;
|
||||||
|
import ninja.bytecode.iris.object.IrisRegion;
|
||||||
|
import ninja.bytecode.iris.util.BiomeResult;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class IrisGenerator extends ParallaxChunkGenerator implements IrisContext
|
||||||
|
{
|
||||||
|
public IrisGenerator(String dimensionName, int threads)
|
||||||
|
{
|
||||||
|
super(dimensionName, threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onClose()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package ninja.bytecode.iris.generator;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import ninja.bytecode.iris.util.HeightMap;
|
||||||
|
import ninja.bytecode.iris.util.RNG;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator
|
||||||
|
{
|
||||||
|
public ParallaxChunkGenerator(String dimensionName, int threads)
|
||||||
|
{
|
||||||
|
super(dimensionName, threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package ninja.bytecode.iris.generator;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import ninja.bytecode.iris.Iris;
|
||||||
|
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||||
|
import ninja.bytecode.iris.object.atomics.AtomicSliverMap;
|
||||||
|
import ninja.bytecode.iris.util.GroupedExecutor;
|
||||||
|
import ninja.bytecode.iris.util.HeightMap;
|
||||||
|
import ninja.bytecode.iris.util.RNG;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public abstract class ParallelChunkGenerator extends BiomeChunkGenerator
|
||||||
|
{
|
||||||
|
private GroupedExecutor tx;
|
||||||
|
private int threads;
|
||||||
|
|
||||||
|
public ParallelChunkGenerator(String dimensionName, int threads)
|
||||||
|
{
|
||||||
|
super(dimensionName);
|
||||||
|
this.threads = threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeThreadCount(int tc)
|
||||||
|
{
|
||||||
|
threads = tc;
|
||||||
|
GroupedExecutor e = tx;
|
||||||
|
tx = new GroupedExecutor(threads, Thread.NORM_PRIORITY, "Iris Generator - " + world.getName());
|
||||||
|
Iris.executors.add(tx);
|
||||||
|
|
||||||
|
if(e != null)
|
||||||
|
{
|
||||||
|
e.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void onGenerateColumn(int cx, int cz, int wx, int wz, int x, int z, AtomicSliver sliver);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
AtomicSliverMap map = new AtomicSliverMap();
|
||||||
|
HeightMap height = new HeightMap();
|
||||||
|
String key = "c" + x + "," + z;
|
||||||
|
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);
|
||||||
|
|
||||||
|
tx.queue(key, () ->
|
||||||
|
{
|
||||||
|
onGenerateColumn(x, z, wx, wz, i, j, sliver);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.waitFor(key);
|
||||||
|
map.write(data, grid, height);
|
||||||
|
onPostGenerate(random, x, z, data, grid, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onInit(World world, RNG rng)
|
||||||
|
{
|
||||||
|
super.onInit(world, rng);
|
||||||
|
changeThreadCount(threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isParallelCapable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package ninja.bytecode.iris.generator;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import ninja.bytecode.iris.object.IrisBiome;
|
||||||
|
import ninja.bytecode.iris.object.IrisRegion;
|
||||||
|
import ninja.bytecode.iris.object.atomics.AtomicSliver;
|
||||||
|
import ninja.bytecode.iris.util.BiomeResult;
|
||||||
|
import ninja.bytecode.iris.util.CNG;
|
||||||
|
import ninja.bytecode.iris.util.RNG;
|
||||||
|
import ninja.bytecode.shuriken.collections.KList;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
|
||||||
|
{
|
||||||
|
protected static final BlockData STONE = Material.STONE.createBlockData();
|
||||||
|
protected static final BlockData WATER = Material.WATER.createBlockData();
|
||||||
|
protected CNG terrainNoise;
|
||||||
|
|
||||||
|
public TerrainChunkGenerator(String dimensionName, int threads)
|
||||||
|
{
|
||||||
|
super(dimensionName, threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onInit(World world, RNG rng)
|
||||||
|
{
|
||||||
|
super.onInit(world, rng);
|
||||||
|
terrainNoise = CNG.signature(masterRandom.nextParallelRNG(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onGenerateColumn(int cx, int cz, int rx, int rz, int x, int z, AtomicSliver sliver)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
IrisRegion region = glBiome.getRegion(wx, wz);
|
||||||
|
BiomeResult biomeResult = glBiome.generateRegionData(wx, wz, region);
|
||||||
|
IrisBiome biome = biomeResult.getBiome();
|
||||||
|
double lo = interpolateHeight(ox, oz, (b) -> b.getLowHeight());
|
||||||
|
double hi = interpolateSurface(ox, oz, (b) -> b.getHighHeight());
|
||||||
|
double noise = lo + (terrainNoise.fitDoubleD(0, hi - lo, wx, wz));
|
||||||
|
int height = (int) Math.round(noise) + fluidHeight;
|
||||||
|
|
||||||
|
if(height < fluidHeight + 1)
|
||||||
|
{
|
||||||
|
if(biome.isLand())
|
||||||
|
{
|
||||||
|
biome = glBiome.generateShoreData(wx, wz, region).getBiome();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KList<BlockData> layers = biome.generateLayers(wx, wz, masterRandom, height);
|
||||||
|
|
||||||
|
for(int k = Math.max(height, fluidHeight); k >= 0; k--)
|
||||||
|
{
|
||||||
|
boolean underwater = k > height && k <= fluidHeight;
|
||||||
|
sliver.set(k, biome.getDerivative());
|
||||||
|
|
||||||
|
if(underwater)
|
||||||
|
{
|
||||||
|
block = WATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block = layers.hasIndex(depth) ? layers.get(depth) : STONE;
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sliver.set(k, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int onSampleColumnHeight(int cx, int cz, int rx, int rz, int x, int z)
|
||||||
|
{
|
||||||
|
int fluidHeight = getDimension().getFluidHeight();
|
||||||
|
double ox = getModifiedX(rx, rz);
|
||||||
|
double oz = getModifiedZ(rx, rz);
|
||||||
|
double lo = interpolateHeight(ox, oz, (b) -> b.getLowHeight());
|
||||||
|
double hi = interpolateSurface(ox, oz, (b) -> b.getHighHeight());
|
||||||
|
double noise = lo + (terrainNoise.fitDoubleD(0, hi - lo, getZoomed(ox), getZoomed(oz)));
|
||||||
|
|
||||||
|
return (int) Math.round(noise) + fluidHeight;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package ninja.bytecode.iris.layer;
|
package ninja.bytecode.iris.layer;
|
||||||
|
|
||||||
import ninja.bytecode.iris.Iris;
|
import ninja.bytecode.iris.Iris;
|
||||||
import ninja.bytecode.iris.IrisGenerator;
|
import ninja.bytecode.iris.generator.DimensionChunkGenerator;
|
||||||
import ninja.bytecode.iris.object.InferredType;
|
import ninja.bytecode.iris.object.InferredType;
|
||||||
import ninja.bytecode.iris.object.IrisBiome;
|
import ninja.bytecode.iris.object.IrisBiome;
|
||||||
import ninja.bytecode.iris.object.IrisRegion;
|
import ninja.bytecode.iris.object.IrisRegion;
|
||||||
@ -19,7 +19,7 @@ public class GenLayerBiome extends GenLayer
|
|||||||
private CellGenerator shore;
|
private CellGenerator shore;
|
||||||
private CellGenerator sea;
|
private CellGenerator sea;
|
||||||
|
|
||||||
public GenLayerBiome(IrisGenerator iris, RNG rng)
|
public GenLayerBiome(DimensionChunkGenerator iris, RNG rng)
|
||||||
{
|
{
|
||||||
super(iris, rng);
|
super(iris, rng);
|
||||||
region = new CellGenerator(rng.nextParallelRNG(1188519));
|
region = new CellGenerator(rng.nextParallelRNG(1188519));
|
||||||
|
@ -5,8 +5,14 @@ import org.bukkit.block.data.BlockData;
|
|||||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import ninja.bytecode.iris.util.BlockDataTools;
|
||||||
|
import ninja.bytecode.iris.util.HeightMap;
|
||||||
|
|
||||||
|
@Data
|
||||||
public class AtomicSliver
|
public class AtomicSliver
|
||||||
{
|
{
|
||||||
|
private static final BlockData AIR = BlockDataTools.getBlockData("AIR");
|
||||||
private BlockData[] block;
|
private BlockData[] block;
|
||||||
private Biome[] biome;
|
private Biome[] biome;
|
||||||
private int highestBlock = 0;
|
private int highestBlock = 0;
|
||||||
@ -37,10 +43,18 @@ public class AtomicSliver
|
|||||||
public void write(ChunkData d)
|
public void write(ChunkData d)
|
||||||
{
|
{
|
||||||
for(int i = 0; i <= highestBlock; i++)
|
for(int i = 0; i <= highestBlock; i++)
|
||||||
|
{
|
||||||
|
if(block[i] == null)
|
||||||
|
{
|
||||||
|
d.setBlock(x, i, z, AIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
{
|
{
|
||||||
d.setBlock(x, i, z, block[i]);
|
d.setBlock(x, i, z, block[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void write(BiomeGrid d)
|
public void write(BiomeGrid d)
|
||||||
{
|
{
|
||||||
@ -49,4 +63,9 @@ public class AtomicSliver
|
|||||||
d.setBiome(x, i, z, biome[i]);
|
d.setBiome(x, i, z, biome[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void write(HeightMap height)
|
||||||
|
{
|
||||||
|
height.setHeight(x, z, highestBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package ninja.bytecode.iris.object.atomics;
|
||||||
|
|
||||||
|
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||||
|
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||||
|
|
||||||
|
import ninja.bytecode.iris.util.HeightMap;
|
||||||
|
|
||||||
|
public class AtomicSliverMap
|
||||||
|
{
|
||||||
|
private final AtomicSliver[] slivers;
|
||||||
|
|
||||||
|
public AtomicSliverMap()
|
||||||
|
{
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,13 @@
|
|||||||
package ninja.bytecode.iris.util;
|
package ninja.bytecode.iris.util;
|
||||||
|
|
||||||
import ninja.bytecode.iris.IrisGenerator;
|
import ninja.bytecode.iris.generator.DimensionChunkGenerator;
|
||||||
|
|
||||||
public abstract class GenLayer
|
public abstract class GenLayer
|
||||||
{
|
{
|
||||||
protected final RNG rng;
|
protected final RNG rng;
|
||||||
protected final IrisGenerator iris;
|
protected final DimensionChunkGenerator iris;
|
||||||
|
|
||||||
public GenLayer(IrisGenerator iris, RNG rng)
|
public GenLayer(DimensionChunkGenerator iris, RNG rng)
|
||||||
{
|
{
|
||||||
this.iris = iris;
|
this.iris = iris;
|
||||||
this.rng = rng;
|
this.rng = rng;
|
||||||
|
24
src/main/java/ninja/bytecode/iris/util/HeightMap.java
Normal file
24
src/main/java/ninja/bytecode/iris/util/HeightMap.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package ninja.bytecode.iris.util;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class HeightMap
|
||||||
|
{
|
||||||
|
private final byte[] height;
|
||||||
|
|
||||||
|
public HeightMap()
|
||||||
|
{
|
||||||
|
height = new byte[256];
|
||||||
|
Arrays.fill(height, Byte.MIN_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(int x, int z, int h)
|
||||||
|
{
|
||||||
|
height[(x & 15) * 16 + (z & 15)] = (byte) (h + Byte.MIN_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight(int x, int z)
|
||||||
|
{
|
||||||
|
return height[(x & 15) * 16 + (z & 15)] - Byte.MIN_VALUE;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user