- fix reading of the defaults file
- fix tree density in flower forest biomes - fix preview map not rendering with the custom default settings when first opening the settings ui - further improvements to village terrain blending
This commit is contained in:
parent
d2ffd01b02
commit
2805ccd9ad
@ -32,6 +32,7 @@ import com.terraforged.mod.data.DataGen;
|
||||
import com.terraforged.mod.feature.decorator.poisson.PoissonAtSurface;
|
||||
import com.terraforged.mod.feature.feature.DiskFeature;
|
||||
import com.terraforged.mod.feature.tree.SaplingManager;
|
||||
import com.terraforged.mod.settings.SettingsHelper;
|
||||
import com.terraforged.mod.util.DataPackFinder;
|
||||
import com.terraforged.mod.util.Environment;
|
||||
import net.minecraft.world.biome.Biomes;
|
||||
@ -61,6 +62,7 @@ public class TerraForgedMod {
|
||||
TerraWorld.init();
|
||||
SaplingManager.init();
|
||||
TerraCommand.init();
|
||||
SettingsHelper.moveSettings();
|
||||
|
||||
// temp fix
|
||||
BiomeDictionary.addTypes(Biomes.BAMBOO_JUNGLE, BiomeDictionary.Type.OVERWORLD);
|
||||
|
@ -135,7 +135,7 @@ public abstract class ObfHelperChunkGenerator<T extends GenerationSettings> exte
|
||||
if (type == Heightmap.Type.OCEAN_FLOOR || type == Heightmap.Type.OCEAN_FLOOR_WG) {
|
||||
return level;
|
||||
}
|
||||
return Math.max(getGroundHeight(), level);
|
||||
return Math.max(getSeaLevel(), level);
|
||||
}
|
||||
|
||||
public final double getSurfaceNoise(int x, int z) {
|
||||
|
@ -109,7 +109,7 @@ public class TerraChunkGenerator extends ObfHelperChunkGenerator<GenerationSetti
|
||||
this.geologyManager = SetupHooks.setup(createGeologyManager(context), context.copy());
|
||||
this.baseDecorators = createBaseDecorators(context);
|
||||
this.postProcessors = createFeatureDecorators(context);
|
||||
this.terrainHelper = new TerrainHelper((int) world.getSeed(), 0.8F);
|
||||
this.terrainHelper = new TerrainHelper(0.75F);
|
||||
this.featureManager = createFeatureManager(context);
|
||||
this.regionCache = createRegionCache(context);
|
||||
SetupHooks.setup(getLayerManager(), context.copy());
|
||||
@ -117,13 +117,13 @@ public class TerraChunkGenerator extends ObfHelperChunkGenerator<GenerationSetti
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateStructures(BiomeManager unused, IChunk chunk, ChunkGenerator<?> generator, TemplateManager templates) {
|
||||
public void generateStructures(BiomeManager biomes, IChunk chunk, ChunkGenerator<?> generator, TemplateManager templates) {
|
||||
ChunkPos pos = chunk.getPos();
|
||||
int regionX = regionCache.chunkToRegion(pos.x);
|
||||
int regionZ = regionCache.chunkToRegion(pos.z);
|
||||
// start generating the heightmap as early as possible
|
||||
regionCache.queueRegion(regionX, regionZ);
|
||||
super.generateStructures(unused, chunk, this, templates);
|
||||
super.generateStructures(biomes, chunk, this, templates);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -160,7 +160,7 @@ public class TerraChunkGenerator extends ObfHelperChunkGenerator<GenerationSetti
|
||||
ctx.biome = container.getBiome(dx, dz);
|
||||
ChunkPopulator.INSTANCE.decorate(ctx.chunk, ctx, px, py, pz);
|
||||
});
|
||||
terrainHelper.flatten(world, chunk, container.getChunkReader(), context.blockX, context.blockZ);
|
||||
terrainHelper.flatten(world, chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,15 +25,11 @@
|
||||
|
||||
package com.terraforged.mod.feature;
|
||||
|
||||
import com.terraforged.api.material.state.States;
|
||||
import com.terraforged.core.region.chunk.ChunkReader;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import me.dags.noise.Module;
|
||||
import me.dags.noise.Source;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
|
||||
import me.dags.noise.util.NoiseUtil;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
@ -50,18 +46,16 @@ import net.minecraft.world.gen.feature.structure.StructureStart;
|
||||
|
||||
public class TerrainHelper {
|
||||
|
||||
private final Module noise;
|
||||
private final float radius;
|
||||
|
||||
public TerrainHelper(int seed, float radius) {
|
||||
this.noise = Source.perlin(++seed, 8, 1).alpha(0.75);
|
||||
public TerrainHelper(float radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public void flatten(IWorld world, IChunk chunk, ChunkReader reader, int chunkStartX, int chunkStartZ) {
|
||||
public void flatten(IWorld world, IChunk chunk) {
|
||||
ObjectList<AbstractVillagePiece> pieces = new ObjectArrayList<>(10);
|
||||
collectPieces(world, chunk, pieces);
|
||||
buildBases(chunk, reader, pieces, chunkStartX, chunkStartZ);
|
||||
buildBases(chunk, pieces);
|
||||
}
|
||||
|
||||
// see NoiseChunkGenerator
|
||||
@ -92,83 +86,73 @@ public class TerrainHelper {
|
||||
}
|
||||
|
||||
// lowers or raises the terrain matcher the base height of each structure piece
|
||||
private void buildBases(IChunk chunk, ChunkReader reader,ObjectList<AbstractVillagePiece> pieces, int chunkStartX, int chunkStartZ) {
|
||||
private void buildBases(IChunk chunk, ObjectList<AbstractVillagePiece> pieces) {
|
||||
int chunkStartX = chunk.getPos().getXStart();
|
||||
int chunkStartZ = chunk.getPos().getZStart();
|
||||
BlockPos.Mutable pos = new BlockPos.Mutable();
|
||||
ObjectListIterator<AbstractVillagePiece> iterator = pieces.iterator();
|
||||
MutableBoundingBox chunkBounds = new MutableBoundingBox(chunkStartX, chunkStartZ, chunkStartX + 15, chunkStartZ + 15);
|
||||
for (AbstractVillagePiece piece : pieces) {
|
||||
|
||||
for (int dz = 0; dz < 16; dz++) {
|
||||
for (int dx = 0; dx < 16; dx++) {
|
||||
int x = chunkStartX + dx;
|
||||
int z = chunkStartZ + dz;
|
||||
int surface = chunk.getTopBlockY(Heightmap.Type.OCEAN_FLOOR_WG, dx, dz);
|
||||
float y = surface;
|
||||
|
||||
AbstractVillagePiece highest = null;
|
||||
while (iterator.hasNext()) {
|
||||
AbstractVillagePiece piece = iterator.next();
|
||||
MutableBoundingBox pieceBounds = piece.getBoundingBox();
|
||||
int length = Math.min(pieceBounds.maxX - pieceBounds.minX, pieceBounds.maxZ - pieceBounds.minZ);
|
||||
int borderRadius = Math.max(5, NoiseUtil.round(length * radius));
|
||||
int borderRadius = Math.min(5, Math.max(10, NoiseUtil.round(length * radius)));
|
||||
MutableBoundingBox expanded = expand(pieceBounds, borderRadius);
|
||||
|
||||
if (!expanded.intersectsWith(chunkBounds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// intersecting area between the generator bounds and the village piece bounds
|
||||
int startX = Math.max(chunkStartX, expanded.minX);
|
||||
int startZ = Math.max(chunkStartZ, expanded.minZ);
|
||||
int endX = Math.min(chunkStartX + 15, expanded.maxX);
|
||||
int endZ = Math.min(chunkStartZ + 15, expanded.maxZ);
|
||||
|
||||
// y position of the structure piece
|
||||
int level = pieceBounds.minY + piece.getGroundLevelDelta();
|
||||
|
||||
// iterate the intersecting area
|
||||
for (int z = startZ; z <= endZ; z++) {
|
||||
for (int x = startX; x <= endX; x++) {
|
||||
// local generator coords
|
||||
int dx = x & 15;
|
||||
int dz = z & 15;
|
||||
|
||||
int surface = chunk.getTopBlockY(Heightmap.Type.OCEAN_FLOOR_WG, dx, dz);
|
||||
if (surface == level) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (surface > level) {
|
||||
flatten(chunk, reader, pieceBounds, pos.setPos(x, surface, z), dx, dz, level, surface, borderRadius);
|
||||
} else {
|
||||
// piece is higher than world-surface .: raise ground to form a base
|
||||
raise(chunk, pieceBounds, pos.setPos(x, surface, z), dx, dz, level, surface, borderRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void flatten(IChunk chunk, ChunkReader reader, MutableBoundingBox bounds, BlockPos.Mutable pos, int dx, int dz, int level, int surface, int borderRadius) {
|
||||
if (pos.getX() >= bounds.minX && pos.getX() <= bounds.maxX && pos.getZ() >= bounds.minZ && pos.getZ() <= bounds.maxZ) {
|
||||
for (int dy = level + 1; dy <= surface; dy++) {
|
||||
chunk.setBlockState(pos.setPos(dx, dy, dz), Blocks.AIR.getDefaultState(), false);
|
||||
if (level > y) {
|
||||
y = raise(pieceBounds, pos.setPos(x, surface, z), level, y, borderRadius);
|
||||
} else if (level < surface && pieceBounds.getYSize() > 4) {
|
||||
if (highest == null) {
|
||||
highest = piece;
|
||||
} else if (highest.getBoundingBox().maxY < pieceBounds.maxY) {
|
||||
highest = piece;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void raise(IChunk chunk, MutableBoundingBox bounds, BlockPos.Mutable pos, int dx, int dz, int level, int surface, int borderRadius) {
|
||||
float radius2 = Math.max(1, borderRadius * borderRadius * noise.getValue(pos.getX(), pos.getZ()));
|
||||
float alpha = getAlpha(bounds, radius2, pos.getX(), pos.getZ());
|
||||
if (alpha == 0F) {
|
||||
// outside of the raise-able radius
|
||||
return;
|
||||
// reset iterator for next pass
|
||||
iterator.back(pieces.size());
|
||||
|
||||
if (y > surface) {
|
||||
int delta = (int) y - surface;
|
||||
for (int dy = 0; dy < delta; dy++) {
|
||||
pos.setPos(dx, surface + dy, dz);
|
||||
chunk.setBlockState(pos, Blocks.STONE.getDefaultState(), false);
|
||||
}
|
||||
}
|
||||
|
||||
int heightDelta = level - surface - 1;
|
||||
if (alpha < 1F) {
|
||||
// sharper fall-off
|
||||
alpha = alpha * alpha;
|
||||
heightDelta = NoiseUtil.round(alpha * heightDelta);
|
||||
}
|
||||
|
||||
BlockState state = States.STONE.getDefaultState();
|
||||
for (int dy = surface + heightDelta; dy >= surface; dy--) {
|
||||
if (highest != null && highest.getBoundingBox().minY < surface) {
|
||||
MutableBoundingBox bounds = highest.getBoundingBox();
|
||||
if (x > bounds.minX && x < bounds.maxX && z > bounds.minZ && z < bounds.maxZ) {
|
||||
for (int dy = bounds.minY + 1; dy <= surface; dy++) {
|
||||
pos.setPos(dx, dy, dz);
|
||||
if (chunk.getBlockState(pos).isSolid()) {
|
||||
return;
|
||||
chunk.setBlockState(pos, Blocks.AIR.getDefaultState(), false);
|
||||
}
|
||||
chunk.setBlockState(pos.setPos(dx, dy, dz), state, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float raise(MutableBoundingBox bounds, BlockPos.Mutable pos, float level, float surface, int borderRadius) {
|
||||
float radius2 = Math.max(1, borderRadius * borderRadius);
|
||||
float alpha = 1 - getDistAlpha(pos.getX(), pos.getZ(), bounds, radius2);
|
||||
alpha = (float) Math.pow(alpha, 2F - alpha);
|
||||
return NoiseUtil.lerp(surface, level, alpha);
|
||||
}
|
||||
|
||||
private static MutableBoundingBox expand(MutableBoundingBox box, int radius) {
|
||||
return new MutableBoundingBox(
|
||||
@ -181,16 +165,16 @@ public class TerrainHelper {
|
||||
);
|
||||
}
|
||||
|
||||
private static float getAlpha(MutableBoundingBox box, float radius2, int x, int y) {
|
||||
private static float getDistAlpha(int x, int z, MutableBoundingBox box, float radius2) {
|
||||
int dx = x < box.minX ? box.minX - x : x > box.maxX ? x - box.maxX : 0;
|
||||
int dy = y < box.minZ ? box.minZ - y : y > box.maxZ ? y - box.maxZ : 0;
|
||||
int d2 = dx * dx + dy * dy;
|
||||
int dz = z < box.minZ ? box.minZ - z : z > box.maxZ ? z - box.maxZ : 0;
|
||||
int d2 = dx * dx + dz * dz;
|
||||
if (d2 == 0) {
|
||||
return 1F;
|
||||
return 0;
|
||||
}
|
||||
if (d2 > radius2) {
|
||||
return 0F;
|
||||
return 1F;
|
||||
}
|
||||
return 1 - (d2 / radius2);
|
||||
return d2 / radius2;
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public class SettingsScreen extends OverlayScreen {
|
||||
public SettingsScreen(CreateWorldScreen parent) {
|
||||
SettingsHelper.applyDefaults(parent.chunkProviderSettingsJson, settings);
|
||||
this.parent = parent;
|
||||
this.preview = new PreviewPage(getSeed(parent));
|
||||
this.preview = new PreviewPage(settings, getSeed(parent));
|
||||
this.pages = new Page[]{
|
||||
new GeneratorPage(settings, preview),
|
||||
new ClimatePage(settings, preview),
|
||||
|
@ -37,11 +37,12 @@ import java.util.function.Consumer;
|
||||
public class PreviewPage extends BasePage {
|
||||
|
||||
private final Preview preview;
|
||||
private final Settings settings = new Settings();
|
||||
private final Settings settings;
|
||||
private final CompoundNBT previewerSettings = NBTHelper.serialize(new PreviewSettings());
|
||||
|
||||
public PreviewPage(int seed) {
|
||||
preview = new Preview(seed);
|
||||
public PreviewPage(Settings settings, int seed) {
|
||||
this.preview = new Preview(seed);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public int getSeed() {
|
||||
|
@ -7,7 +7,6 @@ import com.google.gson.JsonParser;
|
||||
import com.terraforged.mod.Log;
|
||||
import com.terraforged.mod.TerraWorld;
|
||||
import com.terraforged.mod.util.nbt.NBTHelper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.storage.WorldInfo;
|
||||
@ -20,10 +19,13 @@ import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class SettingsHelper {
|
||||
|
||||
public static final String SETTINGS_FILE_NAME = "terraforged-generator.json";
|
||||
public static final File SETTINGS_DIR = new File("config", "terraforged");
|
||||
public static final File SETTINGS_FILE= new File(SETTINGS_DIR, SETTINGS_FILE_NAME);
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
public static int getVersion(WorldInfo info) {
|
||||
@ -43,8 +45,7 @@ public class SettingsHelper {
|
||||
}
|
||||
|
||||
public static void clearDefaults() {
|
||||
File file = new File("config", SettingsHelper.SETTINGS_FILE_NAME);
|
||||
if (file.exists() && file.delete()) {
|
||||
if (SETTINGS_FILE.exists() && SETTINGS_FILE.delete()) {
|
||||
Log.info("Deleted generator defaults");
|
||||
}
|
||||
}
|
||||
@ -52,9 +53,7 @@ public class SettingsHelper {
|
||||
public static void exportDefaults(TerraSettings settings) {
|
||||
CompoundNBT tag = NBTHelper.serializeCompact(settings);
|
||||
JsonElement json = NBTHelper.toJson(tag);
|
||||
File config = new File(Minecraft.getInstance().gameDir, "config");
|
||||
File file = new File(config, SettingsHelper.SETTINGS_FILE_NAME);
|
||||
try (Writer writer = new BufferedWriter(new FileWriter(file))) {
|
||||
try (Writer writer = new BufferedWriter(new FileWriter(SETTINGS_FILE))) {
|
||||
GSON.toJson(json, writer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -63,7 +62,7 @@ public class SettingsHelper {
|
||||
|
||||
public static void applyDefaults(CompoundNBT options, TerraSettings dest) {
|
||||
if (options.isEmpty()) {
|
||||
try (Reader reader = new BufferedReader(new FileReader(new File("config", SETTINGS_FILE_NAME)))) {
|
||||
try (Reader reader = new BufferedReader(new FileReader(SETTINGS_FILE))) {
|
||||
JsonElement json = new JsonParser().parse(reader);
|
||||
options = NBTHelper.fromJson(json);
|
||||
} catch (IOException ignored) {
|
||||
@ -76,11 +75,12 @@ public class SettingsHelper {
|
||||
public static TerraSettings getSettings(IWorld world) {
|
||||
TerraSettings settings = new TerraSettings();
|
||||
if (world.getWorldInfo().getGeneratorOptions().isEmpty()) {
|
||||
File defaults = new File("config", SETTINGS_FILE_NAME);
|
||||
if (defaults.exists()) {
|
||||
try (Reader reader = new BufferedReader(new FileReader(defaults))) {
|
||||
if (SETTINGS_FILE.exists()) {
|
||||
try (Reader reader = new BufferedReader(new FileReader(SETTINGS_FILE))) {
|
||||
Log.info("Loading generator settings from json");
|
||||
return new Gson().fromJson(reader, TerraSettings.class);
|
||||
JsonElement json = new JsonParser().parse(reader);
|
||||
CompoundNBT root = NBTHelper.fromJson(json);
|
||||
NBTHelper.deserialize(root, settings);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
@ -98,4 +98,24 @@ public class SettingsHelper {
|
||||
CompoundNBT options = NBTHelper.serialize(settings);
|
||||
info.setGeneratorOptions(options);
|
||||
}
|
||||
|
||||
public static void moveSettings() {
|
||||
if (SETTINGS_FILE.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File src = new File("config", SETTINGS_FILE_NAME);
|
||||
if (src.exists()) {
|
||||
if (SETTINGS_DIR.exists() || SETTINGS_DIR.mkdirs()) {
|
||||
try {
|
||||
Files.copy(src.toPath(), SETTINGS_FILE.toPath());
|
||||
if (src.delete()) {
|
||||
Log.info("Moved settings file to new location: {}", SETTINGS_FILE.getAbsoluteFile());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
{
|
||||
"biomes": [
|
||||
"minecraft:flower_forest"
|
||||
],
|
||||
"match": [
|
||||
[
|
||||
"minecraft:oak_log",
|
||||
"minecraft:oak_leaves"
|
||||
]
|
||||
],
|
||||
"replace": {
|
||||
"name": "minecraft:decorated",
|
||||
"config": {
|
||||
"feature": {
|
||||
"name": "minecraft:random_selector",
|
||||
"config": {
|
||||
"features": [
|
||||
{
|
||||
"name": "terraforged:birch_forest",
|
||||
"config": {},
|
||||
"chance": 0.2
|
||||
},
|
||||
{
|
||||
"name": "terraforged:birch_large",
|
||||
"config": {},
|
||||
"chance": 0.2
|
||||
},
|
||||
{
|
||||
"name": "terraforged:oak_forest",
|
||||
"config": {},
|
||||
"chance": 0.2
|
||||
},
|
||||
{
|
||||
"name": "terraforged:oak_large",
|
||||
"config": {},
|
||||
"chance": 0.2
|
||||
}
|
||||
],
|
||||
"default": {
|
||||
"name": "terraforged:birch_forest",
|
||||
"config": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"decorator": {
|
||||
"name": "minecraft:count_extra_heightmap",
|
||||
"config": {
|
||||
"count": 2,
|
||||
"extra_chance": 0.1,
|
||||
"extra_count": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
{
|
||||
"biomes": [
|
||||
"minecraft:plains",
|
||||
"minecraft:flower_forest"
|
||||
"minecraft:plains"
|
||||
],
|
||||
"match": [
|
||||
[
|
||||
"minecraft:birch_log",
|
||||
"minecraft:birch_leaves",
|
||||
"minecraft:oak_log",
|
||||
"minecraft:oak_leaves"
|
||||
]
|
||||
|
@ -1,4 +1,4 @@
|
||||
mod_version=0.0.11
|
||||
mod_version=0.0.12
|
||||
mc_version=1.15.2
|
||||
forge_version=31.1.1
|
||||
mcp_channel=snapshot
|
||||
|
Loading…
Reference in New Issue
Block a user