Skip to content

Instantly share code, notes, and snippets.

@Barteks2x
Last active November 29, 2016 19:00
Show Gist options
  • Save Barteks2x/ba8d85ca6e99d4aa08476d1f88898959 to your computer and use it in GitHub Desktop.
Save Barteks2x/ba8d85ca6e99d4aa08476d1f88898959 to your computer and use it in GitHub Desktop.
/*
* This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT).
*
* Copyright (c) 2015 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package cubicchunks.worldgen.generator.custom;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.ChunkProviderSettings;
import org.lwjgl.input.Keyboard;
import java.util.Random;
import java.util.function.ToIntFunction;
import javax.annotation.ParametersAreNonnullByDefault;
import cubicchunks.util.CubePos;
import cubicchunks.world.ICubicWorld;
import cubicchunks.worldgen.generator.ICubePrimer;
import cubicchunks.worldgen.generator.custom.builder.BiomeHeightVolatilitySource;
import cubicchunks.worldgen.generator.custom.builder.IBuilder;
import cubicchunks.worldgen.generator.custom.builder.NoiseSource;
import mcp.MethodsReturnNonnullByDefault;
import static cubicchunks.util.Coords.blockToLocal;
import static cubicchunks.worldgen.generator.GlobalGeneratorConfig.X_SECTION_SIZE;
import static cubicchunks.worldgen.generator.GlobalGeneratorConfig.Z_SECTION_SIZE;
import static cubicchunks.worldgen.generator.custom.builder.IBuilder.NEGATIVE;
import static cubicchunks.worldgen.generator.custom.builder.IBuilder.POSITIVE;
/**
* A terrain generator that supports infinite(*) worlds
*/
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class CustomTerrainGenerator {
private static final int CACHE_SIZE_2D = 16*16;
private static final int CACHE_SIZE_3D = 16*16*16;
private static final ToIntFunction<Vec3i> HASH_2D = (v) -> v.getX() + v.getZ()*5;
private static final ToIntFunction<Vec3i> HASH_3D = (v) -> v.getX() + v.getZ()*5 + v.getY()*25;
// Number of octaves for the noise function
private IBuilder terrainBuilder;
private final BiomeHeightVolatilitySource biomeSource;
public CustomTerrainGenerator(ICubicWorld world, final long seed) {
this.biomeSource = new BiomeHeightVolatilitySource(world.getBiomeProvider(), 2, X_SECTION_SIZE, Z_SECTION_SIZE);
initGenerator(seed);
}
private void initGenerator(long seed) {
Random rnd = new Random(seed);
ChunkProviderSettings.Factory factoryVanilla = new ChunkProviderSettings.Factory();
factoryVanilla.setDefaults();
ChunkProviderSettings confVanilla = factoryVanilla.build();
CustomGeneratorSettings conf = CustomGeneratorSettings.fromVanilla(confVanilla);
IBuilder selector = NoiseSource.perlin()
.seed(rnd.nextLong())
.normalizeTo(-1, 1)
.frequency(conf.selectorNoiseFrequencyX, conf.selectorNoiseFrequencyY, conf.selectorNoiseFrequencyZ)
.octaves(conf.selectorNoiseOctaves)
.create()
.mul(conf.selectorNoiseFactor).add(conf.selectorNoiseOffset);//.clamp(0, 1);
IBuilder low = NoiseSource.perlin()
.seed(rnd.nextLong())
.normalizeTo(-1, 1)
.frequency(conf.lowNoiseFrequencyX, conf.lowNoiseFrequencyY, conf.lowNoiseFrequencyZ)
.octaves(conf.lowNoiseOctaves)
.create()
.mul(conf.lowNoiseFactor).add(conf.lowNoiseOffset);
IBuilder high = NoiseSource.perlin()
.seed(rnd.nextLong())
.normalizeTo(-1, 1)
.frequency(conf.highNoiseFrequencyX, conf.highNoiseFrequencyY, conf.highNoiseFrequencyZ)
.octaves(conf.highNoiseOctaves)
.create()
.mul(conf.highNoiseFactor).add(conf.highNoiseOffset);
IBuilder randomHeight2d = NoiseSource.perlin()
.seed(rnd.nextLong())
.normalizeTo(-1, 1)
.frequency(conf.depthNoiseFrequencyX, 0, conf.depthNoiseFrequencyZ)
.octaves(conf.depthNoiseOctaves)
.create()
.mul(conf.depthNoiseFactor).add(conf.depthNoiseOffset)
.mulIf(NEGATIVE, -0.3).mul(3).sub(2).clamp(-2, 1)
.divIf(NEGATIVE, 2*2*1.4).divIf(POSITIVE, 8)
.mul(0.2*17/64.0)
.cached2d(CACHE_SIZE_2D, HASH_2D);
IBuilder height = ((IBuilder) biomeSource::getHeight)
.mul(conf.heightFactor)
.add(conf.heightOffset);
IBuilder volatility = ((IBuilder) biomeSource::getVolatility)
.mul(conf.heightVariationFactor)
.add(conf.heightVariationOffset);
this.terrainBuilder = selector
//.lerp(low, high)//.mul(volatility).add(height).add(randomHeight2d)
.sub((x, y, z) -> y/8).add(4)
.cached(CACHE_SIZE_3D, HASH_3D);
}
/**
* Generate the cube as the specified location
*
* @param cubePrimer cube primer to use
* @param cubeX cube x location
* @param cubeY cube y location
* @param cubeZ cube z location
*/
public void generate(final ICubePrimer cubePrimer, int cubeX, int cubeY, int cubeZ) {
if(Keyboard.isKeyDown(Keyboard.KEY_L)) {
initGenerator(42);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
CubePos cubePos = new CubePos(cubeX, cubeY, cubeZ);
BlockPos start = cubePos.getMinBlockPos();
BlockPos end = cubePos.getMaxBlockPos();
biomeSource.setChunk(cubeX, cubeZ);
terrainBuilder.scaledIterator(start, end, new Vec3i(4, 8, 4)).
forEachRemaining(e ->
cubePrimer.setBlockState(
blockToLocal(e.getX()),
blockToLocal(e.getY()),
blockToLocal(e.getZ()),
getBlock(e))
);
}
/**
* Retrieve the blockstate appropriate for the specified builder entry
*
* @return The block state
*/
private IBlockState getBlock(IBuilder.IExtendedEntry entry) {
int x = entry.getX();
int y = entry.getY();
int z = entry.getZ();
double density = entry.getValue();
double yGrad = entry.getYGradient();
Biome biome = biomeSource.getBiome(x, y, z);
final int seaLevel = 64;
final double dirtDepth = 4;
IBlockState state = Blocks.AIR.getDefaultState();
if (density > 0) {
state = Blocks.STONE.getDefaultState();
//if the block above would be empty:
if (density + yGrad <= 0) {
if (y < seaLevel - 1) {
state = biome.fillerBlock;
} else {
state = biome.topBlock;
}
//if density decreases as we go up && density < dirtDepth
} else if (yGrad < 0 && density < dirtDepth) {
state = biome.fillerBlock;
}
} else if (y < seaLevel) {
// TODO replace check with GlobalGeneratorConfig.SEA_LEVEL
state = Blocks.WATER.getDefaultState();
}
return state;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment