diff --git a/src/main/java/ninja/bytecode/iris/generator/BiomeChunkGenerator.java b/src/main/java/ninja/bytecode/iris/generator/BiomeChunkGenerator.java index 7f1c6baae..c32e7bab5 100644 --- a/src/main/java/ninja/bytecode/iris/generator/BiomeChunkGenerator.java +++ b/src/main/java/ninja/bytecode/iris/generator/BiomeChunkGenerator.java @@ -31,15 +31,15 @@ public abstract class BiomeChunkGenerator extends DimensionChunkGenerator public IrisRegion sampleRegion(int x, int z) { - double wx = getZoomed(getModifiedX(x, z)); - double wz = getZoomed(getModifiedZ(x, z)); + double wx = getModifiedX(x, z); + double wz = 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)); + double wx = getModifiedX(x, z); + double wz = getModifiedZ(x, z); IrisRegion region = glBiome.getRegion(wx, wz); return glBiome.generateRegionData(wx, wz, region); } diff --git a/src/main/java/ninja/bytecode/iris/generator/ContextualChunkGenerator.java b/src/main/java/ninja/bytecode/iris/generator/ContextualChunkGenerator.java index bc3a4bd89..b306231d0 100644 --- a/src/main/java/ninja/bytecode/iris/generator/ContextualChunkGenerator.java +++ b/src/main/java/ninja/bytecode/iris/generator/ContextualChunkGenerator.java @@ -186,7 +186,7 @@ public abstract class ContextualChunkGenerator extends ChunkGenerator implements { return super.canSpawn(world, x, z); } - + protected ChunkData generateChunkDataFailure(World world, Random no, int x, int z, BiomeGrid biomeGrid) { ChunkData c = Bukkit.createChunkData(world); diff --git a/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java b/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java index 7532639cd..ce0632f96 100644 --- a/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java +++ b/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java @@ -40,7 +40,7 @@ public class IrisGenerator extends ParallaxChunkGenerator implements IrisContext @Override protected void onTick(int ticks) { - super.onTick(ticks); + } @Override diff --git a/src/main/java/ninja/bytecode/iris/generator/ParallaxChunkGenerator.java b/src/main/java/ninja/bytecode/iris/generator/ParallaxChunkGenerator.java index b17e955ed..7138784a7 100644 --- a/src/main/java/ninja/bytecode/iris/generator/ParallaxChunkGenerator.java +++ b/src/main/java/ninja/bytecode/iris/generator/ParallaxChunkGenerator.java @@ -13,6 +13,7 @@ import ninja.bytecode.iris.object.IrisObjectPlacement; import ninja.bytecode.iris.object.atomics.AtomicSliver; import ninja.bytecode.iris.object.atomics.AtomicSliverMap; import ninja.bytecode.iris.object.atomics.AtomicWorldData; +import ninja.bytecode.iris.object.atomics.MasterLock; import ninja.bytecode.iris.util.BiomeMap; import ninja.bytecode.iris.util.ChunkPosition; import ninja.bytecode.iris.util.HeightMap; @@ -26,12 +27,15 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple { private KMap sliverCache; protected AtomicWorldData parallaxMap; - private int sliverBuffer = 0; + private MasterLock masterLock; + private int sliverBuffer; public ParallaxChunkGenerator(String dimensionName, int threads) { super(dimensionName, threads); sliverCache = new KMap<>(); + sliverBuffer = 0; + masterLock = new MasterLock(); } public void onInit(World world, RNG rng) @@ -64,7 +68,9 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple @Override public void set(int x, int y, int z, BlockData d) { + getMasterLock().lock((x >> 4) + "." + (z >> 4)); getParallaxSliver(x, z).set(y, d); + getMasterLock().unlock((x >> 4) + "." + (z >> 4)); } @Override @@ -76,22 +82,24 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple public AtomicSliver getParallaxSliver(int wx, int wz) { - return getParallaxChunk(wx >> 4, wz >> 4).getSliver(wx & 15, wz & 15); + getMasterLock().lock("gpc"); + getMasterLock().lock((wx >> 4) + "." + (wz >> 4)); + AtomicSliverMap map = getParallaxChunk(wx >> 4, wz >> 4); + getMasterLock().unlock("gpc"); + AtomicSliver sliver = map.getSliver(wx & 15, wz & 15); + getMasterLock().unlock((wx >> 4) + "." + (wz >> 4)); + + return sliver; } - public boolean hasParallaxChunk(int x, int z) + public boolean isParallaxGenerated(int x, int z) { - try - { - return getParallaxMap().hasChunk(x, z); - } + return getParallaxChunk(x, z).isParallaxGenerated(); + } - catch(IOException e) - { - fail(e); - } - - return false; + public boolean isWorldGenerated(int x, int z) + { + return getParallaxChunk(x, z).isWorldGenerated(); } public AtomicSliverMap getParallaxChunk(int x, int z) @@ -112,45 +120,65 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple @Override protected void onPostGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid, HeightMap height, BiomeMap biomeMap) { - onGenerateParallax(random, x, z); - getParallaxChunk(x, z).inject(data); - sliverBuffer = sliverCache.size(); - sliverCache.clear(); + if(getDimension().isPlaceObjects()) + { + onGenerateParallax(random, x, z); + getParallaxChunk(x, z).inject(data); + setSliverBuffer(getSliverCache().size()); + getParallaxChunk(x, z).setWorldGenerated(true); + getParallaxMap().clean(x + z); + getSliverCache().clear(); + getMasterLock().clear(); + } } protected void onGenerateParallax(RNG random, int x, int z) { - ChunkPosition pos = Iris.data.getObjectLoader().getParallaxSize(); + String key = "par." + x + "." + "z"; + ChunkPosition rad = Iris.data.getObjectLoader().getParallaxSize(); - for(int i = x - pos.getX() / 2; i <= x + pos.getX() / 2; i++) + for(int ii = x - (rad.getX() / 2); ii <= x + (rad.getX() / 2); ii++) { - for(int j = z - pos.getZ() / 2; j <= z + pos.getZ() / 2; j++) - { - IrisBiome b = sampleBiome((i * 16) + 7, (j * 16) + 7).getBiome(); - int g = 1; + int i = ii; - for(IrisObjectPlacement k : b.getObjects()) + for(int jj = z - (rad.getZ() / 2); jj <= z + (rad.getZ() / 2); jj++) + { + int j = jj; + + if(isParallaxGenerated(ii, jj)) { - placeObject(k, i, j, random.nextParallelRNG((i * 30) + (j * 30) + g++)); + continue; } + + if(isWorldGenerated(ii, jj)) + { + continue; + } + + getTx().queue(key, () -> + { + IrisBiome b = sampleBiome((i * 16) + 7, (j * 16) + 7).getBiome(); + int g = 1; + + for(IrisObjectPlacement k : b.getObjects()) + { + placeObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + g++) * i * j) + i - j + 3569222)); + } + }); + + getParallaxChunk(ii, jj).setParallaxGenerated(true); } } - } - @Override - protected void onTick(int ticks) - { - if(ticks % 100 == 0) - { - parallaxMap.clean(); - } + getTx().waitFor(key); } protected void placeObject(IrisObjectPlacement o, int x, int z, RNG rng) { for(int i = 0; i < o.getTriesForChunk(rng); i++) { - o.getSchematic(rng).place((x * 16) * rng.nextInt(16), (z * 16) + rng.nextInt(16), this); + rng = rng.nextParallelRNG((i * 3 + 8) - 23040); + o.getSchematic(rng).place((x * 16) + rng.nextInt(16), (z * 16) + rng.nextInt(16), this, o, rng); } } diff --git a/src/main/java/ninja/bytecode/iris/object/IrisAxisRotationClamp.java b/src/main/java/ninja/bytecode/iris/object/IrisAxisRotationClamp.java new file mode 100644 index 000000000..da3acb549 --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/object/IrisAxisRotationClamp.java @@ -0,0 +1,41 @@ +package ninja.bytecode.iris.object; + +import lombok.Data; + +@Data +public class IrisAxisRotationClamp +{ + private boolean enabled = false; + private double min = 0; + private double max = 0; + private double interval = 0; + + public IrisAxisRotationClamp() + { + + } + + public IrisAxisRotationClamp(boolean enabled, double min, double max, double interval) + { + this.enabled = enabled; + this.min = min; + this.max = max; + this.interval = interval; + } + + public boolean isUnlimited() + { + return min == max; + } + + public double getRadians(int rng) + { + if(isUnlimited()) + { + return Math.toRadians((rng * interval) % 360D); + } + + double deg = min + (rng * interval) % (Math.abs(max - min) / 360D); + return Math.toRadians(deg); + } +} diff --git a/src/main/java/ninja/bytecode/iris/object/IrisDimension.java b/src/main/java/ninja/bytecode/iris/object/IrisDimension.java index e4b98b353..fd2f53371 100644 --- a/src/main/java/ninja/bytecode/iris/object/IrisDimension.java +++ b/src/main/java/ninja/bytecode/iris/object/IrisDimension.java @@ -32,6 +32,7 @@ public class IrisDimension extends IrisRegisteredObject private double seaZoom = 1; private double continentZoom = 1; private double regionZoom = 1; + private boolean placeObjects = true; private transient CNG coordFracture; private transient Double sinr; diff --git a/src/main/java/ninja/bytecode/iris/object/IrisObject.java b/src/main/java/ninja/bytecode/iris/object/IrisObject.java index 064abed65..41d00758a 100644 --- a/src/main/java/ninja/bytecode/iris/object/IrisObject.java +++ b/src/main/java/ninja/bytecode/iris/object/IrisObject.java @@ -17,6 +17,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import ninja.bytecode.iris.util.BlockDataTools; import ninja.bytecode.iris.util.IObjectPlacer; +import ninja.bytecode.iris.util.RNG; import ninja.bytecode.shuriken.collections.KMap; @Data @@ -37,7 +38,7 @@ public class IrisObject extends IrisRegisteredObject this.d = d; center = new BlockVector(w / 2, h / 2, d / 2); } - + public static BlockVector sampleSize(File file) throws IOException { FileInputStream in = new FileInputStream(file); @@ -113,13 +114,21 @@ public class IrisObject extends IrisRegisteredObject } } - public void place(int x, int z, IObjectPlacer placer) + public void place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng) { - int y = placer.getHighest(x, z) + getCenter().getBlockY(); - - for(BlockVector i : blocks.k()) + boolean yf = rng.nextBoolean(); + boolean xf = rng.nextBoolean(); + int spinx = rng.imax() / 1000; + int spiny = rng.imax() / 1000; + int spinz = rng.imax() / 1000; + int y = placer.getHighest(x, z) + config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), yf, xf, spinx, spiny, spinz).getBlockY(); + + for(BlockVector g : blocks.k()) { - placer.set(x + i.getBlockX(), y + i.getBlockY(), z + i.getBlockZ(), blocks.get(i)); + BlockVector i = g.clone(); + i = config.getRotation().rotate(i.clone(), yf, xf, spinx, spiny, spinz).clone(); + i = config.getTranslate().translate(i.clone()).clone(); + placer.set(x + i.getBlockX(), y + i.getBlockY(), z + i.getBlockZ(), blocks.get(g)); } } diff --git a/src/main/java/ninja/bytecode/iris/object/IrisObjectPlacement.java b/src/main/java/ninja/bytecode/iris/object/IrisObjectPlacement.java index c8a71bc24..5e8b7ca7e 100644 --- a/src/main/java/ninja/bytecode/iris/object/IrisObjectPlacement.java +++ b/src/main/java/ninja/bytecode/iris/object/IrisObjectPlacement.java @@ -1,12 +1,16 @@ package ninja.bytecode.iris.object; +import lombok.Data; import ninja.bytecode.iris.Iris; import ninja.bytecode.iris.util.RNG; import ninja.bytecode.shuriken.collections.KList; +@Data public class IrisObjectPlacement { private KList place = new KList<>(); + private IrisObjectTranslate translate = new IrisObjectTranslate(); + private IrisObjectRotation rotation = new IrisObjectRotation(); private double chance = 1; private int density = 1; @@ -14,14 +18,14 @@ public class IrisObjectPlacement { } - + public IrisObject getSchematic(RNG random) { if(place.isEmpty()) { return null; } - + return Iris.data.getObjectLoader().load(place.get(random.nextInt(place.size()))); } diff --git a/src/main/java/ninja/bytecode/iris/object/IrisObjectRotation.java b/src/main/java/ninja/bytecode/iris/object/IrisObjectRotation.java new file mode 100644 index 000000000..5fcc1a4ea --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/object/IrisObjectRotation.java @@ -0,0 +1,106 @@ +package ninja.bytecode.iris.object; + +import org.bukkit.util.BlockVector; + +import lombok.Data; + +@Data +public class IrisObjectRotation +{ + private boolean enabled = true; + private IrisAxisRotationClamp xAxis = new IrisAxisRotationClamp(); + private IrisAxisRotationClamp yAxis = new IrisAxisRotationClamp(true, 0, 0, 90); + private IrisAxisRotationClamp zAxis = new IrisAxisRotationClamp(); + + public IrisObjectRotation() + { + + } + + public double getYRotation(int spin) + { + return getRotation(spin, yAxis); + } + + public double getXRotation(int spin) + { + return getRotation(spin, xAxis); + } + + public double getZRotation(int spin) + { + return getRotation(spin, zAxis); + } + + public double getRotation(int spin, IrisAxisRotationClamp clamp) + { + if(!enabled) + { + return 0; + } + + if(!clamp.isEnabled()) + { + return 0; + } + + return clamp.getRadians(spin); + } + + public BlockVector rotate(BlockVector b, boolean yf, boolean xf, int spinx, int spiny, int spinz) + { + if(!canRotate()) + { + return b; + } + + BlockVector v = b.clone(); + + if(yf && canRotateY()) + { + v.rotateAroundY(getYRotation(spiny)); + } + + if(xf && canRotateX()) + { + v.rotateAroundX(getXRotation(spinx)); + } + + if(canRotateZ()) + { + v.rotateAroundZ(getZRotation(spinz)); + } + + if(!xf && canRotateX()) + { + v.rotateAroundX(getXRotation(spinx)); + } + + if(!yf && canRotateY()) + { + v.rotateAroundY(getYRotation(spiny)); + } + + return v; + } + + public boolean canRotateX() + { + return enabled && xAxis.isEnabled(); + } + + public boolean canRotateY() + { + return enabled && yAxis.isEnabled(); + } + + public boolean canRotateZ() + { + return enabled && zAxis.isEnabled(); + } + + public boolean canRotate() + { + return canRotateX() || canRotateY() || canRotateZ(); + } +} diff --git a/src/main/java/ninja/bytecode/iris/object/IrisObjectTranslate.java b/src/main/java/ninja/bytecode/iris/object/IrisObjectTranslate.java new file mode 100644 index 000000000..47758e038 --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/object/IrisObjectTranslate.java @@ -0,0 +1,35 @@ +package ninja.bytecode.iris.object; + +import org.bukkit.util.BlockVector; + +import lombok.Data; + +@Data +public class IrisObjectTranslate +{ + private int x; + private int y; + private int z; + + public IrisObjectTranslate() + { + x = 0; + y = 0; + z = 0; + } + + public boolean canTranslate() + { + return x != 0 || y != 0 || z != 0; + } + + public BlockVector translate(BlockVector i) + { + if(canTranslate()) + { + return (BlockVector) i.clone().add(new BlockVector(x, y, z)); + } + + return i; + } +} diff --git a/src/main/java/ninja/bytecode/iris/object/atomics/AtomicSliver.java b/src/main/java/ninja/bytecode/iris/object/atomics/AtomicSliver.java index 6917f3187..7382e2901 100644 --- a/src/main/java/ninja/bytecode/iris/object/atomics/AtomicSliver.java +++ b/src/main/java/ninja/bytecode/iris/object/atomics/AtomicSliver.java @@ -35,6 +35,11 @@ public class AtomicSliver public void set(int h, BlockData d) { + if(d == null) + { + return; + } + block.put(h, d); highestBlock = h > highestBlock ? h : highestBlock; } diff --git a/src/main/java/ninja/bytecode/iris/object/atomics/AtomicSliverMap.java b/src/main/java/ninja/bytecode/iris/object/atomics/AtomicSliverMap.java index df6d96fe9..3111e4c2b 100644 --- a/src/main/java/ninja/bytecode/iris/object/atomics/AtomicSliverMap.java +++ b/src/main/java/ninja/bytecode/iris/object/atomics/AtomicSliverMap.java @@ -9,14 +9,20 @@ import java.io.OutputStream; import org.bukkit.generator.ChunkGenerator.BiomeGrid; import org.bukkit.generator.ChunkGenerator.ChunkData; +import lombok.Data; import ninja.bytecode.iris.util.HeightMap; +@Data public class AtomicSliverMap { private final AtomicSliver[] slivers; + private boolean parallaxGenerated; + private boolean worldGenerated; public AtomicSliverMap() { + parallaxGenerated = false; + worldGenerated = false; slivers = new AtomicSliver[256]; for(int i = 0; i < 16; i++) @@ -35,10 +41,12 @@ public class AtomicSliverMap slivers[i].insert(map.slivers[i]); } } - + public void write(OutputStream out) throws IOException { DataOutputStream dos = new DataOutputStream(out); + dos.writeBoolean(isParallaxGenerated()); + dos.writeBoolean(isWorldGenerated()); for(int i = 0; i < 256; i++) { slivers[i].write(dos); @@ -50,6 +58,9 @@ public class AtomicSliverMap public void read(InputStream in) throws IOException { DataInputStream din = new DataInputStream(in); + parallaxGenerated = din.readBoolean(); + worldGenerated = din.readBoolean(); + for(int i = 0; i < 256; i++) { slivers[i].read(din); diff --git a/src/main/java/ninja/bytecode/iris/object/atomics/AtomicWorldData.java b/src/main/java/ninja/bytecode/iris/object/atomics/AtomicWorldData.java index 615d93c0e..a64315a30 100644 --- a/src/main/java/ninja/bytecode/iris/object/atomics/AtomicWorldData.java +++ b/src/main/java/ninja/bytecode/iris/object/atomics/AtomicWorldData.java @@ -7,7 +7,6 @@ import java.io.IOException; import org.bukkit.World; -import ninja.bytecode.iris.Iris; import ninja.bytecode.iris.util.ChunkPosition; import ninja.bytecode.shuriken.collections.KMap; import ninja.bytecode.shuriken.math.M; @@ -172,8 +171,6 @@ public class AtomicWorldData AtomicSliverMap m = dat.get(x & 31, z & 31); loadedChunks.put(pos, m); - Iris.info("Loaded chunk: sections: " + loadedSections.size()); - return m; } @@ -237,11 +234,11 @@ public class AtomicWorldData return loadedChunks; } - public void clean() + public void clean(int j) { for(ChunkPosition i : lastRegion.k()) { - if(M.ms() - lastRegion.get(i) > 3000) + if(M.ms() - lastRegion.get(i) > 60000) { lastRegion.remove(i); diff --git a/src/main/java/ninja/bytecode/iris/object/atomics/MasterLock.java b/src/main/java/ninja/bytecode/iris/object/atomics/MasterLock.java new file mode 100644 index 000000000..9c3cedc95 --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/object/atomics/MasterLock.java @@ -0,0 +1,48 @@ +package ninja.bytecode.iris.object.atomics; + +import java.util.concurrent.locks.ReentrantLock; + +import ninja.bytecode.shuriken.collections.KMap; + +public class MasterLock +{ + private KMap locks; + private ReentrantLock lock; + + public MasterLock() + { + locks = new KMap<>(); + lock = new ReentrantLock(); + } + + public void clear() + { + locks.clear(); + } + + public void lock(String key) + { + lock.lock(); + if(!locks.containsKey(key)) + { + locks.put(key, new ReentrantLock()); + } + + ReentrantLock l = locks.get(key); + lock.unlock(); + l.lock(); + } + + public void unlock(String key) + { + lock.lock(); + if(!locks.containsKey(key)) + { + locks.put(key, new ReentrantLock()); + } + + ReentrantLock l = locks.get(key); + lock.unlock(); + l.unlock(); + } +}