Co-authored-by: Sebastian Hartte <shartte@users.noreply.github.com>
This commit is contained in:
modmuss50 2022-11-03 13:48:27 +00:00 committed by GitHub
parent f5429c1aa0
commit f75bcd18f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 789 additions and 827 deletions

View file

@ -408,24 +408,11 @@ subprojects {
}
}
task remapMavenJar(type: net.fabricmc.loom.task.RemapJarTask, dependsOn: jar) {
input = jar.archiveFile
archiveFileName = "${archivesBaseName}-${project.version}-maven.jar"
addNestedDependencies = false
}
build.dependsOn remapMavenJar
if (signingEnabled) {
remoteSign {
sign remapMavenJar
}
}
publishing {
publications {
mavenJava(MavenPublication) {
artifact(signingEnabled ? signRemapMavenJar.output : remapMavenJar) {
builtBy(signingEnabled ? signRemapMavenJar : remapMavenJar)
artifact(signingEnabled ? signRemapJar.output : remapJar) {
builtBy(signingEnabled ? signRemapJar : remapJar)
}
artifact(sourcesJar) {

View file

@ -27,7 +27,6 @@ import net.minecraft.sound.BiomeAdditionsSound;
import net.minecraft.sound.BiomeMoodSound;
import net.minecraft.sound.MusicSound;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeEffects;
@ -37,8 +36,6 @@ import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.carver.ConfiguredCarver;
import net.minecraft.world.gen.feature.PlacedFeature;
import net.fabricmc.fabric.impl.biome.modification.BuiltInRegistryKeys;
/**
* Allows {@link Biome} properties to be modified.
*
@ -297,57 +294,16 @@ public interface BiomeModificationContext {
return anyFound;
}
/**
* {@link #removeFeature(RegistryKey)} for built-in features (see {@link #addBuiltInFeature(GenerationStep.Feature, PlacedFeature)}).
*/
default boolean removeBuiltInFeature(PlacedFeature placedFeature) {
return removeFeature(BuiltInRegistryKeys.get(placedFeature));
}
/**
* {@link #removeFeature(GenerationStep.Feature, RegistryKey)} for built-in features (see {@link #addBuiltInFeature(GenerationStep.Feature, PlacedFeature)}).
*/
default boolean removeBuiltInFeature(GenerationStep.Feature step, PlacedFeature placedFeature) {
return removeFeature(step, BuiltInRegistryKeys.get(placedFeature));
}
/**
* Adds a feature to one of this biomes generation steps, identified by the placed feature's registry key.
*
* @see BuiltinRegistries#PLACED_FEATURE
*/
void addFeature(GenerationStep.Feature step, RegistryKey<PlacedFeature> placedFeatureKey);
/**
* Adds a placed feature from {@link BuiltinRegistries#PLACED_FEATURE} to this biome.
*
* <p>This method is intended for use with the placed features found in
* classes such as {@link net.minecraft.world.gen.feature.OrePlacedFeatures}.
*
* <p><b>NOTE:</b> In case the placed feature is overridden in a data pack, the data pack's version
* will be used.
*/
default void addBuiltInFeature(GenerationStep.Feature step, PlacedFeature placedFeature) {
addFeature(step, BuiltInRegistryKeys.get(placedFeature));
}
/**
* Adds a configured carver to one of this biomes generation steps.
*/
void addCarver(GenerationStep.Carver step, RegistryKey<ConfiguredCarver<?>> carverKey);
/**
* Adds a configured carver from {@link BuiltinRegistries#CONFIGURED_CARVER} to this biome.
*
* <p>This method is intended for use with the configured carvers found in {@link net.minecraft.world.gen.carver.ConfiguredCarvers}.
*
* <p><b>NOTE:</b> In case the configured carver is overridden in a data pack, the data pack's version
* will be used.
*/
default void addBuiltInCarver(GenerationStep.Carver step, ConfiguredCarver<?> configuredCarver) {
addCarver(step, BuiltInRegistryKeys.get(configuredCarver));
}
/**
* Removes all carvers with the given key from one of this biomes generation steps.
*
@ -371,20 +327,6 @@ public interface BiomeModificationContext {
return anyFound;
}
/**
* {@link #removeCarver(RegistryKey)} for built-in carvers (see {@link #addBuiltInCarver(GenerationStep.Carver, ConfiguredCarver)}).
*/
default boolean removeBuiltInCarver(ConfiguredCarver<?> configuredCarver) {
return removeCarver(BuiltInRegistryKeys.get(configuredCarver));
}
/**
* {@link #removeCarver(GenerationStep.Carver, RegistryKey)} for built-in carvers (see {@link #addBuiltInCarver(GenerationStep.Carver, ConfiguredCarver)}).
*/
default boolean removeBuiltInCarver(GenerationStep.Carver step, ConfiguredCarver<?> configuredCarver) {
return removeCarver(step, BuiltInRegistryKeys.get(configuredCarver));
}
}
interface SpawnSettingsContext {

View file

@ -29,8 +29,6 @@ import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.PlacedFeature;
import net.minecraft.world.gen.structure.Structure;
import net.fabricmc.fabric.impl.biome.modification.BuiltInRegistryKeys;
/**
* Context given to a biome selector for deciding whether it applies to a biome or not.
*/
@ -44,29 +42,6 @@ public interface BiomeSelectionContext {
RegistryEntry<Biome> getBiomeRegistryEntry();
/**
* Returns true if this biome has the given configured feature, which must be registered
* in the {@link net.minecraft.util.registry.BuiltinRegistries}.
*
* <p>This method is intended for use with the Vanilla configured features found in
* classes such as {@link net.minecraft.world.gen.feature.OreConfiguredFeatures}.
*/
default boolean hasBuiltInFeature(ConfiguredFeature<?, ?> configuredFeature) {
RegistryKey<ConfiguredFeature<?, ?>> key = BuiltInRegistryKeys.get(configuredFeature);
return hasFeature(key);
}
/**
* Returns true if this biome has the given placed feature, which must be registered
* in the {@link net.minecraft.util.registry.BuiltinRegistries}.
*
* <p>This method is intended for use with the Vanilla placed features found in
* classes such as {@link net.minecraft.world.gen.feature.OrePlacedFeatures}.
*/
default boolean hasBuiltInPlacedFeature(PlacedFeature placedFeature) {
return hasPlacedFeature(BuiltInRegistryKeys.get(placedFeature));
}
/**
* Returns true if this biome contains a placed feature referencing a configured feature with the given key.
*/
@ -115,17 +90,6 @@ public interface BiomeSelectionContext {
*/
Optional<RegistryKey<PlacedFeature>> getPlacedFeatureKey(PlacedFeature placedFeature);
/**
* Returns true if the given built-in configured structure from {@link net.minecraft.util.registry.BuiltinRegistries}
* can start in this biome in any of the chunk generators used by the current world-save.
*
* <p>This method is intended for use with the Vanilla configured structures found in {@link net.minecraft.world.gen.structure.Structures}.
*/
default boolean validForBuiltInStructure(Structure structureFeature) {
RegistryKey<Structure> key = BuiltInRegistryKeys.get(structureFeature);
return validForStructure(key);
}
/**
* Returns true if the configured structure with the given key can start in this biome in any chunk generator
* used by the current world-save.

View file

@ -25,12 +25,13 @@ import com.google.common.collect.ImmutableSet;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.tag.TagKey;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.SpawnSettings;
import net.minecraft.world.dimension.DimensionOptions;
import net.fabricmc.fabric.impl.biome.modification.BuiltInRegistryKeys;
/**
* Provides several convenient biome selectors that can be used with {@link BiomeModifications}.
*
@ -47,21 +48,14 @@ public final class BiomeSelectors {
return context -> true;
}
/**
* Matches Biomes that have not been originally defined in a data pack, but that are defined in code.
*/
public static Predicate<BiomeSelectionContext> builtIn() {
return context -> BuiltinRegistries.BIOME.containsId(context.getBiomeKey().getValue());
}
/**
* Returns a biome selector that will match all biomes from the minecraft namespace.
*/
public static Predicate<BiomeSelectionContext> vanilla() {
return context -> {
// In addition to the namespace, we also check that it doesn't come from a data pack.
// In addition to the namespace, we also check that it exists in the vanilla registries
return context.getBiomeKey().getValue().getNamespace().equals("minecraft")
&& BuiltinRegistries.BIOME.containsId(context.getBiomeKey().getValue());
&& BuiltInRegistryKeys.isBuiltinBiome(context.getBiomeKey());
};
}

View file

@ -22,4 +22,6 @@ public interface MultiNoiseSamplerHooks {
PerlinNoiseSampler fabric_getEndBiomesSampler();
void fabric_setSeed(long seed);
long fabric_getSeed();
}

View file

@ -29,8 +29,7 @@ import com.mojang.logging.LogUtils;
import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntryLookup;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.biome.Biome;
@ -38,6 +37,8 @@ import net.minecraft.world.biome.source.BiomeSource;
import net.minecraft.world.biome.source.MultiNoiseBiomeSource;
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import net.fabricmc.fabric.impl.biome.modification.BuiltInRegistryKeys;
/**
* Internal data for modding Vanilla's {@link MultiNoiseBiomeSource.Preset#NETHER}.
*/
@ -67,10 +68,10 @@ public final class NetherBiomeData {
public static boolean canGenerateInNether(RegistryKey<Biome> biome) {
if (NETHER_BIOMES.isEmpty()) {
MultiNoiseBiomeSource source = MultiNoiseBiomeSource.Preset.NETHER.getBiomeSource(BuiltinRegistries.BIOME);
MultiNoiseBiomeSource source = MultiNoiseBiomeSource.Preset.NETHER.getBiomeSource(BuiltInRegistryKeys.biomeRegistryWrapper());
for (RegistryEntry<Biome> entry : source.getBiomes()) {
BuiltinRegistries.BIOME.getKey(entry.value()).ifPresent(NETHER_BIOMES::add);
entry.getKey().ifPresent(NETHER_BIOMES::add);
}
}
@ -81,7 +82,7 @@ public final class NetherBiomeData {
NETHER_BIOMES.clear(); // Clear cached biome source data
}
private static MultiNoiseUtil.Entries<RegistryEntry<Biome>> withModdedBiomeEntries(MultiNoiseUtil.Entries<RegistryEntry<Biome>> entries, Registry<Biome> biomeRegistry) {
private static MultiNoiseUtil.Entries<RegistryEntry<Biome>> withModdedBiomeEntries(MultiNoiseUtil.Entries<RegistryEntry<Biome>> entries, RegistryEntryLookup<Biome> biomes) {
if (NETHER_BIOME_NOISE_POINTS.isEmpty()) {
return entries;
}
@ -89,8 +90,10 @@ public final class NetherBiomeData {
ArrayList<Pair<MultiNoiseUtil.NoiseHypercube, RegistryEntry<Biome>>> entryList = new ArrayList<>(entries.getEntries());
for (Map.Entry<RegistryKey<Biome>, MultiNoiseUtil.NoiseHypercube> entry : NETHER_BIOME_NOISE_POINTS.entrySet()) {
if (biomeRegistry.contains(entry.getKey())) {
entryList.add(Pair.of(entry.getValue(), biomeRegistry.entryOf(entry.getKey())));
RegistryEntry.Reference<Biome> biomeEntry = biomes.getOptional(entry.getKey()).orElse(null);
if (biomeEntry != null) {
entryList.add(Pair.of(entry.getValue(), biomeEntry));
} else {
LOGGER.warn("Nether biome {} not loaded", entry.getKey().getValue());
}
@ -99,7 +102,7 @@ public final class NetherBiomeData {
return new MultiNoiseUtil.Entries<>(entryList);
}
public static void modifyBiomeSource(Registry<Biome> biomeRegistry, BiomeSource biomeSource) {
public static void modifyBiomeSource(RegistryEntryLookup<Biome> biomeRegistry, BiomeSource biomeSource) {
if (biomeSource instanceof MultiNoiseBiomeSource multiNoiseBiomeSource) {
if (((BiomeSourceAccess) multiNoiseBiomeSource).fabric_shouldModifyBiomeEntries() && multiNoiseBiomeSource.matchesInstance(MultiNoiseBiomeSource.Preset.NETHER)) {
multiNoiseBiomeSource.biomeEntries = NetherBiomeData.withModdedBiomeEntries(

View file

@ -29,8 +29,8 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import net.minecraft.util.registry.RegistryEntryLookup;
import net.minecraft.util.math.noise.PerlinNoiseSampler;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.biome.Biome;
@ -43,6 +43,7 @@ import net.minecraft.world.biome.source.util.MultiNoiseUtil;
*/
@ApiStatus.Internal
public final class TheEndBiomeData {
public static final ThreadLocal<RegistryEntryLookup<Biome>> biomeRegistry = new ThreadLocal<>();
public static final Set<RegistryKey<Biome>> ADDED_BIOMES = new HashSet<>();
private static final Map<RegistryKey<Biome>, WeightedPicker<RegistryKey<Biome>>> END_BIOMES_MAP = new IdentityHashMap<>();
private static final Map<RegistryKey<Biome>, WeightedPicker<RegistryKey<Biome>>> END_MIDLANDS_MAP = new IdentityHashMap<>();
@ -89,8 +90,8 @@ public final class TheEndBiomeData {
ADDED_BIOMES.add(barrens);
}
public static Overrides createOverrides(Registry<Biome> biomeRegistry) {
return new Overrides(biomeRegistry);
public static Overrides createOverrides(RegistryEntryLookup<Biome> biomes) {
return new Overrides(biomes);
}
/**
@ -112,12 +113,12 @@ public final class TheEndBiomeData {
// cache for our own sampler (used for random biome replacement selection)
private final Map<MultiNoiseUtil.MultiNoiseSampler, PerlinNoiseSampler> samplers = new WeakHashMap<>();
public Overrides(Registry<Biome> biomeRegistry) {
this.customBiomes = ADDED_BIOMES.stream().map(biomeRegistry::entryOf).collect(Collectors.toSet());
public Overrides(RegistryEntryLookup<Biome> biomeRegistry) {
this.customBiomes = ADDED_BIOMES.stream().map(biomeRegistry::getOrThrow).collect(Collectors.toSet());
this.endMidlands = biomeRegistry.entryOf(BiomeKeys.END_MIDLANDS);
this.endBarrens = biomeRegistry.entryOf(BiomeKeys.END_BARRENS);
this.endHighlands = biomeRegistry.entryOf(BiomeKeys.END_HIGHLANDS);
this.endMidlands = biomeRegistry.getOrThrow(BiomeKeys.END_MIDLANDS);
this.endBarrens = biomeRegistry.getOrThrow(BiomeKeys.END_BARRENS);
this.endHighlands = biomeRegistry.getOrThrow(BiomeKeys.END_HIGHLANDS);
this.endBiomesMap = resolveOverrides(biomeRegistry, END_BIOMES_MAP, BiomeKeys.THE_END);
this.endMidlandsMap = resolveOverrides(biomeRegistry, END_MIDLANDS_MAP, BiomeKeys.END_MIDLANDS);
@ -125,7 +126,7 @@ public final class TheEndBiomeData {
}
// Resolves all RegistryKey instances to RegistryEntries
private @Nullable Map<RegistryEntry<Biome>, WeightedPicker<RegistryEntry<Biome>>> resolveOverrides(Registry<Biome> biomeRegistry, Map<RegistryKey<Biome>, WeightedPicker<RegistryKey<Biome>>> overrides, RegistryKey<Biome> vanillaKey) {
private @Nullable Map<RegistryEntry<Biome>, WeightedPicker<RegistryEntry<Biome>>> resolveOverrides(RegistryEntryLookup<Biome> biomeRegistry, Map<RegistryKey<Biome>, WeightedPicker<RegistryKey<Biome>>> overrides, RegistryKey<Biome> vanillaKey) {
Map<RegistryEntry<Biome>, WeightedPicker<RegistryEntry<Biome>>> result = new Object2ObjectOpenCustomHashMap<>(overrides.size(), RegistryKeyHashStrategy.INSTANCE);
for (Map.Entry<RegistryKey<Biome>, WeightedPicker<RegistryKey<Biome>>> entry : overrides.entrySet()) {
@ -133,7 +134,7 @@ public final class TheEndBiomeData {
int count = picker.getEntryCount();
if (count == 0 || (count == 1 && entry.getKey() == vanillaKey)) continue; // don't use no-op entries, for vanilla key biome check 1 as we have default entry
result.put(biomeRegistry.entryOf(entry.getKey()), picker.map(biomeRegistry::entryOf));
result.put(biomeRegistry.getOrThrow(entry.getKey()), picker.map(biomeRegistry::getOrThrow));
}
return result.isEmpty() ? null : result;

View file

@ -40,7 +40,6 @@ import net.minecraft.sound.BiomeMoodSound;
import net.minecraft.sound.MusicSound;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.collection.Pool;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
@ -329,18 +328,7 @@ public class BiomeModificationContextImpl implements BiomeModificationContext {
RegistryEntry.Reference<T> entry = registry.getEntry(key).orElse(null);
if (entry == null) {
// Entry is missing. Check if it exists in the built-in registries and warn modders
// about the worldgen changing to JSON-only.
DynamicRegistryManager.Immutable builtInAccess = BuiltinRegistries.createBuiltinRegistryManager();
Registry<T> builtInRegistry = builtInAccess.get(registry.getKey());
if (builtInRegistry.contains(key)) {
throw new IllegalArgumentException("Entry " + key + " only exists in the built-in registry "
+ "but a corresponding JSON file couldn't be found in the loaded data packs. "
+ "Since 1.19.3+, the built-in registry for world generation objects is only used for data generation purposes.");
}
// The key doesn't exist in either built-in registries or data packs
// The key doesn't exist in the data packs
throw new IllegalArgumentException("Couldn't find registry entry for " + key);
}

View file

@ -19,38 +19,27 @@ package net.fabricmc.fabric.impl.biome.modification;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntryLookup;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.gen.carver.ConfiguredCarver;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.PlacedFeature;
import net.minecraft.world.gen.structure.Structure;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.world.biome.Biome;
/**
* Utility class for getting the registry keys of built-in worldgen objects and throwing proper exceptions if they
* are not registered.
* Utility class for accessing the worldgen data that vanilla uses to generate its vanilla datapack.
*/
@ApiStatus.Internal
public final class BuiltInRegistryKeys {
private static final RegistryWrapper.WrapperLookup vanillaRegistries = BuiltinRegistries.createWrapperLookup();
private BuiltInRegistryKeys() {
}
public static RegistryKey<Structure> get(Structure structureFeature) {
return BuiltinRegistries.STRUCTURE.getKey(structureFeature)
.orElseThrow(() -> new IllegalArgumentException("Given structure is not built-in: " + structureFeature));
public static boolean isBuiltinBiome(RegistryKey<Biome> key) {
return biomeRegistryWrapper().getOptional(key).isPresent();
}
public static RegistryKey<ConfiguredFeature<?, ?>> get(ConfiguredFeature<?, ?> configuredFeature) {
return BuiltinRegistries.CONFIGURED_FEATURE.getKey(configuredFeature)
.orElseThrow(() -> new IllegalArgumentException("Given configured feature is not built-in: " + configuredFeature));
}
public static RegistryKey<PlacedFeature> get(PlacedFeature placedFeature) {
return BuiltinRegistries.PLACED_FEATURE.getKey(placedFeature)
.orElseThrow(() -> new IllegalArgumentException("Given placed feature is not built-in: " + placedFeature));
}
public static RegistryKey<ConfiguredCarver<?>> get(ConfiguredCarver<?> configuredCarver) {
return BuiltinRegistries.CONFIGURED_CARVER.getKey(configuredCarver)
.orElseThrow(() -> new IllegalArgumentException("Given configured carver is not built-in: " + configuredCarver));
public static RegistryEntryLookup<Biome> biomeRegistryWrapper() {
return vanillaRegistries.getWrapperOrThrow(Registry.BIOME_KEY);
}
}

View file

@ -44,7 +44,7 @@ public class ChunkNoiseSamplerMixin {
@Inject(method = "<init>", at = @At("TAIL"))
private void init(int horizontalSize, NoiseConfig noiseConfig, int i, int j, GenerationShapeConfig generationShapeConfig, DensityFunctionTypes.Beardifying arg, ChunkGeneratorSettings chunkGeneratorSettings, AquiferSampler.FluidLevelSampler fluidLevelSampler, Blender blender, CallbackInfo ci) {
seed = noiseConfig.getLegacyWorldSeed();
seed = ((MultiNoiseSamplerHooks) (Object) noiseConfig.getMultiNoiseSampler()).fabric_getSeed();
}
@Inject(method = "createMultiNoiseSampler", at = @At("RETURN"))

View file

@ -44,6 +44,6 @@ public class MinecraftServerMixin {
// please blame Mojang for using dynamic registry
Registry<DimensionOptions> registry = getRegistryManager().get(Registry.DIMENSION_KEY);
registry.stream().forEach(dimensionOptions -> NetherBiomeData.modifyBiomeSource(getRegistryManager().get(Registry.BIOME_KEY), dimensionOptions.chunkGenerator().getBiomeSource()));
registry.stream().forEach(dimensionOptions -> NetherBiomeData.modifyBiomeSource(getRegistryManager().getWrapperOrThrow(Registry.BIOME_KEY), dimensionOptions.chunkGenerator().getBiomeSource()));
}
}

View file

@ -40,6 +40,11 @@ public class MultiNoiseUtilMultiNoiseSamplerMixin implements MultiNoiseSamplerHo
this.seed = seed;
}
@Override
public long fabric_getSeed() {
return this.seed;
}
@Override
public PerlinNoiseSampler fabric_getEndBiomesSampler() {
if (endBiomesSampler == null) {

View file

@ -23,7 +23,8 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntryLookup;
import net.minecraft.util.math.noise.DoublePerlinNoiseSampler;
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import net.minecraft.world.gen.noise.NoiseConfig;
@ -37,7 +38,7 @@ public class NoiseConfigMixin {
private MultiNoiseUtil.MultiNoiseSampler multiNoiseSampler;
@Inject(method = "<init>", at = @At("TAIL"))
private void init(ChunkGeneratorSettings chunkGeneratorSettings, Registry<?> noiseRegistry, long seed, CallbackInfo ci) {
private void init(ChunkGeneratorSettings chunkGeneratorSettings, RegistryEntryLookup<DoublePerlinNoiseSampler.NoiseParameters> arg, long seed, CallbackInfo ci) {
((MultiNoiseSamplerHooks) (Object) multiNoiseSampler).fabric_setSeed(seed);
}
}

View file

@ -20,13 +20,20 @@ import java.util.Set;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
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.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.util.registry.RegistryEntryLookup;
import net.minecraft.util.dynamic.RegistryOps;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.world.biome.Biome;
@ -37,15 +44,59 @@ import net.fabricmc.fabric.impl.biome.TheEndBiomeData;
@Mixin(TheEndBiomeSource.class)
public class TheEndBiomeSourceMixin extends BiomeSourceMixin {
@Shadow
@Mutable
@Final
static Codec<TheEndBiomeSource> CODEC;
@Unique
private Supplier<TheEndBiomeData.Overrides> overrides;
@Unique
private boolean biomeSetModified = false;
/**
* Modifies the codec, so it calls the static factory method that gives us access to the
* full biome registry instead of just the pre-defined biomes that vanilla uses.
*/
@Inject(method = "<clinit>", at = @At("TAIL"))
private static void modifyCodec(CallbackInfo ci) {
CODEC = RecordCodecBuilder.create((instance) -> {
return instance.group(RegistryOps.getEntryLookupCodec(Registry.BIOME_KEY)).apply(instance, instance.stable(TheEndBiomeSource::method_46680));
});
}
/**
* Captures the biome registry at the beginning of the static factory method to allow access to it in the
* constructor.
*/
@Inject(method = "method_46680", at = @At("HEAD"))
private static void rememberLookup(RegistryEntryLookup<Biome> biomes, CallbackInfoReturnable<?> ci) {
TheEndBiomeData.biomeRegistry.set(biomes);
}
/**
* Frees up the captured biome registry.
*/
@Inject(method = "method_46680", at = @At("TAIL"))
private static void clearLookup(RegistryEntryLookup<Biome> biomes, CallbackInfoReturnable<?> ci) {
TheEndBiomeData.biomeRegistry.remove();
}
/**
* Uses the captured biome registry to set up the modded end biomes.
*/
@Inject(method = "<init>", at = @At("RETURN"))
private void init(Registry<Biome> biomeRegistry, CallbackInfo ci) {
overrides = Suppliers.memoize(() -> TheEndBiomeData.createOverrides(biomeRegistry));
private void init(RegistryEntry<Biome> centerBiome, RegistryEntry<Biome> highlandsBiome, RegistryEntry<Biome> midlandsBiome, RegistryEntry<Biome> smallIslandsBiome, RegistryEntry<Biome> barrensBiome, CallbackInfo ci) {
RegistryEntryLookup<Biome> biomes = TheEndBiomeData.biomeRegistry.get();
if (biomes == null) {
throw new IllegalStateException("Biome registry not set by Mixin");
}
overrides = Suppliers.memoize(() -> {
return TheEndBiomeData.createOverrides(biomes);
});
}
@Inject(method = "getBiome", at = @At("RETURN"), cancellable = true)

View file

@ -17,12 +17,11 @@
package net.fabricmc.fabric.test.biome;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricBuiltinRegistriesProvider;
public class DataGeneratorEntrypoint implements net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint {
@Override
public void onInitializeDataGenerator(FabricDataGenerator dataGenerator) {
FabricDataGenerator.Pack pack = dataGenerator.createPack();
pack.addProvider(FabricBuiltinRegistriesProvider.forCurrentMod());
pack.addProvider(WorldgenProvider::new);
}
}

View file

@ -16,33 +16,16 @@
package net.fabricmc.fabric.test.biome;
import java.util.List;
import net.minecraft.sound.BiomeMoodSound;
import net.minecraft.tag.TagKey;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
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.biome.BiomeEffects;
import net.minecraft.world.biome.BiomeKeys;
import net.minecraft.world.biome.GenerationSettings;
import net.minecraft.world.biome.OverworldBiomeCreator;
import net.minecraft.world.biome.SpawnSettings;
import net.minecraft.world.biome.TheNetherBiomeCreator;
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.DefaultBiomeFeatures;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.EndPlacedFeatures;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.PlacedFeature;
import net.minecraft.world.gen.feature.PlacedFeatures;
import net.minecraft.world.gen.placementmodifier.BiomePlacementModifier;
import net.minecraft.world.gen.placementmodifier.SquarePlacementModifier;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
@ -64,24 +47,26 @@ import net.fabricmc.fabric.api.biome.v1.TheEndBiomes;
public class FabricBiomeTest implements ModInitializer {
public static final String MOD_ID = "fabric-biome-api-v1-testmod";
private static final RegistryKey<Biome> TEST_CRIMSON_FOREST = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_crimson_forest"));
private static final RegistryKey<Biome> CUSTOM_PLAINS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "custom_plains"));
private static final RegistryKey<Biome> TEST_END_HIGHLANDS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_highlands"));
private static final RegistryKey<Biome> TEST_END_MIDLANDS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_midlands"));
private static final RegistryKey<Biome> TEST_END_BARRRENS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_barrens"));
public static final RegistryKey<Biome> TEST_CRIMSON_FOREST = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_crimson_forest"));
public static final RegistryKey<Biome> CUSTOM_PLAINS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "custom_plains"));
public static final RegistryKey<Biome> TEST_END_HIGHLANDS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_highlands"));
public static final RegistryKey<Biome> TEST_END_MIDLANDS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_midlands"));
public static final RegistryKey<Biome> TEST_END_BARRRENS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_barrens"));
public static final RegistryKey<ConfiguredFeature<?, ?>> COMMON_DESERT_WELL = RegistryKey.of(
Registry.CONFIGURED_FEATURE_KEY,
new Identifier(FabricBiomeTest.MOD_ID, "fab_desert_well")
);
public static final RegistryKey<PlacedFeature> PLACED_COMMON_DESERT_WELL = RegistryKey.of(
Registry.PLACED_FEATURE_KEY,
new Identifier(FabricBiomeTest.MOD_ID, "fab_desert_well")
);
@Override
public void onInitialize() {
BuiltinRegistries.add(BuiltinRegistries.BIOME, TEST_CRIMSON_FOREST.getValue(), TheNetherBiomeCreator.createCrimsonForest());
NetherBiomes.addNetherBiome(BiomeKeys.PLAINS, MultiNoiseUtil.createNoiseHypercube(0.0F, 0.5F, 0.0F, 0.0F, 0.0f, 0, 0.1F));
NetherBiomes.addNetherBiome(TEST_CRIMSON_FOREST, MultiNoiseUtil.createNoiseHypercube(0.0F, -0.15F, 0.0f, 0.0F, 0.0f, 0.0F, 0.2F));
BuiltinRegistries.add(BuiltinRegistries.BIOME, CUSTOM_PLAINS.getValue(), OverworldBiomeCreator.createPlains(false, false, false));
BuiltinRegistries.add(BuiltinRegistries.BIOME, TEST_END_HIGHLANDS.getValue(), createEndHighlands());
BuiltinRegistries.add(BuiltinRegistries.BIOME, TEST_END_MIDLANDS.getValue(), createEndMidlands());
BuiltinRegistries.add(BuiltinRegistries.BIOME, TEST_END_BARRRENS.getValue(), createEndBarrens());
// TESTING HINT: to get to the end:
// /execute in minecraft:the_end run tp @s 0 90 0
TheEndBiomes.addHighlandsBiome(BiomeKeys.PLAINS, 5.0);
@ -89,14 +74,6 @@ public class FabricBiomeTest implements ModInitializer {
TheEndBiomes.addMidlandsBiome(TEST_END_HIGHLANDS, TEST_END_MIDLANDS, 10.0);
TheEndBiomes.addBarrensBiome(TEST_END_HIGHLANDS, TEST_END_BARRRENS, 10.0);
ConfiguredFeature<?, ?> COMMON_DESERT_WELL = new ConfiguredFeature<>(Feature.DESERT_WELL, DefaultFeatureConfig.INSTANCE);
BuiltinRegistries.add(BuiltinRegistries.CONFIGURED_FEATURE, new Identifier(MOD_ID, "fab_desert_well"), COMMON_DESERT_WELL);
RegistryEntry<ConfiguredFeature<?, ?>> featureEntry = BuiltinRegistries.CONFIGURED_FEATURE.getOrCreateEntry(BuiltinRegistries.CONFIGURED_FEATURE.getKey(COMMON_DESERT_WELL).orElseThrow());
// The placement config is taken from the vanilla desert well, but no randomness
PlacedFeature PLACED_COMMON_DESERT_WELL = new PlacedFeature(featureEntry, List.of(SquarePlacementModifier.of(), PlacedFeatures.MOTION_BLOCKING_HEIGHTMAP, BiomePlacementModifier.of()));
BuiltinRegistries.add(BuiltinRegistries.PLACED_FEATURE, new Identifier(MOD_ID, "fab_desert_well"), PLACED_COMMON_DESERT_WELL);
BiomeModifications.create(new Identifier("fabric:test_mod"))
.add(ModificationPhase.ADDITIONS,
BiomeSelectors.foundInOverworld(),
@ -105,7 +82,7 @@ public class FabricBiomeTest implements ModInitializer {
BiomeSelectors.includeByKey(BiomeKeys.DESERT), // TODO: switch to fabric desert biome tag once it is there?
context -> {
context.getGenerationSettings().addFeature(GenerationStep.Feature.TOP_LAYER_MODIFICATION,
BuiltinRegistries.PLACED_FEATURE.getKey(PLACED_COMMON_DESERT_WELL).orElseThrow()
PLACED_COMMON_DESERT_WELL
);
})
.add(ModificationPhase.ADDITIONS,
@ -130,27 +107,4 @@ public class FabricBiomeTest implements ModInitializer {
10.0
);
}
// These are used for testing the spacing of custom end biomes.
private static Biome createEndHighlands() {
GenerationSettings.Builder builder = new GenerationSettings.Builder()
.feature(GenerationStep.Feature.SURFACE_STRUCTURES, EndPlacedFeatures.END_GATEWAY_RETURN);
return composeEndSpawnSettings(builder);
}
public static Biome createEndMidlands() {
GenerationSettings.Builder builder = (new GenerationSettings.Builder());
return composeEndSpawnSettings(builder);
}
public static Biome createEndBarrens() {
GenerationSettings.Builder builder = (new GenerationSettings.Builder());
return composeEndSpawnSettings(builder);
}
private static Biome composeEndSpawnSettings(GenerationSettings.Builder builder) {
SpawnSettings.Builder builder2 = new SpawnSettings.Builder();
DefaultBiomeFeatures.addPlainsMobs(builder2);
return (new Biome.Builder()).precipitation(Biome.Precipitation.NONE).temperature(0.5F).downfall(0.5F).effects((new BiomeEffects.Builder()).waterColor(4159204).waterFogColor(329011).fogColor(10518688).skyColor(0).moodSound(BiomeMoodSound.CAVE).build()).spawnSettings(builder2.build()).generationSettings(builder.build()).build();
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.test.biome;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.sound.BiomeMoodSound;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeEffects;
import net.minecraft.world.biome.GenerationSettings;
import net.minecraft.world.biome.OverworldBiomeCreator;
import net.minecraft.world.biome.SpawnSettings;
import net.minecraft.world.biome.TheNetherBiomeCreator;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.DefaultBiomeFeatures;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.EndPlacedFeatures;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.PlacedFeature;
import net.minecraft.world.gen.feature.PlacedFeatures;
import net.minecraft.world.gen.placementmodifier.BiomePlacementModifier;
import net.minecraft.world.gen.placementmodifier.SquarePlacementModifier;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricWorldgenProvider;
public class WorldgenProvider extends FabricWorldgenProvider {
public WorldgenProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
}
@Override
protected void configure(RegistryWrapper.WrapperLookup registries, Entries entries) {
entries.add(FabricBiomeTest.TEST_CRIMSON_FOREST, TheNetherBiomeCreator.createCrimsonForest(entries.placedFeatures(), entries.configuredCarvers()));
entries.add(FabricBiomeTest.CUSTOM_PLAINS, OverworldBiomeCreator.createPlains(entries.placedFeatures(), entries.configuredCarvers(), false, false, false));
entries.add(FabricBiomeTest.TEST_END_HIGHLANDS, createEndHighlands(entries));
;
entries.add(FabricBiomeTest.TEST_END_MIDLANDS, createEndMidlands(entries));
entries.add(FabricBiomeTest.TEST_END_BARRRENS, createEndBarrens(entries));
ConfiguredFeature<?, ?> COMMON_DESERT_WELL = new ConfiguredFeature<>(Feature.DESERT_WELL, DefaultFeatureConfig.INSTANCE);
RegistryEntry<ConfiguredFeature<?, ?>> featureRef = entries.add(FabricBiomeTest.COMMON_DESERT_WELL, COMMON_DESERT_WELL);
// The placement config is taken from the vanilla desert well, but no randomness
PlacedFeature PLACED_COMMON_DESERT_WELL = new PlacedFeature(featureRef, List.of(SquarePlacementModifier.of(), PlacedFeatures.MOTION_BLOCKING_HEIGHTMAP, BiomePlacementModifier.of()));
entries.add(FabricBiomeTest.PLACED_COMMON_DESERT_WELL, PLACED_COMMON_DESERT_WELL);
}
@Override
public String getName() {
return "Fabric Biome Testmod";
}
// These are used for testing the spacing of custom end biomes.
private static Biome createEndHighlands(Entries entries) {
GenerationSettings.Builder builder = new GenerationSettings.Builder(entries.placedFeatures(), entries.configuredCarvers())
.feature(GenerationStep.Feature.SURFACE_STRUCTURES, EndPlacedFeatures.END_GATEWAY_RETURN);
return composeEndSpawnSettings(builder);
}
public static Biome createEndMidlands(Entries entries) {
GenerationSettings.Builder builder = (new GenerationSettings.Builder(entries.placedFeatures(), entries.configuredCarvers()));
return composeEndSpawnSettings(builder);
}
public static Biome createEndBarrens(Entries entries) {
GenerationSettings.Builder builder = (new GenerationSettings.Builder(entries.placedFeatures(), entries.configuredCarvers()));
return composeEndSpawnSettings(builder);
}
private static Biome composeEndSpawnSettings(GenerationSettings.Builder builder) {
SpawnSettings.Builder builder2 = new SpawnSettings.Builder();
DefaultBiomeFeatures.addPlainsMobs(builder2);
return (new Biome.Builder()).precipitation(Biome.Precipitation.NONE).temperature(0.5F).downfall(0.5F).effects((new BiomeEffects.Builder()).waterColor(4159204).waterFogColor(329011).fogColor(10518688).skyColor(0).moodSound(BiomeMoodSound.CAVE).build()).spawnSettings(builder2.build()).generationSettings(builder.method_46671()).build();
}
}

View file

@ -58,7 +58,7 @@ abstract class ClientPlayNetworkHandlerMixin {
private void onGameJoin(GameJoinS2CPacket packet, CallbackInfo info) {
final CommandDispatcher<FabricClientCommandSource> dispatcher = new CommandDispatcher<>();
ClientCommandInternals.setActiveDispatcher(dispatcher);
ClientCommandRegistrationCallback.EVENT.invoker().register(dispatcher, new CommandRegistryAccess(this.combinedDynamicRegistries.getCombinedRegistryManager(), this.enabledFeatures));
ClientCommandRegistrationCallback.EVENT.invoker().register(dispatcher, CommandRegistryAccess.of(this.combinedDynamicRegistries.getCombinedRegistryManager(), this.enabledFeatures));
ClientCommandInternals.finalizeInit();
}

View file

@ -16,6 +16,9 @@
package net.fabricmc.fabric.impl.tag.convention.datagen.generators;
import java.util.concurrent.CompletableFuture;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.tag.BiomeTags;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
@ -25,13 +28,13 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBiomeTags;
public class BiomeTagGenerator extends FabricTagProvider.DynamicRegistryTagProvider<Biome> {
public BiomeTagGenerator(FabricDataOutput output) {
super(output, Registry.BIOME_KEY);
public class BiomeTagGenerator extends FabricTagProvider<Biome> {
public BiomeTagGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
super(output, Registry.BIOME_KEY, completableFuture);
}
@Override
protected void generateTags() {
protected void configure(RegistryWrapper.WrapperLookup arg) {
generateDimensionTags();
generateCategoryTags();
generateOtherBiomeTypes();

View file

@ -16,20 +16,25 @@
package net.fabricmc.fabric.impl.tag.convention.datagen.generators;
import java.util.concurrent.CompletableFuture;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.tag.BlockTags;
import net.minecraft.util.registry.RegistryKey;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBlockTags;
public class BlockTagGenerator extends FabricTagProvider.BlockTagProvider {
public BlockTagGenerator(FabricDataOutput output) {
super(output);
public BlockTagGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
}
@Override
protected void generateTags() {
protected void configure(RegistryWrapper.WrapperLookup registries) {
getOrCreateTagBuilder(ConventionalBlockTags.QUARTZ_ORES)
.add(Blocks.NETHER_QUARTZ_ORE);
getOrCreateTagBuilder(ConventionalBlockTags.ORES)
@ -52,6 +57,11 @@ public class BlockTagGenerator extends FabricTagProvider.BlockTagProvider {
generateShulkerTag();
}
@Override
protected RegistryKey<Block> reverseLookup(Block block) {
return block.getRegistryEntry().registryKey();
}
private void generateShulkerTag() {
getOrCreateTagBuilder(ConventionalBlockTags.SHULKER_BOXES)
.add(Blocks.SHULKER_BOX)

View file

@ -16,21 +16,22 @@
package net.fabricmc.fabric.impl.tag.convention.datagen.generators;
import net.minecraft.enchantment.Enchantment;
import java.util.concurrent.CompletableFuture;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.util.registry.Registry;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalEnchantmentTags;
public class EnchantmentTagGenerator extends FabricTagProvider<Enchantment> {
public EnchantmentTagGenerator(FabricDataOutput output) {
super(output, Registry.ENCHANTMENT);
public class EnchantmentTagGenerator extends FabricTagProvider.EnchantmentTagProvider {
public EnchantmentTagGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
}
@Override
protected void generateTags() {
protected void configure(RegistryWrapper.WrapperLookup registries) {
getOrCreateTagBuilder(ConventionalEnchantmentTags.INCREASES_BLOCK_DROPS)
.add(Enchantments.FORTUNE);
getOrCreateTagBuilder(ConventionalEnchantmentTags.INCREASES_ENTITY_DROPS)

View file

@ -16,6 +16,9 @@
package net.fabricmc.fabric.impl.tag.convention.datagen.generators;
import java.util.concurrent.CompletableFuture;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.entity.EntityType;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
@ -23,12 +26,12 @@ import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalEntityTypeTags;
public class EntityTypeTagGenerator extends FabricTagProvider.EntityTypeTagProvider {
public EntityTypeTagGenerator(FabricDataOutput output) {
super(output);
public EntityTypeTagGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
super(output, completableFuture);
}
@Override
protected void generateTags() {
protected void configure(RegistryWrapper.WrapperLookup registries) {
getOrCreateTagBuilder(ConventionalEntityTypeTags.BOSSES)
.add(EntityType.ENDER_DRAGON)
.add(EntityType.WITHER);

View file

@ -16,6 +16,9 @@
package net.fabricmc.fabric.impl.tag.convention.datagen.generators;
import java.util.concurrent.CompletableFuture;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.tag.FluidTags;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
@ -23,12 +26,12 @@ import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalFluidTags;
public class FluidTagGenerator extends FabricTagProvider.FluidTagProvider {
public FluidTagGenerator(FabricDataOutput output) {
super(output);
public FluidTagGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
super(output, completableFuture);
}
@Override
protected void generateTags() {
protected void configure(RegistryWrapper.WrapperLookup registries) {
getOrCreateTagBuilder(ConventionalFluidTags.WATER)
.addOptionalTag(FluidTags.WATER);
getOrCreateTagBuilder(ConventionalFluidTags.LAVA)

View file

@ -16,6 +16,9 @@
package net.fabricmc.fabric.impl.tag.convention.datagen.generators;
import java.util.concurrent.CompletableFuture;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.item.Items;
import net.minecraft.tag.ItemTags;
import net.minecraft.util.Identifier;
@ -57,12 +60,12 @@ public class ItemTagGenerator extends FabricTagProvider.ItemTagProvider {
@Deprecated
private static final Identifier FABRIC_SWORDS = createFabricId("swords");
public ItemTagGenerator(FabricDataOutput output) {
super(output);
public ItemTagGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
super(output, completableFuture);
}
@Override
protected void generateTags() {
protected void configure(RegistryWrapper.WrapperLookup arg) {
generateToolTags();
generateBucketTags();
generateOreAndRelatedTags();

View file

@ -18,6 +18,7 @@ package net.fabricmc.fabric.api.datagen.v1;
import java.nio.file.Path;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import org.jetbrains.annotations.ApiStatus;
@ -25,6 +26,7 @@ import net.minecraft.SharedConstants;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.util.registry.RegistryWrapper;
import net.fabricmc.loader.api.ModContainer;
@ -35,13 +37,15 @@ public final class FabricDataGenerator extends DataGenerator {
private final ModContainer modContainer;
private final boolean strictValidation;
private final FabricDataOutput fabricOutput;
private final CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture;
@ApiStatus.Internal
public FabricDataGenerator(Path output, ModContainer mod, boolean strictValidation) {
public FabricDataGenerator(Path output, ModContainer mod, boolean strictValidation, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, SharedConstants.getGameVersion(), true);
this.modContainer = Objects.requireNonNull(mod);
this.strictValidation = strictValidation;
this.fabricOutput = new FabricDataOutput(mod, output, strictValidation);
this.registriesFuture = registriesFuture;
}
public Pack createPack() {
@ -85,7 +89,7 @@ public final class FabricDataGenerator extends DataGenerator {
*/
@Override
@Deprecated
public DataGenerator.Pack createVanilla(boolean shouldRun) {
public DataGenerator.Pack createVanillaPack(boolean shouldRun) {
throw new UnsupportedOperationException();
}
@ -112,9 +116,18 @@ public final class FabricDataGenerator extends DataGenerator {
return super.addProvider(output -> factory.create((FabricDataOutput) output));
}
public <T extends DataProvider> T addProvider(RegistryDependentFactory<T> factory) {
return super.addProvider(output -> factory.create((FabricDataOutput) output, registriesFuture));
}
@FunctionalInterface
public interface Factory<T extends DataProvider> {
T create(FabricDataOutput output);
}
@FunctionalInterface
public interface RegistryDependentFactory<T extends DataProvider> {
T create(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture);
}
}
}

View file

@ -1,126 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.datagen.v1.provider;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import com.google.gson.JsonElement;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Encoder;
import com.mojang.serialization.JsonOps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.data.DataOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.data.DataWriter;
import net.minecraft.data.report.WorldgenProvider;
import net.minecraft.util.dynamic.RegistryOps;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.util.registry.RegistryLoader;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
/**
* Data-generates all entries from {@link BuiltinRegistries} that matches a given filter (i.e. mod id).
*
* @see WorldgenProvider For Vanilla's data provider that does the same for the entire registry.
*/
public class FabricBuiltinRegistriesProvider implements DataProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(FabricBuiltinRegistriesProvider.class);
private final Predicate<RegistryKey<?>> entryFilter;
private final FabricDataOutput output;
private FabricBuiltinRegistriesProvider(FabricDataOutput output, Predicate<RegistryKey<?>> entryFilter) {
this.output = output;
this.entryFilter = entryFilter;
}
/**
* @return A provider that will export all entries from {@link BuiltinRegistries} for the mod running the
* data generation.
*/
public static FabricDataGenerator.Pack.Factory<FabricBuiltinRegistriesProvider> forCurrentMod() {
return output -> new FabricBuiltinRegistriesProvider(
output,
e -> e.getValue().getNamespace().equals(output.getModId())
);
}
@Override
public CompletableFuture<?> run(DataWriter writer) {
DynamicRegistryManager dynamicRegistryManager = BuiltinRegistries.createBuiltinRegistryManager();
DynamicOps<JsonElement> dynamicOps = RegistryOps.of(JsonOps.INSTANCE, dynamicRegistryManager);
final List<CompletableFuture<?>> futures = new ArrayList<>();
for (RegistryLoader.Entry<?> entry : RegistryLoader.DYNAMIC_REGISTRIES) {
futures.add(this.writeRegistryEntries(writer, dynamicRegistryManager, dynamicOps, entry));
}
return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
}
private <T> CompletableFuture<?> writeRegistryEntries(DataWriter writer, DynamicRegistryManager registryManager, DynamicOps<JsonElement> ops, RegistryLoader.Entry<T> registry) {
RegistryKey<? extends Registry<T>> registryKey = registry.key();
Registry<T> registry2 = registryManager.get(registryKey);
DataOutput.PathResolver pathResolver = this.output.getResolver(DataOutput.OutputType.DATA_PACK, registryKey.getValue().getPath());
final List<CompletableFuture<?>> futures = new ArrayList<>();
for (Map.Entry<RegistryKey<T>, T> regEntry : registry2.getEntrySet()) {
RegistryKey<T> key = regEntry.getKey();
if (!entryFilter.test(key)) {
continue;
}
Path path = pathResolver.resolveJson(key.getValue());
futures.add(writeToPath(path, writer, ops, registry.elementCodec(), regEntry.getValue()));
}
return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
}
private static <E> CompletableFuture<?> writeToPath(Path path, DataWriter cache, DynamicOps<JsonElement> json, Encoder<E> encoder, E value) {
Optional<JsonElement> optional = encoder.encodeStart(json, value).resultOrPartial((error) -> {
LOGGER.error("Couldn't serialize element {}: {}", path, error);
});
if (optional.isPresent()) {
return DataProvider.writeToPath(cache, optional.get(), path);
}
return CompletableFuture.completedFuture(null);
}
@Override
public String getName() {
return "Built-In Registry Content";
}
}

View file

@ -17,12 +17,17 @@
package net.fabricmc.fabric.api.datagen.v1.provider;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.Block;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.data.server.tag.AbstractTagProvider;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.EntityType;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.Item;
@ -35,15 +40,13 @@ import net.minecraft.tag.TagBuilder;
import net.minecraft.tag.TagEntry;
import net.minecraft.tag.TagKey;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.util.registry.RegistryLoader;
import net.minecraft.world.event.GameEvent;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.impl.datagen.FabricDataGenHelper;
import net.fabricmc.fabric.impl.datagen.ForcedTagEntry;
/**
@ -58,7 +61,6 @@ import net.fabricmc.fabric.impl.datagen.ForcedTagEntry;
* @see FluidTagProvider
* @see EntityTypeTagProvider
* @see GameEventTagProvider
* @see DynamicRegistryTagProvider
*/
public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
/**
@ -67,20 +69,34 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* <p>Common implementations of this class are provided. For example @see BlockTagProvider
*
* @param output The {@link FabricDataOutput} instance
* @param registry The backing registry for the Tag type.
* @param registriesFuture The backing registry for the Tag type.
*/
public FabricTagProvider(FabricDataOutput output, Registry<T> registry) {
super(output, registry);
if (!(this instanceof DynamicRegistryTagProvider) && BuiltinRegistries.REGISTRIES.contains((RegistryKey) registry.getKey())) {
throw new IllegalArgumentException("Using FabricTagProvider to generate dynamic registry tags is not supported, Use DynamicRegistryTagProvider instead.");
}
public FabricTagProvider(FabricDataOutput output, RegistryKey<? extends Registry<T>> registryKey, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registryKey, registriesFuture);
}
/**
* Implement this method and then use {@link FabricTagProvider#getOrCreateTagBuilder} to get and register new tag builders.
*/
protected abstract void generateTags();
protected abstract void configure(RegistryWrapper.WrapperLookup arg);
/**
* Override to enable adding objects to the tag builder directly.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected RegistryKey<T> reverseLookup(T element) {
Registry registry = Registry.REGISTRIES.get((RegistryKey) field_40957);
if (registry != null) {
Optional<RegistryEntry<T>> key = registry.getKey(element);
if (key.isPresent()) {
return (RegistryKey<T>) key.get();
}
}
throw new UnsupportedOperationException("Adding objects is not supported by " + getClass());
}
/**
* Creates a new instance of {@link FabricTagBuilder} for the given {@link TagKey} tag.
@ -89,21 +105,21 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* @return The {@link FabricTagBuilder} instance
*/
@Override
protected FabricTagBuilder<T> getOrCreateTagBuilder(TagKey<T> tag) {
return new FabricTagBuilder<>(super.getOrCreateTagBuilder(tag));
}
@Override
protected final void configure() {
generateTags();
protected FabricTagBuilder getOrCreateTagBuilder(TagKey<T> tag) {
return new FabricTagBuilder(super.getOrCreateTagBuilder(tag));
}
/**
* Extend this class to create {@link Block} tags in the "/blocks" tag directory.
*/
public abstract static class BlockTagProvider extends FabricTagProvider<Block> {
public BlockTagProvider(FabricDataOutput output) {
super(output, Registry.BLOCK);
public BlockTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, Registry.BLOCK_KEY, registriesFuture);
}
@Override
protected RegistryKey<Block> reverseLookup(Block element) {
return element.getRegistryEntry().registryKey();
}
}
@ -119,8 +135,8 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
*
* @param output The {@link FabricDataOutput} instance
*/
public ItemTagProvider(FabricDataOutput output, @Nullable FabricTagProvider.BlockTagProvider blockTagProvider) {
super(output, Registry.ITEM);
public ItemTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture, @Nullable FabricTagProvider.BlockTagProvider blockTagProvider) {
super(output, Registry.ITEM_KEY, completableFuture);
this.blockTagBuilderProvider = blockTagProvider == null ? null : blockTagProvider::getTagBuilder;
}
@ -130,8 +146,8 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
*
* @param output The {@link FabricDataOutput} instance
*/
public ItemTagProvider(FabricDataOutput output) {
this(output, null);
public ItemTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
this(output, completableFuture, null);
}
/**
@ -139,7 +155,6 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
*
* <p>The {@link ItemTagProvider} tag provider must be constructed with an associated {@link BlockTagProvider} tag provider to use this method.
*
* <p>Any block ids that do not exist in the item registry will be filtered out automatically.
*
* @param blockTag The block tag to copy from.
* @param itemTag The item tag to copy to.
@ -147,7 +162,12 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
public void copy(TagKey<Block> blockTag, TagKey<Item> itemTag) {
TagBuilder blockTagBuilder = Objects.requireNonNull(this.blockTagBuilderProvider, "Pass Block tag provider via constructor to use copy").apply(blockTag);
TagBuilder itemTagBuilder = this.getTagBuilder(itemTag);
blockTagBuilder.build().stream().filter((entry) -> entry.canAdd(this.registry::containsId, (id) -> true)).forEach(itemTagBuilder::add);
blockTagBuilder.build().forEach(itemTagBuilder::add);
}
@Override
protected RegistryKey<Item> reverseLookup(Item element) {
return element.getRegistryEntry().registryKey();
}
}
@ -155,8 +175,28 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* Extend this class to create {@link Fluid} tags in the "/fluids" tag directory.
*/
public abstract static class FluidTagProvider extends FabricTagProvider<Fluid> {
public FluidTagProvider(FabricDataOutput output) {
super(output, Registry.FLUID);
public FluidTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
super(output, Registry.FLUID_KEY, completableFuture);
}
@Override
protected RegistryKey<Fluid> reverseLookup(Fluid element) {
return element.getRegistryEntry().registryKey();
}
}
/**
* Extend this class to create {@link Enchantment} tags in the "/enchantments" tag directory.
*/
public abstract static class EnchantmentTagProvider extends FabricTagProvider<Enchantment> {
public EnchantmentTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
super(output, Registry.ENCHANTMENT_KEY, completableFuture);
}
@Override
protected RegistryKey<Enchantment> reverseLookup(Enchantment element) {
return Registry.ENCHANTMENT.getKey(element)
.orElseThrow(() -> new IllegalArgumentException("Enchantment " + element + " is not registered"));
}
}
@ -164,8 +204,13 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* Extend this class to create {@link EntityType} tags in the "/entity_types" tag directory.
*/
public abstract static class EntityTypeTagProvider extends FabricTagProvider<EntityType<?>> {
public EntityTypeTagProvider(FabricDataOutput output) {
super(output, Registry.ENTITY_TYPE);
public EntityTypeTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
super(output, Registry.ENTITY_TYPE_KEY, completableFuture);
}
@Override
protected RegistryKey<EntityType<?>> reverseLookup(EntityType<?> element) {
return element.getRegistryEntry().registryKey();
}
}
@ -173,39 +218,24 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* Extend this class to create {@link GameEvent} tags in the "/game_events" tag directory.
*/
public abstract static class GameEventTagProvider extends FabricTagProvider<GameEvent> {
public GameEventTagProvider(FabricDataOutput output) {
super(output, Registry.GAME_EVENT);
public GameEventTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
super(output, Registry.GAME_EVENT_KEY, completableFuture);
}
@Override
protected RegistryKey<GameEvent> reverseLookup(GameEvent element) {
return element.getRegistryEntry().registryKey();
}
}
/**
* Extend this class to create dynamic registry tags.
* An extension to {@link ObjectBuilder} that provides additional functionality.
*/
public abstract static class DynamicRegistryTagProvider<T> extends FabricTagProvider<T> {
/**
* Construct a new {@link DynamicRegistryTagProvider}.
*
* @param output The {@link FabricDataOutput} instance
* @param registryKey The registry key of the dynamic registry
* @throws IllegalArgumentException if the registry is static registry
*/
protected DynamicRegistryTagProvider(FabricDataOutput output, RegistryKey<? extends Registry<T>> registryKey) {
super(output, FabricDataGenHelper.getFakeDynamicRegistry(registryKey));
if (RegistryLoader.DYNAMIC_REGISTRIES.stream().noneMatch(o -> o.key() == registryKey)
&& RegistryLoader.DIMENSION_REGISTRIES.stream().noneMatch(o -> o.key() == registryKey)) {
throw new IllegalArgumentException("Only dynamic registries are supported in this tag provider.");
}
}
}
/**
* An extension to {@link net.minecraft.data.server.AbstractTagProvider.ObjectBuilder} that provides additional functionality.
*/
public final class FabricTagBuilder<T> extends ObjectBuilder<T> {
public final class FabricTagBuilder extends ObjectBuilder<T> {
private final AbstractTagProvider.ObjectBuilder<T> parent;
private FabricTagBuilder(ObjectBuilder<T> parent) {
super(parent.builder, parent.registry);
super(parent.builder);
this.parent = parent;
}
@ -216,22 +246,52 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
*
* @return the {@link FabricTagBuilder} instance
*/
public FabricTagBuilder<T> setReplace(boolean replace) {
public FabricTagBuilder setReplace(boolean replace) {
((net.fabricmc.fabric.impl.datagen.FabricTagBuilder) builder).fabric_setReplace(replace);
return this;
}
/**
* Add an element to the tag.
*
* @return the {@link FabricTagBuilder} instance
*/
public FabricTagBuilder add(T element) {
add(reverseLookup(element));
return this;
}
/**
* Add multiple elements to the tag.
*
* @return the {@link FabricTagBuilder} instance
*/
@SafeVarargs
public final FabricTagBuilder add(T... element) {
Stream.of(element).map(FabricTagProvider.this::reverseLookup).forEach(this::add);
return this;
}
/**
* Add an element to the tag.
*
* @return the {@link FabricTagBuilder} instance
* @see #add(Identifier)
*/
public FabricTagBuilder add(RegistryKey<T> registryKey) {
parent.method_46835(registryKey);
return this;
}
/**
* Add a single element to the tag.
*
* @return the {@link FabricTagBuilder} instance
* @throws UnsupportedOperationException if the provider is an instance of {@link DynamicRegistryTagProvider}
* @see #add(Identifier)
*/
@Override
public FabricTagBuilder<T> add(T element) {
assertStaticRegistry();
parent.add(element);
public FabricTagBuilder method_46835(RegistryKey<T> registryKey) {
parent.method_46835(registryKey);
return this;
}
@ -240,27 +300,18 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
*
* @return the {@link FabricTagBuilder} instance
*/
public FabricTagBuilder<T> add(Identifier id) {
public FabricTagBuilder add(Identifier id) {
builder.add(id);
return this;
}
/**
* Add a single element to the tag.
*
* @return the {@link FabricTagBuilder} instance
*/
public FabricTagBuilder<T> add(RegistryKey<? extends T> registryKey) {
return add(registryKey.getValue());
}
/**
* Add an optional {@link Identifier} to the tag.
*
* @return the {@link FabricTagBuilder} instance
*/
@Override
public FabricTagBuilder<T> addOptional(Identifier id) {
public FabricTagBuilder addOptional(Identifier id) {
parent.addOptional(id);
return this;
}
@ -270,7 +321,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
*
* @return the {@link FabricTagBuilder} instance
*/
public FabricTagBuilder<T> addOptional(RegistryKey<? extends T> registryKey) {
public FabricTagBuilder addOptional(RegistryKey<? extends T> registryKey) {
return addOptional(registryKey.getValue());
}
@ -290,7 +341,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* @see ItemTags
*/
@Override
public FabricTagBuilder<T> addTag(TagKey<T> tag) {
public FabricTagBuilder addTag(TagKey<T> tag) {
builder.addTag(tag.id());
return this;
}
@ -301,7 +352,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* @return the {@link FabricTagBuilder} instance
*/
@Override
public FabricTagBuilder<T> addOptionalTag(Identifier id) {
public FabricTagBuilder addOptionalTag(Identifier id) {
parent.addOptionalTag(id);
return this;
}
@ -311,7 +362,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
*
* @return the {@link FabricTagBuilder} instance
*/
public FabricTagBuilder<T> addOptionalTag(TagKey<T> tag) {
public FabricTagBuilder addOptionalTag(TagKey<T> tag) {
return addOptionalTag(tag.id());
}
@ -323,7 +374,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
*
* @return the {@link FabricTagBuilder} instance
*/
public FabricTagBuilder<T> forceAddTag(TagKey<T> tag) {
public FabricTagBuilder forceAddTag(TagKey<T> tag) {
builder.add(new ForcedTagEntry(TagEntry.create(tag.id())));
return this;
}
@ -332,26 +383,8 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* Add multiple elements to this tag.
*
* @return the {@link FabricTagBuilder} instance
* @throws UnsupportedOperationException if the provider is an instance of {@link DynamicRegistryTagProvider}
*/
@SafeVarargs
@Override
public final FabricTagBuilder<T> add(T... elements) {
assertStaticRegistry();
for (T element : elements) {
add(element);
}
return this;
}
/**
* Add multiple elements to this tag.
*
* @return the {@link FabricTagBuilder} instance
*/
public FabricTagBuilder<T> add(Identifier... ids) {
public FabricTagBuilder add(Identifier... ids) {
for (Identifier id : ids) {
add(id);
}
@ -365,18 +398,13 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
* @return the {@link FabricTagBuilder} instance
*/
@SafeVarargs
public final FabricTagBuilder<T> add(RegistryKey<T>... registryKeys) {
for (RegistryKey<? extends T> registryKey : registryKeys) {
@Override
public final FabricTagBuilder add(RegistryKey<T>... registryKeys) {
for (RegistryKey<T> registryKey : registryKeys) {
add(registryKey);
}
return this;
}
private void assertStaticRegistry() {
if (FabricTagProvider.this instanceof DynamicRegistryTagProvider) {
throw new UnsupportedOperationException("Adding object instances is not supported for DynamicRegistryTagProvider.");
}
}
}
}

View file

@ -0,0 +1,220 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.datagen.v1.provider;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.google.gson.JsonElement;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Encoder;
import com.mojang.serialization.JsonOps;
import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.data.DataOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.data.DataWriter;
import net.minecraft.data.report.WorldgenProvider;
import net.minecraft.util.Identifier;
import net.minecraft.util.dynamic.RegistryOps;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.util.registry.RegistryEntryLookup;
import net.minecraft.util.registry.RegistryEntryOwner;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.util.registry.RegistryLoader;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.world.gen.carver.ConfiguredCarver;
import net.minecraft.world.gen.feature.PlacedFeature;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
/**
* A provider to help with data-generation of worldgen objects.
*/
@ApiStatus.Experimental
public abstract class FabricWorldgenProvider implements DataProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(WorldgenProvider.class);
private final FabricDataOutput output;
private final CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture;
public FabricWorldgenProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
this.output = output;
this.registriesFuture = registriesFuture;
}
protected abstract void configure(RegistryWrapper.WrapperLookup registries, Entries entries);
public static final class Entries {
private final RegistryWrapper.WrapperLookup registries;
// Registry ID -> Entries for that registry
private final Map<Identifier, RegistryEntries<?>> queuedEntries;
@ApiStatus.Internal
Entries(RegistryWrapper.WrapperLookup registries) {
this.registries = registries;
this.queuedEntries = RegistryLoader.DYNAMIC_REGISTRIES.stream()
.collect(Collectors.toMap(
e -> e.key().getValue(),
e -> RegistryEntries.create(registries, e)
));
}
/**
* Gets access to all lookups.
*/
public RegistryWrapper.WrapperLookup getLookups() {
return registries;
}
/**
* Gets a lookup for entries from the given registry.
*/
public <T> RegistryEntryLookup<T> getLookup(RegistryKey<? extends Registry<T>> registryKey) {
return registries.getWrapperOrThrow(registryKey);
}
/**
* Returns a lookup for placed features. Useful when creating biomes.
*/
public RegistryEntryLookup<PlacedFeature> placedFeatures() {
return getLookup(Registry.PLACED_FEATURE_KEY);
}
/**
* Returns a lookup for configured carvers features. Useful when creating biomes.
*/
public RegistryEntryLookup<ConfiguredCarver<?>> configuredCarvers() {
return getLookup(Registry.CONFIGURED_CARVER_KEY);
}
/**
* Gets a reference to a registry entry for use in other registrations.
*/
public <T> RegistryEntry<T> ref(RegistryKey<T> key) {
RegistryEntries<T> entries = getQueuedEntries(key);
return RegistryEntry.Reference.standAlone(entries.lookup, key);
}
/**
* Adds a new object to be data generated and returns a reference to it for use in other worldgen objects.
*/
public <T> RegistryEntry<T> add(RegistryKey<T> registry, T object) {
return getQueuedEntries(registry).add(registry.getValue(), object);
}
@SuppressWarnings("unchecked")
<T> RegistryEntries<T> getQueuedEntries(RegistryKey<T> key) {
RegistryEntries<?> regEntries = queuedEntries.get(key.getRegistry());
if (regEntries == null) {
throw new IllegalArgumentException("Registry " + key.getRegistry() + " is not loaded from datapacks");
}
return (RegistryEntries<T>) regEntries;
}
}
private static class RegistryEntries<T> {
final RegistryEntryOwner<T> lookup;
final RegistryKey<? extends Registry<T>> registry;
final Codec<T> elementCodec;
Map<RegistryKey<T>, T> entries = new IdentityHashMap<>();
RegistryEntries(RegistryEntryOwner<T> lookup,
RegistryKey<? extends Registry<T>> registry,
Codec<T> elementCodec) {
this.lookup = lookup;
this.registry = registry;
this.elementCodec = elementCodec;
}
static <T> RegistryEntries<T> create(RegistryWrapper.WrapperLookup lookups, RegistryLoader.Entry<T> loaderEntry) {
RegistryWrapper.Impl<T> lookup = lookups.getWrapperOrThrow(loaderEntry.key());
return new RegistryEntries<>(lookup, loaderEntry.key(), loaderEntry.elementCodec());
}
public RegistryEntry<T> add(RegistryKey<T> key, T value) {
if (entries.put(key, value) != null) {
throw new IllegalArgumentException("Trying to add registry key " + key + " more than once.");
}
return RegistryEntry.Reference.standAlone(lookup, key);
}
public RegistryEntry<T> add(Identifier id, T value) {
return add(RegistryKey.of(registry, id), value);
}
}
@Override
public CompletableFuture<?> run(DataWriter writer) {
return registriesFuture.thenCompose(registries -> {
return CompletableFuture
.supplyAsync(() -> {
Entries entries = new Entries(registries);
configure(registries, entries);
return entries;
})
.thenCompose(entries -> {
final RegistryOps<JsonElement> dynamicOps = RegistryOps.of(JsonOps.INSTANCE, registries);
ArrayList<CompletableFuture<?>> futures = new ArrayList<>();
for (RegistryEntries<?> registryEntries : entries.queuedEntries.values()) {
futures.add(writeRegistryEntries(writer, dynamicOps, registryEntries));
}
return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
});
});
}
private <T> CompletableFuture<?> writeRegistryEntries(DataWriter writer, RegistryOps<JsonElement> ops, RegistryEntries<T> entries) {
final RegistryKey<? extends Registry<T>> registry = entries.registry;
final DataOutput.PathResolver pathResolver = output.getResolver(DataOutput.OutputType.DATA_PACK, registry.getValue().getPath());
final List<CompletableFuture<?>> futures = new ArrayList<>();
for (Map.Entry<RegistryKey<T>, T> entry : entries.entries.entrySet()) {
Path path = pathResolver.resolveJson(entry.getKey().getValue());
futures.add(writeToPath(path, writer, ops, entries.elementCodec, entry.getValue()));
}
return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
}
private static <E> CompletableFuture<?> writeToPath(Path path, DataWriter cache, DynamicOps<JsonElement> json, Encoder<E> encoder, E value) {
Optional<JsonElement> optional = encoder.encodeStart(json, value).resultOrPartial((error) -> {
LOGGER.error("Couldn't serialize element {}: {}", path, error);
});
if (optional.isPresent()) {
return DataProvider.writeToPath(cache, optional.get(), path);
}
return CompletableFuture.completedFuture(null);
}
}

View file

@ -22,24 +22,20 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Lifecycle;
import org.apache.commons.lang3.ArrayUtils;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.data.server.tag.AbstractTagProvider;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.util.registry.SimpleRegistry;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.RegistryWrapper;
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider.DynamicRegistryTagProvider;
import net.fabricmc.fabric.api.resource.conditions.v1.ConditionJsonProvider;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
@ -100,6 +96,9 @@ public final class FabricDataGenHelper {
DataGeneratorEntrypoint.class.getName(), ENTRYPOINT_KEY);
}
// Load the registries synchronously
CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture = CompletableFuture.completedFuture(BuiltinRegistries.createWrapperLookup());
for (EntrypointContainer<DataGeneratorEntrypoint> entrypointContainer : dataGeneratorInitializers) {
final String id = entrypointContainer.getProvider().getMetadata().getId();
@ -120,7 +119,7 @@ public final class FabricDataGenHelper {
modContainer = FabricLoader.getInstance().getModContainer(effectiveModId).orElseThrow(() -> new RuntimeException("Failed to find effective mod container for mod id (%s)".formatted(effectiveModId)));
}
FabricDataGenerator dataGenerator = new FabricDataGenerator(outputDir, modContainer, STRICT_VALIDATION);
FabricDataGenerator dataGenerator = new FabricDataGenerator(outputDir, modContainer, STRICT_VALIDATION, registriesFuture);
entrypoint.onInitializeDataGenerator(dataGenerator);
dataGenerator.run();
} catch (Throwable t) {
@ -129,23 +128,6 @@ public final class FabricDataGenHelper {
}
}
/**
* A fake registry instance to be used for {@link DynamicRegistryTagProvider}.
*
* <p>In {@link AbstractTagProvider#run}, it checks for whether the registry has all the elements added to the builder.
* This would be fine for static registry, but there won't be any instance dynamic registry available.
* Therefore, this simply return true for all {@link Registry#containsId} call.
*/
@SuppressWarnings("rawtypes")
public static <T> Registry<T> getFakeDynamicRegistry(RegistryKey<? extends Registry<T>> registryKey) {
return new SimpleRegistry<>(registryKey, Lifecycle.experimental(), false) {
@Override
public boolean containsId(Identifier id) {
return true;
}
};
}
/**
* Used to keep track of conditions associated to generated objects.
*/

View file

@ -19,6 +19,7 @@ package net.fabricmc.fabric.mixin.datagen;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import com.google.gson.JsonElement;
import org.spongepowered.asm.mixin.Mixin;
@ -37,7 +38,7 @@ import net.fabricmc.fabric.impl.datagen.FabricTagBuilder;
@Mixin(AbstractTagProvider.class)
public class AbstractTagProviderMixin {
@Inject(method = "method_27046", at = @At(value = "INVOKE", target = "Lnet/minecraft/data/DataOutput$PathResolver;resolveJson(Lnet/minecraft/util/Identifier;)Ljava/nio/file/Path;"), locals = LocalCapture.CAPTURE_FAILHARD)
public void addReplaced(DataWriter dataWriter, Map.Entry<?, ?> entry, CallbackInfoReturnable<CompletableFuture<?>> ci, Identifier id, TagBuilder builder, List list, List list2, JsonElement jsonElement) {
public void addReplaced(Predicate<?> p, DataWriter dataWriter, Map.Entry<?, ?> entry, CallbackInfoReturnable<CompletableFuture<?>> ci, Identifier id, TagBuilder builder, List list, List list2, JsonElement jsonElement) {
if (builder instanceof FabricTagBuilder fabricTagBuilder) {
jsonElement.getAsJsonObject().addProperty("replace", fabricTagBuilder.fabric_isReplaced());
}

View file

@ -6,10 +6,9 @@ mutable field net/minecraft/data/DataGenerator output Lnet/minecraft/data/DataOu
accessible field net/minecraft/data/server/recipe/RecipeProvider recipesPathResolver Lnet/minecraft/data/DataOutput$PathResolver;
accessible field net/minecraft/data/server/recipe/RecipeProvider advancementsPathResolver Lnet/minecraft/data/DataOutput$PathResolver;
accessible method net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder <init> (Lnet/minecraft/tag/TagBuilder;Lnet/minecraft/util/registry/Registry;)V
extendable method net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder add ([Ljava/lang/Object;)Lnet/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder;
accessible field net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder builder Lnet/minecraft/tag/TagBuilder;
accessible field net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder registry Lnet/minecraft/util/registry/Registry;
extendable method net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder method_46835 (Lnet/minecraft/util/registry/RegistryKey;)Lnet/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder;
extendable method net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder add ([Lnet/minecraft/util/registry/RegistryKey;)Lnet/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder;
accessible field net/minecraft/data/server/tag/AbstractTagProvider tagBuilders Ljava/util/Map;

View file

@ -74,7 +74,7 @@ public class DataGeneratorTestContent implements ModInitializer {
}
@Override
protected void addItems(FeatureSet featureSet, Entries entries) {
protected void addItems(FeatureSet featureSet, Entries entries, boolean showAdminItems) {
entries.addAll(items);
}
}

View file

@ -25,6 +25,7 @@ import static net.fabricmc.fabric.test.datagen.DataGeneratorTestContent.SIMPLE_I
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@ -34,7 +35,7 @@ import org.slf4j.LoggerFactory;
import net.minecraft.advancement.Advancement;
import net.minecraft.advancement.AdvancementFrame;
import net.minecraft.advancement.criterion.OnKilledCriterion;
import net.minecraft.data.DataProvider;
import net.minecraft.util.registry.RegistryWrapper;
import net.minecraft.data.client.BlockStateModelGenerator;
import net.minecraft.data.client.ItemModelGenerator;
import net.minecraft.data.server.recipe.RecipeJsonProvider;
@ -54,7 +55,6 @@ import net.minecraft.tag.ItemTags;
import net.minecraft.tag.TagKey;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeKeys;
@ -90,34 +90,8 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
pack.addProvider(JapaneseLangProvider::new);
TestBlockTagProvider blockTagProvider = pack.addProvider(TestBlockTagProvider::new);
pack.addProvider((FabricDataGenerator.Pack.Factory<TestItemTagProvider>) output -> new TestItemTagProvider(output, blockTagProvider));
pack.addProvider((output, registries) -> new TestItemTagProvider(output, registries, blockTagProvider));
pack.addProvider(TestBiomeTagProvider::new);
try {
pack.addProvider((FabricDataGenerator.Pack.Factory<DataProvider>) output -> {
new FabricTagProvider<>(output, BuiltinRegistries.BIOME) {
@Override
protected void generateTags() {
}
};
throw new AssertionError("Using FabricTagProvider with built-in registry didn't throw an exception!");
});
} catch (IllegalArgumentException e) {
// no-op
}
try {
pack.addProvider((FabricDataGenerator.Pack.Factory<DataProvider>) output -> {
new FabricTagProvider.DynamicRegistryTagProvider<>(output, Registry.ITEM_KEY) {
@Override
protected void generateTags() {
}
};
throw new AssertionError("Using DynamicRegistryTagProvider with static registry didn't throw an exception!");
});
} catch (IllegalArgumentException e) {
// no-op
}
}
private static class TestRecipeProvider extends FabricRecipeProvider {
@ -198,46 +172,39 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
}
private static class TestBlockTagProvider extends FabricTagProvider.BlockTagProvider {
private TestBlockTagProvider(FabricDataOutput output) {
super(output);
TestBlockTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
}
@Override
protected void generateTags() {
protected void configure(RegistryWrapper.WrapperLookup registries) {
getOrCreateTagBuilder(BlockTags.FIRE).add(SIMPLE_BLOCK);
getOrCreateTagBuilder(BlockTags.ANVIL).setReplace(true).add(SIMPLE_BLOCK, BLOCK_WITHOUT_ITEM);
getOrCreateTagBuilder(BlockTags.ANVIL).setReplace(true).add(SIMPLE_BLOCK);
getOrCreateTagBuilder(BlockTags.ACACIA_LOGS).forceAddTag(BlockTags.ANIMALS_SPAWNABLE_ON);
}
}
private static class TestItemTagProvider extends FabricTagProvider.ItemTagProvider {
private TestItemTagProvider(FabricDataOutput output, BlockTagProvider blockTagProvider) {
super(output, blockTagProvider);
private TestItemTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, BlockTagProvider blockTagProvider) {
super(output, registriesFuture, blockTagProvider);
}
@Override
protected void generateTags() {
protected void configure(RegistryWrapper.WrapperLookup registries) {
copy(BlockTags.ANVIL, ItemTags.ANVIL);
}
}
private static class TestBiomeTagProvider extends FabricTagProvider.DynamicRegistryTagProvider<Biome> {
private TestBiomeTagProvider(FabricDataOutput output) {
super(output, Registry.BIOME_KEY);
private static class TestBiomeTagProvider extends FabricTagProvider<Biome> {
private TestBiomeTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, Registry.BIOME_KEY, registriesFuture);
}
@Override
protected void generateTags() {
FabricTagBuilder<Biome> builder = getOrCreateTagBuilder(TagKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "biome_tag_test")))
protected void configure(RegistryWrapper.WrapperLookup registries) {
getOrCreateTagBuilder(TagKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "biome_tag_test")))
.add(BiomeKeys.BADLANDS, BiomeKeys.BAMBOO_JUNGLE)
.add(BiomeKeys.BASALT_DELTAS);
try {
builder.add(BuiltinRegistries.BIOME.get(BiomeKeys.PLAINS));
throw new AssertionError("Adding built-in entry to dynamic registry tag builder didn't throw an exception!");
} catch (UnsupportedOperationException e) {
// no-op
}
}
}

View file

@ -6,10 +6,9 @@ mutable field net/minecraft/data/DataGenerator output Lnet/minecraft/data/DataOu
accessible field net/minecraft/data/server/recipe/RecipeProvider recipesPathResolver Lnet/minecraft/data/DataOutput$PathResolver;
accessible field net/minecraft/data/server/recipe/RecipeProvider advancementsPathResolver Lnet/minecraft/data/DataOutput$PathResolver;
accessible method net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder <init> (Lnet/minecraft/tag/TagBuilder;Lnet/minecraft/util/registry/Registry;)V
extendable method net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder add ([Ljava/lang/Object;)Lnet/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder;
accessible field net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder builder Lnet/minecraft/tag/TagBuilder;
accessible field net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder registry Lnet/minecraft/util/registry/Registry;
extendable method net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder method_46835 (Lnet/minecraft/util/registry/RegistryKey;)Lnet/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder;
extendable method net/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder add ([Lnet/minecraft/util/registry/RegistryKey;)Lnet/minecraft/data/server/tag/AbstractTagProvider$ObjectBuilder;
accessible field net/minecraft/data/server/tag/AbstractTagProvider tagBuilders Ljava/util/Map;

View file

@ -17,7 +17,6 @@
package net.fabricmc.fabric.test.dimension;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
@ -25,7 +24,7 @@ import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.block.BlockState;
import net.minecraft.structure.StructureSet;
import net.minecraft.util.registry.RegistryEntryLookup;
import net.minecraft.util.dynamic.RegistryOps;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
@ -46,14 +45,11 @@ import net.minecraft.world.gen.noise.NoiseConfig;
public class VoidChunkGenerator extends ChunkGenerator {
public static final Codec<VoidChunkGenerator> CODEC = RecordCodecBuilder.create((instance) ->
createStructureSetRegistryGetter(instance).and(RegistryOps.createRegistryCodec(Registry.BIOME_KEY).forGetter((generator) -> generator.biomeRegistry))
instance.group(RegistryOps.getEntryLookupCodec(Registry.BIOME_KEY))
.apply(instance, instance.stable(VoidChunkGenerator::new)));
private final Registry<Biome> biomeRegistry;
public VoidChunkGenerator(Registry<StructureSet> registry, Registry<Biome> biomeRegistry) {
super(registry, Optional.empty(), new FixedBiomeSource(biomeRegistry.getOrCreateEntry(BiomeKeys.PLAINS)));
this.biomeRegistry = biomeRegistry;
public VoidChunkGenerator(RegistryEntryLookup<Biome> biomeRegistry) {
super(new FixedBiomeSource(biomeRegistry.getOrThrow(BiomeKeys.PLAINS)));
}
@Override

View file

@ -40,10 +40,10 @@ public final class EnumRuleWidget<E extends Enum<E>> extends EditGameRulesScreen
// Base translation key needs to be set before the button widget is created.
this.rootTranslationKey = translationKey;
this.buttonWidget = ButtonWidget.method_46430(this.getValueText(rule.get()), (buttonWidget) -> {
this.buttonWidget = ButtonWidget.createBuilder(this.getValueText(rule.get()), (buttonWidget) -> {
rule.cycle();
buttonWidget.setMessage(this.getValueText(rule.get()));
}).method_46433(10, 5).method_46437(88, 20).method_46431();
}).setPosition(10, 5).setSize(88, 20).build();
this.children.add(this.buttonWidget);
}

View file

@ -39,7 +39,7 @@ public class FabricCreativeGuiComponents {
final Type type;
public ItemGroupButtonWidget(int x, int y, Type type, CreativeGuiExtensions extensions) {
super(x, y, 11, 10, type.text, (bw) -> type.clickConsumer.accept(extensions), EMPTY, ButtonWidget.field_40754);
super(x, y, 11, 10, type.text, (bw) -> type.clickConsumer.accept(extensions), EMPTY_TOOLTIP, ButtonWidget.DEFAULT_NARRATION_SUPPLIER);
this.extensions = extensions;
this.type = type;
this.gui = (CreativeInventoryScreen) extensions;
@ -47,7 +47,7 @@ public class FabricCreativeGuiComponents {
@Override
public void render(MatrixStack matrixStack, int mouseX, int mouseY, float float_1) {
this.hovered = mouseX >= this.method_46426() && mouseY >= this.method_46427() && mouseX < this.method_46426() + this.width && mouseY < this.method_46427() + this.height;
this.hovered = mouseX >= this.getX() && mouseY >= this.getY() && mouseX < this.getX() + this.width && mouseY < this.getY() + this.height;
this.visible = extensions.fabric_isButtonVisible(type);
this.active = extensions.fabric_isButtonEnabled(type);
@ -57,7 +57,7 @@ public class FabricCreativeGuiComponents {
RenderSystem.setShaderTexture(0, BUTTON_TEX);
RenderSystem.setShaderColor(1F, 1F, 1F, 1F);
this.drawTexture(matrixStack, this.method_46426(), this.method_46427(), u + (type == Type.NEXT ? 11 : 0), v, 11, 10);
this.drawTexture(matrixStack, this.getX(), this.getY(), u + (type == Type.NEXT ? 11 : 0), v, 11, 10);
if (this.hovered) {
int pageCount = (int) Math.ceil((ItemGroups.GROUPS.length - COMMON_GROUPS.size()) / 9D);

View file

@ -45,15 +45,15 @@ abstract class ItemGroupMixin implements IdentifiableItemGroup {
@Final
private int index;
@Shadow
@Shadow(aliases = "field_40859")
private ItemStackSet displayStacks;
@Shadow
@Shadow(aliases = "field_40860")
private ItemStackSet searchTabStacks;
@SuppressWarnings("ConstantConditions")
@Inject(method = "getStacks", at = @At(value = "FIELD", target = "Lnet/minecraft/item/ItemGroup;searchTabStacks:Lnet/minecraft/item/ItemStackSet;", opcode = Opcodes.PUTFIELD, shift = At.Shift.AFTER))
public void getStacks(FeatureSet enabledFeatures, boolean search, CallbackInfoReturnable<ItemStackSet> cir) {
public void getStacks(FeatureSet enabledFeatures, boolean search, boolean showAdminItems, CallbackInfoReturnable<ItemStackSet> cir) {
// Sanity check for the injection point. It should be after these fields are set.
Objects.requireNonNull(displayStacks, "displayStacks");
Objects.requireNonNull(searchTabStacks, "searchTabStacks");

View file

@ -45,7 +45,7 @@ public class ItemGroupTest implements ModInitializer {
}
@Override
protected void addItems(FeatureSet featureSet, Entries entries) {
protected void addItems(FeatureSet featureSet, Entries entries, boolean opItems) {
entries.addAll(Registry.ITEM.stream()
.map(ItemStack::new)
.toList());

View file

@ -39,22 +39,22 @@ final class ChannelScreen extends Screen {
@Override
protected void init() {
this.s2cButton = this.addDrawableChild(ButtonWidget.method_46430(Text.literal("S2C"), this::toS2C)
.method_46433(this.width / 2 - 55, 5)
.method_46437(50, 20)
.method_46436((button2, matrices1, mouseX1, mouseY1) -> {
this.s2cButton = this.addDrawableChild(ButtonWidget.createBuilder(Text.literal("S2C"), this::toS2C)
.setPosition(this.width / 2 - 55, 5)
.setSize(50, 20)
.setTooltipSupplier((button2, matrices1, mouseX1, mouseY1) -> {
this.renderTooltip(matrices1, Text.literal("Packets this client can receive"), mouseX1, mouseY1);
}).method_46431());
this.c2sButton = this.addDrawableChild(ButtonWidget.method_46430(Text.literal("C2S"), this::toC2S)
.method_46433(this.width / 2 + 5, 5)
.method_46437(50, 20)
.method_46436((button1, matrices, mouseX, mouseY) -> {
}).build());
this.c2sButton = this.addDrawableChild(ButtonWidget.createBuilder(Text.literal("C2S"), this::toC2S)
.setPosition(this.width / 2 + 5, 5)
.setSize(50, 20)
.setTooltipSupplier((button1, matrices, mouseX, mouseY) -> {
this.renderTooltip(matrices, Text.literal("Packets the server can receive"), mouseX, mouseY);
}).method_46431());
this.closeButton = this.addDrawableChild(ButtonWidget.method_46430(Text.literal("Close"), button -> this.close())
.method_46433(this.width / 2 - 60, this.height - 25)
.method_46437(120, 20)
.method_46431());
}).build());
this.closeButton = this.addDrawableChild(ButtonWidget.createBuilder(Text.literal("Close"), button -> this.close())
.setPosition(this.width / 2 - 60, this.height - 25)
.setSize(120, 20)
.build());
this.channelList = this.addDrawable(new ChannelList(this.client, this.width, this.height - 60, 30, this.height - 30, this.textRenderer.fontHeight + 2));
}

View file

@ -1,66 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.registry.sync;
import com.mojang.serialization.Lifecycle;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.MutableRegistry;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
import net.fabricmc.fabric.mixin.registry.sync.RegistryAccessor;
/**
* Handles synchronising changes to the built-in registries into the dynamic registry manager's template manager,
* in case it gets classloaded early.
*/
public class DynamicRegistrySync {
private static final Logger LOGGER = LoggerFactory.getLogger(DynamicRegistrySync.class);
/**
* Sets up a synchronisation that will propagate added entries to the given dynamic registry manager, which
* should be the <em>built-in</em> manager. It is never destroyed. We don't ever have to unregister
* the registry events.
*/
public static void setupSync(DynamicRegistryManager template) {
LOGGER.debug("Setting up synchronisation of new BuiltinRegistries entries to the built-in DynamicRegistryManager");
BuiltinRegistries.REGISTRIES.stream().forEach(source -> setupSync(source, template));
}
/**
* Sets up an event registration for the source registy that will ensure all entries added from now on
* are also added to the template for dynamic registry managers.
*/
private static <T> void setupSync(Registry<T> source, DynamicRegistryManager template) {
@SuppressWarnings("unchecked") RegistryAccessor<T> sourceAccessor = (RegistryAccessor<T>) source;
RegistryKey<? extends Registry<T>> sourceKey = source.getKey();
MutableRegistry<T> target = (MutableRegistry<T>) template.get(sourceKey);
RegistryEntryAddedCallback.event(source).register((rawId, id, object) -> {
LOGGER.trace("Synchronizing {} from built-in registry {} into built-in dynamic registry manager template.",
id, source.getKey());
Lifecycle lifecycle = sourceAccessor.callGetEntryLifecycle(object);
RegistryKey<T> entryKey = RegistryKey.of(sourceKey, id);
target.set(rawId, entryKey, object, lifecycle);
});
}
}

View file

@ -1,33 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.registry.sync;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
@Mixin(BuiltinRegistries.class)
public class BuiltinRegistriesMixin {
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/registry/Registry;freeze()Lnet/minecraft/util/registry/Registry;"))
private static Registry<?> unfreezeBultinRegistries(Registry<?> reg) {
// Don't freeze
return reg;
}
}

View file

@ -25,9 +25,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.SimpleRegistry;
import net.fabricmc.api.EnvType;
import net.fabricmc.fabric.impl.registry.sync.trackers.vanilla.BlockInitTracker;
@ -43,11 +41,6 @@ public class MinecraftServerMixin {
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) {
// Freeze the registries on the server
FABRIC_LOGGER.debug("Freezing registries");
BuiltinRegistries.REGISTRIES.freeze();
for (Registry<?> registry : BuiltinRegistries.REGISTRIES) {
((SimpleRegistry<?>) registry).freeze();
}
Registry.freezeRegistries();
BlockInitTracker.postFreeze();

View file

@ -16,9 +16,13 @@
package net.fabricmc.fabric.mixin.registry.sync;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import com.mojang.datafixers.util.Pair;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -26,7 +30,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.dynamic.RegistryOps;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.MutableRegistry;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.util.registry.RegistryLoader;
import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback;
@ -42,7 +50,33 @@ public class RegistryLoaderMixin {
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private static void beforeLoad(ResourceManager resourceManager, DynamicRegistryManager baseRegistryManager, List<RegistryLoader.Entry<?>> entries, CallbackInfoReturnable<DynamicRegistryManager.Immutable> cir, Map a, List b, DynamicRegistryManager registryManager) {
DynamicRegistrySetupCallback.EVENT.invoker().onRegistrySetup(registryManager);
private static void beforeLoad(ResourceManager resourceManager, DynamicRegistryManager baseRegistryManager, List<RegistryLoader.Entry<?>> entries, CallbackInfoReturnable<DynamicRegistryManager.Immutable> cir, Map a, List<Pair<MutableRegistry<?>, ?>> registriesList, RegistryOps.RegistryInfoGetter registryManager) {
Map<RegistryKey<? extends Registry<?>>, Registry<?>> registries = new IdentityHashMap<>(registriesList.size());
for (Pair<MutableRegistry<?>, ?> pair : registriesList) {
registries.put(pair.getFirst().getKey(), pair.getFirst());
}
DynamicRegistryManager drm = new DynamicRegistryManager.Immutable() {
@SuppressWarnings("unchecked")
public <T> Optional<Registry<T>> getOptional(RegistryKey<? extends Registry<? extends T>> key) {
return Optional.ofNullable((Registry<T>) registries.get(key));
}
public Stream<Entry<?>> streamAllRegistries() {
return registries.values().stream()
.map(this::entry);
}
private <T> Entry<T> entry(Registry<T> registry) {
return new Entry<>(registry.getKey(), registry);
}
public Immutable toImmutable() {
return this;
}
};
DynamicRegistrySetupCallback.EVENT.invoker().onRegistrySetup(drm);
}
}

View file

@ -4,7 +4,6 @@
"compatibilityLevel": "JAVA_16",
"mixins": [
"BootstrapMixin",
"BuiltinRegistriesMixin",
"ChunkSerializerMixin",
"DebugChunkGeneratorAccessor",
"IdListMixin",

View file

@ -30,13 +30,8 @@ import net.minecraft.block.Material;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.SimpleRegistry;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.Feature;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
@ -88,8 +83,6 @@ public class RegistrySyncTest implements ModInitializer {
sender.sendPacket(PACKET_CHECK_COMPARE, PacketByteBufs.empty());
});
testBuiltInRegistrySync();
if (REGISTER_BLOCKS) {
// For checking raw id bulk in direct registry packet, make registry_sync namespace have two bulks.
registerBlocks("registry_sync", 5, 0);
@ -147,45 +140,4 @@ public class RegistrySyncTest implements ModInitializer {
}
}
}
/**
* Tests that built-in registries are properly synchronized even after the dynamic reigstry managers have been
* class-loaded.
*/
private void testBuiltInRegistrySync() {
LOGGER.info("Checking built-in registry sync...");
// Register a configured feature before force-loading the dynamic registry manager
ConfiguredFeature<DefaultFeatureConfig, ?> cf1 = new ConfiguredFeature<>(Feature.BASALT_PILLAR, DefaultFeatureConfig.INSTANCE);
Identifier f1Id = new Identifier("registry_sync", "f1");
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, f1Id, cf1);
// Force-Initialize the dynamic registry manager, doing this in a Mod initializer would cause
// further registrations into BuiltInRegistries to _NOT_ propagate into DynamicRegistryManager.BUILTIN
checkFeature(DynamicRegistryManager.of(BuiltinRegistries.REGISTRIES), f1Id);
ConfiguredFeature<DefaultFeatureConfig, ?> cf2 = new ConfiguredFeature<>(Feature.DESERT_WELL, DefaultFeatureConfig.INSTANCE);
Identifier f2Id = new Identifier("registry_sync", "f2");
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, f2Id, cf2);
DynamicRegistryManager impl2 = DynamicRegistryManager.of(BuiltinRegistries.REGISTRIES);
checkFeature(impl2, f1Id);
checkFeature(impl2, f2Id);
}
private void checkFeature(DynamicRegistryManager manager, Identifier id) {
Registry<ConfiguredFeature<?, ?>> registry = manager.get(Registry.CONFIGURED_FEATURE_KEY);
ConfiguredFeature<?, ?> builtInEntry = BuiltinRegistries.CONFIGURED_FEATURE.get(id);
if (builtInEntry == null) {
throw new IllegalStateException("Expected built-in entry to exist for: " + id);
}
ConfiguredFeature<?, ?> entry = registry.get(id);
if (entry == null) {
throw new IllegalStateException("Expected dynamic registry to contain entry " + id);
}
}
}

View file

@ -34,7 +34,6 @@ import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.world.BlockRenderView;
import net.minecraft.world.biome.BiomeKeys;
@ -42,7 +41,10 @@ import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
public class FluidRenderHandlerRegistryImpl implements FluidRenderHandlerRegistry {
private static final int DEFAULT_WATER_COLOR = BuiltinRegistries.BIOME.get(BiomeKeys.OCEAN).getWaterColor();
/**
* The water color of {@link BiomeKeys#OCEAN}.
*/
private static final int DEFAULT_WATER_COLOR = 0x3f76e4;
private final Map<Fluid, FluidRenderHandler> handlers = new IdentityHashMap<>();
private final Map<Fluid, FluidRenderHandler> modHandlers = new IdentityHashMap<>();
private final Map<Block, Boolean> overlayBlocks = new IdentityHashMap<>();

View file

@ -33,6 +33,7 @@ import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
@ -56,7 +57,7 @@ public abstract class CustomFluid extends FlowableFluid {
}
@Override
protected boolean isInfinite() {
protected boolean isInfinite(World world) {
return true;
}

View file

@ -33,6 +33,7 @@ import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
@ -56,7 +57,7 @@ public abstract class NoOverlayFluid extends FlowableFluid {
}
@Override
protected boolean isInfinite() {
protected boolean isInfinite(World world) {
return true;
}

View file

@ -33,6 +33,7 @@ import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
@ -56,7 +57,7 @@ public abstract class OverlayFluid extends FlowableFluid {
}
@Override
protected boolean isInfinite() {
protected boolean isInfinite(World world) {
return true;
}

View file

@ -33,6 +33,7 @@ import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
@ -56,7 +57,7 @@ public abstract class UnregisteredFluid extends FlowableFluid {
}
@Override
protected boolean isInfinite() {
protected boolean isInfinite(World world) {
return true;
}

View file

@ -39,10 +39,10 @@ class StopSoundButton extends PressableWidget {
public void render(MatrixStack matrices, int mouseX, int mouseY, float tickDelta) {
// Render the armor icon to test
RenderSystem.setShaderTexture(0, InGameHud.GUI_ICONS_TEXTURE);
DrawableHelper.drawTexture(matrices, this.method_46426(), this.method_46427(), this.width, this.height, 43, 27, 9, 9, 256, 256);
DrawableHelper.drawTexture(matrices, this.getX(), this.getY(), this.width, this.height, 43, 27, 9, 9, 256, 256);
if (this.isMouseOver(mouseX, mouseY)) {
this.screen.renderTooltip(matrices, Text.literal("Click to stop all sounds"), this.method_46426(), this.method_46427());
this.screen.renderTooltip(matrices, Text.literal("Click to stop all sounds"), this.getX(), this.getY());
}
}

View file

@ -155,7 +155,7 @@ transitive-accessible method net/minecraft/block/FarmlandBlock <init> (Lnet/mine
transitive-accessible method net/minecraft/block/FernBlock <init> (Lnet/minecraft/block/AbstractBlock$Settings;)V
transitive-accessible method net/minecraft/block/FletchingTableBlock <init> (Lnet/minecraft/block/AbstractBlock$Settings;)V
transitive-accessible method net/minecraft/block/FluidBlock <init> (Lnet/minecraft/fluid/FlowableFluid;Lnet/minecraft/block/AbstractBlock$Settings;)V
transitive-accessible method net/minecraft/block/FungusBlock <init> (Lnet/minecraft/block/AbstractBlock$Settings;Ljava/util/function/Supplier;)V
transitive-accessible method net/minecraft/block/FungusBlock <init> (Lnet/minecraft/block/AbstractBlock$Settings;Lnet/minecraft/util/registry/RegistryKey;)V
transitive-accessible method net/minecraft/block/FurnaceBlock <init> (Lnet/minecraft/block/AbstractBlock$Settings;)V
transitive-accessible method net/minecraft/block/GrindstoneBlock <init> (Lnet/minecraft/block/AbstractBlock$Settings;)V
transitive-accessible method net/minecraft/block/HangingRootsBlock <init> (Lnet/minecraft/block/AbstractBlock$Settings;)V

View file

@ -1,60 +1,60 @@
org.gradle.jvmargs=-Xmx2560M
org.gradle.parallel=true
version=0.65.2
minecraft_version=22w43a
yarn_version=+build.3
version=0.65.3
minecraft_version=22w44a
yarn_version=+build.4
loader_version=0.14.10
prerelease=true
# Do not manually update, use the bumpversions task:
fabric-api-base-version=0.4.14
fabric-api-lookup-api-v1-version=1.6.12
fabric-biome-api-v1-version=10.0.1
fabric-blockrenderlayer-v1-version=1.1.23
fabric-command-api-v1-version=1.2.14
fabric-command-api-v2-version=2.1.10
fabric-commands-v0-version=0.2.31
fabric-containers-v0-version=0.1.37
fabric-content-registries-v0-version=3.4.3
fabric-crash-report-info-v1-version=0.2.8
fabric-data-generation-api-v1-version=8.0.0
fabric-dimensions-v1-version=2.1.34
fabric-entity-events-v1-version=1.4.21
fabric-events-interaction-v0-version=0.4.31
fabric-events-lifecycle-v0-version=0.2.31
fabric-game-rule-api-v1-version=1.0.24
fabric-gametest-api-v1-version=1.1.4
fabric-item-api-v1-version=2.0.1
fabric-item-group-api-v1-version=1.0.2
fabric-key-binding-api-v1-version=1.0.24
fabric-keybindings-v0-version=0.2.22
fabric-lifecycle-events-v1-version=2.2.2
fabric-loot-api-v2-version=1.1.9
fabric-loot-tables-v1-version=1.1.12
fabric-message-api-v1-version=5.0.7
fabric-mining-level-api-v1-version=2.1.20
fabric-models-v0-version=0.3.20
fabric-networking-api-v1-version=1.2.7
fabric-networking-v0-version=0.3.24
fabric-object-builder-api-v1-version=5.0.1
fabric-particles-v1-version=1.0.13
fabric-registry-sync-v0-version=1.0.0
fabric-renderer-api-v1-version=2.0.0
fabric-renderer-indigo-version=0.6.16
fabric-renderer-registries-v1-version=3.2.23
fabric-rendering-data-attachment-v1-version=0.3.17
fabric-rendering-fluids-v1-version=3.0.10
fabric-rendering-v0-version=1.1.25
fabric-rendering-v1-version=1.11.2
fabric-resource-conditions-api-v1-version=2.1.2
fabric-resource-loader-v0-version=0.9.0
fabric-screen-api-v1-version=1.0.29
fabric-screen-handler-api-v1-version=1.3.3
fabric-sound-api-v1-version=1.0.2
fabric-textures-v0-version=2.0.1
fabric-transfer-api-v1-version=2.1.3
fabric-transitive-access-wideners-v1-version=2.0.0
fabric-convention-tags-v1-version=1.1.4
fabric-client-tags-api-v1-version=1.0.4
fabric-api-base-version=0.4.15
fabric-api-lookup-api-v1-version=1.6.13
fabric-biome-api-v1-version=11.0.0
fabric-blockrenderlayer-v1-version=1.1.24
fabric-command-api-v1-version=1.2.15
fabric-command-api-v2-version=2.1.11
fabric-commands-v0-version=0.2.32
fabric-containers-v0-version=0.1.38
fabric-content-registries-v0-version=3.4.4
fabric-crash-report-info-v1-version=0.2.9
fabric-data-generation-api-v1-version=9.0.0
fabric-dimensions-v1-version=2.1.35
fabric-entity-events-v1-version=1.4.22
fabric-events-interaction-v0-version=0.4.32
fabric-events-lifecycle-v0-version=0.2.32
fabric-game-rule-api-v1-version=1.0.25
fabric-gametest-api-v1-version=1.1.5
fabric-item-api-v1-version=2.0.2
fabric-item-group-api-v1-version=1.0.3
fabric-key-binding-api-v1-version=1.0.25
fabric-keybindings-v0-version=0.2.23
fabric-lifecycle-events-v1-version=2.2.3
fabric-loot-api-v2-version=1.1.10
fabric-loot-tables-v1-version=1.1.13
fabric-message-api-v1-version=5.0.8
fabric-mining-level-api-v1-version=2.1.21
fabric-models-v0-version=0.3.21
fabric-networking-api-v1-version=1.2.8
fabric-networking-v0-version=0.3.25
fabric-object-builder-api-v1-version=5.0.2
fabric-particles-v1-version=1.0.14
fabric-registry-sync-v0-version=1.0.1
fabric-renderer-api-v1-version=2.0.1
fabric-renderer-indigo-version=0.6.17
fabric-renderer-registries-v1-version=3.2.24
fabric-rendering-data-attachment-v1-version=0.3.18
fabric-rendering-fluids-v1-version=3.0.11
fabric-rendering-v0-version=1.1.26
fabric-rendering-v1-version=1.11.3
fabric-resource-conditions-api-v1-version=2.1.3
fabric-resource-loader-v0-version=0.9.1
fabric-screen-api-v1-version=1.0.30
fabric-screen-handler-api-v1-version=1.3.4
fabric-sound-api-v1-version=1.0.3
fabric-textures-v0-version=2.0.2
fabric-transfer-api-v1-version=2.1.4
fabric-transitive-access-wideners-v1-version=2.0.1
fabric-convention-tags-v1-version=1.1.5
fabric-client-tags-api-v1-version=1.0.5