From 0c030ee5e10920a3f417a1538056020016bd0724 Mon Sep 17 00:00:00 2001 From: Cyborgmas Date: Sat, 9 Jul 2022 11:51:41 -0400 Subject: [PATCH] 1.19 - Remove GlobalLootModifierSerializer and move to Codecs (#8721) * convert GLM serializer class to codec * cleanup * GLM list needs to be sorted * datagen * simplify serialization * fix test mods (oops) * properly use suppliers for codec as they are registry obj --- .../loot_modifiers/dungeon_loot.json | 3 +- .../data/GlobalLootModifierProvider.java | 23 ++-- .../loot/GlobalLootModifierSerializer.java | 48 -------- .../common/loot/IGlobalLootModifier.java | 59 ++++++++- .../common/loot/LootModifier.java | 30 ++++- .../common/loot/LootModifierManager.java | 81 +++++------- .../registries/ForgeRegistries.java | 8 +- .../minecraftforge/registries/GameData.java | 5 +- .../loot/GlobalLootModifiersTest.java | 116 +++++++----------- 9 files changed, 174 insertions(+), 199 deletions(-) delete mode 100644 src/main/java/net/minecraftforge/common/loot/GlobalLootModifierSerializer.java diff --git a/src/generated_test/resources/data/global_loot_test/loot_modifiers/dungeon_loot.json b/src/generated_test/resources/data/global_loot_test/loot_modifiers/dungeon_loot.json index 12af05c13f..5dba5b78d3 100644 --- a/src/generated_test/resources/data/global_loot_test/loot_modifiers/dungeon_loot.json +++ b/src/generated_test/resources/data/global_loot_test/loot_modifiers/dungeon_loot.json @@ -5,6 +5,5 @@ "condition": "forge:loot_table_id", "loot_table_id": "minecraft:chests/simple_dungeon" } - ], - "multiplication_factor": 2 + ] } \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/common/data/GlobalLootModifierProvider.java b/src/main/java/net/minecraftforge/common/data/GlobalLootModifierProvider.java index 4c4fd9befc..9cf4bdbd06 100644 --- a/src/main/java/net/minecraftforge/common/data/GlobalLootModifierProvider.java +++ b/src/main/java/net/minecraftforge/common/data/GlobalLootModifierProvider.java @@ -7,18 +7,16 @@ package net.minecraftforge.common.data; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.mojang.serialization.JsonOps; import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataGenerator; -import net.minecraft.data.HashCache; import net.minecraft.data.DataProvider; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Tuple; -import net.minecraftforge.common.loot.GlobalLootModifierSerializer; import net.minecraftforge.common.loot.IGlobalLootModifier; import net.minecraftforge.common.loot.LootModifier; -import net.minecraftforge.registries.ForgeRegistries; import java.io.IOException; import java.nio.file.Path; @@ -29,7 +27,7 @@ import java.util.Map; import java.util.stream.Collectors; /** - * Provider for forge's GlobalLootModifier system. See {@link LootModifier} and {@link GlobalLootModifierSerializer}. + * Provider for forge's GlobalLootModifier system. See {@link LootModifier} * * This provider only requires implementing {@link #start()} and calling {@link #add} from it. */ @@ -38,7 +36,7 @@ public abstract class GlobalLootModifierProvider implements DataProvider private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private final DataGenerator gen; private final String modid; - private final Map, JsonObject>> toSerialize = new HashMap<>(); + private final Map toSerialize = new HashMap<>(); private boolean replace = false; public GlobalLootModifierProvider(DataGenerator gen, String modid) @@ -69,14 +67,10 @@ public abstract class GlobalLootModifierProvider implements DataProvider String modPath = "data/" + modid + "/loot_modifiers/"; List entries = new ArrayList<>(); - toSerialize.forEach(LamdbaExceptionUtils.rethrowBiConsumer((name, pair) -> + toSerialize.forEach(LamdbaExceptionUtils.rethrowBiConsumer((name, json) -> { entries.add(new ResourceLocation(modid, name)); Path modifierPath = gen.getOutputFolder().resolve(modPath + name + ".json"); - - JsonObject json = pair.getB(); - json.addProperty("type", ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.get().getKey(pair.getA()).toString()); - DataProvider.saveStable(cache, json, modifierPath); })); @@ -91,11 +85,12 @@ public abstract class GlobalLootModifierProvider implements DataProvider * Passes in the data needed to create the file without any extra objects. * * @param modifier The name of the modifier, which will be the file name. - * @param serializer The serializer of this modifier. + * @param instance The instance to serialize */ - public void add(String modifier, GlobalLootModifierSerializer serializer, T instance) + public void add(String modifier, T instance) { - this.toSerialize.put(modifier, new Tuple<>(serializer, serializer.write(instance))); + JsonElement json = IGlobalLootModifier.DIRECT_CODEC.encodeStart(JsonOps.INSTANCE, instance).getOrThrow(false, s -> {}); + this.toSerialize.put(modifier, json); } @Override diff --git a/src/main/java/net/minecraftforge/common/loot/GlobalLootModifierSerializer.java b/src/main/java/net/minecraftforge/common/loot/GlobalLootModifierSerializer.java deleted file mode 100644 index 8ed66e1788..0000000000 --- a/src/main/java/net/minecraftforge/common/loot/GlobalLootModifierSerializer.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.common.loot; - -import com.google.gson.JsonObject; - -import net.minecraft.advancements.critereon.SerializationContext; -import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraft.resources.ResourceLocation; - -/** - * Abstract base deserializer for LootModifiers. Takes care of Forge registry things.
- * Modders should extend this class to return their modifier and implement the abstract - * read method to deserialize from json. - * @param the Type to deserialize - */ -public abstract class GlobalLootModifierSerializer { - /** - * Most mods will likely not need more than
- * return new MyModifier(conditionsIn)
- * but any additional properties that are needed will need to be deserialized here. - * @param location The resource location (if needed) - * @param object The full json object (including ILootConditions) - * @param ailootcondition An already deserialized list of ILootConditions - */ - public abstract T read(ResourceLocation location, JsonObject object, LootItemCondition[] ailootcondition); - - /** - * Write the serializer to json. - * - * Most serializers won't have to do anything else than {@link #makeConditions} - * Which simply creates the JsonObject from an array of ILootConditions. - */ - public abstract JsonObject write(T instance); - - /** - * Helper to create the json object from the conditions. - * Add any extra properties to the returned json. - */ - public JsonObject makeConditions(LootItemCondition[] conditions) { - JsonObject json = new JsonObject(); - json.add("conditions", SerializationContext.INSTANCE.serializeConditions(conditions)); - return json; - } -} diff --git a/src/main/java/net/minecraftforge/common/loot/IGlobalLootModifier.java b/src/main/java/net/minecraftforge/common/loot/IGlobalLootModifier.java index 799b3a2256..815b7192f6 100644 --- a/src/main/java/net/minecraftforge/common/loot/IGlobalLootModifier.java +++ b/src/main/java/net/minecraftforge/common/loot/IGlobalLootModifier.java @@ -5,17 +5,69 @@ package net.minecraftforge.common.loot; +import com.google.gson.JsonElement; +import com.google.gson.JsonSyntaxException; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.JsonOps; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.util.ExtraCodecs; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraftforge.registries.ForgeRegistries; import org.jetbrains.annotations.NotNull; +import java.util.function.Function; + /** * Implementation that defines what a global loot modifier must implement in order to be functional. * {@link LootModifier} Supplies base functionality; most modders should only need to extend that.
- * Requires an {@link GlobalLootModifierSerializer} to be registered via json (see forge:loot_modifiers/global_loot_modifiers). + * Requires a {@link Codec} to be registered: {@link ForgeRegistries#LOOT_MODIFIER_SERIALIZERS}, and returned in {@link #codec()} + * Individual instances of modifiers must be registered via json, see forge:loot_modifiers/global_loot_modifiers */ public interface IGlobalLootModifier { + Codec DIRECT_CODEC = ExtraCodecs.lazyInitializedCodec(() -> ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.get().getCodec()) + .dispatch(IGlobalLootModifier::codec, Function.identity()); + + Codec LOOT_CONDITIONS_CODEC = Codec.PASSTHROUGH.flatXmap( + d -> + { + try + { + LootItemCondition[] conditions = LootModifierManager.GSON_INSTANCE.fromJson(getJson(d), LootItemCondition[].class); + return DataResult.success(conditions); + } + catch (JsonSyntaxException e) + { + LootModifierManager.LOGGER.warn("Unable to decode loot conditions", e); + return DataResult.error(e.getMessage()); + } + }, + conditions -> + { + try + { + JsonElement element = LootModifierManager.GSON_INSTANCE.toJsonTree(conditions); + return DataResult.success(new Dynamic<>(JsonOps.INSTANCE, element)); + } + catch (JsonSyntaxException e) + { + LootModifierManager.LOGGER.warn("Unable to encode loot conditions", e); + return DataResult.error(e.getMessage()); + } + } + ); + + @SuppressWarnings("unchecked") + static JsonElement getJson(Dynamic dynamic) { + Dynamic typed = (Dynamic) dynamic; + return typed.getValue() instanceof JsonElement ? + (JsonElement) typed.getValue() : + typed.getOps().convertTo(JsonOps.INSTANCE, typed.getValue()); + } + /** * Applies the modifier to the list of generated loot. This function needs to be responsible for * checking ILootConditions as well. @@ -25,4 +77,9 @@ public interface IGlobalLootModifier { */ @NotNull ObjectArrayList apply(ObjectArrayList generatedLoot, LootContext context); + + /** + * Returns the registered codec for this modifier + */ + Codec codec(); } diff --git a/src/main/java/net/minecraftforge/common/loot/LootModifier.java b/src/main/java/net/minecraftforge/common/loot/LootModifier.java index 7aa4e15188..fafc014795 100644 --- a/src/main/java/net/minecraftforge/common/loot/LootModifier.java +++ b/src/main/java/net/minecraftforge/common/loot/LootModifier.java @@ -7,8 +7,11 @@ package net.minecraftforge.common.loot; import java.util.function.Predicate; +import com.mojang.datafixers.Products; +import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.levelgen.feature.trunkplacers.BendingTrunkPlacer; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.level.storage.loot.predicates.LootItemConditions; @@ -16,25 +19,42 @@ import org.jetbrains.annotations.NotNull; /** * A base implementation of a Global Loot Modifier for modders to extend. - * Takes care of ILootCondition matching and comes with a base serializer - * implementation that takes care of Forge registry things. + * Takes care of ILootCondition matching and comes with the base codec to extend. */ -public abstract class LootModifier implements IGlobalLootModifier { +public abstract class LootModifier implements IGlobalLootModifier +{ protected final LootItemCondition[] conditions; private final Predicate combinedConditions; + /** + * Simplifies codec creation, especially if no other fields are added: + *

+ * {@code + * public static final Codec CODEC = RecordCodecBuilder.create(inst -> codecStart(inst).apply(inst, MyLootModifier::new)); + * } + *

+ * Otherwise can follow this with #and() to add more fields. + * Examples: Forge Test Subclasses or {@link BendingTrunkPlacer#CODEC} + */ + protected static Products.P1, LootItemCondition[]> codecStart(RecordCodecBuilder.Instance instance) + { + return instance.group(LOOT_CONDITIONS_CODEC.fieldOf("conditions").forGetter(lm -> lm.conditions)); + } + /** * Constructs a LootModifier. * @param conditionsIn the ILootConditions that need to be matched before the loot is modified. */ - protected LootModifier(LootItemCondition[] conditionsIn) { + protected LootModifier(LootItemCondition[] conditionsIn) + { this.conditions = conditionsIn; this.combinedConditions = LootItemConditions.andConditions(conditionsIn); } @NotNull @Override - public final ObjectArrayList apply(ObjectArrayList generatedLoot, LootContext context) { + public final ObjectArrayList apply(ObjectArrayList generatedLoot, LootContext context) + { return this.combinedConditions.test(context) ? this.doApply(generatedLoot, context) : generatedLoot; } diff --git a/src/main/java/net/minecraftforge/common/loot/LootModifierManager.java b/src/main/java/net/minecraftforge/common/loot/LootModifierManager.java index 97c82c3082..d35d5b05a6 100644 --- a/src/main/java/net/minecraftforge/common/loot/LootModifierManager.java +++ b/src/main/java/net/minecraftforge/common/loot/LootModifierManager.java @@ -6,19 +6,17 @@ package net.minecraftforge.common.loot; import java.io.BufferedReader; -import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; +import java.util.*; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; import net.minecraft.world.level.storage.loot.Deserializers; -import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -39,7 +37,7 @@ import net.minecraftforge.registries.ForgeRegistries; public class LootModifierManager extends SimpleJsonResourceReloadListener { public static final Logger LOGGER = LogManager.getLogger(); - private static final Gson GSON_INSTANCE = Deserializers.createFunctionSerializer().create(); + public static final Gson GSON_INSTANCE = Deserializers.createFunctionSerializer().create(); private Map registeredLootModifiers = ImmutableMap.of(); private static final String folder = "loot_modifiers"; @@ -51,22 +49,7 @@ public class LootModifierManager extends SimpleJsonResourceReloadListener { @Override protected void apply(Map resourceList, ResourceManager resourceManagerIn, ProfilerFiller profilerIn) { Builder builder = ImmutableMap.builder(); - //old way (for reference) - /*Map toLocation = new HashMap(); - resourceList.forEach((location, object) -> { - try { - IGlobalLootModifier modifier = deserializeModifier(location, object); - builder.put(location, modifier); - toLocation.put(modifier, location); - } catch (Exception exception) { - LOGGER.error("Couldn't parse loot modifier {}", location, exception); - } - }); - builder.orderEntriesByValue((x,y) -> { - return toLocation.get(x).compareTo(toLocation.get(y)); - });*/ - //new way - ArrayList finalLocations = new ArrayList(); + List finalLocations = new ArrayList<>(); ResourceLocation resourcelocation = new ResourceLocation("forge","loot_modifiers/global_loot_modifiers.json"); //read in all data files from forge:loot_modifiers/global_loot_modifiers in order to do layering for(Resource iresource : resourceManagerIn.getResourceStack(resourcelocation)) { @@ -75,13 +58,13 @@ public class LootModifierManager extends SimpleJsonResourceReloadListener { ) { JsonObject jsonobject = GsonHelper.fromJson(GSON_INSTANCE, reader, JsonObject.class); boolean replace = jsonobject.get("replace").getAsBoolean(); - if(replace) finalLocations.clear(); + if (replace) + finalLocations.clear(); JsonArray entryList = jsonobject.get("entries").getAsJsonArray(); for(JsonElement entry : entryList) { - String loc = entry.getAsString(); - ResourceLocation res = new ResourceLocation(loc); - if(finalLocations.contains(res)) finalLocations.remove(res); - finalLocations.add(res); + ResourceLocation loc = new ResourceLocation(entry.getAsString()); + finalLocations.remove(loc); //remove and re-add if needed, to update the ordering. + finalLocations.add(loc); } } @@ -90,31 +73,25 @@ public class LootModifierManager extends SimpleJsonResourceReloadListener { } } //use layered config to fetch modifier data files (modifiers missing from config are disabled) - finalLocations.forEach(location -> { - try { - IGlobalLootModifier modifier = deserializeModifier(location, resourceList.get(location)); - if(modifier != null) - builder.put(location, modifier); - } catch (Exception exception) { - LOGGER.error("Couldn't parse loot modifier {}", location, exception); + for (ResourceLocation location : finalLocations) + { + Codec codec = ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.get().getValue(location); + if (codec == null) + { + LOGGER.warn("Unknown or unregistered codec for GlobalLootModifier: {}", location); + continue; } - }); - ImmutableMap immutablemap = builder.build(); - this.registeredLootModifiers = immutablemap; - } - - private IGlobalLootModifier deserializeModifier(ResourceLocation location, JsonElement element) { - if (!element.isJsonObject()) return null; - JsonObject object = element.getAsJsonObject(); - LootItemCondition[] lootConditions = GSON_INSTANCE.fromJson(object.get("conditions"), LootItemCondition[].class); - - ResourceLocation serializer = new ResourceLocation(GsonHelper.getAsString(object, "type")); - - return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.get().getValue(serializer).read(location, object, lootConditions); - } - - public static GlobalLootModifierSerializer getSerializerForName(ResourceLocation resourcelocation) { - return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.get().getValue(resourcelocation); + JsonElement json = resourceList.get(location); + IGlobalLootModifier modifier = codec.decode(JsonOps.INSTANCE, json).get() + .map(Pair::getFirst, partial -> + { + LOGGER.warn("Could not decode GlobalLootModifier with serializer: {} - error: {}", location, partial.message()); + return null; + }); + if(modifier != null) + builder.put(location, modifier); + } + this.registeredLootModifiers = builder.build(); } /** diff --git a/src/main/java/net/minecraftforge/registries/ForgeRegistries.java b/src/main/java/net/minecraftforge/registries/ForgeRegistries.java index 58dfebf957..a43a244be9 100644 --- a/src/main/java/net/minecraftforge/registries/ForgeRegistries.java +++ b/src/main/java/net/minecraftforge/registries/ForgeRegistries.java @@ -41,7 +41,7 @@ import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacerType; import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecoratorType; import net.minecraftforge.common.Tags; -import net.minecraftforge.common.loot.GlobalLootModifierSerializer; +import net.minecraftforge.common.loot.IGlobalLootModifier; import net.minecraftforge.common.world.BiomeModifier; import net.minecraftforge.fluids.FluidType; @@ -97,8 +97,8 @@ public class ForgeRegistries // Custom forge registries static final DeferredRegister> DEFERRED_DATA_SERIALIZERS = DeferredRegister.create(Keys.DATA_SERIALIZERS, Keys.DATA_SERIALIZERS.location().getNamespace()); public static final Supplier>> DATA_SERIALIZERS = DEFERRED_DATA_SERIALIZERS.makeRegistry(GameData::getDataSerializersRegistryBuilder); - static final DeferredRegister> DEFERRED_LOOT_MODIFIER_SERIALIZERS = DeferredRegister.create(Keys.LOOT_MODIFIER_SERIALIZERS, Keys.LOOT_MODIFIER_SERIALIZERS.location().getNamespace()); - public static final Supplier>> LOOT_MODIFIER_SERIALIZERS = DEFERRED_LOOT_MODIFIER_SERIALIZERS.makeRegistry(GameData::getGLMSerializersRegistryBuilder); + static final DeferredRegister> DEFERRED_LOOT_MODIFIER_SERIALIZERS = DeferredRegister.create(Keys.LOOT_MODIFIER_SERIALIZERS, Keys.LOOT_MODIFIER_SERIALIZERS.location().getNamespace()); + public static final Supplier>> LOOT_MODIFIER_SERIALIZERS = DEFERRED_LOOT_MODIFIER_SERIALIZERS.makeRegistry(GameData::getGLMSerializersRegistryBuilder); static final DeferredRegister> DEFERRED_BIOME_MODIFIER_SERIALIZERS = DeferredRegister.create(Keys.BIOME_MODIFIER_SERIALIZERS, Keys.BIOME_MODIFIER_SERIALIZERS.location().getNamespace()); public static final Supplier>> BIOME_MODIFIER_SERIALIZERS = DEFERRED_BIOME_MODIFIER_SERIALIZERS.makeRegistry(() -> new RegistryBuilder>().disableSaving().disableSync()); static final DeferredRegister> DEFERRED_STRUCTURE_MODIFIER_SERIALIZERS = DeferredRegister.create(Keys.STRUCTURE_MODIFIER_SERIALIZERS, Keys.STRUCTURE_MODIFIER_SERIALIZERS.location().getNamespace()); @@ -148,7 +148,7 @@ public class ForgeRegistries // Forge public static final ResourceKey>> DATA_SERIALIZERS = key("forge:data_serializers"); - public static final ResourceKey>> LOOT_MODIFIER_SERIALIZERS = key("forge:loot_modifier_serializers"); + public static final ResourceKey>> LOOT_MODIFIER_SERIALIZERS = key("forge:loot_modifier_serializers"); public static final ResourceKey>> BIOME_MODIFIER_SERIALIZERS = key("forge:biome_modifier_serializers"); public static final ResourceKey>> STRUCTURE_MODIFIER_SERIALIZERS = key("forge:structure_modifier_serializers"); public static final ResourceKey> FLUID_TYPES = key("forge:fluid_type"); diff --git a/src/main/java/net/minecraftforge/registries/GameData.java b/src/main/java/net/minecraftforge/registries/GameData.java index 7aefa954fa..021d3139a5 100644 --- a/src/main/java/net/minecraftforge/registries/GameData.java +++ b/src/main/java/net/minecraftforge/registries/GameData.java @@ -11,6 +11,7 @@ import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; import java.util.LinkedHashSet; import net.minecraft.core.DefaultedRegistry; @@ -37,7 +38,7 @@ import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Material; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.loot.GlobalLootModifierSerializer; +import net.minecraftforge.common.loot.IGlobalLootModifier; import net.minecraftforge.common.util.LogMessageAdapter; import net.minecraftforge.fluids.FluidType; import net.minecraftforge.fml.ModLoader; @@ -142,7 +143,7 @@ public class GameData return makeRegistry(DATA_SERIALIZERS, 256 /*vanilla space*/, MAX_VARINT).disableSaving().disableOverrides(); } - static RegistryBuilder> getGLMSerializersRegistryBuilder() + static RegistryBuilder> getGLMSerializersRegistryBuilder() { return makeRegistry(LOOT_MODIFIER_SERIALIZERS).disableSaving().disableSync(); } diff --git a/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java b/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java index 5daba5f1bb..8fdcaef727 100644 --- a/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java +++ b/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java @@ -5,12 +5,14 @@ package net.minecraftforge.debug.gameplay.loot; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; +import com.google.common.base.Suppliers; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.advancements.critereon.EnchantmentPredicate; import net.minecraft.advancements.critereon.ItemPredicate; import net.minecraft.advancements.critereon.MinMaxBounds; +import net.minecraft.util.ExtraCodecs; import net.minecraft.world.level.block.Blocks; import net.minecraft.data.DataGenerator; import net.minecraft.world.item.enchantment.Enchantment; @@ -32,10 +34,9 @@ import net.minecraft.world.level.storage.loot.LootTable; import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.level.storage.loot.predicates.MatchTool; -import net.minecraft.util.GsonHelper; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.common.data.GlobalLootModifierProvider; -import net.minecraftforge.common.loot.GlobalLootModifierSerializer; +import net.minecraftforge.common.loot.IGlobalLootModifier; import net.minecraftforge.common.loot.LootModifier; import net.minecraftforge.common.loot.LootTableIdCondition; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -49,8 +50,7 @@ import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; +import java.util.function.Supplier; import java.util.stream.Collectors; @Mod(GlobalLootModifiersTest.MODID) @@ -67,13 +67,13 @@ public class GlobalLootModifiersTest { } } - private static final DeferredRegister> GLM = DeferredRegister.create(ForgeRegistries.Keys.LOOT_MODIFIER_SERIALIZERS, MODID); + private static final DeferredRegister> GLM = DeferredRegister.create(ForgeRegistries.Keys.LOOT_MODIFIER_SERIALIZERS, MODID); private static final DeferredRegister ENCHANTS = DeferredRegister.create(ForgeRegistries.ENCHANTMENTS, MODID); - private static final RegistryObject DUNGEON_LOOT = GLM.register("dungeon_loot", DungeonLootEnhancerModifier.Serializer::new); - private static final RegistryObject SMELTING = GLM.register("smelting", SmeltingEnchantmentModifier.Serializer::new); - private static final RegistryObject WHEATSEEDS = GLM.register("wheat_harvest", WheatSeedsConverterModifier.Serializer::new); - private static final RegistryObject SILKTOUCH = GLM.register("silk_touch_bamboo", SilkTouchTestModifier.Serializer::new); + private static final RegistryObject> DUNGEON_LOOT = GLM.register("dungeon_loot", DungeonLootEnhancerModifier.CODEC); + private static final RegistryObject> SMELTING = GLM.register("smelting", SmeltingEnchantmentModifier.CODEC); + private static final RegistryObject> WHEATSEEDS = GLM.register("wheat_harvest", WheatSeedsConverterModifier.CODEC); + private static final RegistryObject> SILKTOUCH = GLM.register("silk_touch_bamboo", SilkTouchTestModifier.CODEC); private static final RegistryObject SMELT = ENCHANTS.register("smelt", () -> new SmelterEnchantment(Rarity.UNCOMMON, EnchantmentCategory.DIGGER, EquipmentSlot.MAINHAND)); @EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD) @@ -96,7 +96,7 @@ public class GlobalLootModifiersTest { @Override protected void start() { - add("smelting", SMELTING.get(), new SmeltingEnchantmentModifier( + add("smelting", new SmeltingEnchantmentModifier( new LootItemCondition[]{ MatchTool.toolMatches( ItemPredicate.Builder.item().hasEnchantment( @@ -105,7 +105,7 @@ public class GlobalLootModifiersTest { }) ); - add("wheat_harvest", WHEATSEEDS.get(), new WheatSeedsConverterModifier( + add("wheat_harvest", new WheatSeedsConverterModifier( new LootItemCondition[] { MatchTool.toolMatches(ItemPredicate.Builder.item().of(Items.SHEARS)).build(), LootItemBlockStatePropertyCondition.hasBlockStateProperties(Blocks.WHEAT).build() @@ -113,8 +113,9 @@ public class GlobalLootModifiersTest { 3, Items.WHEAT_SEEDS, Items.WHEAT) ); - add("dungeon_loot", DUNGEON_LOOT.get(), new DungeonLootEnhancerModifier( - new LootItemCondition[] { LootTableIdCondition.builder(new ResourceLocation("chests/simple_dungeon")).build() }) + add("dungeon_loot", new DungeonLootEnhancerModifier( + new LootItemCondition[] { LootTableIdCondition.builder(new ResourceLocation("chests/simple_dungeon")).build() }, + 2) ); } } @@ -130,6 +131,8 @@ public class GlobalLootModifiersTest { * */ private static class SmeltingEnchantmentModifier extends LootModifier { + public static final Supplier> CODEC = Suppliers.memoize(() -> RecordCodecBuilder.create(inst -> codecStart(inst).apply(inst, SmeltingEnchantmentModifier::new))); + public SmeltingEnchantmentModifier(LootItemCondition[] conditionsIn) { super(conditionsIn); } @@ -150,16 +153,9 @@ public class GlobalLootModifiersTest { .orElse(stack); } - private static class Serializer extends GlobalLootModifierSerializer { - @Override - public SmeltingEnchantmentModifier read(ResourceLocation name, JsonObject json, LootItemCondition[] conditionsIn) { - return new SmeltingEnchantmentModifier(conditionsIn); - } - - @Override - public JsonObject write(SmeltingEnchantmentModifier instance) { - return makeConditions(instance.conditions); - } + @Override + public Codec codec() { + return CODEC.get(); } } @@ -168,6 +164,8 @@ public class GlobalLootModifiersTest { * */ private static class SilkTouchTestModifier extends LootModifier { + public static final Supplier> CODEC = Suppliers.memoize(() -> RecordCodecBuilder.create(inst -> codecStart(inst).apply(inst, SilkTouchTestModifier::new))); + public SilkTouchTestModifier(LootItemCondition[] conditionsIn) { super(conditionsIn); } @@ -187,16 +185,9 @@ public class GlobalLootModifiersTest { return loottable.getRandomItems(ctx); } - private static class Serializer extends GlobalLootModifierSerializer { - @Override - public SilkTouchTestModifier read(ResourceLocation name, JsonObject json, LootItemCondition[] conditionsIn) { - return new SilkTouchTestModifier(conditionsIn); - } - - @Override - public JsonObject write(SilkTouchTestModifier instance) { - return makeConditions(instance.conditions); - } + @Override + public Codec codec() { + return CODEC.get(); } } @@ -206,6 +197,14 @@ public class GlobalLootModifiersTest { * */ private static class WheatSeedsConverterModifier extends LootModifier { + public static final Supplier> CODEC = Suppliers.memoize(() -> 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) + )); + private final int numSeedsToConvert; private final Item itemToCheck; private final Item itemReward; @@ -238,28 +237,18 @@ public class GlobalLootModifiersTest { return generatedLoot; } - private static class Serializer extends GlobalLootModifierSerializer { - - @Override - public WheatSeedsConverterModifier read(ResourceLocation name, JsonObject object, LootItemCondition[] conditionsIn) { - int numSeeds = GsonHelper.getAsInt(object, "numSeeds"); - Item seed = ForgeRegistries.ITEMS.getValue(new ResourceLocation((GsonHelper.getAsString(object, "seedItem")))); - Item wheat = ForgeRegistries.ITEMS.getValue(new ResourceLocation(GsonHelper.getAsString(object, "replacement"))); - return new WheatSeedsConverterModifier(conditionsIn, numSeeds, seed, wheat); - } - - @Override - public JsonObject write(WheatSeedsConverterModifier instance) { - JsonObject json = makeConditions(instance.conditions); - 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; - } + @Override + public Codec codec() { + return CODEC.get(); } } private static class DungeonLootEnhancerModifier extends LootModifier { + public static final Supplier> CODEC = Suppliers.memoize(() -> RecordCodecBuilder.create(inst -> codecStart(inst) + .and(ExtraCodecs.POSITIVE_INT.optionalFieldOf("multiplication_factor", 2).forGetter(m -> m.multiplicationFactor)) + .apply(inst, DungeonLootEnhancerModifier::new) + )); + private final int multiplicationFactor; public DungeonLootEnhancerModifier(final LootItemCondition[] conditionsIn, final int multiplicationFactor) { @@ -267,10 +256,6 @@ public class GlobalLootModifiersTest { this.multiplicationFactor = multiplicationFactor; } - public DungeonLootEnhancerModifier(final LootItemCondition[] conditionsIn) { - this(conditionsIn, 2); - } - @Override protected ObjectArrayList doApply(ObjectArrayList generatedLoot, LootContext context) { return generatedLoot.stream() @@ -279,20 +264,9 @@ public class GlobalLootModifiersTest { .collect(Collectors.toCollection(ObjectArrayList::new)); } - private static class Serializer extends GlobalLootModifierSerializer { - @Override - public DungeonLootEnhancerModifier read(ResourceLocation location, JsonObject object, LootItemCondition[] conditions) { - final int multiplicationFactor = GsonHelper.getAsInt(object, "multiplication_factor", 2); - if (multiplicationFactor <= 0) throw new JsonParseException("Unable to set a multiplication factor to a number lower than 1"); - return new DungeonLootEnhancerModifier(conditions, multiplicationFactor); - } - - @Override - public JsonObject write(DungeonLootEnhancerModifier instance) { - final JsonObject obj = this.makeConditions(instance.conditions); - obj.addProperty("multiplication_factor", instance.multiplicationFactor); - return obj; - } + @Override + public Codec codec() { + return CODEC.get(); } } }