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 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(LootItemCondition[] conditions, int numSeeds, Item itemCheck, Item reward) {
  −
    super(conditions);
  −
    numSeedsToConvert = numSeeds;
  −
    itemToCheck = itemCheck;
  −
    itemReward = reward;
  −
  }
  −
 
  −
  @Nonnull
  −
  @Override
  −
  public List<ItemStack> doApply(List<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 LootItemCondition implementation than to do things here.
   
     */
 
     */
    int numSeeds = 0;
+
// Assume there exists a <code>IForgeRegistry<Codec<T extends LootModifier>></code> LOOT_MODIFIER_REGISTRAR added by a mod
    for(ItemStack stack : generatedLoot) {
+
private static class WheatSeedsConverterModifier extends LootModifier
      if(stack.getItem() == itemToCheck)
+
{
         numSeeds += stack.getCount();
+
        public static final RegistryObject<Codec<WheatSeedsConverterModifier>> CODEC = LOOT_MODIFIER_REGISTRAR.register("wheat_seeds_converter", () ->
    }
+
         RecordCodecBuilder.create(inst -> codecStart(inst).and(
    if(numSeeds >= numSeedsToConvert) {
+
                inst.group(
      generatedLoot.removeIf(x -> x.getItem() == itemToCheck);
+
                        Codec.INT.fieldOf("numSeeds").forGetter(m -> m.numSeedsToConvert),
      generatedLoot.add(new ItemStack(itemReward, (numSeeds/numSeedsToConvert)));
+
                        ForgeRegistries.ITEMS.getCodec().fieldOf("seedItem").forGetter(m -> m.itemToCheck),
      numSeeds = numSeeds % numSeedsToConvert;
+
                        ForgeRegistries.ITEMS.getCodec().fieldOf("replacement").forGetter(m -> m.itemReward)
      if(numSeeds > 0)
+
                )).apply(inst, WheatSeedsConverterModifier::new)
         generatedLoot.add(new ItemStack(itemToCheck, numSeeds));
+
         ));
    }
  −
    return generatedLoot;
  −
  }
     −
  private static class Serializer extends GlobalLootModifierSerializer<WheatSeedsConverterModifier> {
+
        private final int numSeedsToConvert;
 +
        private final Item itemToCheck;
 +
        private final Item itemReward;
 +
        public WheatSeedsConverterModifier(LootItemCondition[] conditionsIn, int numSeeds, Item itemCheck,
 +
            Item reward)
 +
        {
 +
            super(conditionsIn);
 +
            numSeedsToConvert = numSeeds;
 +
            itemToCheck = itemCheck;
 +
            itemReward = reward;
 +
        }
   −
    @Override
+
        @NotNull
    public WheatSeedsConverterModifier read(ResourceLocation name, JsonObject object, LootItemCondition[] conditions) {
+
        @Override
      int numSeeds = GsonHelper.getAsInt(object, "numSeeds");
+
        public ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
      Item seed = ForgeRegistries.ITEMS.getValue(new ResourceLocation((GsonHelper.getAsString(object, "seedItem"))));
+
            //
      Item wheat = ForgeRegistries.ITEMS.getValue(new ResourceLocation(GsonHelper.getAsString(object, "replacement")));
+
            // Additional conditions can be checked, though as much as possible should be parameterized via JSON data.
      return new WheatSeedsConverterModifier(conditions, numSeeds, seed, wheat);
+
            // 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 JsonObject write(WheatSeedsConverterModifier instance) {
+
        public Codec<? extends IGlobalLootModifier> codec() {
      JsonObject json = makeConditions(instance.conditions);
+
            return CODEC.get();
      json.addProperty("numSeeds", instance.numSeedsToConvert);
+
        }
      json.addProperty("seedItem", ForgeRegistries.ITEMS.getKey(instance.itemToCheck).toString());
  −
      json.addProperty("replacement", ForgeRegistries.ITEMS.getKey(instance.itemReward).toString());
  −
      return json;
   
     }
 
     }
  }
  −
}
   
</syntaxhighlight>
 
</syntaxhighlight>
   Line 128: Line 129:  
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(conditions)</code>. However, the full <code>JsonObject</code> is available if needed. The <code>write</code> method, on the other hand, is used for if you want to utilize <code>GlobalLootModifierProvider</code> for [[datageneration|data generation]].
+
The codec can also be used for [[datageneration|data generation]] with a <code>GlobalLootModifierProvider</code>.
    
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.
 
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.