add seed hack for biome provider

This commit is contained in:
dfsek
2022-06-03 20:39:05 -07:00
parent 229886d84c
commit 3b98f8c0ab
8 changed files with 219 additions and 88 deletions

View File

@@ -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;

View File

@@ -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<FabricChunkGeneratorWrapper> 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<FabricChunkGeneratorWrapper> 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))
);
}

View File

@@ -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<StructureSet> noiseRegistry;
private final RegistryEntry<ChunkGeneratorSettings> settings;
private ChunkGenerator delegate;
private ConfigPack pack;
public FabricChunkGeneratorWrapper(Registry<StructureSet> noiseRegistry, TerraBiomeSource biomeSource, long seed, ConfigPack configPack,
public FabricChunkGeneratorWrapper(Registry<StructureSet> noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack,
RegistryEntry<ChunkGeneratorSettings> 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<StructureSet> 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<ChunkGeneratorSettings> getSettings() {
return settings;
}

View File

@@ -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<net.minecraft.world.biome.Biome> biomeRegistry;
private final long seed;
private ConfigPack pack;
public TerraBiomeSource(Registry<net.minecraft.world.biome.Biome> biomes, long seed, ConfigPack pack) {
private final Object2LongMap<MultiNoiseSampler> noiseToSeed = new Object2LongOpenHashMap<>();
public TerraBiomeSource(Registry<net.minecraft.world.biome.Biome> 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;
}
}

View File

@@ -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 = "<init>(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At("TAIL"))
private void mapMultiNoise(ChunkGeneratorSettings chunkGeneratorSettings, Registry<DoublePerlinNoiseSampler.NoiseParameters> noiseRegistry, long seed, CallbackInfo ci) {
SeedHack.register(multiNoiseSampler, seed);
}
}

View File

@@ -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<WorldPreset> register(RegistryKey<WorldPreset> key, DimensionOptions dimensionOptions);
@Shadow
protected abstract DimensionOptions createOverworldOptions(ChunkGenerator chunkGenerator);
@Shadow
@Final
private Registry<StructureSet> structureSetRegistry;
@Shadow
@Final
private Registry<NoiseParameters> noiseParametersRegistry;
@Shadow
@Final
private Registry<Biome> biomeRegistry;
@Shadow
@Final
private Registry<ChunkGeneratorSettings> chunkGeneratorSettingsRegistry;
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
@Inject(method = "initAndGetDefault()Lnet/minecraft/util/registry/RegistryEntry;", at = @At("HEAD"))
private void injectInit(CallbackInfoReturnable<RegistryEntry<WorldPreset>> cir) {
LOGGER.info("Registering Terra world types...");
RegistryEntry<ChunkGeneratorSettings> 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<WorldPreset> terraWorldKey(String packNamespace, String id) {
return RegistryKey.of(Registry.WORLD_PRESET_KEY, Identifier.of("terra", id.toLowerCase(Locale.ROOT) + "/" + id.toLowerCase(
Locale.ROOT)));
}
}

View File

@@ -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<MultiNoiseSampler> 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);
}
}

View File

@@ -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"
}