Generalized Datagen

This commit is contained in:
Frank 2022-12-04 13:37:33 +01:00
parent de2dd60807
commit 982b3aa274
6 changed files with 316 additions and 151 deletions

View file

@ -0,0 +1,64 @@
package org.betterx.bclib.api.v3.datagen;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderSet;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstapContext;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorPreset;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
public class FlatLevelPresetHelper {
public static void register(
BootstapContext<FlatLevelGeneratorPreset> ctx,
ResourceKey<FlatLevelGeneratorPreset> presetKey,
ItemLike icon,
ResourceKey<Biome> biomeKey,
Set<ResourceKey<StructureSet>> allowedStructureSets,
boolean addDecorations,
boolean addLakes,
FlatLayerInfo... flatLayerInfos
) {
final HolderGetter<StructureSet> structureSets = ctx.lookup(Registries.STRUCTURE_SET);
Objects.requireNonNull(structureSets);
final HolderGetter<PlacedFeature> placedFeatures = ctx.lookup(Registries.PLACED_FEATURE);
final HolderGetter<Biome> biomes = ctx.lookup(Registries.BIOME);
HolderSet.Direct<StructureSet> structures = HolderSet.direct(
allowedStructureSets.stream()
.map(structureSets::getOrThrow)
.toList());
FlatLevelGeneratorSettings flatLevelGeneratorSettings = new FlatLevelGeneratorSettings(
Optional.of(structures),
biomes.getOrThrow(biomeKey),
FlatLevelGeneratorSettings.createLakesList(placedFeatures)
);
if (addDecorations) {
flatLevelGeneratorSettings.setDecoration();
}
if (addLakes) {
flatLevelGeneratorSettings.setAddLakes();
}
for (int i = flatLayerInfos.length - 1; i >= 0; --i) {
flatLevelGeneratorSettings.getLayersInfo().add(flatLayerInfos[i]);
}
ctx.register(
presetKey,
new FlatLevelGeneratorPreset(icon.asItem().builtInRegistryHolder(), flatLevelGeneratorSettings)
);
}
}

View file

