Skip to content

Instantly share code, notes, and snippets.

@calebmanley
Last active August 18, 2019 05:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save calebmanley/0fef6312c457289f08f1b0e59f8e722c to your computer and use it in GitHub Desktop.
Save calebmanley/0fef6312c457289f08f1b0e59f8e722c to your computer and use it in GitHub Desktop.
package com.calebmanley.arcaneascension.worldgen;
import java.util.Random;
import java.util.function.Function;
import com.mojang.datafixers.Dynamic;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.GenerationSettings;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.NoFeatureConfig;
public class FloatingIslandFeature extends Feature<NoFeatureConfig> {
int centerX;
int centerZ;
int width;
int length;
public FloatingIslandFeature(Function<Dynamic<?>, ? extends NoFeatureConfig> config) {
super(config);
}
public boolean place(IWorld world, ChunkGenerator<? extends GenerationSettings> generator, Random rand, BlockPos pos, NoFeatureConfig config) {
byte bumpHeightMinTop = 2;
byte bumpHeightMinBottom = 2;
byte blurPassesTop = 5;
byte blurPassesBottom = 5;
int spikeHeightMaxTop = 1;
byte spikeHeightMaxBottom = 3;
byte radialDistanceSamples = 18;
double radialDistanceMin = 0.0D;
double radialDistanceVar = 1.0D;
byte radialDistanceScaling = 5;
byte radialDistanceBlurPasses = 5;
if (rand.nextInt(100) == 0) {
int bumpsWide = randBetween(rand, 20, 35);
int bumpsLong = randBetween(rand, 20, 35);
int bumpHeightMaxTop = randBetween(rand, 2, 3);
int bumpHeightMaxBottom = randBetween(rand, 5, 7);
int blocksPerBumpX = randBetween(rand, 2, 5);
int blocksPerBumpZ = randBetween(rand, rand.nextInt(3) + 2, 5);
int blocksPerBumpTopY = 1;
int blocksPerBumpBottomY = randBetween(rand, 2, 4);
this.generate(world, rand, pos, bumpsWide, bumpsLong, bumpHeightMaxTop, bumpHeightMaxBottom, bumpHeightMinTop, bumpHeightMinBottom, blocksPerBumpX, blocksPerBumpZ, blocksPerBumpTopY, blocksPerBumpBottomY, blurPassesTop, blurPassesBottom, spikeHeightMaxTop, spikeHeightMaxBottom, radialDistanceSamples, radialDistanceMin, radialDistanceVar, radialDistanceScaling, radialDistanceBlurPasses);
System.out.println("Arcane island generated at (X:" + pos.getX() + ", Z:" + pos.getZ() + ")");
return true;
}
return false;
}
private int randBetween(Random rand, int min, int max) {
return rand.nextInt(max - min) + min;
}
public void generate(IWorld world, Random rand, BlockPos pos, int bumpsWide, int bumpsLong, int bumpHeightMaxTop, int bumpHeightMaxBottom, int bumpHeightMinTop, int bumpHeightMinBottom, int blocksPerBumpX, int blocksPerBumpZ, int blocksPerBumpTopY, int blocksPerBumpBottomY, int blurPassesTop, int blurPassesBottom, int spikeHeightMaxTop, int spikeHeightMaxBottom, int radialDistanceSamples, double radialDistanceMin, double radialDistanceVar, int radialDistanceScaling, int radialDistanceBlurPasses) {
double radialDistanceMap[] = createRadialDistanceMap(rand, radialDistanceSamples, radialDistanceMin, radialDistanceVar, radialDistanceScaling, radialDistanceBlurPasses);
generateHalf(world, rand, pos, false, bumpsWide, bumpsLong, bumpHeightMinBottom, bumpHeightMaxBottom, blocksPerBumpX, blocksPerBumpZ, blocksPerBumpBottomY, blurPassesBottom, spikeHeightMaxBottom, radialDistanceMap, radialDistanceSamples * radialDistanceScaling);
generateHalf(world, rand, pos, true, bumpsWide, bumpsLong, bumpHeightMinTop, bumpHeightMaxTop, blocksPerBumpX, blocksPerBumpZ, blocksPerBumpTopY, blurPassesTop, spikeHeightMaxTop, radialDistanceMap, radialDistanceSamples * radialDistanceScaling);
}
private double[] createRadialDistanceMap(Random rand, int rDistanceSamples, double rDistanceMin, double rDistanceMax, int rDistanceScaling, int rDistanceBlurPasses) {
double initRadialDistanceMap[] = initRadialDistanceMap(rand, rDistanceSamples, rDistanceMin, rDistanceMax);
double scaledRadialDistanceMap[] = scaleRadialDistanceMap(initRadialDistanceMap, rDistanceSamples, rDistanceScaling);
double result[] = scaledRadialDistanceMap;
for (int count = 0; count < rDistanceBlurPasses; count++) {
result = blurRadialDistanceMap(result, rDistanceSamples * rDistanceScaling);
}
return result;
}
private double[] initRadialDistanceMap(Random rand, int rDistanceSamples, double rDistanceMin, double rDistanceMax) {
double radialDistanceMap[] = new double[rDistanceSamples];
for (int count = 0; count < rDistanceSamples; count++) {
double distance = rDistanceMin + rand.nextDouble() * rDistanceMax;
radialDistanceMap[count] = distance;
}
return radialDistanceMap;
}
private double[] scaleRadialDistanceMap(double inputMap[], int rDistanceSamples, int rDistanceScaling) {
double outputMap[] = new double[rDistanceSamples * rDistanceScaling];
for (int sampleCount = 0; sampleCount < rDistanceSamples; sampleCount++) {
double distance = inputMap[sampleCount];
for (int scaleCount = 0; scaleCount < rDistanceScaling; scaleCount++) {
outputMap[sampleCount * rDistanceScaling + scaleCount] = distance;
}
}
return outputMap;
}
private double[] blurRadialDistanceMap(double inputMap[], int blurAmount) {
double outputMap[] = new double[blurAmount];
for (int count = 0; count < blurAmount; count++) {
double distance = inputMap[count];
double blur1;
if (count == 0) {
blur1 = inputMap[blurAmount - 1];
} else {
blur1 = inputMap[count - 1];
}
double blur2;
if (count == blurAmount - 1) {
blur2 = inputMap[0];
} else {
blur2 = inputMap[count + 1];
}
double newDistance = (distance + blur1 + blur2) / 3D;
outputMap[count] = newDistance;
}
return outputMap;
}
private void generateHalf(IWorld world, Random rand, BlockPos pos, boolean isTop, int bumpsWide, int bumpsLong, int bumpHeightMin, int bumpHeightMax, int blocksPerBumpX, int blocksPerBumpZ, int blocksPerBumpY, int blurPasses, int spikeHeightMax, double radialDistanceMap[], int i3) {
int heightMap[][] = generateHeightMap(rand, bumpsWide, bumpsLong, bumpHeightMin, bumpHeightMax, blocksPerBumpX, blocksPerBumpZ, blocksPerBumpY, blurPasses, spikeHeightMax, radialDistanceMap, i3);
addToWorld(world, rand, pos, isTop, heightMap, bumpsWide * blocksPerBumpX, bumpsLong * blocksPerBumpZ);
}
private int[][] generateHeightMap(Random rand, int bumpsWide, int bumpsLong, int bumpHeightMin, int bumpHeightMax, int blocksPerBumpX, int blocksPerBumpZ, int blocksPerBumpY, int blurPasses, int spikeHeightMax, double radialDistanceMap[], int j2) {
int width = bumpsWide * blocksPerBumpX;
int length = bumpsLong * blocksPerBumpZ;
int bumpGrid[][] = createBumpGrid(rand, bumpsWide, bumpsLong, bumpHeightMin, bumpHeightMax);
int scaledBumpGrid[][] = scaleBumpGrid(bumpGrid, bumpsWide, bumpsLong, blocksPerBumpX, blocksPerBumpZ, blocksPerBumpY);
int result[][] = applyRadialDistanceMap(scaledBumpGrid, radialDistanceMap, j2, width, length);
for (int count = 0; count < blurPasses; count++) {
result = blurHeightMap(result, width, length);
}
addSpikes(rand, result, width, length, spikeHeightMax);
return result;
}
private int[][] createBumpGrid(Random rand, int bumpsWide, int bumpsLong, int bumpHeightMin, int bumpHeightMax) {
int output[][] = new int[bumpsWide][bumpsLong];
for (int bWide = 0; bWide < bumpsWide; bWide++) {
for (int bLong = 0; bLong < bumpsLong; bLong++) {
int bump = rand.nextInt(bumpHeightMax) + bumpHeightMin;
output[bWide][bLong] = bump;
}
}
return output;
}
private int[][] scaleBumpGrid(int input[][], int bumpsWide, int bumpsLong, int blocksPerBumpX, int blocksPerBumpZ, int blocksPerBumpY) {
int output[][] = new int[bumpsWide * blocksPerBumpX][bumpsLong * blocksPerBumpZ];
for (int x = 0; x < blocksPerBumpX; x++) {
for (int z = 0; z < blocksPerBumpZ; z++) {
for (int bWide = 0; bWide < bumpsWide; bWide++) {
for (int bLong = 0; bLong < bumpsLong; bLong++) {
int bump = input[bWide][bLong];
bump *= blocksPerBumpY;
output[bWide * blocksPerBumpX + x][bLong * blocksPerBumpZ + z] = bump;
}
}
}
}
return output;
}
private int[][] applyRadialDistanceMap(int input[][], double radialDistanceMap[], int i, int width, int length) {
int output[][] = new int[width][length];
this.centerX = width / 2;
this.centerZ = length / 2;
this.width = width;
this.length = length;
for (int widthCount = 0; widthCount < width; widthCount++) {
for (int lengthCount = 0; lengthCount < length; lengthCount++) {
int j1 = widthCount - centerX;
int k1 = lengthCount - centerZ;
double d = Math.sqrt(j1 * j1 + k1 * k1);
if (d == 0.0D) {
d = 0.001D;
}
double d1 = (double)j1 / d;
double d2 = (double)k1 / d;
if (d1 == 0.0D) {
d1 = 0.001D;
}
double d3 = (double)centerX * d1 * d1 + (double)centerZ * d2 * d2;
double d4 = d / d3;
double d5;
for (d5 = Math.atan2(d2, d1); d5 < 0.0D; d5 += (Math.PI * 2D)) { }
d5 %= (Math.PI * 2D);
double d6 = d5 / (Math.PI * 2D);
int l1 = (int)(d6 * (double)i);
double d7 = radialDistanceMap[l1];
if (d4 > d7) {
output[widthCount][lengthCount] = 0;
} else {
output[widthCount][lengthCount] = input[widthCount][lengthCount];
}
}
}
return output;
}
private int[][] blurHeightMap(int input[][], int width, int length) {
int output[][] = new int[width][length];
for (int widthCount = 0; widthCount < width; widthCount++) {
for (int lengthCount = 0; lengthCount < length; lengthCount++) {
int height = input[widthCount][lengthCount];
int lHeight;
if (widthCount == 0) {
lHeight = 0;
} else {
lHeight = input[widthCount - 1][lengthCount];
}
int rHeight;
if (widthCount == width - 1) {
rHeight = 0;
} else {
rHeight = input[widthCount + 1][lengthCount];
}
int bHeight;
if (lengthCount == 0) {
bHeight = 0;
} else {
bHeight = input[widthCount][lengthCount - 1];
}
int fHeight;
if (lengthCount == length - 1) {
fHeight = 0;
} else {
fHeight = input[widthCount][lengthCount + 1];
}
int resultHeight = (height + lHeight + rHeight + fHeight + bHeight) / 5;
output[widthCount][lengthCount] = resultHeight;
}
}
return output;
}
private void addSpikes(Random rand, int heightMap[][], int width, int length, int spikeHeightMax) {
for (int widthCount = 0; widthCount < width; widthCount++) {
for (int lengthCount = 0; lengthCount < length; lengthCount++) {
int height = heightMap[widthCount][lengthCount];
if (height > 0) {
int spike = rand.nextInt(spikeHeightMax);
int resultHeight = height + spike;
heightMap[widthCount][lengthCount] = resultHeight;
}
}
}
}
private void addToWorld(IWorld world, Random rand, BlockPos pos, boolean isTop, int heightMap[][], int width, int length) {
for (int widthCount = 0; widthCount < width; widthCount++) {
for (int lengthCount = 0; lengthCount < length; lengthCount++) {
int height = heightMap[widthCount][lengthCount];
int newX = pos.getX() + widthCount;
int newZ = pos.getZ() + lengthCount;
for (int heightCount = 0; heightCount < height; heightCount++) {
int newY;
if (isTop) {
newY = pos.getY() + heightCount;
} else {
newY = pos.getY() - heightCount - 1;
}
boolean isTopBlock;
if (isTop && heightCount == height - 1) {
isTopBlock = true;
} else {
isTopBlock = heightCount == 0;
}
Block block = materialAtLevel(rand, newY - pos.getY(), isTopBlock);
this.setBlockState(world, new BlockPos(newX, newY, newZ), block.getDefaultState());
}
}
}
}
private Block materialAtLevel(Random rand, int level, boolean isTopBlock) {
byte byte0 = -1;
byte byte1 = 4;
int j = byte0 - rand.nextInt(byte1);
if (level < j) {
return Blocks.STONE;
}
if (isTopBlock) {
return Blocks.GRASS_BLOCK;
} else {
return Blocks.DIRT;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment