Changes

Fix the explanation
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 58: Line 58:       −
{{Tip|<code>conditions</code> is the only object needed by the system specification, everything else is the mod maker's data.   
+
{{Tip|<code>conditions</code> is the only object needed by the system specification, everything else is the mod maker's data.  
 +
   
 
<code>seedItem</code>, <code>numSeeds</code> and <code>replacement</code> are NOT standard elements of Global Loot Modifiers.   
 
<code>seedItem</code>, <code>numSeeds</code> and <code>replacement</code> are NOT standard elements of Global Loot Modifiers.   
 +
 
They are deserialized manually in the next section.}}
 
They are deserialized manually in the next section.}}
    
== 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.