Iris/src/main/java/com/volmit/iris/gen/ParallaxTerrainProvider.java
Daniel Mills c7f612dac0 Fixes
2020-10-16 01:59:18 -04:00

525 lines
13 KiB
Java

package com.volmit.iris.gen;
import java.io.IOException;
import java.util.List;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.generator.BlockPopulator;
import com.volmit.iris.Iris;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.gen.atomics.AtomicSliver;
import com.volmit.iris.gen.atomics.AtomicSliverMap;
import com.volmit.iris.gen.atomics.AtomicWorldData;
import com.volmit.iris.gen.atomics.MasterLock;
import com.volmit.iris.gen.layer.GenLayerText;
import com.volmit.iris.gen.layer.GenLayerUpdate;
import com.volmit.iris.gen.scaffold.TerrainChunk;
import com.volmit.iris.gen.scaffold.TerrainTarget;
import com.volmit.iris.object.IrisBiome;
import com.volmit.iris.object.IrisBiomeMutation;
import com.volmit.iris.object.IrisObjectPlacement;
import com.volmit.iris.object.IrisRegion;
import com.volmit.iris.object.IrisStructurePlacement;
import com.volmit.iris.object.IrisTextPlacement;
import com.volmit.iris.util.BiomeMap;
import com.volmit.iris.util.CarveResult;
import com.volmit.iris.util.CaveResult;
import com.volmit.iris.util.ChunkPosition;
import com.volmit.iris.util.HeightMap;
import com.volmit.iris.util.IObjectPlacer;
import com.volmit.iris.util.IrisLock;
import com.volmit.iris.util.IrisStructureResult;
import com.volmit.iris.util.J;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.KMap;
import com.volmit.iris.util.PrecisionStopwatch;
import com.volmit.iris.util.RNG;
import com.volmit.iris.util.Spiraler;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class ParallaxTerrainProvider extends TopographicTerrainProvider implements IObjectPlacer
{
private short cacheID = 0;
private KMap<ChunkPosition, AtomicSliver> sliverCache;
private AtomicWorldData parallaxMap;
private MasterLock masterLock;
private IrisLock flock = new IrisLock("ParallaxLock");
private IrisLock lock = new IrisLock("ParallaxLock");
private GenLayerUpdate glUpdate;
private GenLayerText glText;
private int sliverBuffer;
public ParallaxTerrainProvider(TerrainTarget t, String dimensionName, int threads)
{
super(t, dimensionName, threads);
setSliverCache(new KMap<>());
setSliverBuffer(sliverBuffer);
setMasterLock(new MasterLock());
getMasterLock().disable();
}
public void onInit(RNG rng)
{
super.onInit(rng);
setParallaxMap(new AtomicWorldData(getTarget()));
setGlText(new GenLayerText(this, rng.nextParallelRNG(32485)));
setGlUpdate(null);
J.a(() -> getDimension().getParallaxSize(this));
}
protected void onClose()
{
super.onClose();
try
{
getParallaxMap().unloadAll(true);
}
catch(IOException e)
{
e.printStackTrace();
}
}
@Override
public int getHighest(int x, int z)
{
return getHighest(x, z, false);
}
@Override
public void onHotload()
{
getData().preferFolder(getDimension().getLoadFile().getParentFile().getParentFile().getName());
super.onHotload();
setCacheID(RNG.r.simax());
if(IrisSettings.get().isRegenerateLoadedChunksOnHotload())
{
World w = getTarget().getRealWorld();
if(w != null)
{
for(Player i : w.getPlayers())
{
new Spiraler(10, 10, (a, b) -> getProvisioner().regenerate(i.getLocation().getChunk().getX() + a, i.getLocation().getChunk().getZ() + b)).drain();
}
for(Chunk i : w.getLoadedChunks())
{
getProvisioner().regenerate(i.getX(), i.getZ());
}
}
}
}
@Override
public int getHighest(int x, int z, boolean ignoreFluid)
{
return getCarvedHeight(x, z, ignoreFluid);
}
@Override
public void set(int x, int y, int z, BlockData d)
{
getParallaxSliver(x, z).set(y, d);
}
@Override
public BlockData get(int x, int y, int z)
{
BlockData b = sampleSliver(x, z).getBlock()[y];
return b == null ? AIR : b;
}
@Override
public boolean isSolid(int x, int y, int z)
{
return get(x, y, z).getMaterial().isSolid();
}
public AtomicSliver getParallaxSliver(int wx, int wz)
{
getMasterLock().lock("gpc");
getMasterLock().lock((wx >> 4) + "." + (wz >> 4));
AtomicSliverMap map = getParallaxChunk(wx >> 4, wz >> 4);
getMasterLock().unlock("gpc");
AtomicSliver sliver = map.getSliver(wx & 15, wz & 15);
getMasterLock().unlock((wx >> 4) + "." + (wz >> 4));
return sliver;
}
public boolean isParallaxGenerated(int x, int z)
{
return getParallaxChunk(x, z).isParallaxGenerated();
}
public boolean isWorldGenerated(int x, int z)
{
return getParallaxChunk(x, z).isWorldGenerated();
}
public AtomicSliverMap getParallaxChunk(int x, int z)
{
try
{
return getParallaxMap().loadChunk(x, z);
}
catch(IOException e)
{
fail(e);
}
return new AtomicSliverMap();
}
@Override
public List<BlockPopulator> getPopulators()
{
List<BlockPopulator> g = new KList<>();
if(getGlUpdate() == null)
{
setGlUpdate(new GenLayerUpdate(this));
}
g.add(getGlUpdate());
return g;
}
public void forgetThisParallaxChunk(int x, int z)
{
getParallaxChunk(x, z).reset();
getSliverCache().clear();
getCache().drop();
}
public void forgetParallaxChunksNear(int x, int z)
{
getSliverCache().clear();
getCache().drop();
ChunkPosition rad = getDimension().getParallaxSize(this);
for(int ii = x - (rad.getX() / 2); ii <= x + (rad.getX() / 2); ii++)
{
for(int jj = z - (rad.getZ() / 2); jj <= z + (rad.getZ() / 2); jj++)
{
getParallaxChunk(ii, jj).reset();
}
}
}
@Override
protected void onPostGenerate(RNG random, int x, int z, TerrainChunk terrain, HeightMap height, BiomeMap biomeMap, AtomicSliverMap map)
{
if(getSliverCache().size() > 20000)
{
getSliverCache().clear();
}
super.onPostGenerate(random, x, z, terrain, height, biomeMap, map);
PrecisionStopwatch p = PrecisionStopwatch.start();
if(getDimension().isPlaceObjects())
{
onGenerateParallax(random, x, z);
getParallaxChunk(x, z).inject(terrain);
getParallaxChunk(x, z).injectUpdates(map);
getParallaxChunk(x, z).setWorldGenerated(true);
}
setSliverBuffer(getSliverCache().size());
getMasterLock().clear();
p.end();
getMetrics().getParallax().put(p.getMilliseconds());
super.onPostParallaxPostGenerate(random, x, z, terrain, height, biomeMap, map);
getParallaxMap().clean();
getData().getObjectLoader().clean();
}
public IrisStructureResult getStructure(int x, int y, int z)
{
return getParallaxChunk(x >> 4, z >> 4).getStructure(this, y);
}
protected void onGenerateParallax(RNG randomx, int x, int z)
{
String key = "par." + x + "." + z;
ChunkPosition rad = getDimension().getParallaxSize(this);
for(int ii = x - (rad.getX() / 2); ii <= x + (rad.getX() / 2); ii++)
{
int i = ii;
for(int jj = z - (rad.getZ() / 2); jj <= z + (rad.getZ() / 2); jj++)
{
int j = jj;
RNG salt = new RNG(2922 + i + j).nextParallelRNG(i - 293938).nextParallelRNG(j + 294416);
RNG random = getMasterRandom().nextParallelRNG(i + salt.imax()).nextParallelRNG(j + salt.imax());
if(isParallaxGenerated(ii, jj))
{
continue;
}
if(isWorldGenerated(ii, jj))
{
continue;
}
getAccelerant().queue(key, () ->
{
IrisBiome b = sampleTrueBiome((i * 16) + 7, (j * 16) + 7);
IrisRegion r = sampleRegion((i * 16) + 7, (j * 16) + 7);
RNG ro = getMasterRandom().nextParallelRNG(196888 + i + j + 2225).nextParallelRNG(salt.i(-i, i)).nextParallelRNG(salt.i(-j, j));
int g = 1;
g = placeMutations(ro, random, i, j, g);
g = placeText(random, r, b, i, j, g);
g = placeObjects(random, r, b, i, j, g);
g = placeCarveObjects(random, r, b, i, j, g);
g = placeCaveObjects(ro, random, i, j, g);
g = placeStructures(randomx, r, b, i, j, g);
});
getParallaxChunk(ii, jj).setParallaxGenerated(true);
}
}
getAccelerant().waitFor(key);
}
private int placeMutations(RNG ro, RNG random, int i, int j, int g)
{
searching: for(IrisBiomeMutation k : getDimension().getMutations())
{
for(int l = 0; l < k.getChecks(); l++)
{
IrisBiome sa = sampleTrueBiome(((i * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()), ((j * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()));
IrisBiome sb = sampleTrueBiome(((i * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()), ((j * 16) + ro.nextInt(16)) + ro.i(-k.getRadius(), k.getRadius()));
if(sa.getLoadKey().equals(sb.getLoadKey()))
{
continue;
}
if(k.getRealSideA(this).contains(sa.getLoadKey()) && k.getRealSideB(this).contains(sb.getLoadKey()))
{
for(IrisObjectPlacement m : k.getObjects())
{
placeObject(m, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + g++) * i * j) + i - j + 1569962));
}
continue searching;
}
}
}
return g;
}
private int placeText(RNG random, IrisRegion r, IrisBiome b, int i, int j, int g)
{
for(IrisTextPlacement k : getDimension().getText())
{
k.place(this, random.nextParallelRNG(g++ + -7228 + (34 * ((i * 30) + (j * 30)) * i * j) + i - j + 1569962), i, j);
}
for(IrisTextPlacement k : r.getText())
{
k.place(this, random.nextParallelRNG(g++ + -4228 + -7228 + (34 * ((i * 30) + (j * 30)) * i * j) + i - j + 1569962), i, j);
}
for(IrisTextPlacement k : b.getText())
{
k.place(this, random.nextParallelRNG(g++ + -22228 + -4228 + -7228 + (34 * ((i * 30) + (j * 30)) * i * j) + i - j + 1569962), i, j);
}
return g;
}
private int placeObjects(RNG random, IrisRegion r, IrisBiome b, int i, int j, int g)
{
for(IrisObjectPlacement k : b.getSurfaceObjects())
{
placeObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + g++) * i * j) + i - j + 3566522));
}
if(r == null)
{
Iris.error("R Null");
}
if(r.getSurfaceObjects() == null)
{
Iris.error("Surface objects null");
}
if(r != null)
{
for(IrisObjectPlacement k : r.getSurfaceObjects())
{
placeObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + g++) * i * j) + i - j + 3569222));
}
}
return g;
}
private int placeCarveObjects(RNG random, IrisRegion r, IrisBiome b, int i, int j, int g)
{
if(!getGlCarve().isCouldCarve())
{
return g;
}
KList<CarveResult> layers = getGlCarve().getCarveLayers((i * 16) + random.nextInt(16), (j * 16) + random.nextInt(16));
if(layers.isEmpty())
{
return g + 2;
}
for(CarveResult c : layers)
{
g = placeCarveObjects(random, r, b, i, j, g, c);
}
return g;
}
private int placeCarveObjects(RNG random, IrisRegion r, IrisBiome b, int i, int j, int g, CarveResult c)
{
for(IrisObjectPlacement k : b.getCarvingObjects())
{
placeCarveObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + g++) * i * j) + i - j + 3569221 + g), c);
}
for(IrisObjectPlacement k : r.getCarvingObjects())
{
placeCarveObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + g++) * i * j) + i - j + 3561222 + g), c);
}
return g;
}
private int placeCaveObjects(RNG ro, RNG random, int i, int j, int g)
{
if(!getDimension().isCaves())
{
return g;
}
int bx = (i * 16) + ro.nextInt(16);
int bz = (j * 16) + ro.nextInt(16);
IrisBiome biome = sampleCaveBiome(bx, bz);
if(biome == null)
{
return g;
}
if(biome.getObjects().isEmpty())
{
return g;
}
for(IrisObjectPlacement k : biome.getObjects())
{
int gg = g++;
placeCaveObject(k, i, j, random.nextParallelRNG((34 * ((i * 30) + (j * 30) + gg) * i * j) + i - j + 1869322));
}
return g;
}
private int placeStructures(RNG random, IrisRegion r, IrisBiome b, int i, int j, int g)
{
for(IrisStructurePlacement k : r.getStructures())
{
k.place(this, random.nextParallelRNG(2228 * 2 * g++), i, j);
}
for(IrisStructurePlacement k : b.getStructures())
{
k.place(this, random.nextParallelRNG(-22228 * 4 * g++), i, j);
}
return g;
}
public void placeObject(IrisObjectPlacement o, int x, int z, RNG rng)
{
for(int i = 0; i < o.getTriesForChunk(rng); i++)
{
rng = rng.nextParallelRNG((i * 3 + 8) - 23040);
o.getSchematic(this, rng).place((x * 16) + rng.nextInt(16), (z * 16) + rng.nextInt(16), this, o, rng, getData());
}
}
public void placeCarveObject(IrisObjectPlacement o, int x, int z, RNG rng, CarveResult c)
{
for(int i = 0; i < o.getTriesForChunk(rng); i++)
{
rng = rng.nextParallelRNG((i * 3 + 8) - 23040);
o.getSchematic(this, rng).place((x * 16) + rng.nextInt(16), (z * 16) + rng.nextInt(16), this, o, rng, c, getData());
}
}
public void placeCaveObject(IrisObjectPlacement o, int x, int z, RNG rng)
{
for(int i = 0; i < o.getTriesForChunk(rng); i++)
{
rng = rng.nextParallelRNG((i * 3 + 8) - 23040);
int xx = (x * 16) + rng.nextInt(16);
int zz = (z * 16) + rng.nextInt(16);
KList<CaveResult> res = getCaves(xx, zz);
if(res.isEmpty())
{
continue;
}
o.getSchematic(this, rng).place(xx, res.get(rng.nextParallelRNG(29345 * (i + 234)).nextInt(res.size())).getFloor() + 2, zz, this, o, rng, getData());
}
}
public AtomicSliver sampleSliver(int x, int z)
{
ChunkPosition key = new ChunkPosition(x, z);
if(getSliverCache().containsKey(key))
{
return getSliverCache().get(key);
}
AtomicSliver s = new AtomicSliver(x & 15, z & 15);
onGenerateColumn(x >> 4, z >> 4, x, z, x & 15, z & 15, s, null, true);
getSliverCache().put(key, s);
return s;
}
@Override
public boolean isDebugSmartBore()
{
return getDimension().isDebugSmartBore();
}
@Override
public boolean isPreventingDecay()
{
return getDimension().isPreventLeafDecay();
}
}