diff --git a/src/main/java/com/volmit/iris/gen/BiomeChunkGenerator.java b/src/main/java/com/volmit/iris/gen/BiomeChunkGenerator.java index 5a7d16584..14ce9630b 100644 --- a/src/main/java/com/volmit/iris/gen/BiomeChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/BiomeChunkGenerator.java @@ -164,43 +164,45 @@ public abstract class BiomeChunkGenerator extends DimensionChunkGenerator { } public IrisRegion sampleRegion(int x, int z) { - + double wx = getModifiedX(x, z); double wz = getModifiedZ(x, z); return glBiome.getRegion(wx, wz); } public BiomeResult sampleBiome(int x, int z) { - if (!getDimension().getFocus().equals("")) { - IrisBiome biome = loadBiome(getDimension().getFocus()); + return getCache().getRawBiome(x, z, () -> { + if (!getDimension().getFocus().equals("")) { + IrisBiome biome = loadBiome(getDimension().getFocus()); - for (String i : getDimension().getRegions()) { - IrisRegion reg = loadRegion(i); + for (String i : getDimension().getRegions()) { + IrisRegion reg = loadRegion(i); - if (reg.getLandBiomes().contains(biome.getLoadKey())) { - biome.setInferredType(InferredType.LAND); - break; + if (reg.getLandBiomes().contains(biome.getLoadKey())) { + biome.setInferredType(InferredType.LAND); + break; + } + + if (reg.getSeaBiomes().contains(biome.getLoadKey())) { + biome.setInferredType(InferredType.SEA); + break; + } + + if (reg.getShoreBiomes().contains(biome.getLoadKey())) { + biome.setInferredType(InferredType.SHORE); + break; + } } - if (reg.getSeaBiomes().contains(biome.getLoadKey())) { - biome.setInferredType(InferredType.SEA); - break; - } - - if (reg.getShoreBiomes().contains(biome.getLoadKey())) { - biome.setInferredType(InferredType.SHORE); - break; - } + return new BiomeResult(biome, 0); } - return new BiomeResult(biome, 0); - } + double wx = getModifiedX(x, z); + double wz = getModifiedZ(x, z); + IrisRegion region = glBiome.getRegion(wx, wz); + BiomeResult res = glBiome.generateRegionData(wx, wz, x, z, region); - double wx = getModifiedX(x, z); - double wz = getModifiedZ(x, z); - IrisRegion region = glBiome.getRegion(wx, wz); - BiomeResult res = glBiome.generateRegionData(wx, wz, x, z, region); - - return res; + return res; + }); } } diff --git a/src/main/java/com/volmit/iris/gen/ContextualChunkGenerator.java b/src/main/java/com/volmit/iris/gen/ContextualChunkGenerator.java index 71e983ef5..6de5b3601 100644 --- a/src/main/java/com/volmit/iris/gen/ContextualChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/ContextualChunkGenerator.java @@ -24,6 +24,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.IrisContext; import com.volmit.iris.IrisDataManager; import com.volmit.iris.IrisMetrics; +import com.volmit.iris.gen.atomics.AtomicMulticache; import com.volmit.iris.noise.CNG; import com.volmit.iris.object.IrisBiome; import com.volmit.iris.object.IrisDimension; @@ -46,6 +47,7 @@ import net.md_5.bungee.api.ChatColor; @Data @EqualsAndHashCode(callSuper = false) public abstract class ContextualChunkGenerator extends ChunkGenerator implements Listener { + private AtomicMulticache cache; private IrisDataManager data; protected boolean failing; protected int task; @@ -70,6 +72,7 @@ public abstract class ContextualChunkGenerator extends ChunkGenerator implements perSecond = new ChronoLatch(1000); hlast = M.ms(); hlock = new IrisLock("HotLock"); + cache = new AtomicMulticache(); CNG.creates = 0; generated = 0; ticks = 0; diff --git a/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java b/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java index a052aabba..0bcb202f8 100644 --- a/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java @@ -81,7 +81,8 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple @Override public int getHighest(int x, int z, boolean ignoreFluid) { - int h = (int) Math.round(ignoreFluid ? getTerrainHeight(x, z) : getTerrainWaterHeight(x, z)); + int h = (int) Math + .round(ignoreFluid ? getTerrainHeight(x, z) : getTerrainWaterHeight(x, z)); if (getDimension().isCarving() && h >= getDimension().getCarvingMin()) { while (getGlCarve().isCarved(x, h, z)) { diff --git a/src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java b/src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java index 96becef7d..b0243c586 100644 --- a/src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/ParallelChunkGenerator.java @@ -20,7 +20,6 @@ import lombok.EqualsAndHashCode; public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { private GroupedExecutor accelerant; private int threads; - protected boolean safe; protected int cacheX; protected int cacheZ; private IrisLock genlock; @@ -28,7 +27,6 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { public ParallelChunkGenerator(String dimensionName, int threads) { super(dimensionName); - safe = false; cacheX = 0; cacheZ = 0; this.threads = threads; @@ -68,6 +66,7 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { genlock.lock(); cacheX = x; cacheZ = z; + getCache().targetChunk(cacheX, cacheZ); PrecisionStopwatch p = PrecisionStopwatch.start(); AtomicSliverMap map = new AtomicSliverMap(); HeightMap height = new HeightMap(); @@ -90,11 +89,7 @@ public abstract class ParallelChunkGenerator extends BiomeChunkGenerator { } } - setCachingAllowed(true); - setSafe(false); accelerant.waitFor(key); - setSafe(true); - setCachingAllowed(false); map.write(data, grid, height); getMetrics().getTerrain().put(p.getMilliseconds()); p = PrecisionStopwatch.start(); diff --git a/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java b/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java index f0e3fc87b..70141c54d 100644 --- a/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java @@ -68,7 +68,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { double wx = getZoomed(ox); double wz = getZoomed(oz); int depth = 0; - double noise = getNoiseHeight(rx, rz) + fluidHeight; + double noise = getTerrainHeight(rx, rz); int height = (int) Math.round(noise); boolean carvable = getDimension().isCarving() && height > getDimension().getCarvingMin(); IrisRegion region = sampleRegion(rx, rz); @@ -409,7 +409,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { } - protected double getNoiseHeight(int rx, int rz) { + private double getNoiseHeight(int rx, int rz) { double wx = getZoomed(rx); double wz = getZoomed(rz); double h = getBiomeHeight(wx, wz, rx, rz); @@ -477,9 +477,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { @Override public IrisRegion sampleRegion(int x, int z) { - IrisRegion r = super.sampleRegion(x, z); - - return r; + return getCache().getRegion(x, z, () -> super.sampleRegion(x, z)); } public BiomeResult sampleTrueBiome(int x, int z, double noise) { @@ -487,27 +485,26 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { return focus(); } - double wx = getModifiedX(x, z); - double wz = getModifiedZ(x, z); - IrisRegion region = sampleRegion(x, z); - int height = (int) Math.round(noise); - double sh = region.getShoreHeight(wx, wz); - BiomeResult res = sampleTrueBiomeBase(x, z, height); - IrisBiome current = res.getBiome(); + return getCache().getBiome(x, z, () -> { + double wx = getModifiedX(x, z); + double wz = getModifiedZ(x, z); + IrisRegion region = sampleRegion(x, z); + int height = (int) Math.round(noise); + double sh = region.getShoreHeight(wx, wz); + BiomeResult res = sampleTrueBiomeBase(x, z, height); + IrisBiome current = res.getBiome(); - if (current.isSea() && height > getDimension().getFluidHeight() - sh) { - return glBiome.generateData(InferredType.SHORE, wx, wz, x, z, region); - } + if (current.isSea() && height > getDimension().getFluidHeight() - sh) { + return glBiome.generateData(InferredType.SHORE, wx, wz, x, z, region); + } - return res; + return res; + }); } @Override protected int onSampleColumnHeight(int cx, int cz, int rx, int rz, int x, int z) { - int fluidHeight = getDimension().getFluidHeight(); - double noise = getNoiseHeight(rx, rz); - - return (int) Math.round(noise) + fluidHeight; + return (int) Math.round(getTerrainHeight(rx, rz)); } private boolean touchesSea(int rx, int rz) { @@ -528,7 +525,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator { } public double getTerrainHeight(int x, int z) { - return getNoiseHeight(x, z) + getFluidHeight(); + return getCache().getHeight(x, z, () -> getNoiseHeight(x, z) + getFluidHeight()); } public double getTerrainWaterHeight(int x, int z) { diff --git a/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java b/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java new file mode 100644 index 000000000..fffcdd98e --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java @@ -0,0 +1,105 @@ +package com.volmit.iris.gen.atomics; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +import com.volmit.iris.Iris; +import com.volmit.iris.object.IrisRegion; +import com.volmit.iris.util.BiomeResult; +import com.volmit.iris.util.Form; +import com.volmit.iris.util.KMap; + +public class AtomicMulticache { + private final AtomicInteger x; + private final AtomicInteger z; + private final KMap height; + private final KMap biome; + private final KMap rawBiome; + private final KMap region; + private int r = 0; + private int w = 0; + private int m = 0; + + public AtomicMulticache() { + x = new AtomicInteger(0); + z = new AtomicInteger(0); + height = new KMap(); + biome = new KMap(); + rawBiome = new KMap(); + region = new KMap(); + } + + public void targetChunk(int x, int z) { + this.x.set(x); + this.z.set(z); + + Iris.info("R: " + Form.f(r) + " W: " + Form.f(w) + " M: " + Form.f(m) + " (" + Form.pc(r / (double) (r + m), 1) + + "), SIZE: " + Form.f(height.size() + biome.size() + region.size())); + height.clear(); + region.size(); + biome.size(); + r = 0; + w = 0; + m = 0; + } + + public double getHeight(int x, int z, Supplier g) { + return height.compute(pos(x, z), (k, v) -> { + if (v == null) { + m++; + w++; + return g.get(); + } + + r++; + + return v; + }); + } + + public IrisRegion getRegion(int x, int z, Supplier g) { + return region.compute(pos(x, z), (k, v) -> { + if (v == null) { + m++; + w++; + return g.get(); + } + + r++; + + return v; + }); + } + + public BiomeResult getBiome(int x, int z, Supplier g) { + return biome.compute(pos(x, z), (k, v) -> { + if (v == null) { + m++; + w++; + return g.get(); + } + + r++; + + return v; + }); + } + + public BiomeResult getRawBiome(int x, int z, Supplier g) { + return rawBiome.compute(pos(x, z), (k, v) -> { + if (v == null) { + m++; + w++; + return g.get(); + } + + r++; + + return v; + }); + } + + private long pos(int x, int z) { + return (((long) x) << 32) | (z & 0xffffffffL); + } +} diff --git a/src/main/java/com/volmit/iris/object/IrisObject.java b/src/main/java/com/volmit/iris/object/IrisObject.java index 166353ff1..1d5f0d9fd 100644 --- a/src/main/java/com/volmit/iris/object/IrisObject.java +++ b/src/main/java/com/volmit/iris/object/IrisObject.java @@ -26,19 +26,21 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = false) -public class IrisObject extends IrisRegistrant -{ +public class IrisObject extends IrisRegistrant { private static final Material SNOW = Material.SNOW; private static final BlockData AIR = B.getBlockData("CAVE_AIR"); - private static final BlockData[] SNOW_LAYERS = new BlockData[] {B.getBlockData("minecraft:snow[layers=1]"), B.getBlockData("minecraft:snow[layers=2]"), B.getBlockData("minecraft:snow[layers=3]"), B.getBlockData("minecraft:snow[layers=4]"), B.getBlockData("minecraft:snow[layers=5]"), B.getBlockData("minecraft:snow[layers=6]"), B.getBlockData("minecraft:snow[layers=7]"), B.getBlockData("minecraft:snow[layers=8]")}; + private static final BlockData[] SNOW_LAYERS = new BlockData[] { B.getBlockData("minecraft:snow[layers=1]"), + B.getBlockData("minecraft:snow[layers=2]"), B.getBlockData("minecraft:snow[layers=3]"), + B.getBlockData("minecraft:snow[layers=4]"), B.getBlockData("minecraft:snow[layers=5]"), + B.getBlockData("minecraft:snow[layers=6]"), B.getBlockData("minecraft:snow[layers=7]"), + B.getBlockData("minecraft:snow[layers=8]") }; private KMap blocks; private int w; private int d; private int h; private transient BlockVector center; - public IrisObject(int w, int h, int d) - { + public IrisObject(int w, int h, int d) { blocks = new KMap<>(); this.w = w; this.h = h; @@ -46,8 +48,7 @@ public class IrisObject extends IrisRegistrant center = new BlockVector(w / 2, h / 2, d / 2); } - public static BlockVector sampleSize(File file) throws IOException - { + public static BlockVector sampleSize(File file) throws IOException { FileInputStream in = new FileInputStream(file); DataInputStream din = new DataInputStream(in); BlockVector bv = new BlockVector(din.readInt(), din.readInt(), din.readInt()); @@ -55,8 +56,7 @@ public class IrisObject extends IrisRegistrant return bv; } - public void read(InputStream in) throws IOException - { + public void read(InputStream in) throws IOException { DataInputStream din = new DataInputStream(in); this.w = din.readInt(); this.h = din.readInt(); @@ -64,36 +64,32 @@ public class IrisObject extends IrisRegistrant center = new BlockVector(w / 2, h / 2, d / 2); int s = din.readInt(); - for(int i = 0; i < s; i++) - { - blocks.put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.getBlockData(din.readUTF())); + for (int i = 0; i < s; i++) { + blocks.put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), + B.getBlockData(din.readUTF())); } } - public void read(File file) throws IOException - { + public void read(File file) throws IOException { FileInputStream fin = new FileInputStream(file); read(fin); fin.close(); } - public void write(File file) throws IOException - { + public void write(File file) throws IOException { file.getParentFile().mkdirs(); FileOutputStream out = new FileOutputStream(file); write(out); out.close(); } - public void write(OutputStream o) throws IOException - { + public void write(OutputStream o) throws IOException { DataOutputStream dos = new DataOutputStream(o); dos.writeInt(w); dos.writeInt(h); dos.writeInt(d); dos.writeInt(blocks.size()); - for(BlockVector i : blocks.k()) - { + for (BlockVector i : blocks.k()) { dos.writeShort(i.getBlockX()); dos.writeShort(i.getBlockY()); dos.writeShort(i.getBlockZ()); @@ -101,83 +97,67 @@ public class IrisObject extends IrisRegistrant } } - public void setUnsigned(int x, int y, int z, BlockData block) - { - if(x >= w || y >= h || z >= d) - { + public void setUnsigned(int x, int y, int z, BlockData block) { + if (x >= w || y >= h || z >= d) { throw new RuntimeException(x + " " + y + " " + z + " exceeds limit of " + w + " " + h + " " + d); } BlockVector v = new BlockVector(x, y, z).subtract(center).toBlockVector(); - if(block == null) - { + if (block == null) { blocks.remove(v); } - else - { + else { blocks.put(v, block); } } - public void place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) - { + public void place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) { place(x, -1, z, placer, config, rng); } - public void place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) - { + public void place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) { int spinx = rng.imax() / 1000; int spiny = rng.imax() / 1000; int spinz = rng.imax() / 1000; - int y = yv < 0 ? placer.getHighest(x, z, config.isUnderwater()) + config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), spinx, spiny, spinz).getBlockY() : yv; + int y = yv < 0 ? placer.getHighest(x, z, config.isUnderwater()) + config.getRotation() + .rotate(new BlockVector(0, getCenter().getBlockY(), 0), spinx, spiny, spinz).getBlockY() : yv; - if(yv >= 0 && config.isBottom()) - { + if (yv >= 0 && config.isBottom()) { y += Math.floorDiv(h, 2); } KMap heightmap = config.getSnow() > 0 ? new KMap<>() : null; - if(yv < 0) - { - if(!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z)) - { + if (yv < 0) { + if (!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z)) { return; } } - if(config.isBore()) - { - for(int i = x - Math.floorDiv(w, 2); i <= x + Math.floorDiv(w, 2) - (w % 2 == 0 ? 1 : 0); i++) - { - for(int j = y - Math.floorDiv(h, 2); j <= y + Math.floorDiv(h, 2) - (h % 2 == 0 ? 1 : 0); j++) - { - for(int k = z - Math.floorDiv(d, 2); k <= z + Math.floorDiv(d, 2) - (d % 2 == 0 ? 1 : 0); k++) - { + if (config.isBore()) { + for (int i = x - Math.floorDiv(w, 2); i <= x + Math.floorDiv(w, 2) - (w % 2 == 0 ? 1 : 0); i++) { + for (int j = y - Math.floorDiv(h, 2); j <= y + Math.floorDiv(h, 2) - (h % 2 == 0 ? 1 : 0); j++) { + for (int k = z - Math.floorDiv(d, 2); k <= z + Math.floorDiv(d, 2) - (d % 2 == 0 ? 1 : 0); k++) { placer.set(i, j, k, AIR); } } } } - for(BlockVector g : blocks.keySet()) - { + for (BlockVector g : blocks.keySet()) { BlockVector i = g.clone(); i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone(); i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone(); BlockData data = blocks.get(g).clone(); - if(placer.isPreventingDecay() && data instanceof Leaves && !((Leaves) data).isPersistent()) - { + if (placer.isPreventingDecay() && data instanceof Leaves && !((Leaves) data).isPersistent()) { ((Leaves) data).setPersistent(true); } - for(IrisObjectReplace j : config.getEdit()) - { - if(j.isExact() ? j.getFind().matches(data) : j.getFind().getMaterial().equals(data.getMaterial())) - { + for (IrisObjectReplace j : config.getEdit()) { + if (j.isExact() ? j.getFind().matches(data) : j.getFind().getMaterial().equals(data.getMaterial())) { data = j.getReplace(); } } @@ -187,44 +167,36 @@ public class IrisObject extends IrisRegistrant int yy = y + (int) Math.round(i.getY()); int zz = z + (int) Math.round(i.getZ()); - if(heightmap != null) - { + if (heightmap != null) { ChunkPosition pos = new ChunkPosition(xx, zz); - if(!heightmap.containsKey(pos)) - { + if (!heightmap.containsKey(pos)) { heightmap.put(pos, yy); } - if(heightmap.get(pos) < yy) - { + if (heightmap.get(pos) < yy) { heightmap.put(pos, yy); } } - if(config.isMeld() && !placer.isSolid(xx, yy, zz)) - { + if (config.isMeld() && !placer.isSolid(xx, yy, zz)) { continue; } placer.set(xx, yy, zz, data); } - if(heightmap != null) - { + if (heightmap != null) { RNG rngx = rng.nextParallelRNG(3468854); - for(ChunkPosition i : heightmap.k()) - { + for (ChunkPosition i : heightmap.k()) { int vx = i.getX(); int vy = heightmap.get(i); int vz = i.getZ(); - if(config.getSnow() > 0) - { + if (config.getSnow() > 0) { BlockData bd = placer.get(vx, vy, vz); - if(bd != null && bd.getMaterial().equals(SNOW)) - { + if (bd != null && bd.getMaterial().equals(SNOW)) { continue; } @@ -235,10 +207,8 @@ public class IrisObject extends IrisRegistrant } } - public void place(Location at) - { - for(BlockVector i : blocks.keySet()) - { + public void place(Location at) { + for (BlockVector i : blocks.keySet()) { at.clone().add(0, getCenter().getY(), 0).add(i).getBlock().setBlockData(blocks.get(i), false); } } diff --git a/src/main/java/com/volmit/iris/util/IObjectPlacer.java b/src/main/java/com/volmit/iris/util/IObjectPlacer.java index 039d1951a..a5a13465f 100644 --- a/src/main/java/com/volmit/iris/util/IObjectPlacer.java +++ b/src/main/java/com/volmit/iris/util/IObjectPlacer.java @@ -2,8 +2,7 @@ package com.volmit.iris.util; import org.bukkit.block.data.BlockData; -public interface IObjectPlacer -{ +public interface IObjectPlacer { public int getHighest(int x, int z); public int getHighest(int x, int z, boolean ignoreFluid);