Line 9: |
Line 9: |
| #* This will contain all of the data about your modification and allows data packs to tweak your effect. | | #* This will contain all of the data about your modification and allows data packs to tweak your effect. |
| # A class that extends <code>LootModifier</code> | | # A class that extends <code>LootModifier</code> |
− | #* The operational code that makes your modifier work and associated serializer. | + | #* The operational code that makes your modifier work and associated codec. |
| | | |
− | Finally, the serializer for your operational class is [[Registration|registered]] as any other <code>ForgeRegistryEntry</code>. | + | Finally, the codec for your operational class is [[Registration|registered]] as any other registry object. |
| | | |
| ==The global_loot_modifiers.json== | | ==The global_loot_modifiers.json== |
Line 45: |
Line 45: |
| }, | | }, |
| { | | { |
− | "condition": "block_state_property", | + | "condition": "minecraft:block_state_property", |
− | "block":"minecraft:wheat" | + | "block": "minecraft:wheat" |
| } | | } |
| ], | | ], |
Line 66: |
Line 66: |
| == The LootModifier Subclass == | | == The LootModifier Subclass == |
| | | |
− | You will also need a static child class that extends <code>GlobalLootModifierSerializer<T></code> where <code>T</code> is your LootModifier subclass in order to deserialize your json data file into operational code. | + | You will also need a <code>Codec<T></code> where <code>T</code> is your LootModifier subclass in order to deserialize your json data file into operational code. The codec must be [[Registration|registered]]. |
| | | |
| <syntaxhighlight lang="java"> | | <syntaxhighlight lang="java"> |
− | private static class WheatSeedsConverterModifier extends LootModifier { | + | /** |
− | private final int numSeedsToConvert;
| + | * When harvesting wheat with shears, this modifier is invoked via the wheat_harvest loot_modifier json<br/> |
− | private final Item itemToCheck;
| + | * This modifier checks how many seeds were harvested and turns X seeds into Y wheat (3:1) |
− | private final Item itemReward;
| + | * |
− | public WheatSeedsConverterModifier(ILootCondition[] conditionsIn, int numSeeds, Item itemCheck, Item reward) {
| + | */ |
− | super(conditionsIn);
| + | // Assume there exists a <code>IForgeRegistry<Codec<T extends LootModifier>></code> LOOT_MODIFIER_REGISTRAR added by a mod |
− | numSeedsToConvert = numSeeds;
| + | private static class WheatSeedsConverterModifier extends LootModifier |
− | itemToCheck = itemCheck;
| + | { |
− | itemReward = reward;
| + | public static final RegistryObject<Codec<WheatSeedsConverterModifier>> CODEC = LOOT_MODIFIER_REGISTRAR.register("wheat_seeds_converter", () -> |
− | }
| + | RecordCodecBuilder.create(inst -> codecStart(inst).and( |
| + | inst.group( |
| + | Codec.INT.fieldOf("numSeeds").forGetter(m -> m.numSeedsToConvert), |
| + | ForgeRegistries.ITEMS.getCodec().fieldOf("seedItem").forGetter(m -> m.itemToCheck), |
| + | ForgeRegistries.ITEMS.getCodec().fieldOf("replacement").forGetter(m -> m.itemReward) |
| + | )).apply(inst, WheatSeedsConverterModifier::new) |
| + | )); |
| | | |
− | @Nonnull
| + | private final int numSeedsToConvert; |
− | @Override
| + | private final Item itemToCheck; |
− | public List<ItemStack> doApply(List<ItemStack> generatedLoot, LootContext context) {
| + | private final Item itemReward; |
− | /*
| + | public WheatSeedsConverterModifier(LootItemCondition[] conditionsIn, int numSeeds, Item itemCheck, |
− | * Additional conditions can be checked, though as much as possible should be parameterized via JSON data.
| + | Item reward) |
− | * It is better to write a new ILootCondition implementation than to do things here.
| + | { |
− | */
| + | super(conditionsIn); |
− | int numSeeds = 0;
| + | numSeedsToConvert = numSeeds; |
− | for(ItemStack stack : generatedLoot) {
| + | itemToCheck = itemCheck; |
− | if(stack.getItem() == itemToCheck)
| + | itemReward = reward; |
− | numSeeds+=stack.getCount();
| + | } |
− | }
| |
− | if(numSeeds >= numSeedsToConvert) {
| |
− | generatedLoot.removeIf(x -> x.getItem() == itemToCheck);
| |
− | generatedLoot.add(new ItemStack(itemReward, (numSeeds/numSeedsToConvert)));
| |
− | numSeeds = numSeeds%numSeedsToConvert;
| |
− | if(numSeeds > 0)
| |
− | generatedLoot.add(new ItemStack(itemToCheck, numSeeds));
| |
− | }
| |
− | return generatedLoot;
| |
− | }
| |
| | | |
− | private static class Serializer extends GlobalLootModifierSerializer<WheatSeedsConverterModifier> {
| + | @NotNull |
| + | @Override |
| + | public ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) { |
| + | // |
| + | // Additional conditions can be checked, though as much as possible should be parameterized via JSON data. |
| + | // It is better to write a new ILootCondition implementation than to do things here. |
| + | // |
| + | int numSeeds = 0; |
| + | generatedLoot.stream().filter(stack -> stack.getItem() == itemToCheck) |
| + | .forEach(stack -> numSeeds+=stack.getCount()) |
| + | if(numSeeds >= numSeedsToConvert) { |
| + | generatedLoot.removeIf(x -> x.getItem() == itemToCheck); |
| + | generatedLoot.add(new ItemStack(itemReward, (numSeeds/numSeedsToConvert))); |
| + | numSeeds = numSeeds%numSeedsToConvert; |
| + | if(numSeeds > 0) |
| + | generatedLoot.add(new ItemStack(itemToCheck, numSeeds)); |
| + | } |
| + | return generatedLoot; |
| + | } |
| | | |
− | @Override
| + | @Override |
− | public WheatSeedsConverterModifier read(ResourceLocation name, JsonObject object, ILootCondition[] conditionsIn) {
| + | public Codec<? extends IGlobalLootModifier> codec() { |
− | int numSeeds = JSONUtils.getInt(object, "numSeeds");
| + | return CODEC.get(); |
− | Item seed = ForgeRegistries.ITEMS.getValue(new ResourceLocation((JSONUtils.getString(object, "seedItem"))));
| + | } |
− | Item wheat = ForgeRegistries.ITEMS.getValue(new ResourceLocation(JSONUtils.getString(object, "replacement")));
| + | } |
− | return new WheatSeedsConverterModifier(conditionsIn, numSeeds, seed, wheat);
| |
− | }
| |
− | }
| |
− | } | |
| </syntaxhighlight> | | </syntaxhighlight> |
| | | |
| The critical portion is the <code>doApply</code> method. | | The critical portion is the <code>doApply</code> method. |
| | | |
− | This method is only called if the <code>conditions</code> specified return <code>true</code> and the modder is now able to make the modifications they desire. In this case we can see that the number of <code>itemToCheck</code> meets or exceeds the <code>numSeedsToConvert</code> before modifying the list by adding an <code>itemReward</code> and removing any excess <code>itemToCheck</code> stacks, matching the previously mentioned effects: When a wheat block is harvested with shears, if enough seeds are generated as loot, they are converted to additional wheat instead. | + | This method is only called if the <code>conditions</code> specified return <code>true</code> and the modder is now able to make the modifications they desire. In this case we can see that the number of <code>itemToCheck</code> meets or exceeds the <code>numSeedsToConvert</code> before modifying the list by adding an <code>itemReward</code> and removing any excess <code>itemToCheck</code> stacks, matching the previously mentioned effects: ''When a wheat block is harvested with shears, if enough seeds are generated as loot, they are converted to additional wheat instead''. |
| | | |
− | Also take note of the <code>read</code> method in the serializer. The conditions are already deserialized for you and if you have no other data, simply <code>return new MyModifier(conditionsIn)</code>. However, the full <code>JsonObject</code> is available if needed.
| + | The codec can also be used for [[datageneration|data generation]] with a <code>GlobalLootModifierProvider</code>. |
| | | |
− | Additional [https://github.com/MinecraftForge/MinecraftForge/blob/1.15.x/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java examples] can be found on the Forge Git repository, including silk touch and smelting effects. | + | Additional [https://github.com/MinecraftForge/MinecraftForge/blob/1.19.x/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java examples] can be found on the Forge Git repository, including silk touch and smelting effects. |