From e470610294a29197488d8cef65cb8479135ab783 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 3 Dec 2021 12:22:00 +0100 Subject: [PATCH] WIP: No longer using Fabric BiomeModification API for features/structures/spawns --- .../ru/bclib/api/biomes/BCLBiomeBuilder.java | 9 +- .../java/ru/bclib/api/biomes/BiomeAPI.java | 221 ++++++++++++------ .../BiomeGenerationSettingsAccessor.java | 21 ++ .../common/MobSpawnSettingsAccessor.java | 21 ++ .../common/StructureSettingsAccessor.java | 28 +++ .../java/ru/bclib/world/biomes/BCLBiome.java | 15 +- .../ru/bclib/world/biomes/BCLBiomeDef.java | 2 +- src/main/resources/bclib.mixins.common.json | 5 +- 8 files changed, 245 insertions(+), 77 deletions(-) create mode 100644 src/main/java/ru/bclib/mixin/common/BiomeGenerationSettingsAccessor.java create mode 100644 src/main/java/ru/bclib/mixin/common/MobSpawnSettingsAccessor.java create mode 100644 src/main/java/ru/bclib/mixin/common/StructureSettingsAccessor.java diff --git a/src/main/java/ru/bclib/api/biomes/BCLBiomeBuilder.java b/src/main/java/ru/bclib/api/biomes/BCLBiomeBuilder.java index 97fde8e7..da74bf61 100644 --- a/src/main/java/ru/bclib/api/biomes/BCLBiomeBuilder.java +++ b/src/main/java/ru/bclib/api/biomes/BCLBiomeBuilder.java @@ -32,6 +32,8 @@ import ru.bclib.world.biomes.BCLBiome; import ru.bclib.world.features.BCLFeature; import ru.bclib.world.structures.BCLStructureFeature; +import java.util.ArrayList; +import java.util.List; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -447,15 +449,14 @@ public class BCLBiomeBuilder { return feature(feature.getDecoration(), feature.getPlacedFeature()); } + private List structures = new ArrayList<>(2); /** * Adds new structure feature into the biome. * @param structure {@link ConfiguredStructureFeature} to add. * @return same {@link BCLBiomeBuilder} instance. */ public BCLBiomeBuilder structure(ConfiguredStructureFeature structure) { - BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE - .getResourceKey(structure) - .ifPresent(key -> BiomeModifications.addStructure(ctx -> ctx.getBiomeKey().location().equals(biomeID), key)); + structures.add(structure); return this; } @@ -514,6 +515,7 @@ public class BCLBiomeBuilder { } final T res = biomeConstructor.apply(biomeID, builder.build()); + res.attachedStructures = structures; res.setFogDensity(fogDensity); return res; } @@ -521,6 +523,7 @@ public class BCLBiomeBuilder { /** * Get or create {@link BiomeSpecialEffects.Builder} for biome visual effects. * For internal usage only. + * For internal usage only. * @return new or same {@link BiomeSpecialEffects.Builder} instance. */ private BiomeSpecialEffects.Builder getEffects() { diff --git a/src/main/java/ru/bclib/api/biomes/BiomeAPI.java b/src/main/java/ru/bclib/api/biomes/BiomeAPI.java index 934ced83..f46e3a5a 100644 --- a/src/main/java/ru/bclib/api/biomes/BiomeAPI.java +++ b/src/main/java/ru/bclib/api/biomes/BiomeAPI.java @@ -1,49 +1,64 @@ package ru.bclib.api.biomes; +import com.google.common.collect.HashMultimap; +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.Environment; -import net.fabricmc.fabric.api.biome.v1.BiomeModifications; import net.fabricmc.fabric.impl.biome.NetherBiomeData; import net.fabricmc.fabric.impl.biome.TheEndBiomeData; import net.minecraft.client.Minecraft; import net.minecraft.core.Registry; -import net.minecraft.core.RegistryAccess; import net.minecraft.data.BuiltinRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.random.WeightedRandomList; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.MobCategory; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.Biome.BiomeCategory; 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.levelgen.GenerationStep.Decoration; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +import net.minecraft.world.level.levelgen.feature.StructureFeature; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import org.jetbrains.annotations.Nullable; +import ru.bclib.BCLib; import ru.bclib.config.Configs; +import ru.bclib.mixin.common.BiomeGenerationSettingsAccessor; +import ru.bclib.mixin.common.MobSpawnSettingsAccessor; +import ru.bclib.mixin.common.StructureSettingsAccessor; import ru.bclib.util.MHelper; import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.biomes.BCLBiomeDef; import ru.bclib.world.biomes.FabricBiomesData; import ru.bclib.world.features.BCLFeature; import ru.bclib.world.generator.BiomePicker; import ru.bclib.world.structures.BCLStructureFeature; -import java.util.HashSet; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.function.BiConsumer; -import java.util.stream.Collectors; +import java.util.function.Consumer; +import java.util.function.Supplier; public class BiomeAPI { /** @@ -272,6 +287,15 @@ public class BiomeAPI { return endBiome; } + /** + * Get biome {@link ResourceKey} from given {@link Biome}. + * @param biome - {@link Biome} from server world. + * @return biome {@link ResourceKey} or {@code null}. + */ + public static ResourceKey getBiomeKey(Biome biome) { + return biomeRegistry.getResourceKey(biome).orElse(null); + } + /** * Get biome {@link ResourceLocation} from given {@link Biome}. * @param biome - {@link Biome} from server world. @@ -428,16 +452,6 @@ public class BiomeAPI { addBiomeFeature(biome, feature.getPlacedFeature(), feature.getDecoration()); } - /** - * Adds new features to existing biome. - * @param biomeID {@link ResourceLocation} for the {@link Biome} to add features in. - * @param feature {@link ConfiguredFeature} to add. - * - */ - public static void addBiomeFeature(ResourceLocation biomeID, BCLFeature feature) { - addBiomeFeature(biomeID, feature.getPlacedFeature(), feature.getDecoration()); - } - /** * Adds new features to existing biome. * @param biome {@link Biome} to add features in. @@ -445,19 +459,13 @@ public class BiomeAPI { * @param step a {@link Decoration} step for the feature. */ public static void addBiomeFeature(Biome biome, PlacedFeature feature, Decoration step) { - addBiomeFeature(getBiomeID(biome), feature, step); - } - - /** - * 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) { - BuiltinRegistries.PLACED_FEATURE - .getResourceKey(feature) - .ifPresent(key -> BiomeModifications.addFeature(ctx -> ctx.getBiomeKey().location().equals(biomeID), step, key)); +// BiomeModificationContextImpl ctx = new BiomeModificationContextImpl(,,biome); +// ctx.getGenerationSettings().addFeature(step, feature.); + BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings(); + List>> biomeFeatures = getMutableList(accessor.bcl_getFeatures()); + List> list = getList(step, biomeFeatures); + list.add(() -> feature); + accessor.bcl_setFeatures(biomeFeatures); } /** @@ -473,50 +481,69 @@ public class BiomeAPI { /** * Adds new structure feature to existing biome. - * @param biome {@link Biome} to add structure feature in. + * @param biomeKey {@link ResourceKey} for the {@link Biome} to add structure feature in. * @param structure {@link ConfiguredStructureFeature} to add. */ + public static void addBiomeStructure(ResourceKey biomeKey, ConfiguredStructureFeature structure) { + //BiomeStructureStartsImpl.addStart(registries, structure, getBiomeID(biome)); + changeStructureStarts(structureMap -> { + Multimap, ResourceKey> configuredMap = structureMap.computeIfAbsent(structure.feature, k -> HashMultimap.create()); + + configuredMap.put(structure, biomeKey); + }); + + + } + public static void addBiomeStructure(Biome biome, ConfiguredStructureFeature structure) { - addBiomeStructure(getBiomeID(biome), structure); + //BiomeStructureStartsImpl.addStart(registries, structure, getBiomeID(biome)); + changeStructureStarts(structureMap -> { + Multimap, ResourceKey> configuredMap = structureMap.computeIfAbsent(structure.feature, k -> HashMultimap.create()); + + var key = getBiomeKey(biome); + if (key!=null) { + configuredMap.put(structure, key); + } else { + BCLib.LOGGER.error("Unable to find Biome " + getBiomeID(biome)); + } + }); + + } + + private static void changeStructureStarts(Consumer, Multimap, ResourceKey>>> modifier) { + Registry chunkGenSettingsRegistry = BuiltinRegistries.NOISE_GENERATOR_SETTINGS; + + for (Map.Entry, NoiseGeneratorSettings> entry : chunkGenSettingsRegistry.entrySet()) { + Map, Multimap, ResourceKey>> structureMap = getMutableStructureConfig(entry.getValue()); + + modifier.accept(structureMap); + setMutableStructureConfig(entry.getValue(), structureMap); + } + + + } + + /** * Adds new structure feature to existing biome. - * @param biomeID {@link ResourceLocation} of the {@link Biome} to add structure feature in. - * @param structure {@link ConfiguredStructureFeature} to add. - */ - public static void addBiomeStructure(ResourceLocation biomeID, ConfiguredStructureFeature structure) { - BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE - .getResourceKey(structure) - .ifPresent(key -> BiomeModifications.addStructure(ctx -> ctx.getBiomeKey().location().equals(biomeID), key)); - } - - /** - * Adds new structure feature to existing biome. - * @param biome {@link Biome} to add structure feature in. + * @param biomeKey {@link ResourceKey} for the {@link Biome} to add structure feature in. * @param structure {@link BCLStructureFeature} to add. */ - public static void addBiomeStructure(Biome biome, BCLStructureFeature structure) { - addBiomeStructure(biome, structure.getFeatureConfigured()); + public static void addBiomeStructure(ResourceKey biomeKey, BCLStructureFeature structure) { + addBiomeStructure(biomeKey, structure.getFeatureConfigured()); } - /** - * Adds new structure feature to existing biome. - * @param biomeID {@link ResourceLocation} of the {@link Biome} to add structure feature in. - * @param structure {@link BCLStructureFeature} to add. - */ - public static void addBiomeStructure(ResourceLocation biomeID, BCLStructureFeature structure) { - addBiomeStructure(biomeID, structure.getFeatureConfigured()); - } /** * Adds new structure features to existing biome. - * @param biome {@link Biome} to add structure features in. + * @param biomeKey {@link ResourceKey} for the {@link Biome} to add structure features in. * @param structures array of {@link BCLStructureFeature} to add. */ - public static void addBiomeStructures(Biome biome, BCLStructureFeature... structures) { + public static void addBiomeStructures(ResourceKey biomeKey, BCLStructureFeature... structures) { for (BCLStructureFeature structure: structures) { - addBiomeStructure(biome, structure.getFeatureConfigured()); + addBiomeStructure(biomeKey, structure.getFeatureConfigured()); } } @@ -529,22 +556,13 @@ public class BiomeAPI { * @param maxGroupCount maximum mobs in group. */ public static void addBiomeMobSpawn(Biome biome, EntityType entityType, int weight, int minGroupCount, int maxGroupCount) { - addBiomeMobSpawn(getBiomeID(biome), entityType, weight, minGroupCount, maxGroupCount); - } - - /** - * Adds mob spawning to specified biome. - * @param biomeID {@link ResourceLocation} of the {@link Biome }to add mob spawning. - * @param entityType {@link EntityType} mob type. - * @param weight spawn weight. - * @param minGroupCount minimum mobs in group. - * @param maxGroupCount maximum mobs in group. - */ - public static void addBiomeMobSpawn(ResourceLocation biomeID, EntityType entityType, int weight, int minGroupCount, int maxGroupCount) { - BiomeModifications.addSpawn( - ctx -> ctx.getBiomeKey().location().equals(biomeID), - entityType.getCategory(), entityType, weight, minGroupCount, maxGroupCount - ); + final MobCategory category = entityType.getCategory(); + MobSpawnSettingsAccessor accessor = (MobSpawnSettingsAccessor) biome.getMobSettings(); + Map> spawners = getMutableMap(accessor.bcl_getSpawners()); + List mobs = spawners.containsKey(category) ? getMutableList(spawners.get(category).unwrap()) : Lists.newArrayList(); + mobs.add(new SpawnerData(entityType, weight, minGroupCount, maxGroupCount)); + spawners.put(category, WeightedRandomList.create(mobs)); + accessor.bcl_setSpawners(spawners); } private static void configureBiome(BCLBiome biome, float chance, float fog) { @@ -553,4 +571,65 @@ public class BiomeAPI { fog = Configs.BIOMES_CONFIG.getFloat(group, "fog_density", fog); biome.setGenChance(chance).setFogDensity(fog); } + + /** + * Getter for correct feature list from all biome feature list of lists. + * @param step feature {@link Decoration} step. + * @param lists biome accessor lists. + * @return mutable {@link ConfiguredFeature} list. + */ + private static List> getList(Decoration step, List>> lists) { + int index = step.ordinal(); + if (lists.size() <= index) { + for (int i = lists.size(); i <= index; i++) { + lists.add(Lists.newArrayList()); + } + } + List> list = getMutableList(lists.get(index)); + lists.set(index, list); + return list; + } + + private static List getMutableList(List input) { + if (input!=null) { + System.out.println("getMutableList: " + input.getClass().getName()); + for (Class cl : input.getClass().getInterfaces()){ + System.out.println(" - " + cl.getName()); + } + } + if (/*input instanceof ImmutableList ||*/ !(input instanceof ArrayList || input instanceof LinkedList)) { + return Lists.newArrayList(input); + } + return input; + } + + private static Map getMutableMap(Map input) { + if (/*input instanceof ImmutableMap*/ !(input instanceof HashMap ||input instanceof EnumMap)) { + return Maps.newHashMap(input); + } + return input; + } + + //inspired by net.fabricmc.fabric.impl.biome.modification.BiomeStructureStartsImpl + private static Map, Multimap, ResourceKey>> getMutableStructureConfig(NoiseGeneratorSettings settings) { + final StructureSettingsAccessor access = (StructureSettingsAccessor)settings.structureSettings(); + ImmutableMap, ImmutableMultimap, ResourceKey>> immutableMap = access.bcl_getStructureConfig(); + Map, Multimap, ResourceKey>> result = new HashMap<>(immutableMap.size()); + + for (Map.Entry, ImmutableMultimap, ResourceKey>> entry : immutableMap.entrySet()) { + result.put(entry.getKey(), HashMultimap.create(entry.getValue())); + } + + return result; + } + + //inspired by net.fabricmc.fabric.impl.biome.modification.BiomeStructureStartsImpl + private static void setMutableStructureConfig(NoiseGeneratorSettings settings, Map, Multimap, ResourceKey>> structureStarts) { + final StructureSettingsAccessor access = (StructureSettingsAccessor)settings.structureSettings(); + access.bcl_setStructureConfig(structureStarts.entrySet().stream() + .collect(ImmutableMap.toImmutableMap( + Map.Entry::getKey, + e -> ImmutableMultimap.copyOf(e.getValue()) + ))); + } } diff --git a/src/main/java/ru/bclib/mixin/common/BiomeGenerationSettingsAccessor.java b/src/main/java/ru/bclib/mixin/common/BiomeGenerationSettingsAccessor.java new file mode 100644 index 00000000..f8037293 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/BiomeGenerationSettingsAccessor.java @@ -0,0 +1,21 @@ +package ru.bclib.mixin.common; + +import net.minecraft.world.level.biome.BiomeGenerationSettings; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; +import java.util.function.Supplier; + +@Mixin(BiomeGenerationSettings.class) +public interface BiomeGenerationSettingsAccessor { + @Accessor("features") + List>> bcl_getFeatures(); + + @Accessor("features") + @Mutable + void bcl_setFeatures(List>> value); +} + diff --git a/src/main/java/ru/bclib/mixin/common/MobSpawnSettingsAccessor.java b/src/main/java/ru/bclib/mixin/common/MobSpawnSettingsAccessor.java new file mode 100644 index 00000000..e3491b73 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/MobSpawnSettingsAccessor.java @@ -0,0 +1,21 @@ +package ru.bclib.mixin.common; + +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(MobSpawnSettings.class) +public interface MobSpawnSettingsAccessor { + @Accessor("spawners") + Map> bcl_getSpawners(); + + @Accessor("spawners") + @Mutable + void bcl_setSpawners(Map> spawners); +} diff --git a/src/main/java/ru/bclib/mixin/common/StructureSettingsAccessor.java b/src/main/java/ru/bclib/mixin/common/StructureSettingsAccessor.java new file mode 100644 index 00000000..e48342ef --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/StructureSettingsAccessor.java @@ -0,0 +1,28 @@ +package ru.bclib.mixin.common; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData; +import net.minecraft.world.level.levelgen.StructureSettings; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +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.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(StructureSettings.class) +public interface StructureSettingsAccessor { + @Accessor("configuredStructures") + ImmutableMap, ImmutableMultimap, ResourceKey>> bcl_getStructureConfig(); + + @Accessor("configuredStructures") + @Mutable + void bcl_setStructureConfig(ImmutableMap, ImmutableMultimap, ResourceKey>> structureConfig); +} diff --git a/src/main/java/ru/bclib/world/biomes/BCLBiome.java b/src/main/java/ru/bclib/world/biomes/BCLBiome.java index 59833b74..ab00606f 100644 --- a/src/main/java/ru/bclib/world/biomes/BCLBiome.java +++ b/src/main/java/ru/bclib/world/biomes/BCLBiome.java @@ -6,9 +6,14 @@ import net.minecraft.data.BuiltinRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; import org.jetbrains.annotations.Nullable; +import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.util.WeightedList; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Random; @@ -58,7 +63,7 @@ public class BCLBiome { } /** - * Get current bime edge. + * Get current biome edge. * @return {@link BCLBiome} edge. */ @Nullable @@ -203,6 +208,14 @@ public class BCLBiome { return this; } + /** + * For internal use only!!! + * maintains a list of all structures added to this biome, this is automatically set by + * {@link ru.bclib.api.biomes.BCLBiomeBuilder} + */ + + public List attachedStructures = null; + /** * Recursively update biomes to correct world biome registry instances, for internal usage only. * @param biomeRegistry {@link Registry} for {@link Biome}. diff --git a/src/main/java/ru/bclib/world/biomes/BCLBiomeDef.java b/src/main/java/ru/bclib/world/biomes/BCLBiomeDef.java index 69a57055..9fe6fdd1 100644 --- a/src/main/java/ru/bclib/world/biomes/BCLBiomeDef.java +++ b/src/main/java/ru/bclib/world/biomes/BCLBiomeDef.java @@ -362,7 +362,7 @@ public class BCLBiomeDef { .generationSettings(generationSettings.build()) .build(); - structures.forEach((structure) -> BiomeAPI.addBiomeStructure(b, structure)); + //structures.forEach((structure) -> BiomeAPI.addBiomeStructure(b., structure)); return b; } diff --git a/src/main/resources/bclib.mixins.common.json b/src/main/resources/bclib.mixins.common.json index 004e65c3..ea83b6ad 100644 --- a/src/main/resources/bclib.mixins.common.json +++ b/src/main/resources/bclib.mixins.common.json @@ -33,7 +33,10 @@ "AnvilBlockMixin", "AnvilMenuMixin", "TagLoaderMixin", - "MainMixin" + "MainMixin", + "BiomeGenerationSettingsAccessor", + "MobSpawnSettingsAccessor", + "StructureSettingsAccessor" ], "injectors": { "defaultRequire": 1