Hi, I'm trying to register a new LootFunction to use in my loot table data generator. I was loosely basing it off of Astral Sorcery's loot table data generators, since I'm trying to achieve a similar effect.
Here's my loot table provider:
package org.tutmods.shungite.data;
import com.google.common.collect.ImmutableList;
import com.mojang.datafixers.util.Pair;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.LootTableProvider;
import net.minecraft.data.loot.BlockLootTables;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.loot.ItemLootEntry;
import net.minecraft.loot.LootParameterSet;
import net.minecraft.loot.LootParameterSets;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.LootTableManager;
import net.minecraft.loot.RandomValueRange;
import net.minecraft.loot.ValidationTracker;
import net.minecraft.loot.functions.ApplyBonus;
import net.minecraft.loot.functions.ExplosionDecay;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.RegistryObject;
import org.tutmods.shungite.loot.ShungiteCrystalPropertiesLoot;
import org.tutmods.shungite.setup.ModBlocks;
import org.tutmods.shungite.setup.ModItems;
import org.tutmods.shungite.setup.Registration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class ModLootTableProvider extends LootTableProvider {
public ModLootTableProvider(DataGenerator generator) {
super(generator);
}
@Override
protected List<Pair<Supplier<Consumer<BiConsumer<ResourceLocation, LootTable.Builder>>>, LootParameterSet>> getTables() {
return ImmutableList.of(Pair.of(ModBlockLootTables::new, LootParameterSets.BLOCK));
}
@Override
protected void validate(Map<ResourceLocation, LootTable> map, ValidationTracker validationtracker) {
map.forEach( (one, two) -> LootTableManager.validate(validationtracker, one, two));
}
public static class ModBlockLootTables extends BlockLootTables {
@Override
protected void addTables() {
this.add(ModBlocks.SHUNGITE_CRYSTAL_ORE.get(), (block) ->
LootTable.lootTable()
.withPool(LootPool.lootPool()
.setRolls(RandomValueRange.between(2F, 5F))
.add(ItemLootEntry.lootTableItem(ModItems.SHUNGITE.get())
.apply(ExplosionDecay.explosionDecay())
.apply(ShungiteCrystalPropertiesLoot.builder()))
));
}
@Override
protected Iterable<Block> getKnownBlocks() {
return Registration.BLOCK_DEFERRED_REGISTER.getEntries()
.stream().map(RegistryObject::get).collect(Collectors.toList());
}
}
}
And the loot function I want to add:
package org.tutmods.shungite.loot;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import net.minecraft.item.ItemStack;
import net.minecraft.loot.LootContext;
import net.minecraft.loot.LootFunction;
import net.minecraft.loot.LootFunctionType;
import net.minecraft.loot.conditions.ILootCondition;
import org.tutmods.shungite.items.crystal.ShungiteCrystal;
import org.tutmods.shungite.items.crystal.properties.ShungiteCrystalProperties;
import org.tutmods.shungite.util.crystal.CrystalUtils;
public class ShungiteCrystalPropertiesLoot extends LootFunction {
protected ShungiteCrystalPropertiesLoot(ILootCondition[] conditions) {
super(conditions);
}
@Override
protected ItemStack run(ItemStack stack, LootContext lootContext) {
if (stack.getItem() instanceof ShungiteCrystal) {
final ShungiteCrystalProperties properties = CrystalPropertyGenerator.getRandomNewCrystalProperties();
CrystalUtils.putProperties(stack, properties);
}
return stack;
}
public static LootFunction.Builder<?> builder() {
return simpleBuilder(ShungiteCrystalPropertiesLoot::new);
}
@Override
public LootFunctionType getType() {
return Functions.ShungiteCrystalsLoot;
}
public static class Functions {
public static LootFunctionType ShungiteCrystalsLoot;
}
public static class Serializer extends LootFunction.Serializer<ShungiteCrystalPropertiesLoot> {
@Override
public ShungiteCrystalPropertiesLoot deserialize(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext, ILootCondition[] iLootConditions) {
return new ShungiteCrystalPropertiesLoot(iLootConditions);
}
}
}
I see Astral doing similar things here:
https://github.com/HellFirePvP/AstralSorcery/blob/1.16-indev/src/main/java/hellfirepvp/astralsorcery/common/loot/RandomCrystalProperty.java
https://github.com/HellFirePvP/AstralSorcery/blob/e8434f1a09356632babefee1925626dc3deefb2a/src/main/java/hellfirepvp/astralsorcery/datagen/data/loot/BlockLootTableProvider.java#L77
However, my trouble comes when running the data generator. I can't register the serializer as Astral does here https://github.com/HellFirePvP/AstralSorcery/blob/e8434f1a09356632babefee1925626dc3deefb2a/src/main/java/hellfirepvp/astralsorcery/common/registry/RegistryLoot.java#L49, since LootFunctionManager.register is private. Is there a new way of doing this?
I tried just calling Registry.register as LootFunctionManager.register does itself, and I was able to generate JSON with that, however my game hung as soon as I broke the block; so I assume I'm doing something wrong. I saw there's a new DeferredRegister for LootModifiers, but I'm not sure if that fulfills the same role as a LootFunction?
So I guess I have two questions:
How do I register my serializer for my LootFunction correctly?
What's the difference between a LootFunction and a LootModifier?