9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-27 11:09:06 +00:00

Parallax Object Generation

This commit is contained in:
Daniel Mills
2020-01-20 14:38:07 -05:00
parent fd561cd45d
commit a4b571ccbc
42 changed files with 3190 additions and 297 deletions

View File

@@ -9,7 +9,7 @@ public class Settings
public static class PerformanceSettings
{
public PerformanceMode performanceMode = PerformanceMode.UNLIMITED;
public PerformanceMode performanceMode = PerformanceMode.HALF_CPU;
public boolean fastDecoration = true;
public int threadPriority = Thread.MAX_PRIORITY;
public int threadCount = 4;
@@ -17,6 +17,7 @@ public class Settings
public int decorationAccuracy = 2;
public boolean interpolation = true;
public boolean surfaceNoise = true;
public boolean noObjectFail = false;
public boolean verbose = false;
public int placeHistoryLimit = 8192;
}
@@ -37,7 +38,7 @@ public class Settings
public double heightScale = 0.56;
public double baseHeight = 0.065;
public int seaLevel = 63;
public double caveDensity = 4;
public double caveDensity = 5;
public double caveScale = 1.45;
public double biomeScale = 0.65;
public boolean flatBedrock = true;

View File

@@ -8,9 +8,9 @@ import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.execution.TaskExecutor;
public class ExecutionController implements IrisController
{
{
GMap<String, TaskExecutor> executors;
@Override
public void onStart()
{
@@ -20,16 +20,19 @@ public class ExecutionController implements IrisController
@Override
public void onStop()
{
for(TaskExecutor i : executors.v())
{
i.close();
}
}
public TaskExecutor getExecutor(World world)
public TaskExecutor getExecutor(World world, String f)
{
TaskExecutor x = new TaskExecutor(getTC(), Iris.settings.performance.threadPriority, "Iris Generator (" + world.getName() + ")");
executors.put(world.getWorldFolder().getAbsolutePath() + " (" + world + ")", x);
TaskExecutor x = new TaskExecutor(getTC(), Iris.settings.performance.threadPriority, "Iris " + f);
executors.put(world.getWorldFolder().getAbsolutePath() + " (" + world + ") " + f, x);
return x;
}
private int getTC()
{
switch(Iris.settings.performance.performanceMode)

View File

@@ -142,6 +142,7 @@ public class PackController implements IrisController
for(String i : compiledDimensions.k())
{
CompiledDimension d = compiledDimensions.get(i);
d.computeObjectSize();
L.i(ChatColor.GREEN + i + ChatColor.WHITE + " (" + d.getEnvironment().toString().toLowerCase() + ")");
L.i(ChatColor.DARK_GREEN + " Biomes: " + ChatColor.GRAY + F.f(d.getBiomes().size()));
L.i(ChatColor.DARK_GREEN + " Objects: " + ChatColor.GRAY + F.f(d.countObjects()));

View File

@@ -1,13 +1,11 @@
package ninja.bytecode.iris.generator;
import java.util.List;
import java.util.Random;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.util.NumberConversions;
import mortar.util.text.C;
@@ -30,14 +28,15 @@ import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.ChunkPlan;
import ninja.bytecode.iris.util.IrisInterpolation;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.ParallelChunkGenerator;
import ninja.bytecode.iris.util.ParallaxWorldGenerator;
import ninja.bytecode.iris.util.SChunkVector;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.CNG;
import ninja.bytecode.shuriken.math.M;
import ninja.bytecode.shuriken.math.RNG;
public class IrisGenerator extends ParallelChunkGenerator
public class IrisGenerator extends ParallaxWorldGenerator
{
//@builder
public static final GList<MB> ROCK = new GList<MB>().add(new MB[] {
@@ -75,7 +74,6 @@ public class IrisGenerator extends ParallelChunkGenerator
private GenLayerCliffs glCliffs;
private RNG rTerrain;
private CompiledDimension dim;
private World world;
public IrisGenerator()
{
@@ -113,7 +111,6 @@ public class IrisGenerator extends ParallelChunkGenerator
}
//@builder
this.world = world;
rTerrain = new RNG(world.getSeed());
glLNoise = new GenLayerLayeredNoise(this, world, random, rTerrain.nextParallelRNG(2));
glBiome = new GenLayerBiome(this, world, random, rTerrain.nextParallelRNG(4), dim.getBiomes());
@@ -124,6 +121,7 @@ public class IrisGenerator extends ParallelChunkGenerator
glCliffs = new GenLayerCliffs(this, world, random, rTerrain.nextParallelRNG(9));
scatterCache = new double[16][][];
scatter = new CNG(rTerrain.nextParallelRNG(52), 1, 1).scale(10);
god = new GenObjectDecorator(this);
//@done
for(int i = 0; i < 16; i++)
{
@@ -242,11 +240,25 @@ public class IrisGenerator extends ParallelChunkGenerator
}
@Override
public Biome genColumn(int wxxf, int wzxf, int x, int z, ChunkPlan plan)
public void onGenParallax(int x, int z, Random random)
{
try
{
god.decorateParallax(x, z, random);
}
catch(Throwable e)
{
e.printStackTrace();
}
}
@Override
public Biome onGenColumn(int wxxf, int wzxf, int x, int z, ChunkPlan plan, AtomicChunkData data)
{
if(disposed)
{
setBlock(x, 0, z, Material.MAGENTA_GLAZED_TERRACOTTA);
data.setBlock(x, 0, z, Material.MAGENTA_GLAZED_TERRACOTTA);
return Biome.VOID;
}
@@ -296,7 +308,7 @@ public class IrisGenerator extends ParallelChunkGenerator
for(int j = 0; j < snowHeight; j++)
{
highest = j == snowHeight - 1 ? highest < j ? j : highest : highest < j + 1 ? j + 1 : highest;
setBlock(x, i + j + 1, z, j == snowHeight - 1 ? Material.SNOW : Material.SNOW_BLOCK, j == snowHeight - 1 ? (byte) layers : (byte) 0);
data.setBlock(x, i + j + 1, z, j == snowHeight - 1 ? Material.SNOW : Material.SNOW_BLOCK, j == snowHeight - 1 ? (byte) layers : (byte) 0);
}
}
@@ -307,24 +319,24 @@ public class IrisGenerator extends ParallelChunkGenerator
if(!mbx.material.equals(Material.AIR))
{
highest = i > highest ? i : highest;
setBlock(x, i + 1, z, mbx.material, mbx.data);
data.setBlock(x, i + 1, z, mbx.material, mbx.data);
}
}
}
highest = i > highest ? i : highest;
setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
glCaves.genCaves(wxx, wzx, x, z, height, this);
glCarving.genCarves(wxx, wzx, x, z, height, this, biome);
glCaverns.genCaverns(wxx, wzx, x, z, height, this, biome);
glCaves.genCaves(wxx, wzx, x, z, height, this, data);
glCarving.genCarves(wxx, wzx, x, z, height, this, biome, data);
glCaverns.genCaverns(wxx, wzx, x, z, height, this, biome, data);
int hw = 0;
int hl = 0;
for(int i = highest; i > 0; i--)
{
Material t = getType(x, i, z);
Material t = data.getType(x, i, z);
hw = i > seaLevel && hw == 0 && (t.equals(Material.WATER) || t.equals(Material.STATIONARY_WATER)) ? i : hw;
hl = hl == 0 && !t.equals(Material.AIR) ? i : hl;
}
@@ -336,31 +348,12 @@ public class IrisGenerator extends ParallelChunkGenerator
return biome.getRealBiome();
}
@Override
public void decorateColumn(int wx, int wz, int x, int z, ChunkPlan plan)
{
}
@Override
public void onPostChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan)
{
}
@Override
public List<BlockPopulator> getDefaultPopulators(World world)
{
GList<BlockPopulator> p = new GList<>();
if(Iris.settings.gen.genObjects)
{
p.add(god = new GenObjectDecorator(this));
}
return p;
}
private double getBiomedHeight(int x, int z, ChunkPlan plan)
{
double xh = plan.getHeight(x, z);
@@ -377,11 +370,6 @@ public class IrisGenerator extends ParallelChunkGenerator
return xh;
}
public World getWorld()
{
return world;
}
public RNG getRTerrain()
{
return rTerrain;
@@ -398,7 +386,7 @@ public class IrisGenerator extends ParallelChunkGenerator
{
return;
}
L.w(C.YELLOW + "Disposed Iris World " + C.RED + world.getName());
L.w(C.YELLOW + "Disposed Iris World " + C.RED + getWorld().getName());
disposed = true;
dim = null;
glLNoise = null;
@@ -407,6 +395,7 @@ public class IrisGenerator extends ParallelChunkGenerator
glCaverns = null;
glSnow = null;
glCliffs = null;
god.dispose();
}
public boolean isDisposed()
@@ -439,4 +428,16 @@ public class IrisGenerator extends ParallelChunkGenerator
{
return god.randomObject(string);
}
@Override
protected SChunkVector getParallaxSize()
{
return dim.getMaxChunkSize();
}
@Override
protected void onUnload()
{
dispose();
}
}

View File

@@ -98,7 +98,7 @@ public class GenObject
}
mountHeight = avg(avy);
mount = new BlockVector(avg(avx), 0, avg(avz));
mount = new BlockVector(0, 0, 0);
}
private int avg(double[] v)
@@ -255,7 +255,7 @@ public class GenObject
public Location place(int wx, int wy, int wz, IPlacer placer)
{
Location start = new Location(placer.getWorld(), wx, wy, wz).clone().add(sh(w), sh(h) + 1, sh(d));
Location start = new Location(placer.getWorld(), wx, wy, wz).clone().add(0, sh(h) + 1, 0);
if(mount == null)
{
@@ -279,21 +279,25 @@ public class GenObject
MB b = getSchematic().get(i);
Location f = start.clone().add(i.toBlockVector());
Material m = placer.get(f.clone().subtract(0, 1, 0)).material;
if(i.getY() == mountHeight && (m.equals(Material.WATER) || m.equals(Material.STATIONARY_WATER) || m.equals(Material.LAVA) || m.equals(Material.STATIONARY_LAVA)))
if(!Iris.settings.performance.noObjectFail)
{
for(Location j : undo.k())
{
placer.set(j, undo.get(j));
}
Material m = placer.get(f.clone().subtract(0, 1, 0)).material;
if(Iris.settings.performance.verbose)
if(i.getY() == mountHeight && (m.equals(Material.WATER) || m.equals(Material.STATIONARY_WATER) || m.equals(Material.LAVA) || m.equals(Material.STATIONARY_LAVA)))
{
L.w(C.WHITE + "Object " + C.YELLOW + getName() + C.WHITE + " failed to place in " + C.YELLOW + m.toString().toLowerCase() + C.WHITE + " at " + C.YELLOW + F.f(f.getBlockX()) + " " + F.f(f.getBlockY()) + " " + F.f(f.getBlockZ()));
}
for(Location j : undo.k())
{
placer.set(j, undo.get(j));
}
failures++;
return null;
if(Iris.settings.performance.verbose)
{
L.w(C.WHITE + "Object " + C.YELLOW + getName() + C.WHITE + " failed to place in " + C.YELLOW + m.toString().toLowerCase() + C.WHITE + " at " + C.YELLOW + F.f(f.getBlockX()) + " " + F.f(f.getBlockY()) + " " + F.f(f.getBlockZ()));
}
failures++;
return null;
}
}
try

View File

@@ -2,41 +2,34 @@ package ninja.bytecode.iris.generator.genobject;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.generator.BlockPopulator;
import mortar.logic.format.F;
import mortar.util.text.C;
import net.md_5.bungee.api.ChatColor;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.generator.placer.BukkitPlacer;
import ninja.bytecode.iris.generator.placer.NMSPlacer;
import ninja.bytecode.iris.generator.placer.AtomicParallaxPlacer;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.IPlacer;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.ParallaxCache;
import ninja.bytecode.iris.util.SMCAVector;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.collections.GSet;
import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.M;
import ninja.bytecode.shuriken.math.RNG;
public class GenObjectDecorator extends BlockPopulator
public class GenObjectDecorator
{
private GList<PlacedObject> placeHistory;
private GMap<IrisBiome, GList<GenObjectGroup>> orderCache;
private GMap<IrisBiome, GMap<GenObjectGroup, Double>> populationCache;
private IPlacer placer;
private Executor ex;
private IrisGenerator g;
private ChronoLatch cl = new ChronoLatch(250);
@@ -46,7 +39,6 @@ public class GenObjectDecorator extends BlockPopulator
placeHistory = new GList<>();
populationCache = new GMap<>();
orderCache = new GMap<>();
ex = Executors.newSingleThreadExecutor();
for(IrisBiome i : generator.getDimension().getBiomes())
{
@@ -100,25 +92,24 @@ public class GenObjectDecorator extends BlockPopulator
L.i("Population Cache is " + populationCache.size());
}
@Override
public void populate(World world, Random rnotusingyou, Chunk source)
public void decorateParallax(int cx, int cz, Random random)
{
if(g.isDisposed())
try
{
placeHistory.clear();
return;
}
if(g.isDisposed())
{
placeHistory.clear();
return;
}
ex.execute(() ->
{
Random random = new Random(((source.getX() - 32) * (source.getZ() + 54)) + world.getSeed());
ParallaxCache cache = new ParallaxCache(g);
GSet<IrisBiome> hits = new GSet<>();
for(int i = 0; i < Iris.settings.performance.decorationAccuracy; i++)
{
int x = (source.getX() << 4) + random.nextInt(16);
int z = (source.getZ() << 4) + random.nextInt(16);
IrisBiome biome = g.getBiome((int) g.getOffsetX(x), (int) g.getOffsetX(z));
int x = (cx << 4) + random.nextInt(16);
int z = (cz << 4) + random.nextInt(16);
IrisBiome biome = cache.getBiome(x, z);
if(hits.contains(biome))
{
@@ -133,20 +124,19 @@ public class GenObjectDecorator extends BlockPopulator
}
hits.add(biome);
populate(world, random, source, biome, orderCache.get(biome));
populate(cx, cz, random, biome, cache);
}
}
if(Iris.settings.performance.verbose)
{
L.flush();
}
});
catch(Throwable e)
{
e.printStackTrace();
}
}
private void populate(World world, Random random, Chunk source, IrisBiome biome, GList<GenObjectGroup> order)
private void populate(int cx, int cz, Random random, IrisBiome biome, ParallaxCache cache)
{
for(GenObjectGroup i : order)
for(GenObjectGroup i : orderCache.get(biome))
{
if(biome.getSchematicGroups().get(i.getName()) == null)
{
@@ -158,60 +148,65 @@ public class GenObjectDecorator extends BlockPopulator
{
if(M.r(Iris.settings.gen.objectDensity))
{
int x = (source.getX() << 4) + random.nextInt(16);
int z = (source.getZ() << 4) + random.nextInt(16);
Block b = world.getHighestBlockAt(x, z).getRelative(BlockFace.DOWN);
Material t = b.getType();
GenObject go = i.getSchematics().get(random.nextInt(i.getSchematics().size()));
int x = (cx << 4) + random.nextInt(16);
int z = (cz << 4) + random.nextInt(16);
if(!t.isSolid() || !biome.isSurface(t))
if(i.getWorldChance() >= 0D)
{
if(Iris.settings.performance.verbose)
{
L.w(C.WHITE + "Object " + C.YELLOW + i.getName() + "/*" + C.WHITE + " failed to place in " + C.YELLOW + t.toString().toLowerCase() + C.WHITE + " at " + C.YELLOW + F.f(b.getX()) + " " + F.f(b.getY()) + " " + F.f(b.getZ()));
}
int rngx = (int) Math.floor(x / (double) (i.getWorldRadius() == 0 ? 32 : i.getWorldRadius()));
int rngz = (int) Math.floor(z / (double) (i.getWorldRadius() == 0 ? 32 : i.getWorldRadius()));
continue;
}
if(placer == null)
{
if(Iris.settings.performance.fastDecoration)
{
placer = new NMSPlacer(world);
}
else
{
placer = new BukkitPlacer(world, false);
}
}
GenObject g = i.getSchematics().get(random.nextInt(i.getSchematics().size()));
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () ->
{
Location start = g.place(x, b.getY(), z, placer);
if(start != null)
if(new RNG(new SMCAVector(rngx, rngz).hashCode()).nextDouble() < i.getWorldChance())
{
if(Iris.settings.performance.verbose)
{
L.v(C.GRAY + "Placed " + C.DARK_GREEN + i.getName() + C.WHITE + "/" + C.DARK_GREEN + g.getName() + C.GRAY + " at " + C.DARK_GREEN + F.f(start.getBlockX()) + " " + F.f(start.getBlockY()) + " " + F.f(start.getBlockZ()));
L.w(C.WHITE + "Object " + C.YELLOW + i.getName() + "/*" + C.WHITE + " failed to place due to a world chance.");
}
if(Iris.settings.performance.debugMode)
{
placeHistory.add(new PlacedObject(start.getBlockX(), start.getBlockY(), start.getBlockZ(), i.getName() + ":" + g.getName()));
break;
}
}
if(placeHistory.size() > Iris.settings.performance.placeHistoryLimit)
int by = cache.getHeight(x, z);
MB mb = cache.get(x, by, z);
if(!Iris.settings.performance.noObjectFail)
{
if(!mb.material.isSolid() || !biome.isSurface(mb.material))
{
if(Iris.settings.performance.verbose)
{
L.w(C.WHITE + "Object " + C.YELLOW + i.getName() + "/*" + C.WHITE + " failed to place in " + C.YELLOW + mb.material.toString().toLowerCase() + C.WHITE + " at " + C.YELLOW + F.f(x) + " " + F.f(by) + " " + F.f(z));
}
return;
}
}
placer = new AtomicParallaxPlacer(g, cache);
Location start = go.place(x, by, z, placer);
if(start != null)
{
if(Iris.settings.performance.verbose)
{
L.v(C.GRAY + "Placed " + C.DARK_GREEN + i.getName() + C.WHITE + "/" + C.DARK_GREEN + go.getName() + C.GRAY + " at " + C.DARK_GREEN + F.f(start.getBlockX()) + " " + F.f(start.getBlockY()) + " " + F.f(start.getBlockZ()));
}
if(Iris.settings.performance.debugMode)
{
placeHistory.add(new PlacedObject(start.getBlockX(), start.getBlockY(), start.getBlockZ(), i.getName() + ":" + go.getName()));
if(placeHistory.size() > Iris.settings.performance.placeHistoryLimit)
{
while(placeHistory.size() > Iris.settings.performance.placeHistoryLimit)
{
while(placeHistory.size() > Iris.settings.performance.placeHistoryLimit)
{
placeHistory.remove(0);
}
placeHistory.remove(0);
}
}
}
});
}
}
}
}
@@ -249,6 +244,11 @@ public class GenObjectDecorator extends BlockPopulator
return placeHistory;
}
public void dispose()
{
}
public PlacedObject randomObject(String string)
{
GList<PlacedObject> v = new GList<>();

View File

@@ -21,6 +21,8 @@ public class GenObjectGroup
private GList<String> flags;
private String name;
private int priority;
private double worldChance;
private int worldRad;
public GenObjectGroup(String name)
{
@@ -28,6 +30,8 @@ public class GenObjectGroup
this.flags = new GList<>();
this.name = name;
priority = Integer.MIN_VALUE;
worldChance = Integer.MIN_VALUE;
worldRad = 32;
}
public void read(DataInputStream din) throws IOException
@@ -295,4 +299,36 @@ public class GenObjectGroup
return true;
}
public double getWorldChance()
{
if(worldChance == Integer.MIN_VALUE)
{
for(String i : flags)
{
if(i.startsWith("world chance "))
{
worldChance = Double.valueOf(i.split("\\Q \\E")[2]);
}
}
}
return worldChance;
}
public double getWorldRadius()
{
if(worldRad == Integer.MIN_VALUE)
{
for(String i : flags)
{
if(i.startsWith("world radius "))
{
worldRad = Integer.valueOf(i.split("\\Q \\E")[2]);
}
}
}
return worldRad;
}
}

View File

@@ -8,6 +8,7 @@ import org.bukkit.World;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.iris.util.IrisInterpolation;
import ninja.bytecode.iris.util.MB;
@@ -68,7 +69,7 @@ public class GenLayerCarving extends GenLayer
return carver.noise(x + fx, y - fy, z + fz);
}
public void genCarves(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome)
public void genCarves(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome, AtomicChunkData data)
{
if(!Iris.settings.gen.genCarving)
{
@@ -103,7 +104,7 @@ public class GenLayerCarving extends GenLayer
if(carve(wxx, i, wzx) < IrisInterpolation.lerpBezier(0, ch, hill))
{
carved++;
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
@@ -113,7 +114,7 @@ public class GenLayerCarving extends GenLayer
for(int i = Iris.settings.gen.maxCarvingHeight; i > Iris.settings.gen.minCarvingHeight; i--)
{
Material m = g.getType(x, i, z);
Material m = data.getType(x, i, z);
if(!m.equals(Material.AIR))
{
hit++;
@@ -126,7 +127,7 @@ public class GenLayerCarving extends GenLayer
{
for(int j = i; j > i - 5; j--)
{
if(g.getType(x, j, z).equals(Material.AIR))
if(data.getType(x, j, z).equals(Material.AIR))
{
fail = true;
break;
@@ -137,12 +138,12 @@ public class GenLayerCarving extends GenLayer
if(!fail)
{
MB mb = biome.getSurface(wxx, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
else
{
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
@@ -151,12 +152,12 @@ public class GenLayerCarving extends GenLayer
if(!fail)
{
MB mb = biome.getSubSurface(wxx, i, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
else
{
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
}

View File

@@ -8,6 +8,7 @@ import org.bukkit.World;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.iris.util.IrisInterpolation;
import ninja.bytecode.iris.util.MB;
@@ -68,7 +69,7 @@ public class GenLayerCaverns extends GenLayer
return carver.noise(x + fx, y - fy, z + fz);
}
public void genCaverns(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome)
public void genCaverns(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome, AtomicChunkData data)
{
if(!Iris.settings.gen.genCaverns)
{
@@ -103,7 +104,7 @@ public class GenLayerCaverns extends GenLayer
if(cavern(wxx, i, wzx) < IrisInterpolation.lerpBezier(0, ch, hill))
{
carved++;
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
@@ -113,7 +114,7 @@ public class GenLayerCaverns extends GenLayer
for(int i = Iris.settings.gen.maxCavernHeight; i > Iris.settings.gen.minCavernHeight; i--)
{
Material m = g.getType(x, i, z);
Material m = data.getType(x, i, z);
if(!m.equals(Material.AIR))
{
hit++;
@@ -126,7 +127,7 @@ public class GenLayerCaverns extends GenLayer
{
for(int j = i; j > i - 5; j--)
{
if(g.getType(x, j, z).equals(Material.AIR))
if(data.getType(x, j, z).equals(Material.AIR))
{
fail = true;
break;
@@ -137,12 +138,12 @@ public class GenLayerCaverns extends GenLayer
if(!fail)
{
MB mb = biome.getSurface(wxx, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
else
{
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
@@ -151,12 +152,12 @@ public class GenLayerCaverns extends GenLayer
if(!fail)
{
MB mb = biome.getSubSurface(wxx, i, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
data.setBlock(x, i, z, mb.material, mb.data);
}
else
{
g.setBlock(x, i, z, Material.AIR);
data.setBlock(x, i, z, Material.AIR);
}
}
}

View File

@@ -7,6 +7,7 @@ import org.bukkit.World;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.iris.util.PolygonGenerator;
import ninja.bytecode.shuriken.math.CNG;
@@ -18,7 +19,7 @@ public class GenLayerCaves extends GenLayer
private CNG caveGirth;
private CNG caveClamp;
private PolygonGenerator caveVeins;
public GenLayerCaves(IrisGenerator iris, World world, Random random, RNG rng)
{
super(iris, world, random, rng);
@@ -27,47 +28,47 @@ public class GenLayerCaves extends GenLayer
caveClamp = new CNG(rng.nextParallelRNG(-10000), 1D, 3).scale(0.1422);
caveVeins = new PolygonGenerator(rng.nextParallelRNG(-99999), 4, 0.002 * Iris.settings.gen.caveScale, 1, (g) -> g.fractureWith(new CNG(rng.nextParallelRNG(-5555), 1D, 4).scale(0.02), 70));
}
public void genCaves(double wxx, double wzx, int x, int z, int s, IrisGenerator g)
public void genCaves(double wxx, double wzx, int x, int z, int s, IrisGenerator g, AtomicChunkData data)
{
if(!Iris.settings.gen.genCaves)
{
return;
}
for(double itr = 0; itr < 0.1 * Iris.settings.gen.caveDensity; itr += 0.1)
{
double thickness = 0.25 + itr + (0.5 * caveClamp.noise(wxx, wzx));
double size = 3.88D * thickness;
double size = (3.88D * thickness);
double variance = 8.34D * thickness;
double w = size + (variance * caveGirth.noise(wxx, wzx));
double h = size + (variance * caveGirth.noise(wzx, wxx));
double width = 0;
double height = h;
double elevation = (caveHeight.noise(wxx + (19949D * itr), wzx - (19949D * itr)) * (350)) - 80;
while(width <= w && height > 1D)
{
width+=2;
height-=2;
width += 2;
height -= 2;
if(caveVeins.hasBorder(3, width, wxx - (19949D * itr), wzx + (19949D * itr)))
{
double r = (((caveGirth.noise(wxx, wzx, width)) * variance) + height) / 2D;
int f = 3;
for(int i = (int) -r; i < r && f >= 0; i++)
for(int i = (int) -r; i < r; i++)
{
if(i + height > s)
{
break;
}
Material t = g.getType(x, (int) (elevation + i) - 55, z);
Material t = data.getType(x, (int) (elevation + i) - 55, z);
if(t.equals(Material.BEDROCK) || t.equals(Material.WATER) || t.equals(Material.STATIONARY_WATER))
{
continue;
}
g.setBlock(x, (int) (elevation + i) - 55, z, Material.AIR);
data.setBlock(x, (int) (elevation + i) - 55, z, Material.AIR);
}
}
}

View File

@@ -0,0 +1,41 @@
package ninja.bytecode.iris.generator.placer;
import org.bukkit.Location;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.IrisWorldData;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.ParallaxCache;
import ninja.bytecode.iris.util.Placer;
public class AtomicParallaxPlacer extends Placer
{
private IrisWorldData data;
private ParallaxCache cache;
public AtomicParallaxPlacer(IrisGenerator g, ParallaxCache cache)
{
super(g.getWorld());
this.data = g.getWorldData();
this.cache = cache;
}
@Override
public MB get(Location l)
{
return cache.get(l.getBlockX(), l.getBlockY(), l.getBlockZ());
}
@SuppressWarnings("deprecation")
@Override
public void set(Location l, MB mb)
{
data.setBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ(), mb.material.getId(), mb.data);
}
@Override
public int getHighestY(Location l)
{
return cache.getHeight(l.getBlockX(), l.getBlockZ());
}
}

View File

@@ -1,45 +0,0 @@
package ninja.bytecode.iris.generator.placer;
import org.bukkit.Location;
import org.bukkit.World;
import ninja.bytecode.iris.util.AtomicChunkData;
import ninja.bytecode.iris.util.ChunkPlan;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.Placer;
public class AtomicPlacer extends Placer
{
private AtomicChunkData data;
private ChunkPlan plan;
public AtomicPlacer(World world)
{
super(world);
}
public void bind(AtomicChunkData data, ChunkPlan plan)
{
this.data = data;
this.plan = plan;
}
@Override
public MB get(Location l)
{
return MB.of(data.getType(l.getBlockX(), l.getBlockY(), l.getBlockZ()), data.getData(l.getBlockX(), l.getBlockY(), l.getBlockZ()));
}
@SuppressWarnings("deprecation")
@Override
public void set(Location l, MB mb)
{
data.setBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ(), mb.material.getId(), mb.data);
}
@Override
public int getHighestY(Location l)
{
return plan.getRealHeight(l.getBlockX(), l.getBlockZ());
}
}

View File

@@ -13,7 +13,10 @@ import org.bukkit.World.Environment;
import org.bukkit.block.Biome;
import net.md_5.bungee.api.ChatColor;
import ninja.bytecode.iris.generator.genobject.GenObject;
import ninja.bytecode.iris.generator.genobject.GenObjectGroup;
import ninja.bytecode.iris.util.SChunkVector;
import ninja.bytecode.iris.util.SBlockVector;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.io.CustomOutputStream;
@@ -29,6 +32,8 @@ public class CompiledDimension
private GList<IrisBiome> biomes;
private GMap<String, IrisBiome> biomeCache;
private GMap<String, GenObjectGroup> objects;
private SBlockVector maxSize;
private SChunkVector maxChunkSize;
public CompiledDimension(IrisDimension dimension)
{
@@ -36,6 +41,8 @@ public class CompiledDimension
biomes = new GList<>();
biomeCache = new GMap<>();
objects = new GMap<>();
maxSize = new SBlockVector(0, 0, 0);
maxChunkSize = new SChunkVector(0, 0);
}
public void read(InputStream in) throws IOException
@@ -182,4 +189,56 @@ public class CompiledDimension
objects.clear();
}
public void computeObjectSize()
{
int maxWidth = 0;
int maxHeight = 0;
int maxDepth = 0;
for(GenObjectGroup i : objects.values())
{
for(GenObject j : i.getSchematics().copy())
{
maxWidth = j.getW() > maxWidth ? j.getW() : maxWidth;
maxHeight = j.getH() > maxHeight ? j.getH() : maxHeight;
maxDepth = j.getD() > maxDepth ? j.getD() : maxDepth;
}
}
maxSize = new SBlockVector(maxWidth, maxHeight, maxDepth);
maxChunkSize = new SChunkVector(Math.ceil((double) (maxWidth) / 16D), Math.ceil((double) (maxDepth) / 16D));
L.i("Max Object Bound is " + maxWidth + ", " + maxHeight + ", " + maxDepth);
L.i("Max Object Region is " + maxChunkSize.getX() + " by " + maxChunkSize.getZ() + " Chunks");
}
public static IrisBiome getTheVoid()
{
return theVoid;
}
public IrisDimension getDimension()
{
return dimension;
}
public GMap<String, IrisBiome> getBiomeCache()
{
return biomeCache;
}
public GMap<String, GenObjectGroup> getObjects()
{
return objects;
}
public SBlockVector getMaxSize()
{
return maxSize;
}
public SChunkVector getMaxChunkSize()
{
return maxChunkSize;
}
}

View File

@@ -1,5 +1,10 @@
package ninja.bytecode.iris.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.concurrent.locks.ReentrantLock;
@@ -10,6 +15,8 @@ import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.ChunkGenerator.ChunkData;
import org.bukkit.material.MaterialData;
import mortar.compute.math.M;
public final class AtomicChunkData implements ChunkGenerator.ChunkData
{
private static final Field t;
@@ -35,11 +42,125 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
private char[] s15;
private char[][] m;
private World w;
private long lastUse;
private int bits;
public AtomicChunkData(World world)
{
this.maxHeight = world.getMaxHeight();
this.w = world;
bits = 0;
lastUse = M.ms();
}
public long getTimeSinceLastUse()
{
return M.ms() - lastUse;
}
public void read(InputStream in) throws IOException
{
read(in, true);
}
public void read(InputStream in, boolean ignoreAir) throws IOException
{
DataInputStream din = new DataInputStream(in);
int bits = din.readInt();
for(int i = 0; i < 16; i++)
{
int bit = getBit(i);
if((bits & bit) == bit)
{
char[] section = getChunkSection(i << 4, true);
for(int j = 0; j < section.length; j++)
{
char c = din.readChar();
if(c == 0 && ignoreAir)
{
continue;
}
section[j] = c;
}
}
}
din.close();
}
public void write(OutputStream out) throws IOException
{
DataOutputStream dos = new DataOutputStream(out);
dos.writeInt(getDataBits());
for(int i = 0; i < 16; i++)
{
if(hasDataBit(i))
{
char[] section = getChunkSection(i << 4, false);
for(int j = 0; j < section.length; j++)
{
dos.writeChar(section[j]);
}
}
}
dos.close();
}
public boolean hasDataBit(int section)
{
int b = getBit(section);
return (bits & b) == b;
}
public void clearDataBits()
{
bits = 0;
}
public void addDataBit(int section)
{
bits |= getBit(section);
}
public void removeDataBit(int section)
{
bits ^= getBit(section);
}
public int getDataBits()
{
return bits;
}
public int getBit(int index)
{
return (int) (index < 0 ? -1 : Math.pow(2, index));
}
public int computeDataBits()
{
int bits = 0;
for(int i = 0; i < 16; i++)
{
try
{
bits |= sections[i].get(this) != null ? getBit(i) : 0;
}
catch(Throwable e)
{
}
}
return bits;
}
@Override
@@ -80,6 +201,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
@Override
public Material getType(int x, int y, int z)
{
lastUse = M.ms();
return Material.getMaterial(getTypeId(x, y, z));
}
@@ -87,18 +209,27 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
@Override
public MaterialData getTypeAndData(int x, int y, int z)
{
lastUse = M.ms();
return getType(x, y, z).getNewData(getData(x, y, z));
}
@SuppressWarnings("deprecation")
public void setBlock(int x, int y, int z, Material blockId, byte data)
{
setBlock(x, y, z, blockId.getId(), data);
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, int blockId)
{
lastUse = M.ms();
setRegion(xMin, yMin, zMin, xMax, yMax, zMax, blockId, (byte) 0);
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, int blockId, int data)
{
lastUse = M.ms();
throw new UnsupportedOperationException("AtomicChunkData does not support setting regions");
}
@@ -114,6 +245,31 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
setBlock(x, y, z, (char) (blockId << 4 | data));
}
@SuppressWarnings("deprecation")
public MB getMB(int x, int y, int z)
{
if(x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf))
{
lastUse = M.ms();
return MB.of(Material.AIR);
}
char[] section = getChunkSection(y, false);
if(section == null)
{
lastUse = M.ms();
return MB.of(Material.AIR);
}
else
{
lastUse = M.ms();
char xf = section[(y & 0xf) << 8 | z << 4 | x];
return MB.of(Material.getMaterial(xf >> 4), xf & 0xf);
}
}
@Override
public int getTypeId(int x, int y, int z)
{
@@ -131,6 +287,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
else
{
lastUse = M.ms();
return section[(y & 0xf) << 8 | z << 4 | x] >> 4;
}
}
@@ -140,6 +297,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
{
if(x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf))
{
lastUse = M.ms();
return (byte) 0;
}
@@ -147,11 +305,13 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
if(section == null)
{
lastUse = M.ms();
return (byte) 0;
}
else
{
lastUse = M.ms();
return (byte) (section[(y & 0xf) << 8 | z << 4 | x] & 0xf);
}
}
@@ -163,6 +323,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
return;
}
lastUse = M.ms();
ReentrantLock l = locks[y >> 4];
l.lock();
getChunkSection(y, true)[(y & 0xf) << 8 | z << 4 | x] = type;
@@ -181,6 +342,7 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
{
sf.set(this, new char[h]);
section = (char[]) sf.get(this);
addDataBit(s);
}
return section;
@@ -263,4 +425,26 @@ public final class AtomicChunkData implements ChunkGenerator.ChunkData
t = x;
}
public void inject(AtomicChunkData data)
{
for(int i = 0; i < 16; i++)
{
if(hasDataBit(i))
{
char[] fromSection = getChunkSection(i << 4, false);
char[] toSection = data.getChunkSection(i << 4, true);
for(int j = 0; j < fromSection.length; j++)
{
char x = fromSection[j];
if(x != 0)
{
toSection[j] = x;
}
}
}
}
}
}

View File

@@ -0,0 +1,80 @@
package ninja.bytecode.iris.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.bukkit.World;
import org.jnbt.ByteArrayTag;
import org.jnbt.CompoundTag;
import org.jnbt.NBTInputStream;
import org.jnbt.NBTOutputStream;
import org.jnbt.Tag;
import ninja.bytecode.shuriken.collections.GMap;
public class AtomicMCAData
{
private final World world;
private GMap<String, Tag> tag;
public AtomicMCAData(World world)
{
this.world = world;
tag = new GMap<>();
}
public void read(InputStream in) throws IOException
{
NBTInputStream nin = new NBTInputStream(in);
tag = new GMap<>();
tag.putAll(((CompoundTag) nin.readTag()).getValue());
nin.close();
}
public void write(OutputStream out) throws IOException
{
NBTOutputStream nos = new NBTOutputStream(out);
nos.writeTag(new CompoundTag("imca", tag));
nos.close();
}
public boolean contains(int rx, int rz)
{
return tag.containsKey(rx + "." + rz);
}
public void delete(int rx, int rz)
{
tag.remove(rx + "." + rz);
}
public void set(int rx, int rz, AtomicChunkData data) throws IOException
{
ByteArrayOutputStream boas = new ByteArrayOutputStream();
data.write(boas);
tag.put(rx + "." + rz, new ByteArrayTag(rx + "." + rz, boas.toByteArray()));
}
public AtomicChunkData get(int rx, int rz) throws IOException
{
if(!contains(rx, rz))
{
return null;
}
AtomicChunkData data = new AtomicChunkData(world);
ByteArrayTag btag = (ByteArrayTag) tag.get(rx + "." + rz);
ByteArrayInputStream in = new ByteArrayInputStream(btag.getValue());
data.read(in);
return data;
}
public World getWorld()
{
return world;
}
}

View File

@@ -0,0 +1,157 @@
package ninja.bytecode.iris.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.bukkit.World;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
public class AtomicWorldData
{
private World world;
private GMap<SMCAVector, AtomicMCAData> loadedSections;
public AtomicWorldData(World world)
{
this.world = world;
loadedSections = new GMap<>();
getSubregionFolder().mkdirs();
}
public GList<SMCAVector> getLoadedRegions()
{
return loadedSections.k();
}
public AtomicMCAData getSubregion(int x, int z) throws IOException
{
if(!isSectionLoaded(x, z))
{
loadedSections.put(new SMCAVector(x, z), loadSection(x, z));
}
AtomicMCAData f = loadedSections.get(new SMCAVector(x, z));
return f;
}
public void saveAll() throws IOException
{
for(SMCAVector i : loadedSections.keySet())
{
saveSection(i);
}
}
public void unloadAll(boolean save) throws IOException
{
for(SMCAVector i : loadedSections.keySet())
{
unloadSection(i, save);
}
}
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 SMCAVector(x, z));
}
public boolean isSectionLoaded(SMCAVector s)
{
return loadedSections.containsKey(s);
}
public boolean unloadSection(int x, int z, boolean save) throws IOException
{
return unloadSection(new SMCAVector(x, z), save);
}
public boolean unloadSection(SMCAVector s, boolean save) throws IOException
{
if(!isSectionLoaded(s))
{
return false;
}
if(save)
{
saveSection(s);
}
loadedSections.remove(s);
return true;
}
public boolean saveSection(int x, int z) throws IOException
{
return saveSection(new SMCAVector(x, z));
}
public boolean saveSection(SMCAVector s) throws IOException
{
if(!isSectionLoaded(s.getX(), s.getZ()))
{
return false;
}
AtomicMCAData data = loadedSections.get(s);
FileOutputStream fos = new FileOutputStream(getSubregionFile(s.getX(), s.getZ()));
data.write(fos);
fos.close();
return true;
}
public AtomicMCAData loadSection(int x, int z) throws IOException
{
if(isSectionLoaded(x, z))
{
return loadedSections.get(new SMCAVector(x, z));
}
File file = getSubregionFile(x, z);
if(!file.exists())
{
return createSection(x, z);
}
FileInputStream fin = new FileInputStream(file);
AtomicMCAData data = new AtomicMCAData(world);
data.read(fin);
fin.close();
return data;
}
public AtomicMCAData createSection(int x, int z)
{
if(isSectionLoaded(x, z))
{
return loadedSections.get(new SMCAVector(x, z));
}
AtomicMCAData data = new AtomicMCAData(world);
loadedSections.put(new SMCAVector(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");
}
}

View File

@@ -5,10 +5,10 @@ import ninja.bytecode.shuriken.collections.GMap;
public class ChunkPlan
{
private final GMap<ChunkedVector, Integer> realHeightCache;
private final GMap<ChunkedVector, Integer> realWaterHeightCache;
private final GMap<ChunkedVector, Double> heightCache;
private final GMap<ChunkedVector, IrisBiome> biomeCache;
private final GMap<SChunkVector, Integer> realHeightCache;
private final GMap<SChunkVector, Integer> realWaterHeightCache;
private final GMap<SChunkVector, Double> heightCache;
private final GMap<SChunkVector, IrisBiome> biomeCache;
public ChunkPlan()
{
@@ -20,17 +20,17 @@ public class ChunkPlan
public IrisBiome getBiome(int x, int z)
{
return biomeCache.get(new ChunkedVector(x, z));
return biomeCache.get(new SChunkVector(x, z));
}
public void setBiome(int x, int z, IrisBiome cng)
{
biomeCache.put(new ChunkedVector(x, z), cng);
biomeCache.put(new SChunkVector(x, z), cng);
}
public double getHeight(int x, int z)
{
ChunkedVector c = new ChunkedVector(x, z);
SChunkVector c = new SChunkVector(x, z);
if(hasHeight(c))
{
return heightCache.get(c);
@@ -41,7 +41,7 @@ public class ChunkPlan
public int getRealHeight(int x, int z)
{
ChunkedVector c = new ChunkedVector(x, z);
SChunkVector c = new SChunkVector(x, z);
if(realHeightCache.containsKey(c))
{
return realHeightCache.get(c);
@@ -52,7 +52,7 @@ public class ChunkPlan
public int getRealWaterHeight(int x, int z)
{
ChunkedVector c = new ChunkedVector(x, z);
SChunkVector c = new SChunkVector(x, z);
if(realWaterHeightCache.containsKey(c))
{
@@ -62,43 +62,43 @@ public class ChunkPlan
return 0;
}
public boolean hasHeight(ChunkedVector c)
public boolean hasHeight(SChunkVector c)
{
return heightCache.containsKey(c);
}
public boolean hasHeight(int x, int z)
{
return hasHeight(new ChunkedVector(x, z));
return hasHeight(new SChunkVector(x, z));
}
public void setHeight(ChunkedVector c, double h)
public void setHeight(SChunkVector c, double h)
{
heightCache.put(c, h);
}
public void setRealHeight(ChunkedVector c, int h)
public void setRealHeight(SChunkVector c, int h)
{
realHeightCache.put(c, h);
}
public void setRealHeight(int x, int z, int h)
{
setRealHeight(new ChunkedVector(x, z), h);
setRealHeight(new SChunkVector(x, z), h);
}
public void setRealWaterHeight(ChunkedVector c, int h)
public void setRealWaterHeight(SChunkVector c, int h)
{
realWaterHeightCache.put(c, h);
}
public void setRealWaterHeight(int x, int z, int h)
{
setRealWaterHeight(new ChunkedVector(x, z), h);
setRealWaterHeight(new SChunkVector(x, z), h);
}
public void setHeight(int x, int z, double h)
{
setHeight(new ChunkedVector(x, z), h);
setHeight(new SChunkVector(x, z), h);
}
}

View File

@@ -10,7 +10,6 @@ import org.bukkit.util.Vector;
import mortar.api.nms.NMP;
import mortar.api.world.MaterialBlock;
import mortar.compute.math.M;
import mortar.util.text.C;
public class GlowingBlock
{

View File

@@ -0,0 +1,253 @@
package ninja.bytecode.iris.util;
import java.io.IOException;
import org.bukkit.Bukkit;
import org.bukkit.World;
import mortar.logic.format.F;
import mortar.util.text.C;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.logging.L;
public class IrisWorldData
{
private final World world;
private final AtomicWorldData data;
private final GMap<SMCAVector, AtomicChunkData> loadedChunks;
public IrisWorldData(World world)
{
this.world = world;
data = new AtomicWorldData(world);
loadedChunks = new GMap<>();
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::softUnloadWorld, 200, 20);
}
private void softUnloadWorld()
{
L.i("Load: " + F.f(getLoadedChunks().size()) + " Chunks in " + F.f(getLoadedRegions().size()) + " Regions");
for(SMCAVector i : getLoadedChunks())
{
try
{
AtomicChunkData d = getChunk(i.getX(), i.getZ());
if(d.getTimeSinceLastUse() > 10000)
{
unloadChunk(i.getX(), i.getZ(), true);
}
}
catch(Throwable e)
{
e.printStackTrace();
}
}
for(SMCAVector i : getLoadedRegions())
{
softUnloadRegion(i.getX(), i.getZ());
}
}
private boolean softUnloadRegion(int rx, int rz)
{
for(SMCAVector i : loadedChunks.keySet())
{
if(i.getX() >> 5 == rx && i.getZ() >> 5 == rz)
{
return false;
}
}
try
{
data.unloadSection(rx, rz, true);
return true;
}
catch(IOException e)
{
e.printStackTrace();
L.f(C.RED + "Failed to save Iris Subregion " + C.YELLOW + rx + " " + rz);
}
return false;
}
public boolean deleteChunk(int x, int z)
{
if(isChunkLoaded(x, z))
{
unloadChunk(x, z, false);
}
try
{
AtomicMCAData region = data.getSubregion(x >> 5, z >> 5);
region.delete(x & 31, z & 31);
return true;
}
catch(IOException e)
{
L.f(C.RED + "Failed delete chunk " + C.YELLOW + x + " " + z + C.RED.toString() + " -> Failed to get Region " + C.YELLOW + (x >> 5) + " " + (z >> 5));
e.printStackTrace();
}
return false;
}
public boolean unloadChunk(int x, int z, boolean save)
{
if(!isChunkLoaded(x, z))
{
return false;
}
if(save)
{
saveChunk(x, z);
}
loadedChunks.remove(new SMCAVector(x, z));
return true;
}
public boolean saveChunk(int x, int z)
{
if(!isChunkLoaded(x, z))
{
return false;
}
try
{
AtomicMCAData region = data.getSubregion(x >> 5, z >> 5);
region.set(x & 31, z & 31, getChunk(x, z));
return true;
}
catch(IOException e)
{
L.f(C.RED + "Failed save chunk " + C.YELLOW + x + " " + z + C.RED.toString() + " -> Failed to get Region " + C.YELLOW + (x >> 5) + " " + (z >> 5));
e.printStackTrace();
}
return false;
}
public AtomicChunkData getOnly(int x, int z)
{
if(!isChunkLoaded(x, z))
{
return null;
}
return getChunk(x, z);
}
public AtomicChunkData getChunk(int x, int z)
{
if(!isChunkLoaded(x, z))
{
try
{
AtomicMCAData region = data.getSubregion(x >> 5, z >> 5);
if(region.contains(x & 31, z & 31))
{
AtomicChunkData chunk = region.get(x & 31, z & 31);
loadedChunks.put(new SMCAVector(x, z), chunk);
}
else
{
AtomicChunkData data = new AtomicChunkData(world);
loadedChunks.put(new SMCAVector(x, z), data);
}
}
catch(IOException e)
{
L.f(C.RED + "Failed load chunk " + C.YELLOW + x + " " + z + C.RED.toString() + " -> Failed to get Region " + C.YELLOW + (x >> 5) + " " + (z >> 5));
e.printStackTrace();
}
}
return loadedChunks.get(new SMCAVector(x, z));
}
public boolean isChunkLoaded(int x, int z)
{
return loadedChunks.containsKey(new SMCAVector(x, z));
}
public void inject(int x, int z, AtomicChunkData data)
{
getChunk(x, z).inject(data);
}
public boolean exists(int x, int z)
{
try
{
return isChunkLoaded(x, z) || data.getSubregion(x >> 5, z >> 5).contains(x & 31, z & 31);
}
catch(IOException e)
{
L.f(C.RED + "Failed check chunk " + C.YELLOW + x + " " + z + C.RED.toString() + " -> Failed to get Region " + C.YELLOW + (x >> 5) + " " + (z >> 5));
e.printStackTrace();
}
return false;
}
public GList<SMCAVector> getLoadedChunks()
{
return loadedChunks.k();
}
public GList<SMCAVector> getLoadedRegions()
{
return data.getLoadedRegions();
}
public void saveAll()
{
for(SMCAVector i : loadedChunks.k())
{
saveChunk(i.getX(), i.getZ());
}
try
{
data.saveAll();
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void setBlock(int x, int y, int z, int id, byte data)
{
getChunk(x >> 4, z >> 4).setBlock(x & 15, y, z & 15, id, data);
}
public void dispose()
{
for(SMCAVector i : getLoadedChunks())
{
unloadChunk(i.getX(), i.getZ(), true);
}
softUnloadWorld();
}
}

View File

@@ -0,0 +1,44 @@
package ninja.bytecode.iris.util;
import ninja.bytecode.iris.pack.IrisBiome;
public class ParallaxAnchor
{
private final int height;
private final int water;
private final IrisBiome biome;
private final AtomicChunkData data;
public ParallaxAnchor(int height, int water, IrisBiome biome, AtomicChunkData data)
{
this.height = height;
this.water = water;
this.biome = biome;
this.data = data;
}
public AtomicChunkData getData()
{
return data;
}
public int getWater()
{
return water;
}
public int getHeight()
{
return height;
}
public int getWaterHeight()
{
return water;
}
public IrisBiome getBiome()
{
return biome;
}
}

View File

@@ -0,0 +1,98 @@
package ninja.bytecode.iris.util;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.collections.GSet;
public class ParallaxCache
{
private GMap<SMCAVector, ChunkPlan> cachePlan;
private GMap<SMCAVector, AtomicChunkData> cacheData;
private GSet<SMCAVector> contains;
private IrisGenerator gen;
public ParallaxCache(IrisGenerator gen)
{
this.gen = gen;
cacheData = new GMap<>();
cachePlan = new GMap<>();
contains = new GSet<>();
}
public MB get(int x, int y, int z)
{
SMCAVector s = new SMCAVector(x, z);
SMCAVector c = new SMCAVector(x >> 4, z >> 4);
if(contains.contains(s) && cacheData.containsKey(c) && cachePlan.containsKey(c) )
{
return cacheData.get(c).getMB(x & 15, y, z & 15);
}
createData(x, z, s, c);
return cacheData.get(c).getMB(x & 15, y, z & 15);
}
public IrisBiome getBiome(int x, int z)
{
SMCAVector s = new SMCAVector(x, z);
SMCAVector c = new SMCAVector(x >> 4, z >> 4);
if(contains.contains(s) && cacheData.containsKey(c) && cachePlan.containsKey(c) )
{
return cachePlan.get(c).getBiome(x & 15, z & 15);
}
createData(x, z, s, c);
return cachePlan.get(c).getBiome(x & 15, z & 15);
}
public int getWaterHeight(int x, int z)
{
SMCAVector s = new SMCAVector(x, z);
SMCAVector c = new SMCAVector(x >> 4, z >> 4);
if(contains.contains(s) && cacheData.containsKey(c) && cachePlan.containsKey(c) )
{
return cachePlan.get(c).getRealWaterHeight(x & 15, z & 15);
}
createData(x, z, s, c);
return cachePlan.get(c).getRealWaterHeight(x & 15, z & 15);
}
public int getHeight(int x, int z)
{
SMCAVector s = new SMCAVector(x, z);
SMCAVector c = new SMCAVector(x >> 4, z >> 4);
if(contains.contains(s) && cacheData.containsKey(c) && cachePlan.containsKey(c) )
{
return cachePlan.get(c).getRealHeight(x & 15, z & 15);
}
createData(x, z, s, c);
return cachePlan.get(c).getRealHeight(x & 15, z & 15);
}
private void createData(int x, int z, SMCAVector s, SMCAVector c)
{
if(!cacheData.containsKey(c))
{
cacheData.put(c, new AtomicChunkData(gen.getWorld()));
}
if(!cachePlan.containsKey(c))
{
cachePlan.put(c, new ChunkPlan());
}
gen.computeAnchor(x, z, cachePlan.get(c), cacheData.get(c));
contains.add(s);
}
}

View File

@@ -0,0 +1,190 @@
package ninja.bytecode.iris.util;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import mortar.api.nms.NMP;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.controller.TimingsController;
import ninja.bytecode.shuriken.bench.PrecisionStopwatch;
import ninja.bytecode.shuriken.collections.GSet;
import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.execution.TaskExecutor.TaskGroup;
import ninja.bytecode.shuriken.format.F;
import ninja.bytecode.shuriken.math.RNG;
public abstract class ParallaxWorldGenerator extends ParallelChunkGenerator implements Listener
{
private World world;
private IrisWorldData data;
private RNG rMaster;
private AtomicChunkData buffer;
private GSet<Chunk> fix;
private ChronoLatch cl;
@Override
public final void init(World world, Random random)
{
this.world = world;
cl = new ChronoLatch(3000);
fix = new GSet<>();
buffer = new AtomicChunkData(world);
this.data = new IrisWorldData(world);
this.rMaster = new RNG(world.getSeed() + 1);
onInit(world, rMaster.nextParallelRNG(1));
Bukkit.getPluginManager().registerEvents(this, Iris.instance);
}
@EventHandler
public void on(ChunkLoadEvent e)
{
if(e.getWorld().equals(world))
{
NMP.host.relight(e.getChunk());
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> fix.add(e.getChunk()), 20);
if(cl.flip())
{
for(Chunk i : fix)
{
for(Player f : e.getWorld().getPlayers())
{
NMP.CHUNK.refreshIgnorePosition(f, i);
}
}
fix.clear();
}
}
}
@EventHandler
public void on(WorldUnloadEvent e)
{
if(e.getWorld().equals(world))
{
getWorldData().dispose();
onUnload();
}
}
@EventHandler
public void on(WorldSaveEvent e)
{
if(e.getWorld().equals(world))
{
getWorldData().saveAll();
}
}
public ParallaxAnchor computeAnchor(int wx, int wz, ChunkPlan heightBuffer, AtomicChunkData data)
{
onGenColumn(wx, wz, wx & 15, wz & 15, heightBuffer, data);
return new ParallaxAnchor(heightBuffer.getRealHeight(wx & 15, wz & 15), heightBuffer.getRealWaterHeight(wx & 15, wz & 15), heightBuffer.getBiome(wx & 15, wz & 15), data);
}
public ParallaxAnchor computeAnchor(int wx, int wz)
{
ChunkPlan heightBuffer = new ChunkPlan();
onGenColumn(wx, wz, wx & 15, wz & 15, heightBuffer, buffer);
return new ParallaxAnchor(heightBuffer.getRealHeight(wx & 15, wz & 15), heightBuffer.getRealWaterHeight(wx & 15, wz & 15), heightBuffer.getBiome(wx & 15, wz & 15), buffer);
}
@Override
public final ChunkPlan initChunk(World world, int x, int z, Random random)
{
PrecisionStopwatch ps = PrecisionStopwatch.start();
TaskGroup g = startWork();
int gg = 0;
int gx = 0;
for(int ii = -(getParallaxSize().getX() / 2) - 1; ii < (getParallaxSize().getX() / 2) + 1; ii++)
{
int i = ii;
for(int jj = -(getParallaxSize().getZ() / 2) - 1; jj < (getParallaxSize().getZ() / 2) + 1; jj++)
{
gx++;
int j = jj;
int cx = x + i;
int cz = z + j;
if(!getWorldData().exists(cx, cz))
{
g.queue(() ->
{
onGenParallax(cx, cz, getRMaster(cx, cz, -59328));
getWorldData().getChunk(cx, cz);
});
gg++;
}
}
}
double a = ps.getMilliseconds();
double b = g.execute().timeElapsed;
System.out.println("MS: " + F.duration(Iris.getController(TimingsController.class).getResult("terrain"), 2) + " \tQMS: " + F.duration(a, 2) + " " + " \tEMS: " + F.duration(b, 2) + "\tSCG: " + gg + " / " + gx + " (" + F.pc(((double) gg / (double) gx)) + ") " + " \tTC: " + F.f(getWorldData().getLoadedChunks().size()) + " \tTR: " + getWorldData().getLoadedRegions().size());
return onInitChunk(world, x, z, random);
}
@Override
public final void postChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan)
{
getWorldData().inject(x, z, data);
onPostChunk(world, x, z, random, data, plan);
}
@Override
public final Biome genColumn(int wx, int wz, int x, int z, ChunkPlan plan, AtomicChunkData data)
{
return onGenColumn(wx, wz, x, z, plan, data);
}
public World getWorld()
{
return world;
}
public IrisWorldData getWorldData()
{
return data;
}
public RNG getRMaster()
{
return rMaster;
}
public RNG getRMaster(int x, int z, int signature)
{
return rMaster.nextParallelRNG((int) (signature + x * z + z + x * 2.12));
}
protected abstract void onUnload();
protected abstract SChunkVector getParallaxSize();
public abstract void onGenParallax(int x, int z, Random random);
public abstract void onInit(World world, Random random);
public abstract ChunkPlan onInitChunk(World world, int x, int z, Random random);
public abstract Biome onGenColumn(int wx, int wz, int x, int z, ChunkPlan plan, AtomicChunkData data2);
public abstract void onPostChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan);
}

View File

@@ -8,7 +8,6 @@ import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator;
import mortar.logic.queue.ChronoLatch;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.controller.ExecutionController;
import ninja.bytecode.iris.controller.TimingsController;
@@ -24,48 +23,64 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
private int j;
private int wx;
private int wz;
private AtomicChunkData data;
private ReentrantLock biomeLock;
private TaskGroup tg;
private ChronoLatch el = new ChronoLatch(5000);
private boolean ready = false;
int cg = 0;
private RollingSequence rs = new RollingSequence(512);
private World world;
private TaskExecutor genPool;
private TaskExecutor genPar;
public World getWorld()
{
return world;
}
public Biome generateFullColumn(int a, int b, int c, int d, ChunkPlan p)
public Biome generateFullColumn(int a, int b, int c, int d, ChunkPlan p, AtomicChunkData data)
{
return genColumn(a, b, c, d, p);
return genColumn(a, b, c, d, p, data);
}
public TaskGroup startParallaxWork()
{
if(genPar == null)
{
genPar = Iris.getController(ExecutionController.class).getExecutor(world, "Parallax");
}
return genPar.startWork();
}
public TaskGroup startWork()
{
if(genPool == null)
{
genPool = Iris.getController(ExecutionController.class).getExecutor(world, "Generator");
}
return genPool.startWork();
}
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome)
{
AtomicChunkData data = new AtomicChunkData(world);
try
{
Iris.getController(TimingsController.class).started("terrain");
if(genPool == null)
{
genPool = Iris.getController(ExecutionController.class).getExecutor(world);
}
this.world = world;
data = new AtomicChunkData(world);
if(!ready)
{
biomeLock = new ReentrantLock();
onInit(world, random);
init(world, random);
ready = true;
}
tg = genPool.startWork();
tg = startWork();
O<ChunkPlan> plan = new O<ChunkPlan>();
for(i = 0; i < 16; i++)
{
wx = (x << 4) + i;
@@ -79,7 +94,7 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
int d = j;
tg.queue(() ->
{
Biome f = generateFullColumn(a, b, c, d, plan.get());
Biome f = generateFullColumn(a, b, c, d, plan.get(), data);
biomeLock.lock();
biome.setBiome(c, d, f);
biomeLock.unlock();
@@ -87,9 +102,9 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
}
}
plan.set(onInitChunk(world, x, z, random));
plan.set(initChunk(world, x, z, random));
TaskResult r = tg.execute();
onPostChunk(world, x, z, random, data, plan.get());
postChunk(world, x, z, random, data, plan.get());
rs.put(r.timeElapsed);
cg++;
Iris.getController(TimingsController.class).stopped("terrain");
@@ -97,61 +112,32 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
catch(Throwable e)
{
for(int i = 0; i < 16; i++)
try
{
for(int j = 0; j < 16; j++)
for(int i = 0; i < 16; i++)
{
data.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA);
for(int j = 0; j < 16; j++)
{
data.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA);
}
}
}
if(el.flip())
catch(Throwable ex)
{
e.printStackTrace();
}
e.printStackTrace();
}
return data.toChunkData();
}
public abstract void onInit(World world, Random random);
public abstract void init(World world, Random random);
public abstract ChunkPlan onInitChunk(World world, int x, int z, Random random);
public abstract ChunkPlan initChunk(World world, int x, int z, Random random);
public abstract void onPostChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan);
public abstract void postChunk(World world, int x, int z, Random random, AtomicChunkData data, ChunkPlan plan);
public abstract Biome genColumn(int wx, int wz, int x, int z, ChunkPlan plan);
public abstract void decorateColumn(int wx, int wz, int x, int z, ChunkPlan plan);
public void setBlock(int x, int y, int z, Material b)
{
setBlock(x, y, z, b, (byte) 0);
}
@SuppressWarnings("deprecation")
public void setBlock(int x, int y, int z, Material b, byte d)
{
setBlock(x, y, z, b.getId(), d);
}
public void setBlock(int x, int y, int z, int b)
{
setBlock(x, y, z, b, (byte) 0);
}
public void setBlock(int x, int y, int z, int b, byte d)
{
data.setBlock(x, y, z, b, d);
}
public Material getType(int x, int y, int z)
{
return data.getType(x, y, z);
}
public byte getData(int x, int y, int z)
{
return data.getData(x, y, z);
}
public abstract Biome genColumn(int wx, int wz, int x, int z, ChunkPlan plan, AtomicChunkData data);
}

View File

@@ -1,28 +1,28 @@
package ninja.bytecode.iris.util;
public class ChunkedVector
public class SChunkVector
{
private byte x;
private byte z;
public ChunkedVector(int x, int z)
public SChunkVector(int x, int z)
{
this.x = (byte) (x);
this.z = (byte) (z);
}
public ChunkedVector(byte x, byte z)
public SChunkVector(byte x, byte z)
{
this.x = x;
this.z = z;
}
public ChunkedVector(double x, double z)
public SChunkVector(double x, double z)
{
this((int) Math.round(x), (int) Math.round(z));
}
public ChunkedVector()
public SChunkVector()
{
this((byte) 0, (byte) 0);
}
@@ -66,13 +66,11 @@ public class ChunkedVector
return false;
if(getClass() != obj.getClass())
return false;
ChunkedVector other = (ChunkedVector) obj;
SChunkVector other = (SChunkVector) obj;
if(x != other.x)
return false;
if(z != other.z)
return false;
return true;
}
}

View File

@@ -0,0 +1,61 @@
package ninja.bytecode.iris.util;
import java.util.Objects;
public class SMCAVector
{
private int x;
private int z;
public SMCAVector(int x, int z)
{
this.x = x;
this.z = z;
}
public SMCAVector()
{
this(0, 0);
}
public int getX()
{
return x;
}
public void setX(int x)
{
this.x = x;
}
public int getZ()
{
return z;
}
public void setZ(int z)
{
this.z = z;
}
@Override
public int hashCode()
{
return Objects.hash(x, z);
}
@Override
public boolean equals(Object obj)
{
if(this == obj)
{
return true;
}
if(!(obj instanceof SMCAVector))
{
return false;
}
SMCAVector other = (SMCAVector) obj;
return x == other.x && z == other.z;
}
}