From 3b98f8c0ab6d3a839c88eeab98691cc844802071 Mon Sep 17 00:00:00 2001 From: dfsek Date: Fri, 3 Jun 2022 20:39:05 -0700 Subject: [PATCH] add seed hack for biome provider --- .../dfsek/terra/fabric/FabricEntryPoint.java | 1 + .../com/dfsek/terra/fabric/data/Codecs.java | 41 ++++---- .../FabricChunkGeneratorWrapper.java | 14 +-- .../fabric/generation/TerraBiomeSource.java | 17 ++-- .../mixin/lifecycle/NoiseConfigMixin.java | 32 +++++++ .../lifecycle/WorldPresetsRegistrarMixin.java | 77 +++++++++++++++ .../com/dfsek/terra/fabric/util/SeedHack.java | 29 ++++++ .../src/main/resources/terra.mixins.json | 96 ++++++++++--------- 8 files changed, 219 insertions(+), 88 deletions(-) create mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java create mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/WorldPresetsRegistrarMixin.java create mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java index 0a85d5abe..7974d8884 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java @@ -20,6 +20,7 @@ package com.dfsek.terra.fabric; import net.fabricmc.api.ModInitializer; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; +import net.minecraft.world.gen.WorldPresets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java index a1164de1e..a2d2222c7 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java @@ -39,32 +39,27 @@ public final class Codecs { .fieldOf("biome_registry") .stable() .forGetter(TerraBiomeSource::getBiomeRegistry), - Codec.LONG.fieldOf("seed") - .stable() - .forGetter(TerraBiomeSource::getSeed), CONFIG_PACK.fieldOf("pack") .stable() .forGetter(TerraBiomeSource::getPack)) .apply(instance, instance.stable(TerraBiomeSource::new))); - public static final Codec FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder.create( - instance -> instance.group( - RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) - .fieldOf("structure_registry") - .stable() - .forGetter(FabricChunkGeneratorWrapper::getNoiseRegistry), - TERRA_BIOME_SOURCE.fieldOf("biome_source") - .stable() - .forGetter(FabricChunkGeneratorWrapper::getBiomeSource), - Codec.LONG.fieldOf("seed") - .stable() - .forGetter(FabricChunkGeneratorWrapper::getSeed), - CONFIG_PACK.fieldOf("pack") - .stable() - .forGetter(FabricChunkGeneratorWrapper::getPack), - ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings") - .stable() - .forGetter(FabricChunkGeneratorWrapper::getSettings) - ).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new)) - ); + public static final Codec FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder + .create( + instance -> instance.group( + RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) + .fieldOf("structure_registry") + .stable() + .forGetter(FabricChunkGeneratorWrapper::getNoiseRegistry), + TERRA_BIOME_SOURCE.fieldOf("biome_source") + .stable() + .forGetter(FabricChunkGeneratorWrapper::getBiomeSource), + CONFIG_PACK.fieldOf("pack") + .stable() + .forGetter(FabricChunkGeneratorWrapper::getPack), + ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings") + .stable() + .forGetter(FabricChunkGeneratorWrapper::getSettings) + ).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new)) + ); } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java index c8471c2bd..9420da166 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java @@ -20,6 +20,7 @@ package com.dfsek.terra.fabric.generation; import com.mojang.serialization.Codec; import net.minecraft.block.BlockState; import net.minecraft.structure.StructureSet; +import net.minecraft.util.Util; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.random.CheckedRandom; @@ -66,14 +67,13 @@ import com.dfsek.terra.fabric.util.FabricAdapter; public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { private static final Logger logger = LoggerFactory.getLogger(FabricChunkGeneratorWrapper.class); - private final long seed; private final TerraBiomeSource biomeSource; private final Registry noiseRegistry; private final RegistryEntry settings; private ChunkGenerator delegate; private ConfigPack pack; - public FabricChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, long seed, ConfigPack configPack, + public FabricChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, RegistryEntry settingsSupplier) { super(noiseRegistry, Optional.empty(), biomeSource); this.noiseRegistry = noiseRegistry; @@ -83,8 +83,6 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C this.delegate = pack.getGeneratorProvider().newInstance(pack); logger.info("Loading world with config pack {}", pack.getID()); this.biomeSource = biomeSource; - - this.seed = seed; } public Registry getNoiseRegistry() { @@ -158,7 +156,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public int getHeight(int x, int z, Type heightmap, HeightLimitView height, NoiseConfig noiseConfig) { int y = height.getTopY(); - WorldProperties properties = FabricAdapter.adapt(height, seed); + WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); while(y >= getMinimumY() && !heightmap.getBlockPredicate().test( (BlockState) delegate.getBlock(properties, x, y - 1, z, biomeProvider))) { @@ -170,7 +168,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height, NoiseConfig noiseConfig) { BlockState[] array = new BlockState[height.getHeight()]; - WorldProperties properties = FabricAdapter.adapt(height, seed); + WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); for(int y = height.getTopY() - 1; y >= height.getBottomY(); y--) { array[y - height.getBottomY()] = (BlockState) delegate.getBlock(properties, x, y, z, biomeProvider); @@ -206,10 +204,6 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C return delegate; } - public long getSeed() { - return seed; - } - public RegistryEntry getSettings() { return settings; } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java index 7767892e2..ebd61ce41 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java @@ -22,7 +22,11 @@ import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.fabric.data.Codecs; import com.dfsek.terra.fabric.util.ProtoPlatformBiome; +import com.dfsek.terra.fabric.util.SeedHack; + import com.mojang.serialization.Codec; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryEntry; import net.minecraft.world.biome.source.BiomeSource; @@ -30,6 +34,7 @@ import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; import java.util.stream.StreamSupport; @@ -37,17 +42,17 @@ public class TerraBiomeSource extends BiomeSource { private static final Logger LOGGER = LoggerFactory.getLogger(TerraBiomeSource.class); private final Registry biomeRegistry; - private final long seed; private ConfigPack pack; - public TerraBiomeSource(Registry biomes, long seed, ConfigPack pack) { + private final Object2LongMap noiseToSeed = new Object2LongOpenHashMap<>(); + + public TerraBiomeSource(Registry biomes, ConfigPack pack) { super(StreamSupport .stream(pack.getBiomeProvider() .getBiomes() .spliterator(), false) .map(b -> biomes.getOrCreateEntry(((ProtoPlatformBiome) b.getPlatformBiome()).getDelegate()))); this.biomeRegistry = biomes; - this.seed = seed; this.pack = pack; LOGGER.debug("Biomes: " + getBiomes()); @@ -63,7 +68,7 @@ public class TerraBiomeSource extends BiomeSource { return biomeRegistry .entryOf(((ProtoPlatformBiome) pack .getBiomeProvider() - .getBiome(biomeX << 2, biomeY << 2, biomeZ << 2, seed) + .getBiome(biomeX << 2, biomeY << 2, biomeZ << 2, SeedHack.getSeed(noiseSampler)) .getPlatformBiome()).getDelegate() ); } @@ -83,8 +88,4 @@ public class TerraBiomeSource extends BiomeSource { public void setPack(ConfigPack pack) { this.pack = pack; } - - public long getSeed() { - return seed; - } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java new file mode 100644 index 000000000..6f9af2ed8 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java @@ -0,0 +1,32 @@ +package com.dfsek.terra.fabric.mixin.lifecycle; + +import com.dfsek.terra.fabric.util.SeedHack; + +import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.source.util.MultiNoiseUtil; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; +import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import net.minecraft.world.gen.noise.NoiseConfig; +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.callback.CallbackInfo; + + +/** + * Hack to map noise sampler to seeds + */ +@Mixin(NoiseConfig.class) +public class NoiseConfigMixin { + @Shadow + @Final + private MultiNoiseSampler multiNoiseSampler; + + @Inject(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At("TAIL")) + private void mapMultiNoise(ChunkGeneratorSettings chunkGeneratorSettings, Registry noiseRegistry, long seed, CallbackInfo ci) { + SeedHack.register(multiNoiseSampler, seed); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/WorldPresetsRegistrarMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/WorldPresetsRegistrarMixin.java new file mode 100644 index 000000000..d450ade4a --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/WorldPresetsRegistrarMixin.java @@ -0,0 +1,77 @@ +package com.dfsek.terra.fabric.mixin.lifecycle; + +import com.dfsek.terra.fabric.FabricEntryPoint; +import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.fabric.generation.TerraBiomeSource; + +import net.minecraft.structure.StructureSet; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.noise.DoublePerlinNoiseSampler.NoiseParameters; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryEntry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.dimension.DimensionOptions; +import net.minecraft.world.gen.WorldPreset; +import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.callback.CallbackInfoReturnable; + +import java.util.Locale; + + +@Mixin(targets = "net/minecraft/world/gen/WorldPresets$Registrar") +public abstract class WorldPresetsRegistrarMixin { + @Shadow + protected abstract RegistryEntry register(RegistryKey key, DimensionOptions dimensionOptions); + + @Shadow + protected abstract DimensionOptions createOverworldOptions(ChunkGenerator chunkGenerator); + + @Shadow + @Final + private Registry structureSetRegistry; + + @Shadow + @Final + private Registry noiseParametersRegistry; + @Shadow + @Final + private Registry biomeRegistry; + @Shadow + @Final + private Registry chunkGeneratorSettingsRegistry; + private final Logger LOGGER = LoggerFactory.getLogger(getClass()); + + @Inject(method = "initAndGetDefault()Lnet/minecraft/util/registry/RegistryEntry;", at = @At("HEAD")) + private void injectInit(CallbackInfoReturnable> cir) { + LOGGER.info("Registering Terra world types..."); + RegistryEntry overworld = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.OVERWORLD); + FabricEntryPoint + .getPlatform() + .getRawConfigRegistry() + .forEach((id, pack) -> register( + terraWorldKey(id.getNamespace(), id.getID()), + createOverworldOptions( + new FabricChunkGeneratorWrapper( + structureSetRegistry, + new TerraBiomeSource(biomeRegistry, pack), + pack, + overworld) + ) + ) + ); + } + + private static RegistryKey terraWorldKey(String packNamespace, String id) { + return RegistryKey.of(Registry.WORLD_PRESET_KEY, Identifier.of("terra", id.toLowerCase(Locale.ROOT) + "/" + id.toLowerCase( + Locale.ROOT))); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java new file mode 100644 index 000000000..c10054114 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java @@ -0,0 +1,29 @@ +package com.dfsek.terra.fabric.util; + +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Holder for hacky biome source seed workaround + */ +public class SeedHack { + private static final Logger LOGGER = LoggerFactory.getLogger(SeedHack.class); + + private static final Object2LongMap seedMap = new Object2LongOpenHashMap<>(); + + public static long getSeed(MultiNoiseSampler sampler) { + if(!seedMap.containsKey(sampler)) { + throw new IllegalArgumentException("Sampler is not registered: " + sampler); + } + return seedMap.getLong(sampler); + } + + public static void register(MultiNoiseSampler sampler, long seed) { + LOGGER.info("Registered seed {} to sampler {}", seed, sampler); + seedMap.put(sampler, seed); + } +} diff --git a/platforms/fabric/src/main/resources/terra.mixins.json b/platforms/fabric/src/main/resources/terra.mixins.json index 4427b2e80..080386eb5 100644 --- a/platforms/fabric/src/main/resources/terra.mixins.json +++ b/platforms/fabric/src/main/resources/terra.mixins.json @@ -1,49 +1,51 @@ { - "required": true, - "minVersion": "0.8", - "package": "com.dfsek.terra.fabric.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "access.MobSpawnerLogicAccessor", - "access.StateAccessor", - "access.StructureAccessorAccessor", - "compat.GenerationSettingsFloraFeaturesMixin", - "implementations.BiomeMixin", - "implementations.HandleImplementationMixin", - "implementations.block.BlockMixin", - "implementations.block.entity.BlockEntityMixin", - "implementations.block.entity.LootableContainerBlockEntityMixin", - "implementations.block.entity.MobSpawnerBlockEntityMixin", - "implementations.block.entity.SignBlockEntityMixin", - "implementations.block.state.BlockStateMixin", - "implementations.block.state.PropertyMixin", - "implementations.chunk.ChunkRegionMixin", - "implementations.chunk.WorldChunkMixin", - "implementations.chunk.data.ProtoChunkMixin", - "implementations.entity.EntityMixin", - "implementations.entity.EntityTypeMixin", - "implementations.entity.PlayerEntityMixin", - "implementations.entity.ServerCommandSourceMixin", - "implementations.inventory.LockableContainerBlockEntityMixin", - "implementations.inventory.item.ItemMixin", - "implementations.inventory.item.ItemStackMixin", - "implementations.inventory.meta.EnchantmentMixin", - "implementations.inventory.meta.ItemStackDamageableMixin", - "implementations.inventory.meta.ItemStackMetaMixin", - "implementations.world.ChunkRegionMixin", - "implementations.world.ServerWorldMixin", - "lifecycle.DataPackContentsMixin", - "lifecycle.MinecraftServerMixin", - "lifecycle.RegistryMixin" - ], - "client": [ - "lifecycle.client.MinecraftClientMixin" - ], - "server": [ - "lifecycle.server.ServerMainMixin" - ], - "injectors": { - "defaultRequire": 1 - }, - "refmap": "terra-refmap.json" + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.fabric.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "access.MobSpawnerLogicAccessor", + "access.StateAccessor", + "access.StructureAccessorAccessor", + "compat.GenerationSettingsFloraFeaturesMixin", + "implementations.BiomeMixin", + "implementations.HandleImplementationMixin", + "implementations.block.BlockMixin", + "implementations.block.entity.BlockEntityMixin", + "implementations.block.entity.LootableContainerBlockEntityMixin", + "implementations.block.entity.MobSpawnerBlockEntityMixin", + "implementations.block.entity.SignBlockEntityMixin", + "implementations.block.state.BlockStateMixin", + "implementations.block.state.PropertyMixin", + "implementations.chunk.ChunkRegionMixin", + "implementations.chunk.WorldChunkMixin", + "implementations.chunk.data.ProtoChunkMixin", + "implementations.entity.EntityMixin", + "implementations.entity.EntityTypeMixin", + "implementations.entity.PlayerEntityMixin", + "implementations.entity.ServerCommandSourceMixin", + "implementations.inventory.LockableContainerBlockEntityMixin", + "implementations.inventory.item.ItemMixin", + "implementations.inventory.item.ItemStackMixin", + "implementations.inventory.meta.EnchantmentMixin", + "implementations.inventory.meta.ItemStackDamageableMixin", + "implementations.inventory.meta.ItemStackMetaMixin", + "implementations.world.ChunkRegionMixin", + "implementations.world.ServerWorldMixin", + "lifecycle.DataPackContentsMixin", + "lifecycle.MinecraftServerMixin", + "lifecycle.NoiseConfigMixin", + "lifecycle.RegistryMixin", + "lifecycle.WorldPresetsRegistrarMixin" + ], + "client": [ + "lifecycle.client.MinecraftClientMixin" + ], + "server": [ + "lifecycle.server.ServerMainMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "terra-refmap.json" } \ No newline at end of file