minecraft-src/net/minecraft/data/loot/LootTableProvider.java
2025-07-04 03:15:13 +03:00

111 lines
5 KiB
Java

package net.minecraft.data.loot;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Lifecycle;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import net.minecraft.Util;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.RegistrationInfo;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.HolderLookup.Provider;
import net.minecraft.core.RegistryAccess.ImmutableRegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ProblemReporter.Collector;
import net.minecraft.util.context.ContextKeySet;
import net.minecraft.world.RandomSequence;
import net.minecraft.world.level.levelgen.RandomSupport.Seed128bit;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.ValidationContext;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import org.slf4j.Logger;
public class LootTableProvider implements DataProvider {
private static final Logger LOGGER = LogUtils.getLogger();
private final PackOutput.PathProvider pathProvider;
private final Set<ResourceKey<LootTable>> requiredTables;
private final List<LootTableProvider.SubProviderEntry> subProviders;
private final CompletableFuture<Provider> registries;
public LootTableProvider(
PackOutput output, Set<ResourceKey<LootTable>> requiredTables, List<LootTableProvider.SubProviderEntry> subProviders, CompletableFuture<Provider> registries
) {
this.pathProvider = output.createRegistryElementsPathProvider(Registries.LOOT_TABLE);
this.subProviders = subProviders;
this.requiredTables = requiredTables;
this.registries = registries;
}
@Override
public CompletableFuture<?> run(CachedOutput output) {
return this.registries.thenCompose(provider -> this.run(output, provider));
}
private CompletableFuture<?> run(CachedOutput output, Provider provider) {
WritableRegistry<LootTable> writableRegistry = new MappedRegistry<>(Registries.LOOT_TABLE, Lifecycle.experimental());
Map<Seed128bit, ResourceLocation> map = new Object2ObjectOpenHashMap<>();
this.subProviders.forEach(subProviderEntry -> ((LootTableSubProvider)subProviderEntry.provider().apply(provider)).generate((resourceKeyx, builder) -> {
ResourceLocation resourceLocation = sequenceIdForLootTable(resourceKeyx);
ResourceLocation resourceLocation2 = (ResourceLocation)map.put(RandomSequence.seedForKey(resourceLocation), resourceLocation);
if (resourceLocation2 != null) {
Util.logAndPauseIfInIde("Loot table random sequence seed collision on " + resourceLocation2 + " and " + resourceKeyx.location());
}
builder.setRandomSequence(resourceLocation);
LootTable lootTable = builder.setParamSet(subProviderEntry.paramSet).build();
writableRegistry.register(resourceKeyx, lootTable, RegistrationInfo.BUILT_IN);
}));
writableRegistry.freeze();
Collector collector = new Collector();
net.minecraft.core.HolderGetter.Provider provider2 = new ImmutableRegistryAccess(List.of(writableRegistry)).freeze();
ValidationContext validationContext = new ValidationContext(collector, LootContextParamSets.ALL_PARAMS, provider2);
for (ResourceKey<LootTable> resourceKey : Sets.difference(this.requiredTables, writableRegistry.registryKeySet())) {
collector.report("Missing built-in table: " + resourceKey.location());
}
writableRegistry.listElements()
.forEach(
reference -> ((LootTable)reference.value())
.validate(
validationContext.setContextKeySet(((LootTable)reference.value()).getParamSet()).enterElement("{" + reference.key().location() + "}", reference.key())
)
);
Multimap<String, String> multimap = collector.get();
if (!multimap.isEmpty()) {
multimap.forEach((string, string2) -> LOGGER.warn("Found validation problem in {}: {}", string, string2));
throw new IllegalStateException("Failed to validate loot tables, see logs");
} else {
return CompletableFuture.allOf((CompletableFuture[])writableRegistry.entrySet().stream().map(entry -> {
ResourceKey<LootTable> resourceKeyx = (ResourceKey<LootTable>)entry.getKey();
LootTable lootTable = (LootTable)entry.getValue();
Path path = this.pathProvider.json(resourceKeyx.location());
return DataProvider.saveStable(output, provider, LootTable.DIRECT_CODEC, lootTable, path);
}).toArray(CompletableFuture[]::new));
}
}
private static ResourceLocation sequenceIdForLootTable(ResourceKey<LootTable> lootTable) {
return lootTable.location();
}
@Override
public final String getName() {
return "Loot Tables";
}
public record SubProviderEntry(Function<Provider, LootTableSubProvider> provider, ContextKeySet paramSet) {
}
}