| 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 56: |
Line 56: |
| | | | |
| | In the above example, the modification only happens if the player harvests wheat when using shears (specified by the two <code>conditions</code> which are automatically <code>AND</code>ed together). The <code>seedsItem</code> and <code>numSeeds</code> values are then used to count how many seeds were generated by the vanilla loot table, and if matched, are substituted for an additional <code>replacement</code> item instead. The operation code will be shown below. | | In the above example, the modification only happens if the player harvests wheat when using shears (specified by the two <code>conditions</code> which are automatically <code>AND</code>ed together). The <code>seedsItem</code> and <code>numSeeds</code> values are then used to count how many seeds were generated by the vanilla loot table, and if matched, are substituted for an additional <code>replacement</code> item instead. The operation code will be shown below. |
| − | <code>conditions</code> is the only object needed by the system specification, everything else is the mod maker's data.
| |
| | | | |
| − | Note that seedItem, numSeeds and replacement are NOT standard elements of Global Loot Modifiers. They are added by the creator of this json, and are parsed manually using the Serializer of the next section:
| + | |
| | + | {{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. |
| | + | |
| | + | 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. |