Skip to content

Commit

Permalink
Brewing recipe matchers support (#2555)
Browse files Browse the repository at this point in the history
* Initial attempt at predicate recipe choice support

* Meta fixes and minor cleanup

* Newline

* Spaces

* Renames

* Meta improvements

* Unstray the stray line
  • Loading branch information
tal5 committed Nov 14, 2023
1 parent a51c2a1 commit f6e6f29
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 53 deletions.
Expand Up @@ -3,8 +3,11 @@
import com.denizenscript.denizen.Denizen;
import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.NMSVersion;
import com.denizenscript.denizen.objects.ItemTag;
import com.denizenscript.denizen.paper.PaperModule;
import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand;
import com.denizenscript.denizen.scripts.containers.core.ItemScriptContainer;
import com.denizenscript.denizen.scripts.containers.core.ItemScriptHelper;
import com.denizenscript.denizen.utilities.FormattedTextHelper;
import com.denizenscript.denizen.utilities.PaperAPITools;
import com.denizenscript.denizencore.DenizenCore;
Expand Down Expand Up @@ -158,18 +161,25 @@ public void teleport(Entity entity, Location loc, PlayerTeleportEvent.TeleportCa
entity.teleport(loc, cause, teleportFlags.toArray(new TeleportFlag[0]));
}

public static HashMap<NamespacedKey, PotionMix> potionMixes = new HashMap<>();
record BrewingRecipeWithMatchers(PotionMix potionMix, String inputMatcher, String ingredientMatcher) {}
public static final Map<NamespacedKey, BrewingRecipeWithMatchers> potionMixes = new HashMap<>();

@Override
public void registerBrewingRecipe(String keyName, ItemStack result, ItemStack[] inputItem, boolean inputExact, ItemStack[] ingredientItem, boolean ingredientExact) {
public void registerBrewingRecipe(String keyName, ItemStack result, String input, String ingredient, ItemScriptContainer itemScriptContainer) {
if (!NMSHandler.getVersion().isAtLeast(NMSVersion.v1_18)) {
throw new UnsupportedOperationException();
}
RecipeChoice inputChoice = parseBrewingRecipeChoice(itemScriptContainer, input);
if (inputChoice == null) {
return;
}
RecipeChoice ingredientChoice = parseBrewingRecipeChoice(itemScriptContainer, ingredient);
if (ingredientChoice == null) {
return;
}
NamespacedKey key = new NamespacedKey(Denizen.getInstance(), keyName);
RecipeChoice inputChoice = itemArrayToChoice(inputItem, inputExact);
RecipeChoice ingredientChoice = itemArrayToChoice(ingredientItem, ingredientExact);
PotionMix mix = new PotionMix(key, result, inputChoice, ingredientChoice);
potionMixes.put(key, mix);
potionMixes.put(key, new BrewingRecipeWithMatchers(mix, input.startsWith("matcher:") ? input : null, ingredient.startsWith("matcher:") ? ingredient : null));
Bukkit.getPotionBrewer().addPotionMix(mix);
}

Expand All @@ -185,27 +195,50 @@ public void clearBrewingRecipes() {
}
}

public static RecipeChoice itemArrayToChoice(ItemStack[] item, boolean exact) {
public static RecipeChoice parseBrewingRecipeChoice(ItemScriptContainer container, String choice) {
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && choice.startsWith("matcher:")) {
String matcher = choice.substring("matcher:".length());
return PotionMix.createPredicateChoice(item -> new ItemTag(item).tryAdvancedMatcher(matcher));
}
boolean exact = true;
if (choice.startsWith("material:")) {
choice = choice.substring("material:".length());
exact = false;
}
ItemStack[] items = ItemScriptHelper.textToItemArray(container, choice, exact);
if (items == null) {
return null;
}
if (exact) {
return new RecipeChoice.ExactChoice(item);
return new RecipeChoice.ExactChoice(items);
}
Material[] mats = new Material[item.length];
for (int i = 0; i < item.length; i++) {
mats[i] = item[i].getType();
Material[] mats = new Material[items.length];
for (int i = 0; i < items.length; i++) {
mats[i] = items[i].getType();
}
return new RecipeChoice.MaterialChoice(mats);
}

@Override
public boolean isDenizenMix(ItemStack currInput, ItemStack ingredient) {
for (PotionMix mix : potionMixes.values()) {
if (mix.getInput().getItemStack().isSimilar(currInput) && mix.getIngredient().getItemStack().isSimilar(ingredient)) {
for (BrewingRecipeWithMatchers brewing : potionMixes.values()) {
if (brewing.potionMix().getInput().test(currInput) && brewing.potionMix().getIngredient().test(ingredient)) {
return true;
}
}
return false;
}

@Override
public String getBrewingRecipeInputMatcher(NamespacedKey recipeId) {
return potionMixes.get(recipeId).inputMatcher();
}

@Override
public String getBrewingRecipeIngredientMatcher(NamespacedKey recipeId) {
return potionMixes.get(recipeId).ingredientMatcher();
}

@Override
public String getDeathMessage(PlayerDeathEvent event) {
return PaperModule.stringifyComponent(event.deathMessage());
Expand Down
Expand Up @@ -189,6 +189,7 @@ public class ItemScriptContainer extends ScriptContainer {
// 7:
// # Brewing recipes take one base item and one ingredient item.
// # | Brewing recipes are only available on Paper versions 1.18 and up.
// # | Brewing recipes also have a special input option on 1.20 and above: "matcher:<item matcher>", to allow advanced matchers on the input/ingredient items.
// type: brewing
// input: ItemTag
// ingredient: ItemTag
Expand Down
@@ -1,18 +1,18 @@
package com.denizenscript.denizen.scripts.containers.core;

import com.denizenscript.denizen.Denizen;
import com.denizenscript.denizen.events.bukkit.ScriptReloadEvent;
import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.NMSVersion;
import com.denizenscript.denizen.nms.util.jnbt.CompoundTag;
import com.denizenscript.denizen.objects.EntityTag;
import com.denizenscript.denizen.objects.ItemTag;
import com.denizenscript.denizen.objects.MaterialTag;
import com.denizenscript.denizen.objects.PlayerTag;
import com.denizenscript.denizen.tags.BukkitTagContext;
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
import com.denizenscript.denizen.utilities.PaperAPITools;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import com.denizenscript.denizen.events.bukkit.ScriptReloadEvent;
import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.objects.ItemTag;
import com.denizenscript.denizen.tags.BukkitTagContext;
import com.denizenscript.denizencore.events.ScriptEvent;
import com.denizenscript.denizencore.objects.core.DurationTag;
import com.denizenscript.denizencore.objects.core.ListTag;
Expand All @@ -21,10 +21,13 @@
import com.denizenscript.denizencore.tags.TagContext;
import com.denizenscript.denizencore.tags.TagManager;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import com.denizenscript.denizen.utilities.BukkitImplDeprecations;
import com.denizenscript.denizencore.utilities.YamlConfiguration;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import com.denizenscript.denizencore.utilities.text.StringHolder;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
Expand Down Expand Up @@ -274,28 +277,6 @@ public static void registerSmithingRecipe(ItemScriptContainer container, ItemSta
NMSHandler.itemHelper.registerSmithingRecipe(internalId, item, baseItems, baseExact, additionItems, additionExact, template, templateExact);
}

public static void registerBrewingRecipe(ItemScriptContainer container, ItemStack item, String inputItemString, String ingredientItemString, String internalId) {
boolean inputExact = true;
if (inputItemString.startsWith("material:")) {
inputExact = false;
inputItemString = inputItemString.substring("material:".length());
}
ItemStack[] inputItems = textToItemArray(container, inputItemString, inputExact);
if (inputItems == null) {
return;
}
boolean ingredientExact = true;
if (ingredientItemString.startsWith("material:")) {
ingredientExact = false;
ingredientItemString = ingredientItemString.substring("material:".length());
}
ItemStack[] ingredientItems = textToItemArray(container, ingredientItemString, ingredientExact);
if (ingredientItems == null) {
return;
}
PaperAPITools.instance.registerBrewingRecipe(internalId, item, inputItems, inputExact, ingredientItems, ingredientExact);
}

public static void rebuildRecipes() {
for (ItemScriptContainer container : item_scripts.values()) {
try {
Expand Down Expand Up @@ -347,7 +328,7 @@ public static void rebuildRecipes() {
}
registerSmithingRecipe(container, item, template, getString.apply("base"), getString.apply("upgrade"), internalId, retain);
}
case "brewing" -> registerBrewingRecipe(container, item, getString.apply("input"), getString.apply("ingredient"), internalId);
case "brewing" -> PaperAPITools.instance.registerBrewingRecipe(internalId, item, getString.apply("input"), getString.apply("ingredient"), container);
}
}
}
Expand Down
Expand Up @@ -26,7 +26,10 @@
import com.denizenscript.denizencore.scripts.commands.core.AdjustCommand;
import com.denizenscript.denizencore.scripts.commands.core.SQLCommand;
import com.denizenscript.denizencore.scripts.containers.ScriptContainer;
import com.denizenscript.denizencore.tags.*;
import com.denizenscript.denizencore.tags.Attribute;
import com.denizenscript.denizencore.tags.PseudoObjectTagBase;
import com.denizenscript.denizencore.tags.TagManager;
import com.denizenscript.denizencore.tags.TagRunnable;
import com.denizenscript.denizencore.tags.core.UtilTagBase;
import com.denizenscript.denizencore.utilities.CoreConfiguration;
import com.denizenscript.denizencore.utilities.CoreUtilities;
Expand Down Expand Up @@ -228,6 +231,7 @@ public void register() {
// This is formatted equivalently to the item script recipe input, with "material:" for non-exact matches, and a full ItemTag for exact matches.
// Note that this won't represent all recipes perfectly (primarily those with multiple input choices per slot).
// Brewing recipes are only supported on Paper, and only custom ones are available.
// For brewing recipes, currently "matcher:<item matcher>" input options are only supported in recipes added by Denizen.
// For furnace-style and stonecutting recipes, this will return a list with only 1 item.
// For shaped recipes, this will include 'air' for slots that are part of the shape but don't require an item.
// For smithing recipes, this will return a list with the 'base' item and the 'addition'.
Expand Down Expand Up @@ -277,8 +281,18 @@ else if (recipe instanceof SmithingRecipe smithingRecipe) {
addChoice.accept(smithingRecipe.getAddition());
}
else if (brewingRecipe != null) {
addChoice.accept(brewingRecipe.ingredient());
addChoice.accept(brewingRecipe.input());
if (brewingRecipe.ingredient() != null) {
addChoice.accept(brewingRecipe.ingredient());
}
else {
recipeItems.addObject(new ElementTag(PaperAPITools.instance.getBrewingRecipeIngredientMatcher(recipeKey), true));
}
if (brewingRecipe.input() != null) {
addChoice.accept(brewingRecipe.input());
}
else {
recipeItems.addObject(new ElementTag(PaperAPITools.instance.getBrewingRecipeInputMatcher(recipeKey), true));
}
}
return recipeItems;
});
Expand Down
Expand Up @@ -3,13 +3,11 @@
import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.NMSVersion;
import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand;
import com.denizenscript.denizen.scripts.containers.core.ItemScriptContainer;
import com.denizenscript.denizencore.utilities.ReflectionHelper;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Nameable;
import org.bukkit.RegionAccessor;
import org.bukkit.*;
import org.bukkit.block.Sign;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
Expand Down Expand Up @@ -116,7 +114,7 @@ public void teleport(Entity entity, Location loc, PlayerTeleportEvent.TeleportCa
entity.teleport(loc, cause);
}

public void registerBrewingRecipe(String keyName, ItemStack result, ItemStack[] inputItem, boolean inputExact, ItemStack[] ingredientItem, boolean ingredientExact) {
public void registerBrewingRecipe(String keyName, ItemStack result, String input, String ingredient, ItemScriptContainer itemScriptContainer) {
throw new UnsupportedOperationException();
}

Expand All @@ -127,6 +125,14 @@ public boolean isDenizenMix(ItemStack currInput, ItemStack ingredient) {
return false;
}

public String getBrewingRecipeInputMatcher(NamespacedKey recipeId) {
return null;
}

public String getBrewingRecipeIngredientMatcher(NamespacedKey recipeId) {
return null;
}

public String getDeathMessage(PlayerDeathEvent event) {
return event.getDeathMessage();
}
Expand Down
Expand Up @@ -61,6 +61,7 @@

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Predicate;

public class ItemHelperImpl extends ItemHelper {

Expand Down Expand Up @@ -503,10 +504,13 @@ public Map<NamespacedKey, BrewingRecipe> getCustomBrewingRecipes() {
if (PaperPotionMix_CLASS == null) {
PaperPotionMix_CLASS = paperMix.getClass();
}
RecipeChoice ingredient = CraftRecipe.toBukkit(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "ingredient", paperMix));
RecipeChoice input = CraftRecipe.toBukkit(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "input", paperMix));
Predicate<net.minecraft.world.item.ItemStack> ingredient = ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "ingredient", paperMix);
Predicate<net.minecraft.world.item.ItemStack> input = ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "input", paperMix);
// Not an instance of net.minecraft.world.item.crafting.Ingredient = a predicate recipe choice
RecipeChoice ingredientChoice = ingredient instanceof Ingredient nmsRecipeChoice ? CraftRecipe.toBukkit(nmsRecipeChoice) : null;
RecipeChoice inputChoice = input instanceof Ingredient nmsRecipeChoice ? CraftRecipe.toBukkit(nmsRecipeChoice) : null;
ItemStack result = CraftItemStack.asBukkitCopy(ReflectionHelper.getFieldValue(PaperPotionMix_CLASS, "result", paperMix));
return new BrewingRecipe(ingredient, input, result);
return new BrewingRecipe(inputChoice, ingredientChoice, result);
});
}
return customBrewingRecipes;
Expand Down

0 comments on commit f6e6f29

Please sign in to comment.