package rtg.world.biome.deco;
import java.util.Random;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.gen.feature.WorldGenerator;
import rtg.api.util.BlockUtil;
import rtg.api.util.RandomUtil;
import rtg.api.world.RTGWorld;
import rtg.world.biome.realistic.RealisticBiomeBase;
import rtg.world.gen.feature.WorldGenSeaweed;
/**
* @author WhichOnesPink
*/
public class DecoSeaweed extends DecoBase {
protected int loops;
protected float strengthFactorForLoops; // If set, this overrides and dynamically calculates 'loops' based on the strength parameter.
protected boolean strengthNoiseFactorForLoops; // If true, this overrides and dynamically calculates 'loops' based on (noise * strength)
protected boolean strengthNoiseFactorXForLoops; // If true, this overrides and dynamically calculates 'loops' based on (noise * X * strength)
protected DecoSeaweed.Distribution distribution; // Parameter object for noise calculations.
protected Condition condition; // Enum for the various conditions/chances for seaweed gen.
protected float conditionNoise; // Only applies to a noise-related Condition.
protected float conditionNoise2; // Only applies to a noise-related Condition.
protected int conditionChance; // Only applies to a chance-related Condition.
protected float conditionFloat; // Multi-purpose float.
protected int minY; // Lower height restriction.
protected int maxY; // Upper height restriction.
protected IBlockState seaweedBlock;
protected int minHeight; // Min seaweed height (only used with certain seaweed presets)
protected int maxHeight; // Max seaweed height (only used with certain seaweed presets)
protected Scatter scatter;
public DecoSeaweed() {
super();
/**
* Default values.
* These can be overridden when configuring the Deco object in the realistic biome.
*/
this.setLoops(1);
this.setStrengthFactorForLoops(0f);
this.setStrengthNoiseFactorForLoops(false);
this.setStrengthNoiseFactorXForLoops(false);
this.setDistribution(new DecoSeaweed.Distribution(100f, 5f, 0.8f));
this.setCondition(condition.NOISE_GREATER_AND_RANDOM_CHANCE);
this.setConditionNoise(0f);
this.setConditionNoise2(0f);
this.setConditionFloat(0f);
this.setConditionChance(1);
this.setMinY(15); // Few blocks below min ocean floor by default.
this.setMaxY(58); // No seaweed sticking out of the water by default.
this.setSeaweedBlock(BlockUtil.getStateLeaf(3));
this.setMinHeight(1);
this.setMaxHeight(4);
this.setScatter(new Scatter(16, 0));
this.addDecoTypes(DecoType.SEAWEED);
}
@Override
public boolean properlyDefined() {
return super.properlyDefined();
}
@Override
public void generate(RealisticBiomeBase biome, RTGWorld rtgWorld, Random rand, int worldX, int worldZ, float strength, float river, boolean hasPlacedVillageBlocks) {
if (this.allowed) {
/*
* Determine how much seaweed we're going to try to generate (loopCount).
* The actual amount of seaweed that ends up being generated could be *less* than this value,
* depending on environmental conditions.
*/
float noise = rtgWorld.simplex.noise2(worldX / this.distribution.noiseDivisor, worldZ / this.distribution.noiseDivisor) * this.distribution.noiseFactor + this.distribution.noiseAddend;
int loopCount = this.loops;
loopCount = (this.strengthFactorForLoops > 0f) ? (int) (this.strengthFactorForLoops * strength) : loopCount;
loopCount = (this.strengthNoiseFactorForLoops) ? (int) (noise * strength) : loopCount;
loopCount = (this.strengthNoiseFactorXForLoops) ? (int) (noise * this.strengthFactorForLoops * strength) : loopCount;
if (loopCount < 1) {
return;
}
WorldGenerator worldGen = new WorldGenSeaweed(this.seaweedBlock, RandomUtil.getRandomInt(rand, this.minHeight, this.maxHeight));
for (int i = 0; i < loopCount; i++) {
int intX = scatter.get(rand, worldX); // + 8;
int intZ = scatter.get(rand, worldZ); // + 8;
int intY = RandomUtil.getRandomInt(rand, this.minY, this.maxY);
//Logger.info("noise = %f", noise);
if (intY <= this.maxY && intY >= this.minY && isValidCondition(noise, rand, strength)) {
worldGen.generate(rtgWorld.world, rand, new BlockPos(intX, intY, intZ));
}
}
}
}
public boolean isValidCondition(float noise, Random rand, float strength) {
switch (this.condition) {
case ALWAYS_GENERATE:
return true;
case NOISE_GREATER_AND_RANDOM_CHANCE:
return (noise > this.conditionNoise && rand.nextInt(this.conditionChance) == 0);
case NOISE_LESSER_AND_RANDOM_CHANCE:
return (noise < this.conditionNoise && rand.nextInt(this.conditionChance) == 0);
case NOISE_BETWEEN_AND_RANDOM_CHANCE:
return (noise > this.conditionNoise && noise < this.conditionNoise2 && rand.nextInt(this.conditionChance) == 0);
case RANDOM_CHANCE:
return rand.nextInt(this.conditionChance) == 0;
case X_DIVIDED_BY_STRENGTH:
return rand.nextInt((int) (this.conditionFloat / strength)) == 0;
default:
return false;
}
}
public enum Condition {
ALWAYS_GENERATE,
NOISE_GREATER_AND_RANDOM_CHANCE,
NOISE_LESSER_AND_RANDOM_CHANCE,
NOISE_BETWEEN_AND_RANDOM_CHANCE,
RANDOM_CHANCE,
X_DIVIDED_BY_STRENGTH;
}
public static class Scatter {
int bound;
int reach;
public Scatter(int bound, int reach) {
if (bound < 1) {
throw new RuntimeException("Scatter bound must be greater than 0.");
};
this.bound = bound;
this.reach = reach;
}
public int get(Random rand, int coord) {
return coord + rand.nextInt(bound) + reach;
}
}
/**
* Parameter object for noise calculations.
* <p>
* simplex.noise2(chunkX / noiseDivisor, chunkZ / noiseDivisor) * noiseFactor + noiseAddend;
*
* @author WhichOnesPink
* @author Zeno410
*/
public static class Distribution {
protected float noiseDivisor;
protected float noiseFactor;
protected float noiseAddend;
public Distribution(float noiseDivisor, float noiseFactor, float noiseAddend) {
this.noiseDivisor = noiseDivisor;
this.noiseFactor = noiseFactor;
this.noiseAddend = noiseAddend;
}
public float getNoiseDivisor() {
return noiseDivisor;
}
public Distribution setNoiseDivisor(float noiseDivisor) {
this.noiseDivisor = noiseDivisor;
return this;
}
public float getNoiseFactor() {
return noiseFactor;
}
public Distribution setNoiseFactor(float noiseFactor) {
this.noiseFactor = noiseFactor;
return this;
}
public float getNoiseAddend() {
return noiseAddend;
}
public Distribution setNoiseAddend(float noiseAddend) {
this.noiseAddend = noiseAddend;
return this;
}
}
public int getLoops() {
return loops;
}
public DecoSeaweed setLoops(int loops) {
this.loops = loops;
return this;
}
public float getStrengthFactorForLoops() {
return strengthFactorForLoops;
}
public DecoSeaweed setStrengthFactorForLoops(float strengthFactorForLoops) {
this.strengthFactorForLoops = strengthFactorForLoops;
return this;
}
public boolean isStrengthNoiseFactorForLoops() {
return strengthNoiseFactorForLoops;
}
public DecoSeaweed setStrengthNoiseFactorForLoops(boolean strengthNoiseFactorForLoops) {
this.strengthNoiseFactorForLoops = strengthNoiseFactorForLoops;
return this;
}
public boolean isStrengthNoiseFactorXForLoops() {
return strengthNoiseFactorXForLoops;
}
public DecoSeaweed setStrengthNoiseFactorXForLoops(boolean strengthNoiseFactorXForLoops) {
this.strengthNoiseFactorXForLoops = strengthNoiseFactorXForLoops;
return this;
}
public Distribution getDistribution() {
return distribution;
}
public DecoSeaweed setDistribution(Distribution distribution) {
this.distribution = distribution;
return this;
}
public Condition getCondition() {
return condition;
}
public DecoSeaweed setCondition(Condition condition) {
this.condition = condition;
return this;
}
public float getConditionNoise() {
return conditionNoise;
}
public DecoSeaweed setConditionNoise(float conditionNoise) {
this.conditionNoise = conditionNoise;
return this;
}
public float getConditionNoise2() {
return conditionNoise2;
}
public DecoSeaweed setConditionNoise2(float conditionNoise2) {
this.conditionNoise2 = conditionNoise2;
return this;
}
public int getConditionChance() {
return conditionChance;
}
public DecoSeaweed setConditionChance(int conditionChance) {
this.conditionChance = conditionChance;
return this;
}
public float getConditionFloat() {
return conditionFloat;
}
public DecoSeaweed setConditionFloat(float conditionFloat) {
this.conditionFloat = conditionFloat;
return this;
}
public int getMinY() {
return minY;
}
public DecoSeaweed setMinY(int minY) {
this.minY = minY;
return this;
}
public int getMaxY() {
return maxY;
}
public DecoSeaweed setMaxY(int maxY) {
this.maxY = maxY;
return this;
}
public IBlockState getSeaweedBlock() {
return seaweedBlock;
}
public DecoSeaweed setSeaweedBlock(IBlockState seaweedBlock) {
this.seaweedBlock = seaweedBlock;
return this;
}
public int getMinHeight() {
return minHeight;
}
public DecoSeaweed setMinHeight(int minHeight) {
this.minHeight = minHeight;
return this;
}
public int getMaxHeight() {
return maxHeight;
}
public DecoSeaweed setMaxHeight(int maxHeight) {
this.maxHeight = maxHeight;
return this;
}
public Scatter getScatter() {
return scatter;
}
public DecoSeaweed setScatter(Scatter scatter) {
this.scatter = scatter;
return this;
}
}