@ -0,0 +1,217 @@
package org.betterx.bclib.api.v3.datagen;
import org.betterx.worlds.together.util.Logger;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Encoder;
import com.mojang.serialization.JsonOps;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.Registry;
import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.resources.RegistryDataLoader;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import com.google.gson.JsonElement;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import org.jetbrains.annotations.Nullable;
public abstract class RegistriesDataProvider implements DataProvider {
public class InfoList extends LinkedList<RegistryInfo<?>> {
public <T> void add(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec) {
this.add(new RegistryInfo<T>(key, elementCodec));
}
public <T> void add(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec, String... modIDs) {
this.add(new RegistryInfo<T>(key, elementCodec, modIDs));
}
public <T> void add(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec, List<String> modIDs) {
this.add(new RegistryInfo<T>(key, elementCodec, modIDs));
}
public <T> void addUnfiltered(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec) {
this.add(new RegistryInfo<T>(key, elementCodec, RegistryInfo.UNFILTERED));
}
}
public final class RegistryInfo<T> {
public static final List<String> UNFILTERED = null;
public final RegistryDataLoader.RegistryData<T> data;
public final List<String> modIDs;
public RegistryInfo(RegistryDataLoader.RegistryData<T> data, List<String> modIDs) {
this.data = data;
this.modIDs = modIDs;
}
public RegistryInfo(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec) {
this(new RegistryDataLoader.RegistryData<>(key, elementCodec), RegistriesDataProvider.this.defaultModIDs);
}
public RegistryInfo(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec, String... modIDs) {
this(new RegistryDataLoader.RegistryData<>(key, elementCodec), List.of(modIDs));
}
public RegistryInfo(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec, List<String> modIDs) {
this(new RegistryDataLoader.RegistryData<>(key, elementCodec), modIDs);
}
public ResourceKey<? extends Registry<T>> key() {
return data.key();
}
public Codec<T> elementCodec() {
return data.elementCodec();
}
List<Holder<T>> allElements(HolderLookup.Provider registryAccess) {
final HolderLookup.RegistryLookup<T> registry = registryAccess.lookupOrThrow(key());
return registry
.listElementIds()
.filter(k -> modIDs == null || modIDs.isEmpty() || modIDs.contains(k.location().getNamespace()))
.map(k -> (Holder<T>) registry.get(k).orElseThrow())
.toList();
}
public RegistryDataLoader.RegistryData<T> data() {
return data;
}
public List<String> modIDs() {
return modIDs;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (RegistryInfo) obj;
return Objects.equals(this.data, that.data) &&
Objects.equals(this.modIDs, that.modIDs);
}
@Override
public int hashCode() {
return Objects.hash(data, modIDs);
}
@Override
public String toString() {
return "RegistryInfo[" +
"data=" + data + ", " +
"modIDs=" + modIDs + ']';
}
}
protected final List<RegistryInfo<?>> registries;
protected final PackOutput output;
protected final Logger LOGGER;
protected final CompletableFuture<HolderLookup.Provider> registriesFuture;
private @Nullable List<String> defaultModIDs;
protected RegistriesDataProvider(
Logger logger,
@Nullable List<String> defaultModIDs,
FabricDataOutput generator,
CompletableFuture<HolderLookup.Provider> registriesFuture
) {
this.defaultModIDs = defaultModIDs;
this.LOGGER = logger;
this.output = generator;
this.registriesFuture = registriesFuture;
this.registries = initializeRegistryList(defaultModIDs);
}
protected abstract List<RegistryInfo<?>> initializeRegistryList(@Nullable List<String> modIDs);
@Override
public CompletableFuture<?> run(CachedOutput cachedOutput) {
LOGGER.info("Serialize Registries " + defaultModIDs);
return registriesFuture.thenCompose(registriesProvider -> CompletableFuture
.supplyAsync(() -> registries)
.thenCompose(entries -> {
final List<CompletableFuture<?>> futures = new ArrayList<>();
final RegistryOps<JsonElement> dynamicOps = RegistryOps.create(
JsonOps.INSTANCE,
registriesProvider
);
futures.add(CompletableFuture.runAsync(() -> {
for (RegistryInfo<?> registryData : entries) {
// futures.add(CompletableFuture.runAsync(() ->
serializeRegistry(
cachedOutput, registriesProvider, dynamicOps, registryData
);
// ));
}
}));
return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
}));
}
private <T> void serializeRegistry(
CachedOutput cachedOutput,
HolderLookup.Provider registryAccess,
DynamicOps<JsonElement> dynamicOps,
RegistryInfo<T> registryData
) {
final List<Holder<T>> elements = registryData.allElements(registryAccess);
if (!elements.isEmpty()) {
PackOutput.PathProvider pathProvider = this.output.createPathProvider(
PackOutput.Target.DATA_PACK,
registryData.key().location().getPath()
);
elements.forEach(entry ->
serializeElements(
pathProvider.json(entry.unwrapKey().orElseThrow().location()),
cachedOutput,
dynamicOps,
registryData.elementCodec(),
entry.value()
)
);
}
}
private <E> void serializeElements(
Path path,
CachedOutput cachedOutput,
DynamicOps<JsonElement> dynamicOps,
Encoder<E> encoder,
E object
) {
Optional<JsonElement> optional = encoder.encodeStart(dynamicOps, object)
.resultOrPartial(string -> this.LOGGER.error(
"Couldn't serialize element {}: {}",
path,
string
));
if (optional.isPresent()) {
DataProvider.saveStable(cachedOutput, optional.get(), path);
}
}
@Override
public String getName() {
return "Registries";
}
}

View file

@ -6,7 +6,6 @@ import org.betterx.datagen.bclib.tests.*;
import org.betterx.datagen.bclib.worldgen.BCLibRegistriesDataProvider;
import org.betterx.datagen.bclib.worldgen.NoiseTypesDataProvider;
import org.betterx.datagen.bclib.worldgen.VanillaBCLBiomesDataProvider;
import org.betterx.datagen.bclib.worldgen.WorldgenRegistriesDataProvider;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.core.registries.Registries;
@ -29,7 +28,6 @@ public class BCLibDatagen implements DataGeneratorEntrypoint {
pack.addProvider(TestBiomes::new);
}
pack.addProvider(WorldgenRegistriesDataProvider::new);
pack.addProvider(WorldPresetDataProvider::new);
pack.addProvider(BCLibRegistriesDataProvider::new);
}
@ -48,6 +46,5 @@ public class BCLibDatagen implements DataGeneratorEntrypoint {
registryBuilder.add(Registries.BIOME, TestBiomes::bootstrap);
registryBuilder.add(Registries.NOISE_SETTINGS, NoiseTypesDataProvider::bootstrap);
registryBuilder.add(Registries.WORLD_PRESET, WorldPresetDataProvider::bootstrap);
}
}

