mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-23 09:09:15 +00:00
Fix seed drift
This commit is contained in:
@@ -501,7 +501,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
|
|
||||||
IrisWorld w = IrisWorld.builder()
|
IrisWorld w = IrisWorld.builder()
|
||||||
.name(worldName)
|
.name(worldName)
|
||||||
.seed(RNG.r.lmax())
|
.seed(1337)
|
||||||
.environment(dim.getEnvironment())
|
.environment(dim.getEnvironment())
|
||||||
.worldFolder(new File(worldName))
|
.worldFolder(new File(worldName))
|
||||||
.minHeight(0)
|
.minHeight(0)
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class IrisPapiExpansion extends PlaceholderExpansion {
|
|||||||
}
|
}
|
||||||
} else if (p.equalsIgnoreCase("world_seed")) {
|
} else if (p.equalsIgnoreCase("world_seed")) {
|
||||||
if (a != null) {
|
if (a != null) {
|
||||||
return a.getTarget().getWorld().seed() + "";
|
return a.getEngine().getSeedManager().getSeed() + "";
|
||||||
}
|
}
|
||||||
} else if (p.equalsIgnoreCase("world_speed")) {
|
} else if (p.equalsIgnoreCase("world_speed")) {
|
||||||
if (a != null) {
|
if (a != null) {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public class IrisCreator {
|
|||||||
/**
|
/**
|
||||||
* The seed to use for this generator
|
* The seed to use for this generator
|
||||||
*/
|
*/
|
||||||
private long seed = RNG.r.nextLong();
|
private long seed = 1337;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The dimension to use. This can be any online dimension, or a dimension in the
|
* The dimension to use. This can be any online dimension, or a dimension in the
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package com.volmit.iris.engine;
|
|||||||
import com.google.common.util.concurrent.AtomicDouble;
|
import com.google.common.util.concurrent.AtomicDouble;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
|
import com.volmit.iris.engine.data.cache.Cache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.object.*;
|
import com.volmit.iris.engine.object.*;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
@@ -69,8 +70,6 @@ public class IrisComplex implements DataProvider {
|
|||||||
private ProceduralStream<Integer> trueHeightStreamNoFeatures;
|
private ProceduralStream<Integer> trueHeightStreamNoFeatures;
|
||||||
private ProceduralStream<Double> slopeStream;
|
private ProceduralStream<Double> slopeStream;
|
||||||
private ProceduralStream<Integer> topSurfaceStream;
|
private ProceduralStream<Integer> topSurfaceStream;
|
||||||
private ProceduralStream<RNG> rngStream;
|
|
||||||
private ProceduralStream<RNG> chunkRngStream;
|
|
||||||
private ProceduralStream<IrisDecorator> terrainSurfaceDecoration;
|
private ProceduralStream<IrisDecorator> terrainSurfaceDecoration;
|
||||||
private ProceduralStream<IrisDecorator> terrainCeilingDecoration;
|
private ProceduralStream<IrisDecorator> terrainCeilingDecoration;
|
||||||
private ProceduralStream<IrisDecorator> terrainCaveSurfaceDecoration;
|
private ProceduralStream<IrisDecorator> terrainCaveSurfaceDecoration;
|
||||||
@@ -108,7 +107,7 @@ public class IrisComplex implements DataProvider {
|
|||||||
int cacheSize = 131072;
|
int cacheSize = 131072;
|
||||||
IrisBiome emptyBiome = new IrisBiome();
|
IrisBiome emptyBiome = new IrisBiome();
|
||||||
UUID focusUUID = UUID.nameUUIDFromBytes("focus".getBytes());
|
UUID focusUUID = UUID.nameUUIDFromBytes("focus".getBytes());
|
||||||
this.rng = new RNG(engine.getWorld().seed());
|
this.rng = new RNG(engine.getSeedManager().getComplex());
|
||||||
this.data = engine.getData();
|
this.data = engine.getData();
|
||||||
double height = engine.getHeight();
|
double height = engine.getHeight();
|
||||||
fluidHeight = engine.getDimension().getFluidHeight();
|
fluidHeight = engine.getDimension().getFluidHeight();
|
||||||
@@ -121,7 +120,6 @@ public class IrisComplex implements DataProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IrisRegion focusRegion = focus != null ? findRegion(focus, engine) : null;
|
IrisRegion focusRegion = focus != null ? findRegion(focus, engine) : null;
|
||||||
RNG rng = new RNG(engine.getWorld().seed());
|
|
||||||
//@builder
|
//@builder
|
||||||
engine.getDimension().getRegions().forEach((i) -> data.getRegionLoader().load(i)
|
engine.getDimension().getRegions().forEach((i) -> data.getRegionLoader().load(i)
|
||||||
.getAllBiomes(this).forEach((b) -> b
|
.getAllBiomes(this).forEach((b) -> b
|
||||||
@@ -129,9 +127,6 @@ public class IrisComplex implements DataProvider {
|
|||||||
.forEach((c) -> registerGenerator(c.getCachedGenerator(this)))));
|
.forEach((c) -> registerGenerator(c.getCachedGenerator(this)))));
|
||||||
overlayStream = ProceduralStream.ofDouble((x, z) -> 0D);
|
overlayStream = ProceduralStream.ofDouble((x, z) -> 0D);
|
||||||
engine.getDimension().getOverlayNoise().forEach((i) -> overlayStream.add((x, z) -> i.get(rng, getData(), x, z)));
|
engine.getDimension().getOverlayNoise().forEach((i) -> overlayStream.add((x, z) -> i.get(rng, getData(), x, z)));
|
||||||
rngStream = ProceduralStream.of((x, z) -> new RNG(((x.longValue()) << 32) | (z.longValue() & 0xffffffffL))
|
|
||||||
.nextParallelRNG(engine.getWorld().seed()), Interpolated.RNG);
|
|
||||||
chunkRngStream = rngStream.blockToChunkCoords();
|
|
||||||
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
|
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
|
||||||
.select(engine.getDimension().getRockPalette().getBlockData(data));
|
.select(engine.getDimension().getRockPalette().getBlockData(data));
|
||||||
fluidStream = engine.getDimension().getFluidPalette().getLayerGenerator(rng.nextParallelRNG(78), data).stream()
|
fluidStream = engine.getDimension().getFluidPalette().getLayerGenerator(rng.nextParallelRNG(78), data).stream()
|
||||||
@@ -198,11 +193,11 @@ public class IrisComplex implements DataProvider {
|
|||||||
.convertAware2D(this::implode).cache2D(cacheSize);
|
.convertAware2D(this::implode).cache2D(cacheSize);
|
||||||
heightStream = ProceduralStream.of((x, z) -> {
|
heightStream = ProceduralStream.of((x, z) -> {
|
||||||
IrisBiome b = focus != null ? focus : baseBiomeStream.get(x, z);
|
IrisBiome b = focus != null ? focus : baseBiomeStream.get(x, z);
|
||||||
return getHeight(engine, b, x, z, engine.getWorld().seed(), true);
|
return getHeight(engine, b, x, z, engine.getSeedManager().getHeight(), true);
|
||||||
}, Interpolated.DOUBLE).clamp(0, engine.getHeight()).cache2D(cacheSize);
|
}, Interpolated.DOUBLE).clamp(0, engine.getHeight()).cache2D(cacheSize);
|
||||||
heightStreamNoFeatures = ProceduralStream.of((x, z) -> {
|
heightStreamNoFeatures = ProceduralStream.of((x, z) -> {
|
||||||
IrisBiome b = focus != null ? focus : baseBiomeStream.get(x, z);
|
IrisBiome b = focus != null ? focus : baseBiomeStream.get(x, z);
|
||||||
return getHeight(engine, b, x, z, engine.getWorld().seed(), false);
|
return getHeight(engine, b, x, z, engine.getSeedManager().getHeight(), false);
|
||||||
}, Interpolated.DOUBLE).clamp(0, engine.getHeight()).cache2D(cacheSize);
|
}, Interpolated.DOUBLE).clamp(0, engine.getHeight()).cache2D(cacheSize);
|
||||||
slopeStream = heightStream.slope(3).cache2D(cacheSize);
|
slopeStream = heightStream.slope(3).cache2D(cacheSize);
|
||||||
objectChanceStream = ProceduralStream.ofDouble((x, z) -> {
|
objectChanceStream = ProceduralStream.ofDouble((x, z) -> {
|
||||||
@@ -332,7 +327,7 @@ public class IrisComplex implements DataProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private IrisDecorator decorateFor(IrisBiome b, double x, double z, IrisDecorationPart part) {
|
private IrisDecorator decorateFor(IrisBiome b, double x, double z, IrisDecorationPart part) {
|
||||||
RNG rngc = chunkRngStream.get(x, z);
|
RNG rngc = new RNG(Cache.key(((int)x), ((int)z)));
|
||||||
|
|
||||||
for (IrisDecorator i : b.getDecorators()) {
|
for (IrisDecorator i : b.getDecorators()) {
|
||||||
if (!i.getPartOf().equals(part)) {
|
if (!i.getPartOf().equals(part)) {
|
||||||
|
|||||||
@@ -100,10 +100,14 @@ public class IrisEngine implements Engine {
|
|||||||
private final AtomicCache<IrisEngineData> engineData = new AtomicCache<>();
|
private final AtomicCache<IrisEngineData> engineData = new AtomicCache<>();
|
||||||
private final AtomicBoolean cleaning;
|
private final AtomicBoolean cleaning;
|
||||||
private final ChronoLatch cleanLatch;
|
private final ChronoLatch cleanLatch;
|
||||||
|
private final SeedManager seedManager;
|
||||||
|
|
||||||
public IrisEngine(EngineTarget target, boolean studio) {
|
public IrisEngine(EngineTarget target, boolean studio) {
|
||||||
this.studio = studio;
|
this.studio = studio;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
getEngineData();
|
||||||
|
verifySeed();
|
||||||
|
this.seedManager = new SeedManager(target.getWorld().getRawWorldSeed());
|
||||||
bud = new AtomicInteger(0);
|
bud = new AtomicInteger(0);
|
||||||
buds = new AtomicInteger(0);
|
buds = new AtomicInteger(0);
|
||||||
metrics = new EngineMetrics(32);
|
metrics = new EngineMetrics(32);
|
||||||
@@ -120,9 +124,8 @@ public class IrisEngine implements Engine {
|
|||||||
context = new IrisContext(this);
|
context = new IrisContext(this);
|
||||||
cleaning = new AtomicBoolean(false);
|
cleaning = new AtomicBoolean(false);
|
||||||
context.touch();
|
context.touch();
|
||||||
Iris.info("Initializing Engine: " + target.getWorld().name() + "/" + target.getDimension().getLoadKey() + " (" + 256 + " height)");
|
Iris.info("Initializing Engine: " + target.getWorld().name() + "/" + target.getDimension().getLoadKey() + " (" + 256 + " height) Seed: " + getSeedManager().toString());
|
||||||
getData().setEngine(this);
|
getData().setEngine(this);
|
||||||
getEngineData();
|
|
||||||
minHeight = 0;
|
minHeight = 0;
|
||||||
failing = false;
|
failing = false;
|
||||||
closed = false;
|
closed = false;
|
||||||
@@ -131,6 +134,13 @@ public class IrisEngine implements Engine {
|
|||||||
Iris.debug("Engine Initialized " + getCacheID());
|
Iris.debug("Engine Initialized " + getCacheID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verifySeed() {
|
||||||
|
if(getEngineData().getSeed() != null && getEngineData().getSeed() != target.getWorld().getRawWorldSeed())
|
||||||
|
{
|
||||||
|
target.getWorld().setRawWorldSeed(getEngineData().getSeed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void tickRandomPlayer() {
|
private void tickRandomPlayer() {
|
||||||
if (perSecondBudLatch.flip()) {
|
if (perSecondBudLatch.flip()) {
|
||||||
buds.set(bud.get());
|
buds.set(bud.get());
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class IrisBiomeActuator extends EngineAssignedActuator<Biome> {
|
|||||||
|
|
||||||
public IrisBiomeActuator(Engine engine) {
|
public IrisBiomeActuator(Engine engine) {
|
||||||
super(engine, "Biome");
|
super(engine, "Biome");
|
||||||
rng = new RNG(engine.getWorld().seed() + 243995);
|
rng = new RNG(engine.getSeedManager().getBiome());
|
||||||
}
|
}
|
||||||
|
|
||||||
@BlockCoordinates
|
@BlockCoordinates
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class IrisDecorantActuator extends EngineAssignedActuator<BlockData> {
|
|||||||
public IrisDecorantActuator(Engine engine) {
|
public IrisDecorantActuator(Engine engine) {
|
||||||
super(engine, "Decorant");
|
super(engine, "Decorant");
|
||||||
shouldRay = shouldRayDecorate();
|
shouldRay = shouldRayDecorate();
|
||||||
this.rng = new RNG(engine.getTarget().getWorld().seed());
|
this.rng = new RNG(engine.getSeedManager().getDecorator());
|
||||||
surfaceDecorator = new IrisSurfaceDecorator(getEngine());
|
surfaceDecorator = new IrisSurfaceDecorator(getEngine());
|
||||||
ceilingDecorator = new IrisCeilingDecorator(getEngine());
|
ceilingDecorator = new IrisCeilingDecorator(getEngine());
|
||||||
seaSurfaceDecorator = new IrisSeaSurfaceDecorator(getEngine());
|
seaSurfaceDecorator = new IrisSeaSurfaceDecorator(getEngine());
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
|
|||||||
|
|
||||||
public IrisTerrainNormalActuator(Engine engine) {
|
public IrisTerrainNormalActuator(Engine engine) {
|
||||||
super(engine, "Terrain");
|
super(engine, "Terrain");
|
||||||
rng = new RNG(engine.getWorld().seed());
|
rng = new RNG(engine.getSeedManager().getTerrain());
|
||||||
}
|
}
|
||||||
|
|
||||||
@BlockCoordinates
|
@BlockCoordinates
|
||||||
|
|||||||
@@ -146,6 +146,8 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
saveEngineData();
|
saveEngineData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SeedManager getSeedManager();
|
||||||
|
|
||||||
void saveEngineData();
|
void saveEngineData();
|
||||||
|
|
||||||
default String getName() {
|
default String getName() {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
|
|||||||
public void on(EntitySpawnEvent e) {
|
public void on(EntitySpawnEvent e) {
|
||||||
if (e.getEntity().getWorld().equals(getTarget().getWorld().realWorld())) {
|
if (e.getEntity().getWorld().equals(getTarget().getWorld().realWorld())) {
|
||||||
if (e.getEntityType().equals(EntityType.ENDER_SIGNAL)) {
|
if (e.getEntityType().equals(EntityType.ENDER_SIGNAL)) {
|
||||||
KList<Position2> p = getEngine().getDimension().getStrongholds(getEngine().getWorld().seed());
|
KList<Position2> p = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getSpawn());
|
||||||
Position2 px = new Position2(e.getEntity().getLocation().getBlockX(), e.getEntity().getLocation().getBlockZ());
|
Position2 px = new Position2(e.getEntity().getLocation().getBlockX(), e.getEntity().getLocation().getBlockZ());
|
||||||
Position2 pr = null;
|
Position2 pr = null;
|
||||||
double d = Double.MAX_VALUE;
|
double d = Double.MAX_VALUE;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public interface EngineComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default long getSeed() {
|
default long getSeed() {
|
||||||
return getTarget().getWorld().seed();
|
return getEngine().getSeedManager().getComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
default int getParallelism() {
|
default int getParallelism() {
|
||||||
|
|||||||
107
src/main/java/com/volmit/iris/engine/framework/SeedManager.java
Normal file
107
src/main/java/com/volmit/iris/engine/framework/SeedManager.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.engine.framework;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.object.NoiseStyle;
|
||||||
|
import com.volmit.iris.util.math.RNG;
|
||||||
|
import com.volmit.iris.util.noise.CNG;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SeedManager
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
private static final String IRIS_SIGNATURE = "Iris World Generator";
|
||||||
|
private static final long IRIS_TERRAIN_VERSION = 1;
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Setter(AccessLevel.NONE)
|
||||||
|
private long fullMixedSeed;
|
||||||
|
private final RNG rlock;
|
||||||
|
private final CNG soup;
|
||||||
|
private final long seed;
|
||||||
|
private final long complex;
|
||||||
|
private final long complexStreams;
|
||||||
|
private final long basic;
|
||||||
|
private final long height;
|
||||||
|
private final long component;
|
||||||
|
private final long script;
|
||||||
|
private final long mantle;
|
||||||
|
private final long entity;
|
||||||
|
private final long biome;
|
||||||
|
private final long decorator;
|
||||||
|
private final long terrain;
|
||||||
|
private final long spawn;
|
||||||
|
private final long jigsaw;
|
||||||
|
private final long carve;
|
||||||
|
private final long deposit;
|
||||||
|
private final long post;
|
||||||
|
|
||||||
|
public SeedManager(long seed)
|
||||||
|
{
|
||||||
|
soup = createSoup(seed);
|
||||||
|
rlock = new RNG(Double.doubleToLongBits(soup.fitDouble(Double.MIN_VALUE, Double.MAX_VALUE, seed + 1337, seed * 69, seed)));
|
||||||
|
this.seed = seed;
|
||||||
|
complex = of("complex");
|
||||||
|
complexStreams = of("complex_streams");
|
||||||
|
basic = of("basic");
|
||||||
|
height = of("height");
|
||||||
|
component = of("component");
|
||||||
|
script = of("script");
|
||||||
|
mantle = of("mantle");
|
||||||
|
entity = of("entity");
|
||||||
|
biome = of("biome");
|
||||||
|
decorator = of("decorator");
|
||||||
|
terrain = of("terrain");
|
||||||
|
spawn = of("spawn");
|
||||||
|
jigsaw = of("jigsaw");
|
||||||
|
carve = of("carve");
|
||||||
|
deposit = of("deposit");
|
||||||
|
post = of("post");
|
||||||
|
}
|
||||||
|
|
||||||
|
private long of(String name)
|
||||||
|
{
|
||||||
|
RNG rng = new RNG(name + IRIS_SIGNATURE + "::" + IRIS_TERRAIN_VERSION + ((seed + rlock.imax()) * rlock.lmax()));
|
||||||
|
long f = rlock.imax() * ((rlock.chance(0.5) ? 1 : -1) * (name.hashCode() + Double.doubleToLongBits(soup.fitDouble(Double.MIN_VALUE, Double.MAX_VALUE, rng.imax(), rng.imax(), rng.imax()))));
|
||||||
|
fullMixedSeed += (f * rlock.imax());
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CNG createSoup(long seed) {
|
||||||
|
RNG a = new RNG((seed - 2043905) * 4_385_677_888L);
|
||||||
|
RNG b = new RNG((seed * -305) + 45_858_458_555L);
|
||||||
|
RNG c = new RNG((seed * (a.lmax() - b.lmax())) + IRIS_SIGNATURE.hashCode());
|
||||||
|
RNG d = new RNG((seed - (c.lmax() * -IRIS_TERRAIN_VERSION)) + IRIS_TERRAIN_VERSION);
|
||||||
|
RNG e = new RNG((IRIS_TERRAIN_VERSION * 42) + IRIS_SIGNATURE);
|
||||||
|
double gsoup = 0;
|
||||||
|
int gk = a.i(1_000, 10_000);
|
||||||
|
for(char i : (a.s(4) + b.s(4) + c.s(4) + d.s(4) + e.s(4)).toCharArray())
|
||||||
|
{
|
||||||
|
gsoup += ((gk * b.d(3, Math.PI)) / c.d(10, 18 * Math.E)) + 6_549;
|
||||||
|
gsoup *= d.d(90.5, 1_234_567);
|
||||||
|
gsoup += e.d(39.95, 99.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoiseStyle.STATIC.create(new RNG(4_966_866 * Double.doubleToLongBits((gsoup * a.imax() + b.imax() + c.lmax() + d.lmax()) * e.lmax())));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ public interface MantleComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default long seed() {
|
default long seed() {
|
||||||
return getEngineMantle().getEngine().getTarget().getWorld().seed();
|
return getEngineMantle().getEngine().getSeedManager().getMantle();
|
||||||
}
|
}
|
||||||
|
|
||||||
default BurstExecutor burst() {
|
default BurstExecutor burst() {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
|
|||||||
|
|
||||||
public MantleJigsawComponent(EngineMantle engineMantle) {
|
public MantleJigsawComponent(EngineMantle engineMantle) {
|
||||||
super(engineMantle, MantleFlag.JIGSAW);
|
super(engineMantle, MantleFlag.JIGSAW);
|
||||||
cng = NoiseStyle.STATIC.create(new RNG(engineMantle.getEngine().getWorld().seed() + 24398848585L));
|
cng = NoiseStyle.STATIC.create(new RNG(engineMantle.getEngine().getSeedManager().getJigsaw()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
|
|||||||
|
|
||||||
public IrisCarveModifier(Engine engine) {
|
public IrisCarveModifier(Engine engine) {
|
||||||
super(engine, "Carve");
|
super(engine, "Carve");
|
||||||
rng = new RNG(getEngine().getWorld().seed() + 3297778).nextParallelRNG(67648777);
|
rng = new RNG(getEngine().getSeedManager().getCarve());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
|
|||||||
|
|
||||||
public IrisDepositModifier(Engine engine) {
|
public IrisDepositModifier(Engine engine) {
|
||||||
super(engine, "Deposit");
|
super(engine, "Deposit");
|
||||||
rng = new RNG(getEngine().getWorld().seed() + 12938).nextParallelRNG(28348777);
|
rng = new RNG(getEngine().getSeedManager().getDeposit());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class IrisPostModifier extends EngineAssignedModifier<BlockData> {
|
|||||||
|
|
||||||
public IrisPostModifier(Engine engine) {
|
public IrisPostModifier(Engine engine) {
|
||||||
super(engine, "Post");
|
super(engine, "Post");
|
||||||
rng = new RNG(getEngine().getWorld().seed() + 12938).nextParallelRNG(28348777);
|
rng = new RNG(getEngine().getSeedManager().getPost());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public class HeadlessWorld {
|
|||||||
public World load() {
|
public World load() {
|
||||||
World w = new WorldCreator(worldName)
|
World w = new WorldCreator(worldName)
|
||||||
.environment(dimension.getEnvironment())
|
.environment(dimension.getEnvironment())
|
||||||
.seed(world.seed())
|
.seed(world.getRawWorldSeed())
|
||||||
.generator(new BukkitChunkGenerator(world, studio, dimension.getLoader().getDataFolder(),
|
.generator(new BukkitChunkGenerator(world, studio, dimension.getLoader().getDataFolder(),
|
||||||
dimension.getLoadKey()))
|
dimension.getLoadKey()))
|
||||||
.createWorld();
|
.createWorld();
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public class IrisEngineData {
|
|||||||
private IrisEngineStatistics statistics = new IrisEngineStatistics();
|
private IrisEngineStatistics statistics = new IrisEngineStatistics();
|
||||||
private KList<IrisEngineSpawnerCooldown> spawnerCooldowns = new KList<>();
|
private KList<IrisEngineSpawnerCooldown> spawnerCooldowns = new KList<>();
|
||||||
private KList<IrisEngineChunkData> chunks = new KList<>();
|
private KList<IrisEngineChunkData> chunks = new KList<>();
|
||||||
|
private Long seed = null;
|
||||||
|
|
||||||
public void removeChunk(int x, int z) {
|
public void removeChunk(int x, int z) {
|
||||||
long k = Cache.key(x, z);
|
long k = Cache.key(x, z);
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ public class IrisEntitySpawn implements IRare {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rng.aquire(() -> new RNG(g.getTarget().getWorld().seed() + 4)).i(1, getRarity()) == 1) {
|
if (rng.aquire(() -> new RNG(g.getSeedManager().getEntity())).i(1, getRarity()) == 1) {
|
||||||
return spawn100(g, at);
|
return spawn100(g, at);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ public class IrisEntitySpawn implements IRare {
|
|||||||
if (!irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock()))
|
if (!irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock()))
|
||||||
return null; //Make sure it can spawn on the block
|
return null; //Make sure it can spawn on the block
|
||||||
|
|
||||||
Entity e = irisEntity.spawn(g, at.add(0.5, 0, 0.5), rng.aquire(() -> new RNG(g.getTarget().getWorld().seed() + 4)));
|
Entity e = irisEntity.spawn(g, at.add(0.5, 0, 0.5), rng.aquire(() -> new RNG(g.getSeedManager().getEntity())));
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
Iris.debug("Spawned " + C.DARK_AQUA + "Entity<" + getEntity() + "> " + C.GREEN + e.getType() + C.LIGHT_PURPLE + " @ " + C.GRAY + e.getLocation().getX() + ", " + e.getLocation().getY() + ", " + e.getLocation().getZ());
|
Iris.debug("Spawned " + C.DARK_AQUA + "Entity<" + getEntity() + "> " + C.GREEN + e.getType() + C.LIGHT_PURPLE + " @ " + C.GRAY + e.getLocation().getX() + ", " + e.getLocation().getY() + ", " + e.getLocation().getZ());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
|
||||||
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.volmit.iris.engine.object;
|
|
||||||
|
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import com.volmit.iris.engine.object.annotations.*;
|
|
||||||
import com.volmit.iris.util.math.RNG;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.EntityType;
|
|
||||||
import org.bukkit.event.entity.EntitySpawnEvent;
|
|
||||||
|
|
||||||
@Snippet("entity-spawn-override")
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Desc("Represents an entity spawn")
|
|
||||||
@Data
|
|
||||||
public class IrisEntitySpawnOverride {
|
|
||||||
@RegistryListResource(IrisEntity.class)
|
|
||||||
@Required
|
|
||||||
@Desc("The entity")
|
|
||||||
private String entity = "";
|
|
||||||
|
|
||||||
@Required
|
|
||||||
@Desc("If the following entity type spawns, spawn this entity. Set to unknown for any entity spawn")
|
|
||||||
private EntityType trigger = EntityType.UNKNOWN;
|
|
||||||
|
|
||||||
@Desc("If the source is triggered, cancel spawning the original entity instead of ADDING a new entity.")
|
|
||||||
private boolean cancelSourceSpawn = false;
|
|
||||||
|
|
||||||
@MinNumber(1)
|
|
||||||
@Desc("The 1 in RARITY chance for this entity to spawn")
|
|
||||||
private int rarity = 1;
|
|
||||||
|
|
||||||
private final transient AtomicCache<RNG> rng = new AtomicCache<>();
|
|
||||||
private final transient AtomicCache<IrisEntity> ent = new AtomicCache<>();
|
|
||||||
|
|
||||||
|
|
||||||
public Entity on(Engine g, Location at, EntityType t, EntitySpawnEvent ee) {
|
|
||||||
if (!trigger.equals(EntityType.UNKNOWN)) {
|
|
||||||
if (!trigger.equals(t)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity e = spawn(g, at);
|
|
||||||
|
|
||||||
if (e != null && isCancelSourceSpawn()) {
|
|
||||||
ee.setCancelled(true);
|
|
||||||
ee.getEntity().remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Entity spawn(Engine g, Location at) {
|
|
||||||
if (getRealEntity(g) == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rng.aquire(() -> new RNG(g.getTarget().getWorld().seed() + 4)).i(1, getRarity()) == 1) {
|
|
||||||
return getRealEntity(g).spawn(g, at, rng.aquire(() -> new RNG(g.getTarget().getWorld().seed() + 4)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IrisEntity getRealEntity(Engine g) {
|
|
||||||
return ent.aquire(() -> g.getData().getEntityLoader().load(getEntity()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,8 +21,7 @@ package com.volmit.iris.engine.object;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import lombok.Builder;
|
import lombok.*;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -42,6 +41,9 @@ public class IrisWorld {
|
|||||||
private static final KList<? extends Entity> NO_ENTITIES = new KList<>();
|
private static final KList<? extends Entity> NO_ENTITIES = new KList<>();
|
||||||
private String name;
|
private String name;
|
||||||
private File worldFolder;
|
private File worldFolder;
|
||||||
|
|
||||||
|
@Getter(AccessLevel.NONE)
|
||||||
|
@Setter(AccessLevel.NONE)
|
||||||
private long seed;
|
private long seed;
|
||||||
private World.Environment environment;
|
private World.Environment environment;
|
||||||
private World realWorld;
|
private World realWorld;
|
||||||
@@ -55,13 +57,22 @@ public class IrisWorld {
|
|||||||
private static IrisWorld bindWorld(IrisWorld iw, World world) {
|
private static IrisWorld bindWorld(IrisWorld iw, World world) {
|
||||||
return iw.name(world.getName())
|
return iw.name(world.getName())
|
||||||
.worldFolder(world.getWorldFolder())
|
.worldFolder(world.getWorldFolder())
|
||||||
.seed(world.getSeed())
|
|
||||||
.minHeight(world.getMinHeight())
|
.minHeight(world.getMinHeight())
|
||||||
.maxHeight(world.getMaxHeight())
|
.maxHeight(world.getMaxHeight())
|
||||||
.realWorld(world)
|
.realWorld(world)
|
||||||
.environment(world.getEnvironment());
|
.environment(world.getEnvironment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getRawWorldSeed()
|
||||||
|
{
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRawWorldSeed(long seed)
|
||||||
|
{
|
||||||
|
this.seed = seed;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean tryGetRealWorld() {
|
public boolean tryGetRealWorld() {
|
||||||
if (hasRealWorld()) {
|
if (hasRealWorld()) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import java.io.File;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@@ -73,18 +74,18 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
private final ReactiveFolder folder;
|
private final ReactiveFolder folder;
|
||||||
private final KList<BlockPopulator> populators;
|
private final KList<BlockPopulator> populators;
|
||||||
private final ChronoLatch hotloadChecker;
|
private final ChronoLatch hotloadChecker;
|
||||||
private final Looper hotloader;
|
private Looper hotloader;
|
||||||
|
private final AtomicBoolean setup;
|
||||||
private StudioMode lastMode;
|
private StudioMode lastMode;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private StudioGenerator studioGenerator;
|
private StudioGenerator studioGenerator;
|
||||||
private final boolean studio;
|
private final boolean studio;
|
||||||
private long lastSeed;
|
|
||||||
|
|
||||||
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
|
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
|
||||||
|
setup = new AtomicBoolean(false);
|
||||||
studioGenerator = null;
|
studioGenerator = null;
|
||||||
populators = new KList<>();
|
populators = new KList<>();
|
||||||
lastSeed = world.seed();
|
|
||||||
loadLock = new Semaphore(LOAD_LOCKS);
|
loadLock = new Semaphore(LOAD_LOCKS);
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.hotloadChecker = new ChronoLatch(1000, false);
|
this.hotloadChecker = new ChronoLatch(1000, false);
|
||||||
@@ -92,23 +93,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
this.dataLocation = dataLocation;
|
this.dataLocation = dataLocation;
|
||||||
this.dimensionKey = dimensionKey;
|
this.dimensionKey = dimensionKey;
|
||||||
this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload());
|
this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload());
|
||||||
setupEngine();
|
|
||||||
this.hotloader = studio ? new Looper() {
|
|
||||||
@Override
|
|
||||||
protected long loop() {
|
|
||||||
if (hotloadChecker.flip()) {
|
|
||||||
folder.check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 250;
|
|
||||||
}
|
|
||||||
} : null;
|
|
||||||
|
|
||||||
if (studio) {
|
|
||||||
hotloader.setPriority(Thread.MIN_PRIORITY);
|
|
||||||
hotloader.start();
|
|
||||||
hotloader.setName(getTarget().getWorld().name() + " Hotloader");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupEngine() {
|
private void setupEngine() {
|
||||||
@@ -153,14 +137,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
@Override
|
@Override
|
||||||
public void injectChunkReplacement(World world, int x, int z, Consumer<Runnable> jobs) {
|
public void injectChunkReplacement(World world, int x, int z, Consumer<Runnable> jobs) {
|
||||||
try {
|
try {
|
||||||
if (lastSeed != world.getSeed()) {
|
|
||||||
Iris.debug("Seed for engine " + lastSeed + " does not match world seed if " + world.getSeed());
|
|
||||||
lastSeed = world.getSeed();
|
|
||||||
engine.getTarget().getWorld().seed(lastSeed);
|
|
||||||
engine.hotload();
|
|
||||||
Iris.debug("Updated Engine seed to " + lastSeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadLock.acquire();
|
loadLock.acquire();
|
||||||
IrisBiomeStorage st = new IrisBiomeStorage();
|
IrisBiomeStorage st = new IrisBiomeStorage();
|
||||||
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
|
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
|
||||||
@@ -204,17 +180,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadLock.release();
|
loadLock.release();
|
||||||
} catch (WrongEngineBroException e) {
|
|
||||||
Iris.warn("Trying to generate with a shut-down engine! Did you reload? Attempting to resolve this...");
|
|
||||||
|
|
||||||
try {
|
|
||||||
setupEngine();
|
|
||||||
Iris.success("Resolved! Should generate now!");
|
|
||||||
} catch (Throwable fe) {
|
|
||||||
Iris.error("FATAL! Iris cannot generate in this world since it was reloaded! This will cause a crash, with missing chunks, so we're crashing right now!");
|
|
||||||
Bukkit.shutdown();
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
loadLock.release();
|
loadLock.release();
|
||||||
Iris.error("======================================");
|
Iris.error("======================================");
|
||||||
@@ -232,6 +197,40 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Engine getEngine(World world)
|
||||||
|
{
|
||||||
|
if(setup.get())
|
||||||
|
{
|
||||||
|
return getEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
getWorld().setRawWorldSeed(world.getSeed());
|
||||||
|
setupEngine();
|
||||||
|
this.hotloader = studio ? new Looper() {
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
if (hotloadChecker.flip()) {
|
||||||
|
folder.check();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 250;
|
||||||
|
}
|
||||||
|
} : null;
|
||||||
|
|
||||||
|
if (studio) {
|
||||||
|
hotloader.setPriority(Thread.MIN_PRIORITY);
|
||||||
|
hotloader.start();
|
||||||
|
hotloader.setName(getTarget().getWorld().name() + " Hotloader");
|
||||||
|
}
|
||||||
|
|
||||||
|
setup.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
withExclusiveControl(() -> {
|
withExclusiveControl(() -> {
|
||||||
@@ -272,14 +271,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
@Override
|
@Override
|
||||||
public @NotNull ChunkData generateChunkData(@NotNull World world, @NotNull Random ignored, int x, int z, @NotNull BiomeGrid biome) {
|
public @NotNull ChunkData generateChunkData(@NotNull World world, @NotNull Random ignored, int x, int z, @NotNull BiomeGrid biome) {
|
||||||
try {
|
try {
|
||||||
if (lastSeed != world.getSeed()) {
|
getEngine(world);
|
||||||
Iris.debug("Seed for engine " + lastSeed + " does not match world seed if " + world.getSeed());
|
|
||||||
lastSeed = world.getSeed();
|
|
||||||
engine.getTarget().getWorld().seed(lastSeed);
|
|
||||||
engine.hotload();
|
|
||||||
Iris.debug("Updated Engine seed to " + lastSeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadLock.acquire();
|
loadLock.acquire();
|
||||||
computeStudioGenerator();
|
computeStudioGenerator();
|
||||||
TerrainChunk tc = TerrainChunk.create(world, biome);
|
TerrainChunk tc = TerrainChunk.create(world, biome);
|
||||||
@@ -297,19 +289,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
Iris.debug("Generated " + x + " " + z);
|
Iris.debug("Generated " + x + " " + z);
|
||||||
loadLock.release();
|
loadLock.release();
|
||||||
return c;
|
return c;
|
||||||
} catch (WrongEngineBroException e) {
|
|
||||||
Iris.warn("Trying to generate with a shut-down engine! Did you reload? Attempting to resolve this...");
|
|
||||||
|
|
||||||
try {
|
|
||||||
setupEngine();
|
|
||||||
Iris.success("Resolved! Should generate now!");
|
|
||||||
} catch (Throwable fe) {
|
|
||||||
Iris.error("FATAL! Iris cannot generate in this world since it was reloaded! This will cause a crash, with missing chunks, so we're crashing right now!");
|
|
||||||
Bukkit.shutdown();
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return generateChunkData(world, ignored, x, z, biome);
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
loadLock.release();
|
loadLock.release();
|
||||||
Iris.error("======================================");
|
Iris.error("======================================");
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class IrisScriptingAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getSeed() {
|
public long getSeed() {
|
||||||
return getEngine().getTarget().getWorld().seed();
|
return getEngine().getSeedManager().getScript();
|
||||||
}
|
}
|
||||||
|
|
||||||
public double expression(String expressionName, double x, double y, double z) {
|
public double expression(String expressionName, double x, double y, double z) {
|
||||||
|
|||||||
Reference in New Issue
Block a user