Cleanup and Speed Improvement of SurfaceRules/Structures (paulevsGitch/BetterNether#485, paulevsGitch/BetterEnd#420)

This commit is contained in:
Frank 2022-01-26 17:56:54 +01:00
parent 01f728c282
commit baf1e0f4b1
10 changed files with 144 additions and 189 deletions

View file

@ -48,8 +48,6 @@ public class BCLib implements ModInitializer {
Chunker.DESCRIPTOR Chunker.DESCRIPTOR
)); ));
BiomeAPI.registerStructureEvents();
BCLibPatch.register(); BCLibPatch.register();
Configs.save(); Configs.save();
} }

View file

@ -1,12 +1,6 @@
package ru.bclib.api.biomes; package ru.bclib.api.biomes;
import com.google.common.collect.HashMultimap; import com.google.common.collect.*;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
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;
@ -28,11 +22,7 @@ import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.*;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData; import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@ -43,6 +33,7 @@ import net.minecraft.world.level.levelgen.GenerationStep.Carving;
import net.minecraft.world.level.levelgen.GenerationStep.Decoration; import net.minecraft.world.level.levelgen.GenerationStep.Decoration;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; 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.SurfaceRules;
import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource; import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource;
import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
@ -56,10 +47,7 @@ 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.entity.BCLEntityWrapper; import ru.bclib.entity.BCLEntityWrapper;
import ru.bclib.interfaces.BiomeSourceAccessor; import ru.bclib.interfaces.*;
import ru.bclib.interfaces.SurfaceMaterialProvider;
import ru.bclib.interfaces.SurfaceProvider;
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.BiomeSourceMixin;
import ru.bclib.mixin.common.MobSpawnSettingsAccessor; import ru.bclib.mixin.common.MobSpawnSettingsAccessor;
@ -73,16 +61,8 @@ import ru.bclib.world.features.BCLFeature;
import ru.bclib.world.generator.BiomePicker; import ru.bclib.world.generator.BiomePicker;
import ru.bclib.world.structures.BCLStructureFeature; import ru.bclib.world.structures.BCLStructureFeature;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -108,8 +88,8 @@ public class BiomeAPI {
private final static Map<StructureID, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>>> STRUCTURE_STARTS = new HashMap<>(); private final static Map<StructureID, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>>> STRUCTURE_STARTS = new HashMap<>();
private static final Map<ResourceKey, List<BiConsumer<ResourceLocation, Biome>>> MODIFICATIONS = Maps.newHashMap(); private static final Map<ResourceKey, List<BiConsumer<ResourceLocation, Biome>>> MODIFICATIONS = Maps.newHashMap();
private static final Map<ResourceLocation, SurfaceRules.RuleSource> SURFACE_RULES = Maps.newHashMap(); private static final Map<ResourceLocation, SurfaceRules.RuleSource> SURFACE_RULES = Maps.newHashMap();
private static final Set<NoiseGeneratorSettings> NOISE_GENERATOR_SETTINGS = new HashSet<>(); private static final Set<SurfaceRuleProvider> MODIFIED_SURFACE_PROVIDERS = new HashSet<>(8);
public static final BCLBiome NETHER_WASTES_BIOME = registerNetherBiome(getFromRegistry(Biomes.NETHER_WASTES)); public static final BCLBiome NETHER_WASTES_BIOME = registerNetherBiome(getFromRegistry(Biomes.NETHER_WASTES));
public static final BCLBiome CRIMSON_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.CRIMSON_FOREST)); public static final BCLBiome CRIMSON_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.CRIMSON_FOREST));
public static final BCLBiome WARPED_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.WARPED_FOREST)); public static final BCLBiome WARPED_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.WARPED_FOREST));
@ -155,42 +135,18 @@ public class BiomeAPI {
CLIENT.clear(); CLIENT.clear();
} }
} }
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);
}
private static WorldData worldData;
public static void registerWorldData(WorldData w){
worldData = w;
if (worldData!=null){
worldData.worldGenSettings().dimensions().forEach(dim->{
StructureSettingsAccessor a = (StructureSettingsAccessor)dim.generator().getSettings();
STRUCTURE_STARTS.entrySet().forEach(entry -> applyStructureStarts(a, entry.getValue()));
});
}
}
/** /**
* For internal use only. * For internal use only.
* *
* This method gets called before a world is loaded/created to flush cashes we build. The Method is * 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} * called from {@link ru.bclib.mixin.client.MinecraftMixin}
*/ */
public static void prepareWorldData(){ public static void prepareNewLevel(){
STRUCTURE_STARTS.clear(); STRUCTURE_STARTS.clear();
worldSources.clear();
NOISE_GENERATOR_SETTINGS.clear(); MODIFIED_SURFACE_PROVIDERS.forEach(p->p.bclib_clearBiomeSources());
MODIFIED_SURFACE_PROVIDERS.clear();
} }
/** /**
@ -517,34 +473,60 @@ public class BiomeAPI {
* @param level * @param level
*/ */
public static void applyModifications(ServerLevel level) { public static void applyModifications(ServerLevel level) {
BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource(); final BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource();
Set<Biome> biomes = source.possibleBiomes(); final StructureSettings settings = level.getChunkSource().getGenerator().getSettings();
final Set<Biome> biomes = source.possibleBiomes();
NoiseGeneratorSettings generator = null;
if (level.dimension() == Level.NETHER) { NoiseGeneratorSettings generator = level
generator = BuiltinRegistries.NOISE_GENERATOR_SETTINGS.get(NoiseGeneratorSettings.NETHER); .getServer()
.getWorldData()
.worldGenSettings()
.dimensions()
.stream()
.filter(dim->dim.generator().getSettings()==settings)
.map(dim->((NoiseGeneratorSettingsProvider)dim.generator()).bclib_getNoiseGeneratorSettings()).findFirst().orElse(null);;
// Datapacks (like Amplified Nether)will change the GeneratorSettings upon load, so we will
// only use the default Setting for Nether/End if we were unable to find a settings object
if (generator==null){
if (level.dimension() == Level.NETHER) {
generator = BuiltinRegistries.NOISE_GENERATOR_SETTINGS.get(NoiseGeneratorSettings.NETHER);
} else if (level.dimension() == Level.END) {
generator = BuiltinRegistries.NOISE_GENERATOR_SETTINGS.get(NoiseGeneratorSettings.END);
}
} }
else if (level.dimension() == Level.END) {
generator = BuiltinRegistries.NOISE_GENERATOR_SETTINGS.get(NoiseGeneratorSettings.END);
}
if (generator != null) {
List<SurfaceRules.RuleSource> rules = getRuleSources(biomes);
SurfaceRuleProvider provider = SurfaceRuleProvider.class.cast(generator);
changeSurfaceRules(rules, provider);
}
List<BiConsumer<ResourceLocation, Biome>> modifications = MODIFICATIONS.get(level.dimension()); List<BiConsumer<ResourceLocation, Biome>> modifications = MODIFICATIONS.get(level.dimension());
if (modifications == null) { if (modifications == null) {
biomes.forEach(biome -> sortBiomeFeatures(biome)); biomes.forEach(biome -> sortBiomeFeatures(biome));
((BiomeSourceAccessor) source).bclRebuildFeatures(); } else {
return; biomes.forEach(biome -> {
applyModificationsToBiome(modifications, biome);
});
} }
biomes.forEach(biome -> { if (generator != null) {
applyModificationsToBiome(modifications, biome); final SurfaceRuleProvider provider = SurfaceRuleProvider.class.cast(generator);
}); // Multiple Biomes can use the same generator. So we need to keep track of all Biomes that are
// Provided by all the BiomeSources that use the same generator.
// This happens for example when using the MiningDimensions, which reuses the generator for the
// Nethering Dimension
MODIFIED_SURFACE_PROVIDERS.add(provider);
provider.bclib_addBiomeSource(source);
} else {
BCLib.LOGGER.warning("No generator for " + source);
}
if (settings!=null){
final StructureSettingsAccessor settingsAccessor = (StructureSettingsAccessor)settings;
final Set<ResourceLocation> biomeIDs = biomes.stream().map(BiomeAPI::getBiomeID).collect(Collectors.toSet());
for (Entry<StructureID, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>>> e : STRUCTURE_STARTS.entrySet()) {
if (biomeIDs.contains(e.getKey().biomeID)) {
applyStructureStarts(settingsAccessor, e.getValue());
}
}
}
((BiomeSourceAccessor) source).bclRebuildFeatures(); ((BiomeSourceAccessor) source).bclRebuildFeatures();
} }
@ -562,6 +544,10 @@ public class BiomeAPI {
sortBiomeFeatures(biome); sortBiomeFeatures(biome);
} }
/**
* Create a unique sort order for all Features of the Biome
* @param biome The {@link Biome} to sort the features for
*/
public static void sortBiomeFeatures(Biome biome) { public static void sortBiomeFeatures(Biome biome) {
BiomeGenerationSettings settings = biome.getGenerationSettings(); BiomeGenerationSettings settings = biome.getGenerationSettings();
BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) settings; BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) settings;
@ -575,7 +561,7 @@ public class BiomeAPI {
accessor.bclib_setFeatures(featureList); accessor.bclib_setFeatures(featureList);
} }
private static List<SurfaceRules.RuleSource> getRuleSources(Set<Biome> biomes) { private static List<SurfaceRules.RuleSource> getRuleSourcesForBiomes(Set<Biome> biomes) {
Set<ResourceLocation> biomeIDs = biomes Set<ResourceLocation> biomeIDs = biomes
.stream() .stream()
.map(biome -> getBiomeID(biome)) .map(biome -> getBiomeID(biome))
@ -583,12 +569,23 @@ public class BiomeAPI {
return getRuleSourcesFromIDs(biomeIDs); return getRuleSourcesFromIDs(biomeIDs);
} }
private static List<SurfaceRules.RuleSource> getAllRuleSources() { /**
List<SurfaceRules.RuleSource> rules = Lists.newArrayList(); * Creates a list of SurfaceRules for all Biomes that are managed by the passed {@link BiomeSource}.
SURFACE_RULES.forEach((biomeID, rule) -> { * If we have Surface rules for any of the Biomes from the given set of {@link BiomeSource}, they
rules.add(rule); * will be added to the result
}); *
return rules; * Note: This Method is used in the {@link ru.bclib.mixin.common.NoiseGeneratorSettingsMixin} which in turn
* is called from {@link #applyModifications(ServerLevel)}.
* @param sources The Set of {@link BiomeSource} we want to consider
* @return A list of {@link RuleSource}-Objects that are needed to create those Biomes
*/
public static List<SurfaceRules.RuleSource> getRuleSources(Set<BiomeSource> sources) {
final Set<Biome> biomes = new HashSet<>();
for (BiomeSource s : sources) {
biomes.addAll(s.possibleBiomes());
}
return getRuleSourcesForBiomes(biomes);
} }
private static List<SurfaceRules.RuleSource> getRuleSourcesFromIDs(Set<ResourceLocation> biomeIDs) { private static List<SurfaceRules.RuleSource> getRuleSourcesFromIDs(Set<ResourceLocation> biomeIDs) {
@ -643,11 +640,12 @@ public class BiomeAPI {
/** /**
* For internal use only! * For internal use only!
* *
* Adds new features to existing biome. Called from {@link BCLBiome#setFeatures(Map)} when the Biome is first built * Adds new features to existing biome. Called from {@link #applyModificationsToBiome(List, Biome)} when the Biome is
* present in any {@link BiomeSource}
* @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 addStepFeaturesToBiome(Biome biome, Map<Decoration, List<Supplier<PlacedFeature>>> featureMap) { private 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());
@ -685,7 +683,12 @@ public class BiomeAPI {
} }
}); });
} }
/**
* Add an existing StructureFeature to a Biome
* @param biome The {@link Biome} you want to add teh feature to
* @param structure The {@link ConfiguredStructureFeature} to add
*/
public static void addBiomeStructure(Biome biome, ConfiguredStructureFeature structure) { public static void addBiomeStructure(Biome biome, ConfiguredStructureFeature structure) {
changeStructureStarts(BiomeAPI.getBiomeID(biome), structure, (structureMap, configMap) -> { 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());
@ -744,7 +747,7 @@ public class BiomeAPI {
*/ */
public static void addSurfaceRule(ResourceLocation biomeID, SurfaceRules.RuleSource source) { public static void addSurfaceRule(ResourceLocation biomeID, SurfaceRules.RuleSource source) {
SURFACE_RULES.put(biomeID, source); SURFACE_RULES.put(biomeID, source);
NOISE_GENERATOR_SETTINGS.forEach(BiomeAPI::changeSurfaceRulesForGenerator); //NOISE_GENERATOR_SETTINGS.forEach(BiomeAPI::changeSurfaceRulesForGenerator);
} }
/** /**
@ -859,17 +862,17 @@ public class BiomeAPI {
} }
static class StructureID { static class StructureID {
public final ResourceLocation id; public final ResourceLocation biomeID;
public final ConfiguredStructureFeature structure; public final ConfiguredStructureFeature structure;
StructureID(ResourceLocation id, ConfiguredStructureFeature structure){ StructureID(ResourceLocation biomeID, ConfiguredStructureFeature structure){
this.id = id; this.biomeID = biomeID;
this.structure = structure; this.structure = structure;
} }
@Override @Override
public String toString() { public String toString() {
return "StructureID{" + "id=" + id + ", structure=" + structure + '}'; return "StructureID{" + "id=" + biomeID + ", structure=" + structure + '}';
} }
@Override @Override
@ -877,91 +880,19 @@ public class BiomeAPI {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
StructureID that = (StructureID) o; StructureID that = (StructureID) o;
return id.equals(that.id) && structure.equals(that.structure); return biomeID.equals(that.biomeID) && structure.equals(that.structure);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id, structure); return Objects.hash(biomeID, structure);
} }
} }
private static void registerNoiseGeneratorAndChangeSurfaceRules(NoiseGeneratorSettings settings){ private static void changeStructureStarts(ResourceLocation biomeID, ConfiguredStructureFeature structure, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>> modifier) {
NOISE_GENERATOR_SETTINGS.add(settings); STRUCTURE_STARTS.put(new StructureID(biomeID, structure), modifier);
changeSurfaceRulesForGenerator(settings);
} }
public static void registerStructureEvents(){
DynamicRegistrySetupCallback.EVENT.register(registryManager -> {
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 (oBiomeSourceRegistry.isPresent()) {
// RegistryEntryAddedCallback
// .event(oBiomeSourceRegistry.get())
// .register((rawId, id, source) -> {
// BCLib.LOGGER.info(" #### " + rawId + ", " + source + ", " + id);
// });
// }
if (oGeneratorRegistry.isPresent()) {
oGeneratorRegistry.get().forEach(BiomeAPI::registerNoiseGeneratorAndChangeSurfaceRules);
RegistryEntryAddedCallback
.event(oGeneratorRegistry.get())
.register((rawId, id, settings) -> {
//BCLib.LOGGER.info(" #### " + rawId + ", " + object + ", " + id);
//add back modded structures
StructureSettingsAccessor a = (StructureSettingsAccessor)settings.structureSettings();
STRUCTURE_STARTS.entrySet().forEach(entry -> applyStructureStarts(a, entry.getValue()));
//add surface rules
registerNoiseGeneratorAndChangeSurfaceRules(settings);
});
}
});
}
private static void changeSurfaceRulesForGenerator(NoiseGeneratorSettings settings){
List<SurfaceRules.RuleSource> rules;
if (biomeRegistry!=null) {
rules = getRuleSourcesFromIDs(biomeRegistry.keySet());
} else {
rules = getAllRuleSources();
}
SurfaceRuleProvider provider = SurfaceRuleProvider.class.cast(settings);
changeSurfaceRules(rules, provider);
}
private static void changeSurfaceRules(List<RuleSource> rules, SurfaceRuleProvider provider) {
if (rules.size() > 0) {
provider.addCustomRules(rules);
}
else {
provider.clearCustomRules();
}
}
private static void changeStructureStarts(ResourceLocation id, ConfiguredStructureFeature structure, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>> modifier) {
STRUCTURE_STARTS.put(new StructureID(id, structure), modifier);
Registry<NoiseGeneratorSettings> chunkGenSettingsRegistry = BuiltinRegistries.NOISE_GENERATOR_SETTINGS;
for (Map.Entry<ResourceKey<NoiseGeneratorSettings>, NoiseGeneratorSettings> entry : chunkGenSettingsRegistry.entrySet()) {
final StructureSettingsAccessor access = (StructureSettingsAccessor) entry.getValue().structureSettings();
applyStructureStarts(access, modifier);
}
if (worldData!=null){
worldData.worldGenSettings().dimensions().forEach(dim->{
StructureSettingsAccessor access = (StructureSettingsAccessor)dim.generator().getSettings();
applyStructureStarts(access, modifier);
});
}
}
private static void applyStructureStarts(StructureSettingsAccessor access, BiConsumer<Map<StructureFeature<?>, Multimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>>, Map<StructureFeature<?>, StructureFeatureConfiguration>> modifier) { private static void applyStructureStarts(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;
Map<StructureFeature<?>, StructureFeatureConfiguration> configMap; Map<StructureFeature<?>, StructureFeatureConfiguration> configMap;

View file

@ -0,0 +1,7 @@
package ru.bclib.interfaces;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
public interface NoiseGeneratorSettingsProvider {
NoiseGeneratorSettings bclib_getNoiseGeneratorSettings();
}

View file

@ -1,10 +1,11 @@
package ru.bclib.interfaces; package ru.bclib.interfaces;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource; import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource;
import java.util.List; import java.util.List;
public interface SurfaceRuleProvider { public interface SurfaceRuleProvider {
void clearCustomRules(); void bclib_addBiomeSource(BiomeSource source);
void addCustomRules(List<RuleSource> rules); void bclib_clearBiomeSources();
} }

View file

@ -62,7 +62,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.prepareWorldData(); BiomeAPI.prepareNewLevel();
if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> { if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> {
LifeCycleAPI._runBeforeLevelLoad(); LifeCycleAPI._runBeforeLevelLoad();
@ -84,7 +84,7 @@ 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(); DataExchangeAPI.prepareServerside();
BiomeAPI.prepareWorldData(); BiomeAPI.prepareNewLevel();
DataFixerAPI.initializeWorldData(this.levelSource, levelID, true); DataFixerAPI.initializeWorldData(this.levelSource, levelID, true);
LifeCycleAPI._runBeforeLevelLoad(); LifeCycleAPI._runBeforeLevelLoad();

View file

@ -30,9 +30,4 @@ public abstract class BiomeSourceMixin implements BiomeSourceAccessor {
BCLib.LOGGER.info("Rebuilding features in BiomeSource " + this.getClass()); BCLib.LOGGER.info("Rebuilding features in BiomeSource " + this.getClass());
featuresPerStep = buildFeaturesPerStep(this.possibleBiomes().stream().toList(), true); 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

@ -46,7 +46,6 @@ public class MinecraftServerMixin {
@Inject(method = "<init>*", at = @At("TAIL")) @Inject(method = "<init>*", at = @At("TAIL"))
private void bclib_onServerInit(Thread thread, RegistryHolder registryHolder, LevelStorageAccess levelStorageAccess, WorldData worldData, PackRepository packRepository, Proxy proxy, DataFixer dataFixer, ServerResources serverResources, MinecraftSessionService minecraftSessionService, GameProfileRepository gameProfileRepository, GameProfileCache gameProfileCache, ChunkProgressListenerFactory chunkProgressListenerFactory, CallbackInfo ci) { private void bclib_onServerInit(Thread thread, RegistryHolder registryHolder, LevelStorageAccess levelStorageAccess, WorldData worldData, PackRepository packRepository, Proxy proxy, DataFixer dataFixer, ServerResources serverResources, MinecraftSessionService minecraftSessionService, GameProfileRepository gameProfileRepository, GameProfileCache gameProfileCache, ChunkProgressListenerFactory chunkProgressListenerFactory, CallbackInfo ci) {
DataExchangeAPI.prepareServerside(); DataExchangeAPI.prepareServerside();
BiomeAPI.registerWorldData(worldData);
} }
@Inject(method = "reloadResources", at = @At(value = "RETURN"), cancellable = true) @Inject(method = "reloadResources", at = @At(value = "RETURN"), cancellable = true)

View file

@ -19,6 +19,7 @@ import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import ru.bclib.BCLib; import ru.bclib.BCLib;
import ru.bclib.interfaces.NoiseGeneratorSettingsProvider;
import ru.bclib.interfaces.SurfaceProvider; import ru.bclib.interfaces.SurfaceProvider;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -26,7 +27,7 @@ import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
@Mixin(NoiseBasedChunkGenerator.class) @Mixin(NoiseBasedChunkGenerator.class)
public abstract class NoiseBasedChunkGeneratorMixin implements SurfaceProvider { public abstract class NoiseBasedChunkGeneratorMixin implements SurfaceProvider, NoiseGeneratorSettingsProvider {
@Final @Final
@Shadow @Shadow
private NoiseSampler sampler; private NoiseSampler sampler;
@ -41,6 +42,11 @@ public abstract class NoiseBasedChunkGeneratorMixin implements SurfaceProvider {
private static BlockState bclib_air = Blocks.AIR.defaultBlockState(); private static BlockState bclib_air = Blocks.AIR.defaultBlockState();
private static Constructor<?> bclib_constructor; private static Constructor<?> bclib_constructor;
@Override
public NoiseGeneratorSettings bclib_getNoiseGeneratorSettings(){
return settings.get();
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")

View file

@ -1,5 +1,6 @@
package ru.bclib.mixin.common; package ru.bclib.mixin.common;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.SurfaceRules; import net.minecraft.world.level.levelgen.SurfaceRules;
import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource; import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource;
@ -7,9 +8,12 @@ import org.spongepowered.asm.mixin.Final;
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.Shadow; import org.spongepowered.asm.mixin.Shadow;
import ru.bclib.api.biomes.BiomeAPI;
import ru.bclib.interfaces.SurfaceRuleProvider; import ru.bclib.interfaces.SurfaceRuleProvider;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Mixin(NoiseGeneratorSettings.class) @Mixin(NoiseGeneratorSettings.class)
@ -20,17 +24,32 @@ public class NoiseGeneratorSettingsMixin implements SurfaceRuleProvider {
private SurfaceRules.RuleSource surfaceRule; private SurfaceRules.RuleSource surfaceRule;
private SurfaceRules.RuleSource bclib_originalSurfaceRule; private SurfaceRules.RuleSource bclib_originalSurfaceRule;
private Set<BiomeSource> bclib_biomeSources = new HashSet<>();
private void bclib_updateCutomRules(){
bclib_setCustomRules(BiomeAPI.getRuleSources(bclib_biomeSources));
}
@Override @Override
public void clearCustomRules() { public void bclib_addBiomeSource(BiomeSource source) {
bclib_biomeSources.add(source);
bclib_updateCutomRules();
}
@Override
public void bclib_clearBiomeSources(){
bclib_biomeSources.clear();
bclib_clearCustomRules();
}
private void bclib_clearCustomRules() {
if (bclib_originalSurfaceRule != null){ if (bclib_originalSurfaceRule != null){
this.surfaceRule = bclib_originalSurfaceRule; this.surfaceRule = bclib_originalSurfaceRule;
bclib_originalSurfaceRule = null; bclib_originalSurfaceRule = null;
} }
} }
@Override private void bclib_setCustomRules(List<RuleSource> rules) {
public void addCustomRules(List<RuleSource> rules) {
RuleSource org = getOriginalSurfaceRule(); RuleSource org = getOriginalSurfaceRule();
if (org instanceof SurfaceRules.SequenceRuleSource sequenceRule){ if (org instanceof SurfaceRules.SequenceRuleSource sequenceRule){
List<RuleSource> currentSequence = sequenceRule.sequence(); List<RuleSource> currentSequence = sequenceRule.sequence();

View file

@ -288,7 +288,7 @@ public class BCLBiome extends BCLBiomeSettings {
this.surfaceInit = (actualBiome) -> { this.surfaceInit = (actualBiome) -> {
ResourceKey key = BiomeAPI.getBiomeKey(actualBiome); ResourceKey key = BiomeAPI.getBiomeKey(actualBiome);
if (key == null) { if (key == null) {
BCLib.LOGGER.warning("BCL Biome " + biomeID + " don't have registry key!"); BCLib.LOGGER.warning("BCL Biome " + biomeID + " does not have registry key!");
} }
else { else {
BiomeAPI.addSurfaceRule(biomeID, SurfaceRules.ifTrue(SurfaceRules.isBiome(key), surface)); BiomeAPI.addSurfaceRule(biomeID, SurfaceRules.ifTrue(SurfaceRules.isBiome(key), surface));
@ -304,7 +304,6 @@ public class BCLBiome extends BCLBiomeSettings {
*/ */
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);
} }
/** /**