View file

@ -121,9 +121,11 @@ public class TestBiomes extends FabricTagProvider<Biome> {
protected void addTags(HolderLookup.Provider arg) {
TagManager.BIOMES.forEachTag((tag, locs, tags) -> {
final FabricTagProvider<Biome>.FabricTagBuilder builder = getOrCreateTagBuilder(tag);
locs.forEach(builder::add);
tags.forEach(builder::addTag);
boolean modTag = tag.location().getNamespace().equals(BCLib.MOD_ID);
locs.stream().filter(l -> modTag || l.getNamespace().equals(BCLib.MOD_ID)).forEach(builder::add);
tags.stream()
.filter(t -> modTag || t.location().getNamespace().equals(BCLib.MOD_ID))
.forEach(builder::addTag);
});
}
}

View file

@ -1,136 +1,57 @@
package org.betterx.datagen.bclib.worldgen;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeData;
import org.betterx.bclib.api.v3.datagen.RegistriesDataProvider;
import org.betterx.datagen.bclib.BCLibDatagen;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.surfaceRules.AssignedSurfaceRule;
import org.betterx.worlds.together.surfaceRules.SurfaceRuleRegistry;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Encoder;
import com.mojang.serialization.JsonOps;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.data.registries.VanillaRegistries;
import net.minecraft.resources.RegistryDataLoader;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.minecraft.world.level.levelgen.presets.WorldPreset;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import com.google.gson.JsonElement;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import org.jetbrains.annotations.Nullable;
public class BCLibRegistriesDataProvider implements DataProvider {
public static final List<RegistryDataLoader.RegistryData<?>> REGISTRIES = List.of(
new RegistryDataLoader.RegistryData<>(BCLBiomeRegistry.BCL_BIOMES_REGISTRY, BiomeData.CODEC),
new RegistryDataLoader.RegistryData<>(
SurfaceRuleRegistry.SURFACE_RULES_REGISTRY,
AssignedSurfaceRule.CODEC
),
new RegistryDataLoader.RegistryData<>(Registries.STRUCTURE, Structure.DIRECT_CODEC)
//new RegistryDataLoader.RegistryData<>(Registries.WORLD_PRESET, WorldPreset.DIRECT_CODEC)
// new RegistryDataLoader.RegistryData<>(Registries.BIOME, Biome.DIRECT_CODEC),
// new RegistryDataLoader.RegistryData<>(Registries.CONFIGURED_FEATURE, ConfiguredFeature.DIRECT_CODEC),
// new RegistryDataLoader.RegistryData<>(Registries.PLACED_FEATURE, PlacedFeature.DIRECT_CODEC),
// new RegistryDataLoader.RegistryData<>(Registries.STRUCTURE, Structure.DIRECT_CODEC)
);
private final PackOutput output;
public BCLibRegistriesDataProvider(FabricDataOutput generator) {
this.output = generator;
public class BCLibRegistriesDataProvider extends RegistriesDataProvider {
public BCLibRegistriesDataProvider(
FabricDataOutput generator,
CompletableFuture<HolderLookup.Provider> registriesFuture
) {
super(BCLib.LOGGER, List.of(BCLib.MOD_ID, WorldsTogether.MOD_ID), generator, registriesFuture);
}
@Override
public CompletableFuture<?> run(CachedOutput cachedOutput) {
HolderLookup.Provider registryAccess = VanillaRegistries.createLookup();
RegistryOps<JsonElement> dynamicOps = RegistryOps.create(JsonOps.INSTANCE, registryAccess);
final List<CompletableFuture<?>> futures = new ArrayList<>();
protected List<RegistryInfo<?>> initializeRegistryList(@Nullable List<String> modIDs) {
InfoList registries = new InfoList();
for (RegistryDataLoader.RegistryData<?> registryData : REGISTRIES) {
futures.add(this.dumpRegistryCapFuture(
cachedOutput,
registryAccess,
dynamicOps,
(RegistryDataLoader.RegistryData) registryData
));
}
return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
}
registries.addUnfiltered(BCLBiomeRegistry.BCL_BIOMES_REGISTRY, BiomeData.CODEC);
registries.addUnfiltered(SurfaceRuleRegistry.SURFACE_RULES_REGISTRY, AssignedSurfaceRule.CODEC);
private <T> CompletableFuture dumpRegistryCapFuture(
CachedOutput cachedOutput,
HolderLookup.Provider registryAccess,
DynamicOps<JsonElement> dynamicOps,
RegistryDataLoader.RegistryData<T> registryData
) {
return CompletableFuture.runAsync(() -> dumpRegistryCap(
cachedOutput,
registryAccess,
dynamicOps,
registryData
));
}
private <T> void dumpRegistryCap(
CachedOutput cachedOutput,
HolderLookup.Provider registryAccess,
DynamicOps<JsonElement> dynamicOps,
RegistryDataLoader.RegistryData<T> registryData
) {
ResourceKey<? extends Registry<T>> resourceKey = registryData.key();
HolderLookup.RegistryLookup<T> registry = registryAccess.lookupOrThrow(resourceKey);
PackOutput.PathProvider pathProvider = this.output.createPathProvider(
PackOutput.Target.DATA_PACK,
resourceKey.location().getPath()
);
registry.listElementIds().forEach(entry ->
dumpValue(
pathProvider.json(entry.location()),
cachedOutput,
dynamicOps,
registryData.elementCodec(),
registry.get(entry).orElseThrow().value()
)
);
}
private static <E> void dumpValue(
Path path,
CachedOutput cachedOutput,
DynamicOps<JsonElement> dynamicOps,
Encoder<E> encoder,
E object
) {
Optional<JsonElement> optional = encoder.encodeStart(dynamicOps, object)
.resultOrPartial(string -> WorldsTogether.LOGGER.error(
"Couldn't serialize element {}: {}",
path,
string
));
if (optional.isPresent()) {
DataProvider.saveStable(cachedOutput, optional.get(), path);
if (BCLibDatagen.ADD_TESTS) {
registries.add(Registries.STRUCTURE, Structure.DIRECT_CODEC);
registries.add(Registries.STRUCTURE_SET, StructureSet.DIRECT_CODEC);
registries.add(Registries.CONFIGURED_FEATURE, ConfiguredFeature.DIRECT_CODEC);
registries.add(Registries.PLACED_FEATURE, PlacedFeature.DIRECT_CODEC);
registries.add(Registries.BIOME, Biome.DIRECT_CODEC);
}
}
registries.add(Registries.NOISE_SETTINGS, NoiseGeneratorSettings.DIRECT_CODEC);
registries.add(Registries.WORLD_PRESET, WorldPreset.DIRECT_CODEC);
@Override
public String getName() {
return "BCL Registries";
return registries;
}
}

View file

@ -1,36 +0,0 @@
package org.betterx.datagen.bclib.worldgen;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import org.betterx.worlds.together.surfaceRules.SurfaceRuleRegistry;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricDynamicRegistryProvider;
import java.util.concurrent.CompletableFuture;
public class WorldgenRegistriesDataProvider extends FabricDynamicRegistryProvider {
public WorldgenRegistriesDataProvider(
FabricDataOutput output,
CompletableFuture<HolderLookup.Provider> registriesFuture
) {
super(output, registriesFuture);
}
@Override
protected void configure(HolderLookup.Provider registries, Entries entries) {
entries.addAll(registries.lookupOrThrow(Registries.NOISE_SETTINGS));
entries.addAll(registries.lookupOrThrow(Registries.WORLD_PRESET));
entries.addAll(registries.lookupOrThrow(BCLBiomeRegistry.BCL_BIOMES_REGISTRY));
entries.addAll(registries.lookupOrThrow(SurfaceRuleRegistry.SURFACE_RULES_REGISTRY));
entries.addAll(registries.lookupOrThrow(Registries.STRUCTURE));
entries.addAll(registries.lookupOrThrow(Registries.STRUCTURE_SET));
}
@Override
public String getName() {
return "WorldGen Provider";
}
}