Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve OSM feature generation capabilities #43

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package net.buildtheearth.terraplusplus.dataset.vector.draw;

import java.io.IOException;

import com.google.gson.annotations.JsonAdapter;
import com.google.gson.stream.JsonReader;

import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import net.buildtheearth.terraplusplus.TerraConstants;
import net.buildtheearth.terraplusplus.dataset.osm.JsonParser;
import net.buildtheearth.terraplusplus.generator.CachedChunkData;
import net.minecraft.block.state.IBlockState;

import java.io.IOException;

/**
* {@link DrawFunction} which sets the surface block to a fixed block state.
*
Expand All @@ -24,7 +25,7 @@ public final class Block implements DrawFunction {

@Override
public void drawOnto(@NonNull CachedChunkData.Builder data, int x, int z, int weight) {
data.surfaceBlocks()[x * 16 + z] = this.state;
data.surfaceBlocks()[x * 16 + z].setBetween(0, 1, this.state);
}

static class Parser extends JsonParser<Block> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package net.buildtheearth.terraplusplus.dataset.vector.draw;

import java.util.Map;

import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.buildtheearth.terraplusplus.dataset.osm.JsonParser;

import java.util.Map;

/**
* @author DaPorkchop_
*/
Expand All @@ -20,6 +20,7 @@ public class DrawFunctionParser extends JsonParser.Typed<DrawFunction> {
TYPES.put("weight_less_than", WeightLessThan.class);

TYPES.put("block", Block.class);
TYPES.put("blocks", MultiBlock.class);
TYPES.put("no_trees", NoTrees.class);
TYPES.put("ocean", Ocean.class);
TYPES.put("water", Water.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package net.buildtheearth.terraplusplus.dataset.vector.draw;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.google.gson.annotations.JsonAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

import lombok.NonNull;
import net.buildtheearth.terraplusplus.TerraConstants;
import net.buildtheearth.terraplusplus.dataset.osm.JsonParser;
import net.buildtheearth.terraplusplus.generator.CachedChunkData;
import net.buildtheearth.terraplusplus.generator.CachedChunkData.SurfaceColumn;
import net.daporkchop.lib.common.util.PValidation;
import net.minecraft.block.state.IBlockState;

/**
* {@link DrawFunction} which sets the surface to a fixed surface pattern.
*
* @author SmylerMC
*/
@JsonAdapter(MultiBlock.Parser.class)
public class MultiBlock implements DrawFunction {

private int offset;
private IBlockState[] states;

public MultiBlock(int offset, IBlockState... states) {
this.offset = offset;
this.states = states;
}

@Override
public void drawOnto(@NonNull CachedChunkData.Builder data, int x, int z, int weight) {
SurfaceColumn column = data.surfaceBlocks()[x * 16 + z];
for (int i = 0; i < states.length; i++) {
column.setBetween(i + this.offset, i + this.offset + 1, this.states[i]);
}
}

static class Parser extends JsonParser<MultiBlock> {
@Override
public MultiBlock read(JsonReader in) throws IOException {
in.beginObject();
int offset = 0;
List<IBlockState> states = new ArrayList<>();
while (in.peek() != JsonToken.END_OBJECT) {
String name = in.nextName();
switch (name) {
case "offset":
offset = in.nextInt();
break;
case "blocks":
in.beginArray();
while (in.peek() != JsonToken.END_ARRAY) {
states.add(TerraConstants.GSON.fromJson(in, IBlockState.class));
}
in.endArray();
break;
default:
throw new IllegalStateException("invalid property: " + name);
}
}
in.endObject();
PValidation.checkState(states.size() > 0, "Illegal block state array: at least one required");
Collections.reverse(states);
IBlockState[] blocks = states.toArray(new IBlockState[0]);
return new MultiBlock(offset, blocks);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
package net.buildtheearth.terraplusplus.generator;

import static java.lang.Math.max;
import static java.lang.Math.min;
import static net.daporkchop.lib.common.math.PMath.clamp;
import static net.daporkchop.lib.common.math.PMath.floorI;
import static net.daporkchop.lib.common.math.PMath.lerp;

import java.util.Arrays;
import java.util.Map;

import com.google.common.collect.ImmutableMap;

import io.github.opencubicchunks.cubicchunks.api.util.Coords;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import net.buildtheearth.terraplusplus.util.CustomAttributeContainer;
import net.buildtheearth.terraplusplus.util.ImmutableCompactArray;
import net.buildtheearth.terraplusplus.util.StabbingTree;
import net.daporkchop.lib.common.ref.Ref;
import net.daporkchop.lib.common.ref.ThreadRef;
import net.daporkchop.lib.common.util.PorkUtil;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Biomes;
import net.minecraft.world.biome.Biome;

import java.util.Arrays;
import java.util.Map;

import static java.lang.Math.*;
import static net.daporkchop.lib.common.math.PMath.*;

/**
* A collection of data cached per-column by {@link EarthGenerator}.
*
Expand Down Expand Up @@ -53,7 +57,7 @@ private static int extractActualDepth(int waterDepth) {
@Getter
private final byte[] biomes;

private final ImmutableCompactArray<IBlockState> surfaceBlocks;
private final SurfaceColumn[] surfaceBlocks;

private final int surfaceMinCube;
private final int surfaceMaxCube;
Expand Down Expand Up @@ -99,13 +103,16 @@ private CachedChunkData(@NonNull Builder builder, @NonNull Map<String, Object> c
this.biomes[i] = (byte) Biome.getIdForBiome(PorkUtil.fallbackIfNull(builder.biomes[i], Biomes.DEEP_OCEAN));
}

this.surfaceBlocks = new ImmutableCompactArray<>(builder.surfaceBlocks);
this.surfaceBlocks = new SurfaceColumn[16 * 16];
for (int i = 0; i < 16 * 16; i++) {
this.surfaceBlocks[i] = builder.surfaceBlocks[i].copy();
}

int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0; i < 16 * 16; i++) {
min = min(min, min(this.groundHeight[i], this.surfaceHeight[i]));
max = max(max, max(this.groundHeight[i], this.surfaceHeight[i]));
min = min(min, min(this.groundHeight[i], this.surfaceHeight[i]) - this.surfaceBlocks[i].lowestBlock());
max = max(max, max(this.groundHeight[i], this.surfaceHeight[i]) + this.surfaceBlocks[i].highestBlock());
}
this.surfaceMinCube = Coords.blockToCube(min) - 1;
this.surfaceMaxCube = Coords.blockToCube(max) + 1;
Expand Down Expand Up @@ -139,8 +146,8 @@ public int waterHeight(int x, int z) {
return this.surfaceHeight(x, z) - 1;
}

public IBlockState surfaceBlock(int x, int z) {
return this.surfaceBlocks.get(x * 16 + z);
public SurfaceColumn surfaceBlock(int x, int z) {
return this.surfaceBlocks[x * 16 + z];
}

public int biome(int x, int z) {
Expand All @@ -160,14 +167,17 @@ public static final class Builder extends CustomAttributeContainer implements IE

private final Biome[] biomes = new Biome[16 * 16];

protected final IBlockState[] surfaceBlocks = new IBlockState[16 * 16];
protected final SurfaceColumn[] surfaceBlocks = new SurfaceColumn[16 * 16];

/**
* @deprecated use {@link #builder()} unless you have a specific reason to invoke this constructor directly
*/
@Deprecated
public Builder() {
super(new Object2ObjectOpenHashMap<>());
for (int i = 0; i< this.surfaceBlocks.length; i++) {
this.surfaceBlocks[i] = new SurfaceColumn();
}
this.reset();
}

Expand Down Expand Up @@ -203,7 +213,7 @@ public void putCustom(@NonNull String key, @NonNull Object value) {
public Builder reset() {
Arrays.fill(this.surfaceHeight, BLANK_HEIGHT);
Arrays.fill(this.waterDepth, (byte) WATERDEPTH_DEFAULT);
Arrays.fill(this.surfaceBlocks, null);
Arrays.stream(this.surfaceBlocks).forEach(SurfaceColumn::clear);
this.custom.clear();
return this;
}
Expand All @@ -215,4 +225,29 @@ public CachedChunkData build() {
return new CachedChunkData(this, custom);
}
}

/**
* This is mostly to avoid generic type shenanigans
*/
public static class SurfaceColumn extends StabbingTree<Integer, IBlockState> {

public SurfaceColumn copy() {
SurfaceColumn other = new SurfaceColumn();
for (Node node: this.nodes) {
other.nodes.add(node);
}
return other;
}

public int highestBlock() {
int size = this.nodes.size();
return size > 0 ? this.nodes.get(size - 1).start() - 1 : 0;
}

public int lowestBlock() {
int size = this.nodes.size();
return size > 0 ? this.nodes.get(0).start() : 0;
}
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
package net.buildtheearth.terraplusplus.generator;

import static java.lang.Math.max;
import static java.lang.Math.min;

import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import io.github.opencubicchunks.cubicchunks.api.util.Coords;
import io.github.opencubicchunks.cubicchunks.api.util.CubePos;
import io.github.opencubicchunks.cubicchunks.api.world.ICube;
Expand All @@ -29,6 +42,7 @@
import lombok.NonNull;
import net.buildtheearth.terraplusplus.TerraConstants;
import net.buildtheearth.terraplusplus.TerraMod;
import net.buildtheearth.terraplusplus.generator.CachedChunkData.SurfaceColumn;
import net.buildtheearth.terraplusplus.generator.data.IEarthDataBaker;
import net.buildtheearth.terraplusplus.generator.populate.IEarthPopulator;
import net.buildtheearth.terraplusplus.projection.GeographicProjection;
Expand All @@ -51,17 +65,6 @@
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.fml.common.registry.ForgeRegistries;

import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import static java.lang.Math.*;

public class EarthGenerator extends BasicCubeGenerator {
public static final int WATER_DEPTH_OFFSET = 1;

Expand Down Expand Up @@ -263,11 +266,20 @@ protected void generateCube(int cubeX, int cubeY, int cubeZ, CubePrimer primer,
if (data.intersectsSurface(cubeY)) { //render surface blocks onto cube surface
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
int y = data.surfaceHeight(x, z) - Coords.cubeToMinBlock(cubeY);
IBlockState state;
if ((y & 0xF) == y //don't set surface blocks outside of this cube
&& (state = data.surfaceBlock(x, z)) != null) {
primer.setBlockState(x, y, z, state);
SurfaceColumn column = data.surfaceBlock(x, z);
if (data != null) {
int cx = x;
int surfaceY = data.surfaceHeight(x, z) - Coords.cubeToMinBlock(cubeY);
int cz = z;
column.forEachSection(-surfaceY, -surfaceY + 16, (startNode, endNode) -> {
IBlockState state = startNode.value();
if (state == null) return;
int start = startNode.start();
int end = endNode.start();
for (int y = start; y < end; y++) {
primer.setBlockState(cx, y + surfaceY, cz, state);
}
});
}
}
}
Expand Down Expand Up @@ -371,7 +383,7 @@ public void populate(ICube cube) {
Random random = Coords.coordsSeedRandom(this.world.getSeed(), cube.getX(), cube.getY(), cube.getZ());
Biome biome = cube.getBiome(Coords.getCubeCenter(cube));

this.cubiccfg.expectedBaseHeight = (float) datas[0].groundHeight(15, 15);
this.cubiccfg.expectedBaseHeight = datas[0].groundHeight(15, 15);

for (IEarthPopulator populator : this.populators) {
populator.populate(this.world, random, cube.getCoords(), biome, datas);
Expand Down
Loading