Fix for crash when biomeSource is not initialized twice (paulevsGitch/BetterNether#468)

This commit is contained in:
Frank 2021-12-18 00:27:50 +01:00
parent 1bb15de385
commit b60df41c6c
8 changed files with 179 additions and 86 deletions

View file

@ -7,12 +7,14 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.mojang.serialization.Codec;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback; import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback;
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback; import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
import net.fabricmc.fabric.impl.biome.NetherBiomeData; import net.fabricmc.fabric.impl.biome.NetherBiomeData;
import net.fabricmc.fabric.impl.biome.TheEndBiomeData; import net.fabricmc.fabric.impl.biome.TheEndBiomeData;
import net.fabricmc.fabric.impl.structure.FabricStructureImpl;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
@ -45,16 +47,19 @@ import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.feature.StructureFeature; import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.levelgen.feature.configurations.StructureFeatureConfiguration;
import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableInt;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import ru.bclib.BCLib; import ru.bclib.BCLib;
import ru.bclib.config.Configs; import ru.bclib.config.Configs;
import ru.bclib.entity.BCLEntityWrapper; import ru.bclib.entity.BCLEntityWrapper;
import ru.bclib.interfaces.BiomeSourceAccessor;
import ru.bclib.interfaces.SurfaceMaterialProvider; import ru.bclib.interfaces.SurfaceMaterialProvider;
import ru.bclib.interfaces.SurfaceProvider; import ru.bclib.interfaces.SurfaceProvider;
import ru.bclib.interfaces.SurfaceRuleProvider; import ru.bclib.interfaces.SurfaceRuleProvider;
import ru.bclib.mixin.common.BiomeGenerationSettingsAccessor; import ru.bclib.mixin.common.BiomeGenerationSettingsAccessor;
import ru.bclib.mixin.common.BiomeSourceMixin;
import ru.bclib.mixin.common.MobSpawnSettingsAccessor; import ru.bclib.mixin.common.MobSpawnSettingsAccessor;
import ru.bclib.mixin.common.StructureSettingsAccessor; import ru.bclib.mixin.common.StructureSettingsAccessor;
import ru.bclib.util.CollectionsUtil; import ru.bclib.util.CollectionsUtil;
@ -67,14 +72,15 @@ import ru.bclib.world.structures.BCLStructureFeature;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -118,21 +124,19 @@ public class BiomeAPI {
return; return;
} }
BuiltinRegistries.BIOME BuiltinRegistries.BIOME.entrySet()
.entrySet()
.stream() .stream()
.filter(entry -> entry.getKey().location().getNamespace().equals("minecraft")) .filter(entry -> entry.getKey()
.map(entry -> entry.getValue()) .location()
.forEach(biome -> { .getNamespace()
BiomeGenerationSettingsAccessor accessor = BiomeGenerationSettingsAccessor.class.cast(biome.getGenerationSettings()); .equals("minecraft"))
List<List<Supplier<PlacedFeature>>> features = accessor.bclib_getFeatures(); .map(Entry::getValue)
features.forEach(step -> { .map(biome -> (BiomeGenerationSettingsAccessor) biome.getGenerationSettings())
step.forEach(provider -> { .map(BiomeGenerationSettingsAccessor::bclib_getFeatures)
PlacedFeature feature = provider.get(); .forEach(stepFeatureSuppliers -> stepFeatureSuppliers.forEach(step -> step.forEach(featureSupplier -> {
PlacedFeature feature = featureSupplier.get();
FEATURE_ORDER.computeIfAbsent(feature, f -> FEATURE_ORDER_ID.getAndIncrement()); FEATURE_ORDER.computeIfAbsent(feature, f -> FEATURE_ORDER_ID.getAndIncrement());
}); })));
});
});
} }
/** /**
@ -156,17 +160,56 @@ public class BiomeAPI {
} }
} }
private static final Set<BiomeSource> worldSources = new HashSet<>();
/**
* For internal use only.
*
* Used by {@link BiomeSourceMixin} to add new BiomeSources to the BiomeAPI. We need to know all
* created Sources in order to rebuild their feature set whenever biomes get recreated
* through a datapack.
* @param source The new {@link BiomeSource}
*/
public static void registerBiomeSource(BiomeSource source){
worldSources.add(source);
}
/**
* For internal use only.
*
* This method gets called before a world is loaded/created to flush cashes we build. The Method is
* called from {@link ru.bclib.mixin.client.MinecraftMixin}
*/
public static void prepareWorldData(){
structureStarts.clear();
worldSources.clear();
}
/**
* Registered by {@link #initRegistry(Registry)} as a callback for whenever a new Biome was
* added to our registry
* @param biome The {@link Biome} that got added
*/
private static void onAddedBiome(Biome biome) { private static void onAddedBiome(Biome biome) {
boolean didChange = false;
//BCLib.LOGGER.info(" ++++ " + getBiomeID(biome) + ", " + getBiomeKey(biome) + ", " + biome); //BCLib.LOGGER.info(" ++++ " + getBiomeID(biome) + ", " + getBiomeKey(biome) + ", " + biome);
for (var dim : MODIFICATIONS.keySet()) { for (var dim : MODIFICATIONS.keySet()) {
List<BiConsumer<ResourceLocation, Biome>> modifications = MODIFICATIONS.get(dim); List<BiConsumer<ResourceLocation, Biome>> modifications = MODIFICATIONS.get(dim);
if (modifications == null) { if (modifications == null) {
sortBiomeFeatures(biome); sortBiomeFeatures(biome);
return; continue;
} }
applyModifications(modifications, biome); didChange=true;
applyModificationsToBiome(modifications, biome);
} }
// if (didChange) {
// worldSources.stream()
// .filter(s -> s.possibleBiomes()
// .contains(biome))
// .forEach(s -> ((BiomeSourceAccessor) s).bclRebuildFeatures());
// }
} }
/** /**
@ -214,7 +257,7 @@ public class BiomeAPI {
MHelper.randRange(-1.5F, 1.5F, random), MHelper.randRange(-1.5F, 1.5F, random),
random.nextFloat() random.nextFloat()
); );
ResourceKey<Biome> key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); ResourceKey<Biome> key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).orElseThrow();
NetherBiomeData.addNetherBiome(key, parameters); NetherBiomeData.addNetherBiome(key, parameters);
return biome; return biome;
} }
@ -244,7 +287,7 @@ public class BiomeAPI {
configureBiome(biome); configureBiome(biome);
END_LAND_BIOME_PICKER.addBiome(biome); END_LAND_BIOME_PICKER.addBiome(biome);
float weight = biome.getGenChance(); float weight = biome.getGenChance();
ResourceKey<Biome> key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); ResourceKey<Biome> key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).orElseThrow();
TheEndBiomeData.addEndBiomeReplacement(Biomes.END_HIGHLANDS, key, weight); TheEndBiomeData.addEndBiomeReplacement(Biomes.END_HIGHLANDS, key, weight);
TheEndBiomeData.addEndBiomeReplacement(Biomes.END_MIDLANDS, key, weight); TheEndBiomeData.addEndBiomeReplacement(Biomes.END_MIDLANDS, key, weight);
return biome; return biome;
@ -290,7 +333,7 @@ public class BiomeAPI {
configureBiome(biome); configureBiome(biome);
END_VOID_BIOME_PICKER.addBiome(biome); END_VOID_BIOME_PICKER.addBiome(biome);
float weight = biome.getGenChance(); float weight = biome.getGenChance();
ResourceKey<Biome> key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); ResourceKey<Biome> key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).orElseThrow();
TheEndBiomeData.addEndBiomeReplacement(Biomes.SMALL_END_ISLANDS, key, weight); TheEndBiomeData.addEndBiomeReplacement(Biomes.SMALL_END_ISLANDS, key, weight);
return biome; return biome;
} }
@ -317,7 +360,6 @@ public class BiomeAPI {
* @return {@link BCLBiome} * @return {@link BCLBiome}
*/ */
public static BCLBiome registerEndVoidBiome(Biome biome, float genChance) { public static BCLBiome registerEndVoidBiome(Biome biome, float genChance) {
ResourceKey<Biome> key = BuiltinRegistries.BIOME.getResourceKey(biome).get();
BCLBiome bclBiome = new BCLBiome(biome).setGenChance(genChance); BCLBiome bclBiome = new BCLBiome(biome).setGenChance(genChance);
configureBiome(bclBiome); configureBiome(bclBiome);
END_VOID_BIOME_PICKER.addBiome(bclBiome); END_VOID_BIOME_PICKER.addBiome(bclBiome);
@ -361,8 +403,9 @@ public class BiomeAPI {
*/ */
@Nullable @Nullable
public static ResourceKey getBiomeKey(Biome biome) { public static ResourceKey getBiomeKey(Biome biome) {
ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).orElse(null); return BuiltinRegistries.BIOME.getResourceKey(biome)
return key != null ? key : biomeRegistry != null ? biomeRegistry.getResourceKey(biome).orElse(null) : null; .orElseGet(() -> biomeRegistry != null ? biomeRegistry.getResourceKey(biome)
.orElse(null) : null);
} }
/** /**
@ -460,11 +503,7 @@ public class BiomeAPI {
* @param modification {@link BiConsumer} with {@link ResourceKey} biome ID and {@link Biome} parameters. * @param modification {@link BiConsumer} with {@link ResourceKey} biome ID and {@link Biome} parameters.
*/ */
public static void registerBiomeModification(ResourceKey dimensionID, BiConsumer<ResourceLocation, Biome> modification) { public static void registerBiomeModification(ResourceKey dimensionID, BiConsumer<ResourceLocation, Biome> modification) {
List<BiConsumer<ResourceLocation, Biome>> modifications = MODIFICATIONS.get(dimensionID); List<BiConsumer<ResourceLocation, Biome>> modifications = MODIFICATIONS.computeIfAbsent(dimensionID, k -> Lists.newArrayList());
if (modifications == null) {
modifications = Lists.newArrayList();
MODIFICATIONS.put(dimensionID, modifications);
}
modifications.add(modification); modifications.add(modification);
} }
@ -521,11 +560,13 @@ public class BiomeAPI {
} }
biomes.forEach(biome -> { biomes.forEach(biome -> {
applyModifications(modifications, biome); applyModificationsToBiome(modifications, biome);
}); });
((BiomeSourceAccessor) source).bclRebuildFeatures();
} }
private static void applyModifications(List<BiConsumer<ResourceLocation, Biome>> modifications, Biome biome) { private static void applyModificationsToBiome(List<BiConsumer<ResourceLocation, Biome>> modifications, Biome biome) {
ResourceLocation biomeID = getBiomeID(biome); ResourceLocation biomeID = getBiomeID(biome);
boolean modify = isDatapackBiome(biomeID); boolean modify = isDatapackBiome(biomeID);
if (biome != BuiltinRegistries.BIOME.get(biomeID)) { if (biome != BuiltinRegistries.BIOME.get(biomeID)) {
@ -543,7 +584,7 @@ public class BiomeAPI {
final BCLBiome bclBiome = BiomeAPI.getBiome(biome); final BCLBiome bclBiome = BiomeAPI.getBiome(biome);
if (bclBiome!=null) { if (bclBiome!=null) {
addBiomeFeature(biome, bclBiome.getFeatures()); addStepFeaturesToBiome(biome, bclBiome.getFeatures());
} }
sortBiomeFeatures(biome); sortBiomeFeatures(biome);
@ -551,7 +592,7 @@ public class BiomeAPI {
public static void sortBiomeFeatures(Biome biome) { public static void sortBiomeFeatures(Biome biome) {
BiomeGenerationSettings settings = biome.getGenerationSettings(); BiomeGenerationSettings settings = biome.getGenerationSettings();
BiomeGenerationSettingsAccessor accessor = BiomeGenerationSettingsAccessor.class.cast(settings); BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) settings;
List<List<Supplier<PlacedFeature>>> featureList = CollectionsUtil.getMutable(accessor.bclib_getFeatures()); List<List<Supplier<PlacedFeature>>> featureList = CollectionsUtil.getMutable(accessor.bclib_getFeatures());
final int size = featureList.size(); final int size = featureList.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@ -629,7 +670,7 @@ public class BiomeAPI {
* @param step a {@link Decoration} step for the feature. * @param step a {@link Decoration} step for the feature.
* @param featureList List of {@link ConfiguredFeature} to add. * @param featureList List of {@link ConfiguredFeature} to add.
*/ */
public static void addBiomeFeature(Biome biome, Decoration step, List<PlacedFeature> featureList) { private static void addBiomeFeature(Biome biome, Decoration step, List<PlacedFeature> featureList) {
BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings(); BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings();
List<List<Supplier<PlacedFeature>>> allFeatures = CollectionsUtil.getMutable(accessor.bclib_getFeatures()); List<List<Supplier<PlacedFeature>>> allFeatures = CollectionsUtil.getMutable(accessor.bclib_getFeatures());
Set<PlacedFeature> set = CollectionsUtil.getMutable(accessor.bclib_getFeatureSet()); Set<PlacedFeature> set = CollectionsUtil.getMutable(accessor.bclib_getFeatureSet());
@ -643,11 +684,14 @@ public class BiomeAPI {
} }
/** /**
* Adds new features to existing biome. * For internal use only!
*
* Adds new features to existing biome. Called from {@link BCLBiome#setFeatures(Map)} when the Biome is
* first built, and from {@link #onAddedBiome(Biome)} whenever a Biome is readded through a Datapack
* @param biome {@link Biome} to add features in. * @param biome {@link Biome} to add features in.
* @param featureMap Map of {@link ConfiguredFeature} to add. * @param featureMap Map of {@link ConfiguredFeature} to add.
*/ */
public static void addBiomeFeature(Biome biome, Map<Decoration, List<Supplier<PlacedFeature>>> featureMap) { public static void addStepFeaturesToBiome(Biome biome, Map<Decoration, List<Supplier<PlacedFeature>>> featureMap) {
BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings(); BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings();
List<List<Supplier<PlacedFeature>>> allFeatures = CollectionsUtil.getMutable(accessor.bclib_getFeatures()); List<List<Supplier<PlacedFeature>>> allFeatures = CollectionsUtil.getMutable(accessor.bclib_getFeatures());
Set<PlacedFeature> set = CollectionsUtil.getMutable(accessor.bclib_getFeatureSet()); Set<PlacedFeature> set = CollectionsUtil.getMutable(accessor.bclib_getFeatureSet());
@ -665,34 +709,6 @@ public class BiomeAPI {
accessor.bclib_setFeatureSet(set); accessor.bclib_setFeatureSet(set);
} }
/**
* Adds new features to existing biome.
* @param biomeID {@link ResourceLocation} of the {@link Biome} to add features in.
* @param feature {@link ConfiguredFeature} to add.
* @param step a {@link Decoration} step for the feature.
*/
private static void addBiomeFeature(ResourceLocation biomeID, PlacedFeature feature, Decoration step) {
addBiomeFeature(BuiltinRegistries.BIOME.get(biomeID), step, feature);
}
/**
* Adds new features to existing biome.
* @param biome {@link Biome} to add features in.
* @param features array of {@link BCLFeature} to add.
*/
public static void addBiomeFeatures(Biome biome, BCLFeature... features) {
BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings();
List<List<Supplier<PlacedFeature>>> allFeatures = CollectionsUtil.getMutable(accessor.bclib_getFeatures());
Set<PlacedFeature> set = CollectionsUtil.getMutable(accessor.bclib_getFeatureSet());
for (BCLFeature feature: features) {
List<Supplier<PlacedFeature>> featureList = getFeaturesList(allFeatures, feature.getDecoration());
featureList.add(() -> feature.getPlacedFeature());
set.add(feature.getPlacedFeature());
}
accessor.bclib_setFeatures(allFeatures);
accessor.bclib_setFeatureSet(set);
}
/** /**
* Adds new structure feature to existing biome. * Adds new structure feature to existing biome.
* @param biomeKey {@link ResourceKey} for the {@link Biome} to add structure feature in. * @param biomeKey {@link ResourceKey} for the {@link Biome} to add structure feature in.
@ -703,17 +719,26 @@ public class BiomeAPI {
BCLib.LOGGER.error("null is not a valid biomeKey for " + structure); BCLib.LOGGER.error("null is not a valid biomeKey for " + structure);
return; return;
} }
changeStructureStarts(biomeKey.location(), structure, structureMap -> { changeStructureStarts(biomeKey.location(), structure, (structureMap, configMap) -> {
Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>> configuredMap = structureMap.computeIfAbsent(structure.feature, k -> HashMultimap.create()); Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>> configuredMap = structureMap.computeIfAbsent(structure.feature, k -> HashMultimap.create());
configuredMap.put(structure, biomeKey); configuredMap.put(structure, biomeKey);
StructureFeatureConfiguration config = FabricStructureImpl.STRUCTURE_TO_CONFIG_MAP.get(structure.feature);
if (config!=null){
configMap.put(structure.feature, config);
}
}); });
} }
public static void addBiomeStructure(Biome biome, ConfiguredStructureFeature structure) { public static void addBiomeStructure(Biome biome, ConfiguredStructureFeature structure) {
changeStructureStarts(BiomeAPI.getBiomeID(biome), structure, structureMap -> { changeStructureStarts(BiomeAPI.getBiomeID(biome), structure, (structureMap, configMap) -> {
Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>> configuredMap = structureMap.computeIfAbsent(structure.feature, k -> HashMultimap.create()); Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>> configuredMap = structureMap.computeIfAbsent(structure.feature, k -> HashMultimap.create());
var key = getBiomeKey(biome); var key = getBiomeKey(biome);
if (key!=null) { if (key!=null) {
StructureFeatureConfiguration config = FabricStructureImpl.STRUCTURE_TO_CONFIG_MAP.get(structure.feature);
if (config!=null){
configMap.put(structure.feature, config);
}
configuredMap.put(structure, key); configuredMap.put(structure, key);
} else { } else {
BCLib.LOGGER.warning("Unable to find Biome " + getBiomeID(biome)); BCLib.LOGGER.warning("Unable to find Biome " + getBiomeID(biome));
@ -881,11 +906,13 @@ public class BiomeAPI {
} }
} }
private final static Map<StructureID, Consumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>>> structureStarts = new HashMap<>(); private final static Map<StructureID, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>>> structureStarts = new HashMap<>();
public static void registerStructureEvents(){ public static void registerStructureEvents(){
DynamicRegistrySetupCallback.EVENT.register(registryManager -> { DynamicRegistrySetupCallback.EVENT.register(registryManager -> {
Optional<? extends Registry<NoiseGeneratorSettings>> oGeneratorRegistry = registryManager.registry(Registry.NOISE_GENERATOR_SETTINGS_REGISTRY); Optional<? extends Registry<NoiseGeneratorSettings>> oGeneratorRegistry = registryManager.registry(Registry.NOISE_GENERATOR_SETTINGS_REGISTRY);
Optional<? extends Registry<Codec<? extends BiomeSource>>> oBiomeSourceRegistry = registryManager.registry(Registry.BIOME_SOURCE_REGISTRY);
if (oGeneratorRegistry.isPresent()) { if (oGeneratorRegistry.isPresent()) {
RegistryEntryAddedCallback RegistryEntryAddedCallback
@ -895,7 +922,7 @@ public class BiomeAPI {
//add back modded structures //add back modded structures
StructureSettingsAccessor a = (StructureSettingsAccessor)settings.structureSettings(); StructureSettingsAccessor a = (StructureSettingsAccessor)settings.structureSettings();
structureStarts.values().forEach(modifier -> changeStructureStarts(a, modifier)); structureStarts.entrySet().forEach(entry -> changeStructureStarts(a, entry.getValue()));
//add surface rules //add surface rules
if (biomeRegistry!=null) { if (biomeRegistry!=null) {
@ -919,11 +946,7 @@ public class BiomeAPI {
} }
} }
public static void clearStructureStarts(){ private static void changeStructureStarts(ResourceLocation id, ConfiguredStructureFeature structure, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>> modifier) {
structureStarts.clear();
}
private static void changeStructureStarts(ResourceLocation id, ConfiguredStructureFeature structure, Consumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>> modifier) {
structureStarts.put(new StructureID(id, structure), modifier); structureStarts.put(new StructureID(id, structure), modifier);
Registry<NoiseGeneratorSettings> chunkGenSettingsRegistry = BuiltinRegistries.NOISE_GENERATOR_SETTINGS; Registry<NoiseGeneratorSettings> chunkGenSettingsRegistry = BuiltinRegistries.NOISE_GENERATOR_SETTINGS;
@ -934,11 +957,17 @@ public class BiomeAPI {
} }
private static void changeStructureStarts(StructureSettingsAccessor access, Consumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>> modifier) { private static void changeStructureStarts(StructureSettingsAccessor access, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>> modifier) {
Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> structureMap; Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> structureMap;
structureMap = getMutableStructureConfig(access); Map<StructureFeature<?>, StructureFeatureConfiguration> configMap;
modifier.accept(structureMap);
setMutableStructureConfig(access, structureMap); structureMap = getMutableConfiguredStructures(access);
configMap = getMutableStructureConfig(access);
modifier.accept(structureMap, configMap);
setMutableConfiguredStructures(access, structureMap);
setMutableStructureConfig(access, configMap);
} }
private static void sortFeatures(List<Supplier<PlacedFeature>> features) { private static void sortFeatures(List<Supplier<PlacedFeature>> features) {
@ -1000,7 +1029,7 @@ public class BiomeAPI {
} }
//inspired by net.fabricmc.fabric.impl.biome.modification.BiomeStructureStartsImpl //inspired by net.fabricmc.fabric.impl.biome.modification.BiomeStructureStartsImpl
private static Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> getMutableStructureConfig(StructureSettingsAccessor access) { private static Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> getMutableConfiguredStructures(StructureSettingsAccessor access) {
ImmutableMap<StructureFeature<?>, ImmutableMultimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> configuredStructures = access.bcl_getConfiguredStructures(); ImmutableMap<StructureFeature<?>, ImmutableMultimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> configuredStructures = access.bcl_getConfiguredStructures();
Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> result = new HashMap<>(configuredStructures.size()); Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> result = new HashMap<>(configuredStructures.size());
@ -1012,7 +1041,7 @@ public class BiomeAPI {
} }
//inspired by net.fabricmc.fabric.impl.biome.modification.BiomeStructureStartsImpl //inspired by net.fabricmc.fabric.impl.biome.modification.BiomeStructureStartsImpl
private static void setMutableStructureConfig(StructureSettingsAccessor access, Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> structureStarts) { private static void setMutableConfiguredStructures(StructureSettingsAccessor access, Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> structureStarts) {
access.bcl_setConfiguredStructures( access.bcl_setConfiguredStructures(
structureStarts structureStarts
.entrySet() .entrySet()
@ -1020,4 +1049,12 @@ public class BiomeAPI {
.collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, e -> ImmutableMultimap.copyOf(e.getValue()))) .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, e -> ImmutableMultimap.copyOf(e.getValue())))
); );
} }
private static Map<StructureFeature<?>, StructureFeatureConfiguration> getMutableStructureConfig(StructureSettingsAccessor access) {
return CollectionsUtil.getMutable(access.bcl_getStructureConfig());
}
private static void setMutableStructureConfig(StructureSettingsAccessor access, Map<StructureFeature<?>, StructureFeatureConfiguration> structureConfig) {
access.bcl_setStructureConfig(structureConfig);
}
} }

View file

@ -0,0 +1,5 @@
package ru.bclib.interfaces;
public interface BiomeSourceAccessor {
void bclRebuildFeatures();
}

View file

@ -61,7 +61,7 @@ public abstract class MinecraftMixin {
@Inject(method = "loadLevel", cancellable = true, at = @At("HEAD")) @Inject(method = "loadLevel", cancellable = true, at = @At("HEAD"))
private void bclib_callFixerOnLoad(String levelID, CallbackInfo ci) { private void bclib_callFixerOnLoad(String levelID, CallbackInfo ci) {
DataExchangeAPI.prepareServerside(); DataExchangeAPI.prepareServerside();
BiomeAPI.clearStructureStarts(); BiomeAPI.prepareWorldData();
if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> { if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> {
LifeCycleAPI._runBeforeLevelLoad(); LifeCycleAPI._runBeforeLevelLoad();
@ -76,6 +76,9 @@ public abstract class MinecraftMixin {
@Inject(method = "createLevel", at = @At("HEAD")) @Inject(method = "createLevel", at = @At("HEAD"))
private void bclib_initPatchData(String levelID, LevelSettings levelSettings, RegistryHolder registryHolder, WorldGenSettings worldGenSettings, CallbackInfo ci) { private void bclib_initPatchData(String levelID, LevelSettings levelSettings, RegistryHolder registryHolder, WorldGenSettings worldGenSettings, CallbackInfo ci) {
DataExchangeAPI.prepareServerside();
BiomeAPI.prepareWorldData();
DataFixerAPI.initializeWorldData(this.levelSource, levelID, true); DataFixerAPI.initializeWorldData(this.levelSource, levelID, true);
LifeCycleAPI._runBeforeLevelLoad(); LifeCycleAPI._runBeforeLevelLoad();
} }

View file

@ -0,0 +1,38 @@
package ru.bclib.mixin.common;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.BiomeSource.StepFeatureData;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.bclib.BCLib;
import ru.bclib.api.biomes.BiomeAPI;
import ru.bclib.interfaces.BiomeSourceAccessor;
import java.util.List;
import java.util.Set;
@Mixin(BiomeSource.class)
public abstract class BiomeSourceMixin implements BiomeSourceAccessor {
@Shadow protected abstract List<StepFeatureData> buildFeaturesPerStep(List<Biome> list, boolean bl);
@Shadow public abstract Set<Biome> possibleBiomes();
@Mutable @Shadow @Final private List<StepFeatureData> featuresPerStep;
public void bclRebuildFeatures(){
BCLib.LOGGER.info("Rebuilding features in BiomeSource " + this.getClass());
featuresPerStep = buildFeaturesPerStep(this.possibleBiomes().stream().toList(), true);
}
@Inject(method="<init>(Ljava/util/List;)V", at=@At(value="INVOKE", shift = Shift.AFTER, target="Lnet/minecraft/world/level/biome/BiomeSource;buildFeaturesPerStep(Ljava/util/List;Z)Ljava/util/List;"))
private void bcl_Init(List list, CallbackInfo ci){
BiomeAPI.registerBiomeSource((BiomeSource)(Object)this);
}
}

View file

@ -7,16 +7,26 @@ import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.StructureSettings; import net.minecraft.world.level.levelgen.StructureSettings;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.feature.StructureFeature; import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.levelgen.feature.configurations.StructureFeatureConfiguration;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(StructureSettings.class) @Mixin(StructureSettings.class)
public interface StructureSettingsAccessor { public interface StructureSettingsAccessor {
@Accessor("configuredStructures") @Accessor("configuredStructures")
ImmutableMap<StructureFeature<?>, ImmutableMultimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> bcl_getConfiguredStructures(); ImmutableMap<StructureFeature<?>, ImmutableMultimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> bcl_getConfiguredStructures();
@Accessor("structureConfig")
Map<StructureFeature<?>, StructureFeatureConfiguration> bcl_getStructureConfig();
@Accessor("configuredStructures") @Accessor("configuredStructures")
@Mutable @Mutable
void bcl_setConfiguredStructures(ImmutableMap<StructureFeature<?>, ImmutableMultimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> structureConfig); void bcl_setConfiguredStructures(ImmutableMap<StructureFeature<?>, ImmutableMultimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> configuredStructures);
@Accessor("structureConfig")
@Mutable
void bcl_setStructureConfig(Map<StructureFeature<?>, StructureFeatureConfiguration> structureConfig);
} }

View file

@ -15,10 +15,8 @@ import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import ru.bclib.BCLib; import ru.bclib.BCLib;
import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.api.biomes.BiomeAPI;
import ru.bclib.util.Pair;
import ru.bclib.util.WeightedList; import ru.bclib.util.WeightedList;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -370,6 +368,7 @@ public class BCLBiome {
*/ */
public void setFeatures(Map<Decoration, List<Supplier<PlacedFeature>>> features) { public void setFeatures(Map<Decoration, List<Supplier<PlacedFeature>>> features) {
this.features = features; this.features = features;
BiomeAPI.addStepFeaturesToBiome(getBiome(), features);
} }
/** /**

View file

@ -39,7 +39,8 @@
"AnvilMenuMixin", "AnvilMenuMixin",
"TagLoaderMixin", "TagLoaderMixin",
"MainMixin", "MainMixin",
"SurfaceRulesContextAccessor" "SurfaceRulesContextAccessor",
"BiomeSourceMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1