From ee449e427c97fd29fea9a549ff007ed4168fd1b7 Mon Sep 17 00:00:00 2001 From: Thanh-Phuong Date: Wed, 9 Aug 2017 16:20:45 -0400 Subject: [PATCH] Add support for oredict item predicates in advancements, and add a registry for item predicates (#4188) --- .../critereon/ItemPredicate.java.patch | 16 ++ .../critereon/ItemPredicates.java | 49 +++++ .../critereon/OredictItemPredicate.java | 50 +++++ .../debug/OredictItemPredicateTest.java | 198 ++++++++++++++++++ .../advancements/recipes/wood_unlock_tnt.json | 24 +++ 5 files changed, 337 insertions(+) create mode 100644 patches/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java.patch create mode 100644 src/main/java/net/minecraftforge/advancements/critereon/ItemPredicates.java create mode 100644 src/main/java/net/minecraftforge/advancements/critereon/OredictItemPredicate.java create mode 100644 src/test/java/net/minecraftforge/debug/OredictItemPredicateTest.java create mode 100644 src/test/resources/assets/oredict_predicate/advancements/recipes/wood_unlock_tnt.json diff --git a/patches/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java.patch b/patches/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java.patch new file mode 100644 index 0000000000..d16a9b79c1 --- /dev/null +++ b/patches/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java.patch @@ -0,0 +1,16 @@ +--- ../src-base/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java ++++ ../src-work/minecraft/net/minecraft/advancements/critereon/ItemPredicate.java +@@ -104,6 +104,7 @@ + if (p_192492_0_ != null && !p_192492_0_.isJsonNull()) + { + JsonObject jsonobject = JsonUtils.func_151210_l(p_192492_0_, "item"); ++ if (jsonobject.has("type")) ++ { ++ final ResourceLocation rl = new ResourceLocation(JsonUtils.func_151200_h(jsonobject, "type")); ++ final Map> map = net.minecraftforge.advancements.critereon.ItemPredicates.getPredicates(); ++ if (map.containsKey(rl)) return map.get(rl).apply(jsonobject); ++ else throw new JsonSyntaxException("There is no ItemPredicate of type "+rl); ++ } + MinMaxBounds minmaxbounds = MinMaxBounds.func_192515_a(jsonobject.get("count")); + MinMaxBounds minmaxbounds1 = MinMaxBounds.func_192515_a(jsonobject.get("durability")); + Integer integer = jsonobject.has("data") ? JsonUtils.func_151203_m(jsonobject, "data") : null; diff --git a/src/main/java/net/minecraftforge/advancements/critereon/ItemPredicates.java b/src/main/java/net/minecraftforge/advancements/critereon/ItemPredicates.java new file mode 100644 index 0000000000..ff551e0a91 --- /dev/null +++ b/src/main/java/net/minecraftforge/advancements/critereon/ItemPredicates.java @@ -0,0 +1,49 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * 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.advancements.critereon; + +import com.google.gson.JsonObject; +import gnu.trove.map.hash.THashMap; +import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.util.ResourceLocation; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Function; + +public class ItemPredicates +{ + private static final Map> predicates = new THashMap<>(); + + static + { + register(new ResourceLocation("forge:ore_dict"), OredictItemPredicate::new); + } + + public static void register(ResourceLocation rl, Function jsonToPredicate) + { + predicates.put(rl, jsonToPredicate); + } + + public static Map> getPredicates() + { + return Collections.unmodifiableMap(predicates); + } +} diff --git a/src/main/java/net/minecraftforge/advancements/critereon/OredictItemPredicate.java b/src/main/java/net/minecraftforge/advancements/critereon/OredictItemPredicate.java new file mode 100644 index 0000000000..9c36975783 --- /dev/null +++ b/src/main/java/net/minecraftforge/advancements/critereon/OredictItemPredicate.java @@ -0,0 +1,50 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * 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.advancements.critereon; + + +import com.google.gson.JsonObject; +import net.minecraft.util.JsonUtils; +import org.apache.commons.lang3.ArrayUtils; + +import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; + +/** + * An {@link ItemPredicate} that matches oredicts. + */ +public class OredictItemPredicate extends ItemPredicate +{ + private final String ore; + + public OredictItemPredicate(String ore) + { + this.ore = ore; + } + + public OredictItemPredicate(JsonObject jsonObject) { this(JsonUtils.getString(jsonObject, "ore")); } + + @Override + public boolean test(ItemStack stack) + { + return !stack.isEmpty() && ArrayUtils.contains(OreDictionary.getOreIDs(stack), OreDictionary.getOreID(ore)); + } +} diff --git a/src/test/java/net/minecraftforge/debug/OredictItemPredicateTest.java b/src/test/java/net/minecraftforge/debug/OredictItemPredicateTest.java new file mode 100644 index 0000000000..07c154bfc2 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/OredictItemPredicateTest.java @@ -0,0 +1,198 @@ +package net.minecraftforge.debug; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.advancements.critereon.AbstractCriterionInstance; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Most of the real work is in the advancements directory of this mod. + * This mod tests ore-dict advancement triggers. + */ +@Mod.EventBusSubscriber +@Mod(modid = OredictItemPredicateTest.MODID, name = "Oredict Item Predicate Test", version = "1.0", acceptableRemoteVersions = "*") +public class OredictItemPredicateTest +{ + public static final String MODID = "oredict_predicate"; + + static final boolean ENABLED = false; + + private static final MethodHandle ctRegister; + static + { + try + { + final Method tmp = CriteriaTriggers.class.getDeclaredMethod("register"/* func_192118_a */, ICriterionTrigger.class); + tmp.setAccessible(true); + ctRegister = MethodHandles.lookup().unreflect(tmp); + } + catch (Throwable e) + { + throw new RuntimeException(e); + } + } + + public static final EnabledTrigger ENABLED_TRIGGER; + static + { + try + { + ENABLED_TRIGGER = (EnabledTrigger)(ICriterionTrigger)ctRegister.invokeExact((ICriterionTrigger)new EnabledTrigger()); + } + catch (Throwable e) + { + throw new RuntimeException(e); + } + } + + // trigger the enabled advancement on player entry + @SubscribeEvent + public static void triggerAdv(EntityJoinWorldEvent event) + { + if (event.getEntity() instanceof EntityPlayerMP) + { + final EntityPlayerMP player = (EntityPlayerMP)event.getEntity(); + ENABLED_TRIGGER.trigger(player, player.inventory); + } + } + + + /** + * Far more work than expected…oh well. + */ + public static class EnabledTrigger implements ICriterionTrigger + { + public static final ResourceLocation ID = new ResourceLocation(MODID, "is_enabled"); + private final Map listeners = new HashMap<>(); + + @Override + public ResourceLocation getId() + { + return ID; + } + + @Override + public void addListener(PlayerAdvancements playerAdvancementsIn, Listener listener) + { + Listeners listeners = this.listeners.computeIfAbsent(playerAdvancementsIn, Listeners::new); + + listeners.add(listener); + } + + @Override + public void removeListener(PlayerAdvancements playerAdvancementsIn, Listener listener) + { + Listeners listeners = this.listeners.get(playerAdvancementsIn); + + if (listeners != null) + { + listeners.remove(listener); + + if (listeners.isEmpty()) + { + this.listeners.remove(playerAdvancementsIn); + } + } + } + + @Override + public void removeAllListeners(PlayerAdvancements playerAdvancementsIn) + { + this.listeners.remove(playerAdvancementsIn); + } + + @Override + public Instance deserializeInstance(JsonObject json, JsonDeserializationContext context) + { + return new Instance(); + } + + public void trigger(EntityPlayerMP player, InventoryPlayer inventory) + { + Listeners listeners = this.listeners.get(player.getAdvancements()); + + if (listeners != null) + { + listeners.trigger(inventory); + } + } + + public static class Instance extends AbstractCriterionInstance + { + public Instance() + { + super(ID); + } + } + + static class Listeners + { + private final PlayerAdvancements playerAdvancements; + private final Set> listeners = new HashSet<>(); + + public Listeners(PlayerAdvancements playerAdvancementsIn) + { + this.playerAdvancements = playerAdvancementsIn; + } + + public boolean isEmpty() + { + return this.listeners.isEmpty(); + } + + public void add(ICriterionTrigger.Listener listener) + { + this.listeners.add(listener); + } + + public void remove(ICriterionTrigger.Listener listener) + { + this.listeners.remove(listener); + } + + public void trigger(InventoryPlayer inventory) + { + List> list = null; + + for (ICriterionTrigger.Listener listener : this.listeners) + { + if (ENABLED) + { + if (list == null) + { + list = new ArrayList<>(); + } + + list.add(listener); + } + } + + if (list != null) + { + for (ICriterionTrigger.Listener listener1 : list) + { + listener1.grantCriterion(this.playerAdvancements); + } + } + } + } + } +} diff --git a/src/test/resources/assets/oredict_predicate/advancements/recipes/wood_unlock_tnt.json b/src/test/resources/assets/oredict_predicate/advancements/recipes/wood_unlock_tnt.json new file mode 100644 index 0000000000..396bf2b761 --- /dev/null +++ b/src/test/resources/assets/oredict_predicate/advancements/recipes/wood_unlock_tnt.json @@ -0,0 +1,24 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ "minecraft:tnt" ] + }, + "criteria": { + "has_wood": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "type": "forge:ore_dict", + "ore": "plankWood" + } + ] + } + }, + "mod_enabled": { + "trigger": "oredict_predicate:is_enabled", + "conditions": {} + } + }, + "requirements": [["has_wood"], ["mod_enabled"]] +}