fixes a fundamental issue with Regions that causes heightmap lookups to be incorrectly offset by the Region border size

This commit is contained in:
dags- 2020-03-09 20:30:27 +00:00
parent 5adfa887a4
commit c344ddb137
10 changed files with 113 additions and 35 deletions

@ -1 +1 @@
Subproject commit d48538cb76877d65ba67dcadf61cb36c47516419
Subproject commit 0bbb025ead269860fe3a41dcb95f04c356164970

View File

@ -1,5 +1,5 @@
/*
*
*
* MIT License
*
* Copyright (c) 2020 TerraForged
@ -35,7 +35,11 @@ public class Steepness implements Filter, Filter.Visitor {
private final Terrains terrains;
public Steepness(Terrains terrains) {
this(1, 16F, terrains);
this(2, 16F, terrains);
}
public Steepness(float scaler, Terrains terrains) {
this(2, scaler, terrains);
}
public Steepness(int radius, float scaler, Terrains terrains) {
@ -52,8 +56,8 @@ public class Steepness implements Filter, Filter.Visitor {
@Override
public void visit(Filterable<?> cellMap, Cell cell, int cx, int cz) {
float totalHeightDif = 0F;
for (int dz = -1; dz <= 2; dz++) {
for (int dx = -1; dx <= 2; dx++) {
for (int dz = -radius; dz <= radius; dz++) {
for (int dx = -radius; dx <= radius; dx++) {
if (dx == 0 && dz == 0) {
continue;
}

View File

@ -143,8 +143,8 @@ public class Region implements Extent {
}
public void generateZoom(Heightmap heightmap, float offsetX, float offsetZ, float zoom, Batcher batcher) {
float translateX = offsetX - ((blockSize.total * zoom) / 2F);
float translateZ = offsetZ - ((blockSize.total * zoom) / 2F);
float translateX = offsetX - ((blockSize.size * zoom) / 2F);
float translateZ = offsetZ - ((blockSize.size * zoom) / 2F);
for (int cz = 0; cz < chunkSize.total; cz++) {
for (int cx = 0; cx < chunkSize.total; cx++) {
int index = chunkSize.indexOf(cx, cz);
@ -190,8 +190,8 @@ public class Region implements Extent {
}
public void decorateZoom(Collection<Decorator> decorators, float offsetX, float offsetZ, float zoom) {
float translateX = offsetX - ((blockSize.total * zoom) / 2F);
float translateZ = offsetZ - ((blockSize.total * zoom) / 2F);
float translateX = offsetX - ((blockSize.size * zoom) / 2F);
float translateZ = offsetZ - ((blockSize.size * zoom) / 2F);
for (int cz = 0; cz < chunkSize.total; cz++) {
for (int cx = 0; cx < chunkSize.total; cx++) {
int index = chunkSize.indexOf(cx, cz);
@ -205,17 +205,6 @@ public class Region implements Extent {
});
}
}
// for (int dz = 0; dz < blockSize.total; dz++) {
// for (int dx = 0; dx < blockSize.total; dx++) {
// int index = blockSize.indexOf(dx, dz);
// GenCell cell = blocks[index];
// for (Decorator decorator : decorators) {
// decorator.apply(cell, getBlockX() + translateX + dx, getBlockZ() + translateZ + dz);
// }
// }
// }
}
public void iterate(Consumer<ChunkReader> consumer) {
@ -303,8 +292,8 @@ public class Region implements Extent {
this.regionBlockX = regionChunkX << 4;
this.regionBlockZ = regionChunkZ << 4;
// the real coordinate of this chunk within the world
this.chunkX = Region.this.chunkX + regionChunkX;
this.chunkZ = Region.this.chunkZ + regionChunkZ;
this.chunkX = Region.this.chunkX + regionChunkX - chunkSize.border;
this.chunkZ = Region.this.chunkZ + regionChunkZ - chunkSize.border;
// the real block coordinate of this chunk within the world
this.blockX = chunkX << 4;
this.blockZ = chunkZ << 4;

View File

@ -1,5 +1,5 @@
/*
*
*
* MIT License
*
* Copyright (c) 2020 TerraForged
@ -45,7 +45,7 @@ public class WorldFilters {
this.settings = context.settings.filters;
this.erosion = new Erosion(context.settings, context.levels);
this.smoothing = new Smoothing(context.settings, context.levels);
this.steepness = new Steepness(1, 10F, context.terrain);
this.steepness = new Steepness(2, 10F, context.terrain);
}
public void apply(Region region) {

View File

@ -62,8 +62,12 @@ public class WorldGeneratorFactory implements Supplier<WorldGenerator> {
return decorators;
}
public WorldFilters getFilters() {
return new WorldFilters(context);
}
@Override
public WorldGenerator get() {
return new WorldGenerator(heightmap, decorators, new WorldFilters(context));
return new WorldGenerator(heightmap, decorators, getFilters());
}
}

View File

@ -0,0 +1,44 @@
package com.terraforged.core.world.heightmap;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.world.GeneratorContext;
import com.terraforged.core.world.WorldDecorators;
import com.terraforged.core.world.WorldGeneratorFactory;
import com.terraforged.core.world.decorator.Decorator;
import com.terraforged.core.world.terrain.Terrain;
public class WorldLookup {
private final float waterLevel;
private final float beachLevel;
private final Heightmap heightmap;
private final WorldDecorators decorators;
private final GeneratorContext context;
public WorldLookup(WorldGeneratorFactory factory, GeneratorContext context) {
this.context = context;
this.heightmap = factory.getHeightmap();
this.decorators = factory.getDecorators();
this.waterLevel = context.levels.water;
this.beachLevel = context.levels.water(5);
}
public Cell<Terrain> getCell(int x, int z) {
Cell<Terrain> cell = new Cell<>();
heightmap.apply(cell, x, z);
// approximation - actual beaches depend on steepness but that's too expensive to calculate
if (cell.tag == context.terrain.coast && cell.value > waterLevel && cell.value <= beachLevel) {
cell.tag = context.terrain.beach;
}
for (Decorator decorator : decorators.getDecorators()) {
if (decorator.apply(cell, x, z)) {
break;
}
}
return cell;
}
}

View File

@ -31,6 +31,11 @@ import net.minecraft.entity.EntityType;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import net.minecraft.world.biome.DefaultBiomeFeatures;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.placement.FrequencyConfig;
import net.minecraft.world.gen.placement.HeightWithChanceConfig;
import net.minecraft.world.gen.placement.Placement;
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder;
public class Marshland extends BiomeVariant {
@ -51,6 +56,7 @@ public class Marshland extends BiomeVariant {
DefaultBiomeFeatures.addGrass(this);
DefaultBiomeFeatures.addVeryDenseGrass(this);
DefaultBiomeFeatures.addReedsAndPumpkins(this);
Marshland.addSwampVegetation(this);
DefaultBiomeFeatures.addFreezeTopLayer(this);
this.addSpawn(EntityClassification.CREATURE, new SpawnListEntry(EntityType.SHEEP, 12, 4, 4));
this.addSpawn(EntityClassification.CREATURE, new SpawnListEntry(EntityType.PIG, 10, 4, 4));
@ -83,4 +89,12 @@ public class Marshland extends BiomeVariant {
public Biome getBase() {
return Biomes.SWAMP;
}
private static void addSwampVegetation(Biome biome) {
biome.addFeature(GenerationStage.Decoration.VEGETAL_DECORATION, Feature.RANDOM_PATCH.withConfiguration(DefaultBiomeFeatures.LILY_PAD_CONFIG).withPlacement(Placement.COUNT_HEIGHTMAP_DOUBLE.configure(new FrequencyConfig(4))));
biome.addFeature(GenerationStage.Decoration.VEGETAL_DECORATION, Feature.RANDOM_PATCH.withConfiguration(DefaultBiomeFeatures.DEAD_BUSH_CONFIG).withPlacement(Placement.COUNT_HEIGHTMAP_DOUBLE.configure(new FrequencyConfig(1))));
biome.addFeature(GenerationStage.Decoration.VEGETAL_DECORATION, Feature.RANDOM_PATCH.withConfiguration(DefaultBiomeFeatures.LILY_PAD_CONFIG).withPlacement(Placement.COUNT_HEIGHTMAP_DOUBLE.configure(new FrequencyConfig(4))));
biome.addFeature(GenerationStage.Decoration.VEGETAL_DECORATION, Feature.RANDOM_PATCH.withConfiguration(DefaultBiomeFeatures.BROWN_MUSHROOM_CONFIG).withPlacement(Placement.COUNT_CHANCE_HEIGHTMAP.configure(new HeightWithChanceConfig(8, 0.25F))));
biome.addFeature(GenerationStage.Decoration.VEGETAL_DECORATION, Feature.RANDOM_PATCH.withConfiguration(DefaultBiomeFeatures.RED_MUSHROOM_CONFIG).withPlacement(Placement.COUNT_CHANCE_HEIGHTMAP_DOUBLE.configure(new HeightWithChanceConfig(8, 0.125F))));
}
}

View File

@ -29,6 +29,7 @@ import com.google.common.collect.Sets;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.region.chunk.ChunkReader;
import com.terraforged.core.world.decorator.Decorator;
import com.terraforged.core.world.heightmap.WorldLookup;
import com.terraforged.core.world.terrain.Terrain;
import com.terraforged.mod.biome.map.BiomeMap;
import com.terraforged.mod.biome.modifier.BiomeModifierManager;
@ -52,23 +53,22 @@ public class BiomeProvider extends AbstractBiomeProvider {
private final BiomeMap biomeMap;
private final TerraContext context;
private final WorldLookup worldLookup;
private final BiomeModifierManager modifierManager;
private final Map<Biome, List<Decorator>> decorators = new HashMap<>();
public BiomeProvider(TerraContext context) {
this.context = context;
this.biomeMap = BiomeHelper.getDefaultBiomeMap();
this.worldLookup = new WorldLookup(context.factory, context);
this.modifierManager = SetupHooks.setup(new BiomeModifierManager(context, biomeMap), context.copy());
}
@Override
public Biome getNoiseBiome(int x, int y, int z) {
// I don't know why +24, just seems to provide slightly more accurate results
x = (x << 2) + 24;
z = (z << 2) + 24;
Cell<Terrain> cell = new Cell<>();
context.heightmap.apply(cell, x, z);
return getBiome(cell, x, z);
x = (x << 2);
z = (z << 2);
return getBiome(worldLookup.getCell(x, z), x, z);
}
@Override
@ -171,8 +171,7 @@ public class BiomeProvider extends AbstractBiomeProvider {
}
private static boolean overridesRiver(Biome biome) {
return biome.getCategory() == Biome.Category.SWAMP
|| biome.getCategory() == Biome.Category.JUNGLE;
return biome.getCategory() == Biome.Category.SWAMP || biome.getCategory() == Biome.Category.JUNGLE;
}
private static class SearchContext {

View File

@ -114,8 +114,8 @@ public class TerraContainer extends BiomeContainer {
for (int dy = 0; dy < 64; dy++) {
for (int dz = 0; dz < 4; dz++) {
for (int dx = 0; dx < 4; dx++) {
int x = 2 + (dx * 4);
int z = 2 + (dz * 4);
int x = dx * 4;
int z = dz * 4;
int index = indexOf(dx, dy, dz);
biomes[index] = surfaceBiomeCache[indexOf(x, z)];
}

View File

@ -49,6 +49,7 @@ import com.terraforged.mod.data.DataGen;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
@ -60,6 +61,7 @@ import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.ColumnFuzzedBiomeMagnifier;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@ -92,6 +94,8 @@ public class TerraCommand {
.then(Commands.literal("data")
.then(Commands.literal("dump")
.executes(TerraCommand::dump)))
.then(Commands.literal("debug")
.executes(TerraCommand::debugBiome))
.then(Commands.literal("locate")
.then(Commands.argument("biome", BiomeArgType.biome())
.executes(TerraCommand::findBiome)
@ -132,6 +136,26 @@ public class TerraCommand {
return Command.SINGLE_SUCCESS;
}
private static int debugBiome(CommandContext<CommandSource> context) throws CommandSyntaxException {
ServerPlayerEntity player = context.getSource().asPlayer();
BlockPos position = player.getPosition();
int x = position.getX();
int y = position.getY();
int z = position.getZ();
long seed = player.getServerWorld().getSeed();
Biome actual = player.getServerWorld().getBiome(position);
Biome biome2 = ColumnFuzzedBiomeMagnifier.INSTANCE.getBiome(seed, x, 0, z, player.getServerWorld().getWorldServer().getChunkProvider().generator.getBiomeProvider());
context.getSource().sendFeedback(new StringTextComponent(
"Actual Biome = " + actual.getRegistryName()
+ "\nLookup Biome = " + biome2.getRegistryName()),
false
);
return Command.SINGLE_SUCCESS;
}
private static int findTerrain(CommandContext<CommandSource> context) throws CommandSyntaxException {
// get the generator's context
TerraContext terraContext = getContext(context).orElseThrow(() -> createException(