diff --git a/src/main/java/ru/betterend/mixin/common/NoiseBasedChunkGeneratorMixin.java b/src/main/java/ru/betterend/mixin/common/NoiseBasedChunkGeneratorMixin.java index 5aa420b4..e67932ad 100644 --- a/src/main/java/ru/betterend/mixin/common/NoiseBasedChunkGeneratorMixin.java +++ b/src/main/java/ru/betterend/mixin/common/NoiseBasedChunkGeneratorMixin.java @@ -1,19 +1,52 @@ package ru.betterend.mixin.common; +import java.util.HashSet; +import java.util.OptionalInt; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.stream.IntStream; +import com.google.common.collect.Sets; +import net.minecraft.Util; import net.minecraft.core.Registry; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.Mth; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureFeatureManager; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Beardifier; +import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseChunk; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.levelgen.StructureSettings; +import net.minecraft.world.level.levelgen.SurfaceRules; +import net.minecraft.world.level.levelgen.SurfaceSystem; +import net.minecraft.world.level.levelgen.WorldGenerationContext; +import net.minecraft.world.level.levelgen.blending.Blender; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import ru.betterend.world.generator.EndNoiseFiller; +import ru.betterend.world.generator.GeneratorOptions; import ru.betterend.world.generator.TerrainGenerator; @Mixin(NoiseBasedChunkGenerator.class) @@ -22,6 +55,14 @@ public abstract class NoiseBasedChunkGeneratorMixin extends ChunkGenerator { @Shadow protected Supplier settings; + @Final + @Shadow + protected BlockState defaultBlock; + + @Final + @Shadow + private SurfaceSystem surfaceSystem; + public NoiseBasedChunkGeneratorMixin(BiomeSource populationSource, BiomeSource biomeSource, StructureSettings structuresConfig, long worldSeed) { super(populationSource, biomeSource, structuresConfig, worldSeed); } @@ -29,6 +70,9 @@ public abstract class NoiseBasedChunkGeneratorMixin extends ChunkGenerator { @Inject(method = "(Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/biome/BiomeSource;Lnet/minecraft/world/level/biome/BiomeSource;JLjava/util/function/Supplier;)V", at = @At("TAIL")) private void beOnInit(Registry registry, BiomeSource biomeSource, BiomeSource biomeSource2, long seed, Supplier supplier, CallbackInfo ci) { TerrainGenerator.initNoise(seed); + if (GeneratorOptions.useNewGenerator() && settings.get().stable(NoiseGeneratorSettings.END)) { + EndNoiseFiller.INSTANCE.setBiomeSource(biomeSource); + } } //TODO: 1.18 Find another place for this @@ -39,4 +83,106 @@ public abstract class NoiseBasedChunkGeneratorMixin extends ChunkGenerator { // info.cancel(); // } // } + + @Inject(method = "buildSurface", at = @At("HEAD"), cancellable = true) + private void be_buildSurface(WorldGenRegion worldGenRegion, StructureFeatureManager structureFeatureManager, ChunkAccess chunkAccess, CallbackInfo info) { + //NoiseChunk noiseChunk = chunkAccess.getOrCreateNoiseChunk(this.sampler, () -> new Beardifier(structureFeatureManager, chunkAccess), noiseGeneratorSettings, this.globalFluidPicker, Blender.of(worldGenRegion)); + /*WorldGenerationContext worldGenerationContext = new WorldGenerationContext(this, worldGenRegion); + NoiseGeneratorSettings noiseGeneratorSettings = this.settings.get(); + surfaceSystem.buildSurface( + worldGenRegion.getBiomeManager(), + worldGenRegion.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), + noiseGeneratorSettings.useLegacyRandomSource(), + worldGenerationContext, + chunkAccess, + null, + noiseGeneratorSettings.surfaceRule() + );*/ + //System.out.println("Build surface!"); + } + + @Inject(method = "fillFromNoise", at = @At("HEAD"), cancellable = true) + private void be_fillFromNoise(Executor executor, Blender blender, StructureFeatureManager structureFeatureManager, ChunkAccess chunkAccess2, CallbackInfoReturnable> info) { + info.setReturnValue(CompletableFuture.supplyAsync( + Util.wrapThreadWithTaskName( + "wgen_fill_noise", + () -> this.fill(chunkAccess2) + ), + Util.backgroundExecutor() + )); + } + + private ChunkAccess fill(ChunkAccess chunkAccess) { + ChunkPos chunkPos = chunkAccess.getPos(); + + int px = chunkPos.x << 1; + int pz = chunkPos.z << 1; + double[][][] noiseColumns = new double[3][3][33]; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + TerrainGenerator.fillTerrainDensity(noiseColumns[i][j], px + i, pz + j, biomeSource); + } + } + + // Testing + BlockState grass = Blocks.GRASS_BLOCK.defaultBlockState(); + + Heightmap heightmap = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG); + Heightmap heightmap2 = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG); + + short maxHeight = (short) (Math.min(127, chunkAccess.getMaxBuildHeight()) - chunkAccess.getMinBuildHeight()); + short start = (short) ((-chunkAccess.getMinBuildHeight()) >> 4); + short end = (short) (maxHeight >> 4); + + //IntStream.range(start, end).parallel().forEach(sectionIndex -> { + for (short sectionIndex = start; sectionIndex <= end; sectionIndex++) { + LevelChunkSection section = chunkAccess.getSection(sectionIndex); + for (byte y = 0; y < 16; y++) { + short iy = (short) ((y >> 2) | ((sectionIndex - start) << 2)); + float dy = (y & 3) / 4F; + for (byte x = 0; x < 16; x++) { + float dx = (x & 7) / 8F; + byte ix = (byte) (x >> 3); + for (byte z = 0; z < 16; z++) { + float dz = (z & 7) / 8F; + byte iz = (byte) (z >> 3); + + float a = (float) noiseColumns[ix][iz][iy]; + float b = (float) noiseColumns[ix + 1][iz][iy]; + float c = (float) noiseColumns[ix][iz][iy + 1]; + float d = (float) noiseColumns[ix + 1][iz][iy + 1]; + + float e = (float) noiseColumns[ix][iz + 1][iy]; + float f = (float) noiseColumns[ix + 1][iz + 1][iy]; + float g = (float) noiseColumns[ix][iz + 1][iy + 1]; + float h = (float) noiseColumns[ix + 1][iz + 1][iy + 1]; + + a = Mth.lerp(dx, a, b); + b = Mth.lerp(dx, c, d); + c = Mth.lerp(dx, e, f); + d = Mth.lerp(dx, g, h); + + a = Mth.lerp(dy, a, b); + b = Mth.lerp(dy, c, d); + + if (Mth.lerp(dz, a, b) > 0) { + section.setBlockState(x, y, z, defaultBlock); + heightmap.update(x, y, z, defaultBlock); + heightmap2.update(x, y, z, defaultBlock); + } + else if (iy > 0) { + byte py = (byte) ((y - 1) & 15); + LevelChunkSection section2 = y == 0 ? chunkAccess.getSection(sectionIndex - 1) : section; + if (section2.getBlockState(x, py, z).equals(defaultBlock)) { + section2.setBlockState(x, py, z, grass); + } + } + } + } + } + } + //}); + + return chunkAccess; + } } diff --git a/src/main/java/ru/betterend/mixin/common/NoiseInterpolatorMixin.java b/src/main/java/ru/betterend/mixin/common/NoiseInterpolatorMixin.java new file mode 100644 index 00000000..bd4a557f --- /dev/null +++ b/src/main/java/ru/betterend/mixin/common/NoiseInterpolatorMixin.java @@ -0,0 +1,24 @@ +package ru.betterend.mixin.common; + +import net.minecraft.world.level.levelgen.NoiseChunk; +import net.minecraft.world.level.levelgen.NoiseChunk.NoiseFiller; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import ru.betterend.world.generator.EndNoiseFiller; + +@Mixin(NoiseChunk.NoiseInterpolator.class) +public class NoiseInterpolatorMixin { + /*@Redirect( + method = "fillSlice([[DI)V", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/level/levelgen/NoiseChunk$NoiseInterpolator;noiseFiller:Lnet/minecraft/world/level/levelgen/NoiseChunk$NoiseFiller;", + opcode = Opcodes.GETFIELD + ) + ) + private NoiseFiller getFiller(NoiseChunk.NoiseInterpolator interpolator) { + return EndNoiseFiller.INSTANCE; + }*/ +} diff --git a/src/main/java/ru/betterend/world/generator/EndNoiseFiller.java b/src/main/java/ru/betterend/world/generator/EndNoiseFiller.java new file mode 100644 index 00000000..97e445c5 --- /dev/null +++ b/src/main/java/ru/betterend/world/generator/EndNoiseFiller.java @@ -0,0 +1,67 @@ +package ru.betterend.world.generator; + +import net.minecraft.util.Mth; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.levelgen.NoiseChunk.NoiseFiller; + +public class EndNoiseFiller implements NoiseFiller { + public static final EndNoiseFiller INSTANCE = new EndNoiseFiller(); + private double[][][] noiseColumns = new double[3][3][33]; + private BiomeSource biomeSource; + private int chunkX; + private int chunkZ; + + private EndNoiseFiller() {} + + public void setBiomeSource(BiomeSource biomeSource) { + this.biomeSource = biomeSource; + } + + @Override + public double calculateNoise(int x, int y, int z) { + if (y < 0 || y > 127) { + return -10; + } + + int cx = x >> 4; + int cz = z >> 4; + if (chunkX != cx || chunkZ != cz) { + chunkX = cx; + chunkZ = cz; + int px = cx << 1; + int pz = cz << 1; + for (byte i = 0; i < 3; i++) { + for (byte j = 0; j < 3; j++) { + TerrainGenerator.fillTerrainDensity(noiseColumns[i][j], px + i, pz + j, biomeSource); + } + } + } + + byte ix = (byte) ((x & 15) >> 3); + byte iy = (byte) (y >> 2); + byte iz = (byte) ((z & 15) >> 3); + float dx = (x & 7) / 8F; + float dy = (y & 3) / 4F; + float dz = (z & 7) / 8F; + + float a = (float) noiseColumns[ix][iz][iy]; + float b = (float) noiseColumns[ix + 1][iz][iy]; + float c = (float) noiseColumns[ix][iz][iy + 1]; + float d = (float) noiseColumns[ix + 1][iz][iy + 1]; + + float e = (float) noiseColumns[ix][iz + 1][iy]; + float f = (float) noiseColumns[ix + 1][iz + 1][iy]; + float g = (float) noiseColumns[ix][iz + 1][iy + 1]; + float h = (float) noiseColumns[ix + 1][iz + 1][iy + 1]; + + a = Mth.lerp(dx, a, b); + b = Mth.lerp(dx, c, d); + c = Mth.lerp(dx, e, f); + d = Mth.lerp(dx, g, h); + + a = Mth.lerp(dy, a, b); + b = Mth.lerp(dy, c, d); + + return Mth.lerp(dz, a, b); + } +} diff --git a/src/main/java/ru/betterend/world/generator/TerrainGenerator.java b/src/main/java/ru/betterend/world/generator/TerrainGenerator.java index f8c3bfbb..3de5c44e 100644 --- a/src/main/java/ru/betterend/world/generator/TerrainGenerator.java +++ b/src/main/java/ru/betterend/world/generator/TerrainGenerator.java @@ -84,8 +84,49 @@ public class TerrainGenerator { LOCKER.unlock(); } + public static float getTerrainDensity(int x, int y, int z, BiomeSource biomeSource) { + LOCKER.lock(); + + largeIslands.clearCache(); + mediumIslands.clearCache(); + smallIslands.clearCache(); + + double distortion1 = noise1.eval(x * 0.1, z * 0.1) * 20 + noise2.eval( + x * 0.2, + z * 0.2 + ) * 10 + noise1.eval(x * 0.4, z * 0.4) * 5; + double distortion2 = noise2.eval(x * 0.1, z * 0.1) * 20 + noise1.eval( + x * 0.2, + z * 0.2 + ) * 10 + noise2.eval(x * 0.4, z * 0.4) * 5; + double px = (double) x * SCALE_XZ + distortion1; + double pz = (double) z * SCALE_XZ + distortion2; + + largeIslands.updatePositions(px, pz); + mediumIslands.updatePositions(px, pz); + smallIslands.updatePositions(px, pz); + + float height = getAverageDepth(biomeSource, x << 1, z << 1) * 0.5F; + + double py = (double) y * SCALE_Y; + float dist = largeIslands.getDensity(px, py, pz, height); + dist = dist > 1 ? dist : MHelper.max(dist, mediumIslands.getDensity(px, py, pz, height)); + dist = dist > 1 ? dist : MHelper.max(dist, smallIslands.getDensity(px, py, pz, height)); + if (dist > -0.5F) { + dist += noise1.eval(px * 0.01, py * 0.01, pz * 0.01) * 0.02 + 0.02; + dist += noise2.eval(px * 0.05, py * 0.05, pz * 0.05) * 0.01 + 0.01; + dist += noise1.eval(px * 0.1, py * 0.1, pz * 0.1) * 0.005 + 0.005; + } + if (py > 100) { + dist = (float) Mth.lerp((py - 100) / 27F, dist, -1); + } + + LOCKER.unlock(); + return dist; + } + private static float getAverageDepth(BiomeSource biomeSource, int x, int z) { - if (getBiome(biomeSource, x, z).getTerrainHeight() < 0.1F) { + /*if (getBiome(biomeSource, x, z).getTerrainHeight() < 0.1F) { return 0F; } float depth = 0F; @@ -94,7 +135,8 @@ public class TerrainGenerator { int pz = z + OFFS[i].y; depth += getBiome(biomeSource, px, pz).getTerrainHeight() * COEF[i]; } - return depth; + return depth;*/ + return 0F; } private static BCLBiome getBiome(BiomeSource biomeSource, int x, int z) { diff --git a/src/main/resources/betterend.mixins.common.json b/src/main/resources/betterend.mixins.common.json index 006ceeee..6764b2a1 100644 --- a/src/main/resources/betterend.mixins.common.json +++ b/src/main/resources/betterend.mixins.common.json @@ -25,7 +25,8 @@ "EntityMixin", "PlayerMixin", "SlimeMixin", - "StructureFeaturesMixin" + "StructureFeaturesMixin", + "NoiseInterpolatorMixin" ], "injectors": { "defaultRequire": 1