Skip to content

Commit

Permalink
use better system for shaped recipes in 1.13+, for #1851
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmonkey4eva committed Sep 15, 2019
1 parent 7eee969 commit c5b45fc
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 154 deletions.
Expand Up @@ -12,6 +12,8 @@

public abstract class ItemHelper {

public abstract void clearDenizenRecipes();

public abstract String getInternalNameFromMaterial(Material material);

public abstract Material getMaterialFromInternalName(String internalName);
Expand Down
Expand Up @@ -21,9 +21,7 @@
import org.bukkit.inventory.meta.ItemMeta;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ItemScriptContainer extends ScriptContainer {

Expand Down Expand Up @@ -103,10 +101,6 @@ public class ItemScriptContainer extends ScriptContainer {
//
// -->

// A map storing special recipes that use itemscripts as ingredients
public static Map<ItemScriptContainer, List<ItemTag>> specialrecipesMap = new HashMap<>();
public static Map<ItemScriptContainer, List<ItemTag>> shapelessRecipesMap = new HashMap<>();

public NPCTag npc = null;
public PlayerTag player = null;
public boolean bound = false;
Expand All @@ -117,26 +111,6 @@ public ItemScriptContainer(YamlConfiguration configurationSection, String script

ItemScriptHelper.item_scripts.put(getName(), this);
ItemScriptHelper.item_scripts_by_hash_id.put(ItemScriptHelper.createItemScriptID(this), this);

// Set Recipe
if (contains("RECIPE")) {

// Get recipe list from item script
List<String> recipeList = getStringList("RECIPE");

// Process later so that any item script ingredients can be fulfilled
ItemScriptHelper.recipes_to_register.put(this, recipeList);

}

if (contains("SHAPELESS_RECIPE")) {
ItemScriptHelper.shapeless_to_register.put(this, getString("SHAPELESS_RECIPE"));
}

if (contains("FURNACE_RECIPE")) {
// Process later so that any item script ingredients can be fulfilled
ItemScriptHelper.furnace_to_register.put(this, getString("FURNACE_RECIPE"));
}
}

private ItemTag cleanReference;
Expand Down
@@ -1,5 +1,6 @@
package com.denizenscript.denizen.scripts.containers.core;

import com.denizenscript.denizen.nms.NMSVersion;
import com.denizenscript.denizen.utilities.DenizenAPI;
import com.denizenscript.denizen.utilities.debugging.Debug;
import com.denizenscript.denizen.events.bukkit.ScriptReloadEvent;
Expand All @@ -11,6 +12,7 @@
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.objects.core.ScriptTag;
import com.denizenscript.denizencore.tags.TagManager;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import org.bukkit.*;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
Expand All @@ -20,11 +22,7 @@
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.FurnaceRecipe;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.*;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
Expand All @@ -36,28 +34,30 @@ public class ItemScriptHelper implements Listener {

public static final Map<String, ItemScriptContainer> item_scripts = new ConcurrentHashMap<>(8, 0.9f, 1);
public static final Map<String, ItemScriptContainer> item_scripts_by_hash_id = new HashMap<>();
public static final Map<ItemScriptContainer, List<String>> recipes_to_register = new HashMap<>();
public static final Map<ItemScriptContainer, String> shapeless_to_register = new HashMap<>();
public static final Map<ItemScriptContainer, String> furnace_to_register = new HashMap<>();

public ItemScriptHelper() {
DenizenAPI.getCurrentInstance().getServer().getPluginManager()
.registerEvents(this, DenizenAPI.getCurrentInstance());
}

// Remove all recipes stored by Denizen
public static void removeDenizenRecipes() {
ItemScriptContainer.specialrecipesMap.clear();
ItemScriptContainer.shapelessRecipesMap.clear();
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_13)) {
NMSHandler.getItemHelper().clearDenizenRecipes();
}
else {
specialrecipesMap.clear();
shapelessRecipesMap.clear();
}
}

@EventHandler
public void scriptReload(ScriptReloadEvent event) {

for (Map.Entry<ItemScriptContainer, List<String>> entry : recipes_to_register.entrySet()) {

ItemScriptContainer container = entry.getKey();
List<String> recipeList = entry.getValue();
for (ItemScriptContainer container : item_scripts.values()) {
if (!container.contains("RECIPE")) {
continue;
}
List<String> recipeList = container.getStringList("RECIPE");

// Process all tags in list
for (int n = 0; n < recipeList.size(); n++) {
Expand All @@ -84,17 +84,27 @@ public void scriptReload(ScriptReloadEvent event) {
}
}

// Add the recipe to Denizen's item script recipe list so it
// will be checked manually inside ItemScriptHelper
if (shouldRegister) {
ItemScriptContainer.specialrecipesMap.put(container, ingredients);
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_13)) {
NamespacedKey key = new NamespacedKey("denizen", "item_" + CoreUtilities.toLowerCase(container.getName()) + "_shaped_recipe");
ShapedRecipe recipe = new ShapedRecipe(key, container.getCleanReference().getItemStack()).shape("ABC", "DEF", "GHI");
for (int i = 0; i < ingredients.size(); i++) {
recipe.setIngredient("ABCDEFGHI".charAt(i), new RecipeChoice.ExactChoice(ingredients.get(i).getItemStack().clone()));
}
Debug.log("Added " + recipe.getIngredientMap() + " asa " + key + " for " + recipe.getResult()); // TODO: Delete line
Bukkit.addRecipe(recipe);
}
else {
specialrecipesMap.put(container, ingredients);
}
}
}

for (Map.Entry<ItemScriptContainer, String> entry : shapeless_to_register.entrySet()) {

ItemScriptContainer container = entry.getKey();
String string = entry.getValue();
for (ItemScriptContainer container : item_scripts.values()) {
if (!container.contains("SHAPELESS_RECIPE")) {
continue;
}
String string = container.getString("SHAPELESS_RECIPE");

String list = TagManager.tag(string, new BukkitTagContext(container.player, container.npc, new ScriptTag(container)));

Expand All @@ -112,61 +122,47 @@ public void scriptReload(ScriptReloadEvent event) {
ingredients.add(ingredient);
}
if (shouldRegister) {
ItemScriptContainer.shapelessRecipesMap.put(container, ingredients);
// TODO: When ExactChoice is patched:
/*if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_13)) {
NamespacedKey key = new NamespacedKey("denizen", "item_" + CoreUtilities.toLowerCase(container.getName()) + "_shapeless_recipe");
ShapelessRecipe recipe = new ShapelessRecipe(key, container.getCleanReference().getItemStack());
for (ItemTag ingredient : ingredients) {
recipe.addIngredient(new RecipeChoice.ExactChoice(ingredient.getItemStack().clone()));
}
Bukkit.addRecipe(recipe);
}
else*/ {
shapelessRecipesMap.put(container, ingredients);
}
}
}

for (Map.Entry<ItemScriptContainer, String> entry : furnace_to_register.entrySet()) {
currentFurnaceRecipes.clear();
for (ItemScriptContainer container : item_scripts.values()) {
if (!container.contains("FURNACE_RECIPE")) {
continue;
}
String string = container.getString("FURNACE_RECIPE");

ItemTag furnace_item = ItemTag.valueOf(entry.getValue(), entry.getKey());
ItemTag furnace_item = ItemTag.valueOf(string, container);
if (furnace_item == null) {
Debug.echoError("Invalid item '" + entry.getValue() + "'");
Debug.echoError("Invalid item '" + string + "', furnace recipe will not be registered for item script '" + container.getName() + "'.");
continue;
}
FurnaceRecipe recipe = new FurnaceRecipe(entry.getKey().getCleanReference().getItemStack(), furnace_item.getMaterial().getMaterial(), furnace_item.getItemStack().getDurability());
Bukkit.getServer().addRecipe(recipe);
}
currentFurnaceRecipes = new HashMap<>(furnace_to_register);

recipes_to_register.clear();
shapeless_to_register.clear();
furnace_to_register.clear();
}

public Map<ItemScriptContainer, String> currentFurnaceRecipes = new HashMap<>();

@EventHandler
public void furnaceSmeltHandler(FurnaceSmeltEvent event) {
if (isItemscript(event.getResult())) {
ItemScriptContainer isc = getItemScriptContainer(event.getResult());
String inp = currentFurnaceRecipes.get(isc);
if (inp != null) {
ItemTag itm = ItemTag.valueOf(inp, isc);
if (itm != null) {
itm.setAmount(1);
ItemTag src = new ItemTag(event.getSource().clone());
src.setAmount(1);
if (!itm.getFullString().equals(src.getFullString())) {
List<Recipe> recipes = Bukkit.getServer().getRecipesFor(event.getSource());
for (Recipe rec : recipes) {
if (rec instanceof FurnaceRecipe) {
// TODO: Also make sure non-script recipes still burn somehow. FurnaceBurnEvent? Maybe also listen to inventory clicking and manually start a burn?
event.setResult(rec.getResult());
return;
}
}
event.setCancelled(true);
return;
}
}
// TODO: When ExactChoice is patched:
/*if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_13)) {
NamespacedKey key = new NamespacedKey("denizen", "item_" + CoreUtilities.toLowerCase(container.getName()) + "_furnace_recipe");
FurnaceRecipe recipe = new FurnaceRecipe(key, container.getCleanReference().getItemStack(), new RecipeChoice.ExactChoice(furnace_item.getItemStack().clone()), 0, 20);
Bukkit.addRecipe(recipe);
}
else*/ {
FurnaceRecipe recipe = new FurnaceRecipe(container.getCleanReference().getItemStack(), furnace_item.getMaterial().getMaterial(), furnace_item.getItemStack().getDurability());
Bukkit.addRecipe(recipe);
currentFurnaceRecipes.put(container, furnace_item);
}
}
}

public static boolean isBound(ItemStack item) {
return (isItemscript(item) && getItemScriptContainer(item).bound);
}

public static boolean isItemscript(ItemStack item) {
return getItemScriptContainer(item) != null;
}
Expand Down Expand Up @@ -221,14 +217,45 @@ public static String createItemScriptID(String name) {
return colors.toString();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////// All the below is for the legacy crafting system, which is still used for 1.12 and some recipe types! ///////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


public static Map<ItemScriptContainer, List<ItemTag>> specialrecipesMap = new HashMap<>();
public static Map<ItemScriptContainer, List<ItemTag>> shapelessRecipesMap = new HashMap<>();
public Map<ItemScriptContainer, ItemTag> currentFurnaceRecipes = new HashMap<>();

@EventHandler
public void furnaceSmeltHandler(FurnaceSmeltEvent event) {
if (isItemscript(event.getResult())) {
ItemScriptContainer isc = getItemScriptContainer(event.getResult());
ItemTag itm = new ItemTag(currentFurnaceRecipes.get(isc).getItemStack().clone());
itm.setAmount(1);
ItemTag src = new ItemTag(event.getSource().clone());
src.setAmount(1);
if (!itm.getFullString().equals(src.getFullString())) {
List<Recipe> recipes = Bukkit.getServer().getRecipesFor(event.getSource());
for (Recipe rec : recipes) {
if (rec instanceof FurnaceRecipe) {
// TODO: Also make sure non-script recipes still burn somehow. FurnaceBurnEvent? Maybe also listen to inventory clicking and manually start a burn?
event.setResult(rec.getResult());
return;
}
}
event.setCancelled(true);
return;
}
}
}

// When special Denizen recipes that have itemscripts as ingredients
// are being used, check crafting matrix for recipe matches whenever
// clicks are made in CRAFTING or RESULT slots
@EventHandler
public void specialRecipeClick(InventoryClickEvent event) {
// Proceed only if at least one special recipe has been stored
if (ItemScriptContainer.specialrecipesMap.isEmpty()
&& ItemScriptContainer.shapelessRecipesMap.isEmpty()) {
if (specialrecipesMap.isEmpty() && shapelessRecipesMap.isEmpty()) {
return;
}

Expand Down Expand Up @@ -343,10 +370,8 @@ public void run() {
// drags (which are entirely separate from clicks) are made in CRAFTING slots
@EventHandler
public void specialRecipeDrag(InventoryDragEvent event) {

// Proceed only if at least one special recipe has been stored
if (ItemScriptContainer.specialrecipesMap.isEmpty()
&& ItemScriptContainer.shapelessRecipesMap.isEmpty()) {
if (specialrecipesMap.isEmpty() && shapelessRecipesMap.isEmpty()) {
return;
}

Expand Down Expand Up @@ -440,8 +465,7 @@ public void run() {
public Map.Entry<ItemScriptContainer, List<ItemTag>> getSpecialRecipeEntry(ItemStack[] matrix) {
// Iterate through all the special recipes
master:
for (Map.Entry<ItemScriptContainer, List<ItemTag>> entry :
ItemScriptContainer.specialrecipesMap.entrySet()) {
for (Map.Entry<ItemScriptContainer, List<ItemTag>> entry : specialrecipesMap.entrySet()) {

// Check if the two sets of items match each other
for (int n = 0; n < 9; n++) {
Expand Down Expand Up @@ -480,8 +504,7 @@ public Map.Entry<ItemScriptContainer, List<ItemTag>> getSpecialRecipeEntry(ItemS

// Forms a shaped recipe from a shapeless recipe
primary:
for (Map.Entry<ItemScriptContainer, List<ItemTag>> entry :
ItemScriptContainer.shapelessRecipesMap.entrySet()) {
for (Map.Entry<ItemScriptContainer, List<ItemTag>> entry : shapelessRecipesMap.entrySet()) {

// Clone recipe & matrix so we can remove items from them
List<ItemStack> entryList = new ArrayList<>();
Expand Down Expand Up @@ -625,55 +648,4 @@ public boolean emulateSpecialRecipeResultShiftClick(CraftingInventory inventory,
}
return false;
}

@EventHandler
public void boundInventoryClickEvent(InventoryClickEvent event) {
// Proceed only if this is a CraftingInventory
if (!(event.getInventory() instanceof CraftingInventory)) {
return;
}

// Proceed only if the click has a cursor item that is bound
ItemStack item = event.getCursor();
if (item == null || !isBound(item)) {
return;
}

if (event.getInventory().getType() != InventoryType.PLAYER) {
event.setCancelled(true);
return;
}

if (!((Player) event.getInventory().getHolder()).getName().equalsIgnoreCase(event.getWhoClicked().getName())) {
event.setCancelled(true);
return;
}
}

@EventHandler
public void boundInventoryDragEvent(InventoryDragEvent event) {
// Proceed only if this is a CraftingInventory
if (!(event.getInventory() instanceof CraftingInventory)) {
return;
}

// Proceed only if the items are bound
ItemStack item = event.getOldCursor();
if (item == null || !isBound(item)) {
return;
}

if (event.getInventory().getType() != InventoryType.PLAYER) {
event.setCancelled(true);
return;
}
}

@EventHandler
public void boundDropItem(PlayerDropItemEvent event) {
// If the item is bound, don't let them drop it!
if (isBound(event.getItemDrop().getItemStack())) {
event.setCancelled(true);
}
}
}

0 comments on commit c5b45fc

Please sign in to comment.