Line 11:
Line 11:
#* The operational code that makes your modifier work and associated serializer.
#* The operational code that makes your modifier work and associated serializer.
−
Finally, the serializer for your operational class is [[Registration|registered]] as any other <code>ForgeRegistryEntry</code>.
+
Finally, the serializer for your operational class is [[Registration|registered]] as any other registry object.
==The global_loot_modifiers.json==
==The global_loot_modifiers.json==
Line 69:
Line 69:
<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;
+
private static class WheatSeedsConverterModifier extends LootModifier
−
for(ItemStack stack : generatedLoot) {
+
{
−
if(stack.getItem() == itemToCheck)
+
public static final Supplier<Codec<WheatSeedsConverterModifier>> CODEC = Suppliers.memoize(() ->
−
numSeeds += stack.getCount();
+
RecordCodecBuilder.create(inst -> codecStart(inst).and(
−
}
+
inst.group(
−
if(numSeeds >= numSeedsToConvert) {
+
Codec.INT.fieldOf("numSeeds").forGetter(m -> m.numSeedsToConvert),
−
generatedLoot.removeIf(x -> x.getItem() == itemToCheck);
+
ForgeRegistries.ITEMS.getCodec().fieldOf("seedItem").forGetter(m -> m.itemToCheck),
−
generatedLoot.add(new ItemStack(itemReward, (numSeeds/numSeedsToConvert)));
+
ForgeRegistries.ITEMS.getCodec().fieldOf("replacement").forGetter(m -> m.itemReward)
−
numSeeds = numSeeds % numSeedsToConvert;
+
)).apply(inst, WheatSeedsConverterModifier::new)
−
if(numSeeds > 0)
+
));
−
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 128:
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]].
+
Utilize <code>GlobalLootModifierProvider</code> for [[datageneration|data generation]].
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.