From 4acafcccfd1852ec1dd701a1df9b0902d4ef1058 Mon Sep 17 00:00:00 2001 From: Unbekannt1998 <20846147+Unbekannt1998@users.noreply.github.com> Date: Fri, 15 Oct 2021 05:00:18 +0200 Subject: [PATCH] Make AdvancementProvider extensible by modders (#8120) --- .../advancements/Advancement.java.patch | 9 +++ .../AdvancementProvider.java.patch | 38 ++++++++++ .../extensions/IForgeAdvancementBuilder.java | 66 ++++++++++++++++ .../debug/DataGeneratorTest.java | 76 +++++++++++++++++++ .../data/forge/advancements/dummy_parent.json | 35 +++++++++ 5 files changed, 224 insertions(+) create mode 100644 patches/minecraft/net/minecraft/data/advancements/AdvancementProvider.java.patch create mode 100644 src/main/java/net/minecraftforge/common/extensions/IForgeAdvancementBuilder.java create mode 100644 src/test/resources/data/forge/advancements/dummy_parent.json diff --git a/patches/minecraft/net/minecraft/advancements/Advancement.java.patch b/patches/minecraft/net/minecraft/advancements/Advancement.java.patch index bd2b709383..4923f08a81 100644 --- a/patches/minecraft/net/minecraft/advancements/Advancement.java.patch +++ b/patches/minecraft/net/minecraft/advancements/Advancement.java.patch @@ -1,5 +1,14 @@ --- a/net/minecraft/advancements/Advancement.java +++ b/net/minecraft/advancements/Advancement.java +@@ -127,7 +_,7 @@ + return this.f_138305_; + } + +- public static class Builder { ++ public static class Builder implements net.minecraftforge.common.extensions.IForgeAdvancementBuilder { + private ResourceLocation f_138332_; + private Advancement f_138333_; + private DisplayInfo f_138334_; @@ -311,6 +_,7 @@ } diff --git a/patches/minecraft/net/minecraft/data/advancements/AdvancementProvider.java.patch b/patches/minecraft/net/minecraft/data/advancements/AdvancementProvider.java.patch new file mode 100644 index 0000000000..d4f276513b --- /dev/null +++ b/patches/minecraft/net/minecraft/data/advancements/AdvancementProvider.java.patch @@ -0,0 +1,38 @@ +--- a/net/minecraft/data/advancements/AdvancementProvider.java ++++ b/net/minecraft/data/advancements/AdvancementProvider.java +@@ -22,11 +_,18 @@ + private static final Gson f_123961_ = (new GsonBuilder()).setPrettyPrinting().create(); + private final DataGenerator f_123962_; + private final List>> f_123963_ = ImmutableList.of(new TheEndAdvancements(), new HusbandryAdvancements(), new AdventureAdvancements(), new NetherAdvancements(), new StoryAdvancements()); ++ protected net.minecraftforge.common.data.ExistingFileHelper fileHelper; + ++ @Deprecated + public AdvancementProvider(DataGenerator p_123966_) { + this.f_123962_ = p_123966_; + } + ++ public AdvancementProvider(DataGenerator generatorIn, net.minecraftforge.common.data.ExistingFileHelper fileHelperIn) { ++ this.f_123962_ = generatorIn; ++ this.fileHelper = fileHelperIn; ++ } ++ + public void m_6865_(HashCache p_123969_) { + Path path = this.f_123962_.m_123916_(); + Set set = Sets.newHashSet(); +@@ -45,6 +_,16 @@ + } + }; + ++ registerAdvancements(consumer, fileHelper); ++ } ++ ++ /** ++ * Override this method for registering and generating custom {@link Advancement}s.
++ * Just use {@link Advancement.Builder} to build your Advancements, you don't need an extra consumer like the vanilla classes. ++ * @param consumer used for the register function from {@link Advancement.Builder} ++ * @param fileHelper used for the register function from {@link Advancement.Builder} ++ */ ++ protected void registerAdvancements(Consumer consumer, net.minecraftforge.common.data.ExistingFileHelper fileHelper) { + for(Consumer> consumer1 : this.f_123963_) { + consumer1.accept(consumer); + } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeAdvancementBuilder.java b/src/main/java/net/minecraftforge/common/extensions/IForgeAdvancementBuilder.java new file mode 100644 index 0000000000..7b67492198 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeAdvancementBuilder.java @@ -0,0 +1,66 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2021. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.extensions; + +import com.google.common.collect.Maps; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementRewards; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; +import net.minecraftforge.common.data.ExistingFileHelper; + +import java.util.function.Consumer; + +public interface IForgeAdvancementBuilder +{ + + private Advancement.Builder self() + { + return (Advancement.Builder) this; + } + + /** + * save function for the {@link Advancement.Builder} which uses the {@link ExistingFileHelper} to check if the parent is already known + * @param consumer A {@link Consumer} which the build {@link Advancement} is passed to + * @param id The {@link ResourceLocation} for the new {@link Advancement} + * @param fileHelper The {@link ExistingFileHelper} where all known {@link Advancement}s are registered + * @return The build {@link Advancement} + * @throws IllegalStateException is thrown if the parent of the {@link Advancement} is not known + */ + default Advancement save(Consumer consumer ,ResourceLocation id, ExistingFileHelper fileHelper) + { + boolean canBuild = self().canBuild((advancementId) -> + { + if (fileHelper.exists(advancementId, PackType.SERVER_DATA, ".json", "advancements")) + { + return new Advancement(advancementId, null, null, AdvancementRewards.EMPTY, Maps.newHashMap(), null); + } + return null; + }); + if (!canBuild) + { + throw new IllegalStateException("Tried to build Advancement without valid Parent!"); + } + + Advancement advancement = self().build(id); + consumer.accept(advancement); + return advancement; + } +} diff --git a/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java b/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java index 73cdfd7d28..1feb58c3fb 100644 --- a/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java +++ b/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java @@ -40,6 +40,9 @@ import java.util.stream.Stream; import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; +import net.minecraft.advancements.critereon.InventoryChangeTrigger; +import net.minecraft.data.advancements.AdvancementProvider; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.sounds.SoundEvents; import net.minecraftforge.common.data.SoundDefinition; import net.minecraftforge.common.data.SoundDefinitionsProvider; @@ -148,6 +151,7 @@ public class DataGeneratorTest { gen.addProvider(new Recipes(gen)); gen.addProvider(new Tags(gen, event.getExistingFileHelper())); + gen.addProvider(new Advancements(gen, event.getExistingFileHelper())); } } @@ -895,6 +899,78 @@ public class DataGeneratorTest } } + public static class Advancements extends AdvancementProvider + { + + public Advancements(DataGenerator generatorIn, ExistingFileHelper fileHelper) + { + super(generatorIn, fileHelper); + } + + @Override + protected void registerAdvancements(Consumer consumer, ExistingFileHelper fileHelper) + { + Advancement.Builder.advancement().display(Items.DIRT, + new TranslatableComponent(Items.DIRT.getDescriptionId()), + new TranslatableComponent("dirt_description"), + new ResourceLocation("textures/gui/advancements/backgrounds/stone.png"), + FrameType.TASK, + true, + true, + false) + .addCriterion("has_dirt", InventoryChangeTrigger.TriggerInstance.hasItems(Items.DIRT)) + .save(consumer, new ResourceLocation(MODID, "obtain_dirt"), fileHelper); + + Advancement.Builder.advancement().display(Items.DIAMOND_BLOCK, + new TranslatableComponent(Items.DIAMOND_BLOCK.getDescriptionId()), + new TextComponent("You obtained a DiamondBlock"), + new ResourceLocation("textures/gui/advancements/backgrounds/stone.png"), + FrameType.CHALLENGE, + true, + true, + false) + .addCriterion("obtained_diamond_block", InventoryChangeTrigger.TriggerInstance.hasItems(Items.DIAMOND_BLOCK)) + .save(consumer, new ResourceLocation("obtain_diamond_block"), fileHelper); + + Advancement.Builder.advancement() + .display(Blocks.GRASS_BLOCK, + new TranslatableComponent("advancements.story.root.title"), + new TextComponent("Changed Description"), + new ResourceLocation("textures/gui/advancements/backgrounds/stone.png"), + FrameType.TASK, + false, + false, + false) + .addCriterion("crafting_table", InventoryChangeTrigger.TriggerInstance.hasItems(Blocks.CRAFTING_TABLE)) + .save(consumer, new ResourceLocation("story/root"), fileHelper); + + // This should cause an error because of the parent not existing +/* Advancement.Builder.advancement().display(Blocks.COBBLESTONE, + new TranslationTextComponent(Items.COBBLESTONE.getDescriptionId()), + new StringTextComponent("You got cobblestone"), + new ResourceLocation("textures/gui/advancements/backgrounds/stone.png"), + FrameType.TASK, + false, + false, + false) + .addCriterion("get_cobbleStone", InventoryChangeTrigger.Instance.hasItems(Items.COBBLESTONE)) + .parent(new ResourceLocation("not_there/not_here")) + .save(consumer, new ResourceLocation("illegal_parent"), fileHelper);*/ + + Advancement.Builder.advancement().display(Blocks.COBBLESTONE, + new TranslatableComponent(Items.COBBLESTONE.getDescriptionId()), + new TextComponent("You got cobblestone"), + new ResourceLocation("textures/gui/advancements/backgrounds/stone.png"), + FrameType.TASK, + false, + false, + false) + .addCriterion("get_cobbleStone", InventoryChangeTrigger.TriggerInstance.hasItems(Items.COBBLESTONE)) + .parent(new ResourceLocation("forge", "dummy_parent")) + .save(consumer, new ResourceLocation("good_parent"), fileHelper); + } + } + private static > List testModelResults(Map models, ExistingFileHelper existingFileHelper, Set toIgnore) { List ret = new ArrayList<>(); models.forEach((loc, model) -> { diff --git a/src/test/resources/data/forge/advancements/dummy_parent.json b/src/test/resources/data/forge/advancements/dummy_parent.json new file mode 100644 index 0000000000..10bc90a6bb --- /dev/null +++ b/src/test/resources/data/forge/advancements/dummy_parent.json @@ -0,0 +1,35 @@ +{ + "display": { + "icon": { + "item": "minecraft:dirt" + }, + "title": { + "translate": "block.minecraft.dirt" + }, + "description": { + "translate": "dirt_description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false, + "background": "minecraft:textures/gui/advancements/backgrounds/stone.png" + }, + "criteria": { + "has_dirt": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "minecraft:dirt" + } + ] + } + } + }, + "requirements": [ + [ + "has_dirt" + ] + ] +} \ No newline at end of file