mirror of
https://github.com/exituser/Brewery.git
synced 2026-09-17 10:08:54 +00:00
Rewrite of the Custom item into RecipeItem
and Ingredient with subclasses Implemented adding custom items to Ingredients Added support for plugin-items
This commit is contained in:
@@ -0,0 +1,314 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import com.dre.brewery.P;
|
||||
import com.dre.brewery.filedata.BConfig;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Item that can be used in a Recipe.
|
||||
* They are not necessarily only loaded from config
|
||||
* They are immutable if used in a recipe. If one implements Ingredient,
|
||||
* it can be used as mutable copy directly in a
|
||||
* BIngredients. Otherwise it needs to be converted to an Ingredient
|
||||
*/
|
||||
public abstract class RecipeItem implements Cloneable {
|
||||
|
||||
private String cfgId;
|
||||
private int amount;
|
||||
private boolean immutable = false;
|
||||
|
||||
|
||||
/**
|
||||
* Does this RecipeItem match the given ItemStack?
|
||||
* Used to determine if the given item corresponds to this recipeitem
|
||||
*
|
||||
* @param item The ItemStack for comparison
|
||||
* @return True if the given item matches this recipeItem
|
||||
*/
|
||||
public abstract boolean matches(ItemStack item);
|
||||
|
||||
/**
|
||||
* Does this Item match the given Ingredient.
|
||||
* A RecipeItem matches an Ingredient if all required info of the RecipeItem are fulfilled on the Ingredient
|
||||
* This does not imply that the same holds the other way round, as the ingredient item might have more info than needed
|
||||
*
|
||||
*
|
||||
* @param ingredient The ingredient that needs to fulfill the requirements
|
||||
* @return True if the ingredient matches the required info of this
|
||||
*/
|
||||
public abstract boolean matches(Ingredient ingredient);
|
||||
|
||||
/**
|
||||
* Get the Corresponding Ingredient Item. For Items implementing Ingredient, just getMutableCopy()
|
||||
* This is called when this recipe item is added to a BIngredients
|
||||
*
|
||||
* @param forItem The ItemStack that has previously matched this RecipeItem. Used if the resulting Ingredient needs more info from the ItemStack
|
||||
* @return The IngredientItem corresponding to this RecipeItem
|
||||
*/
|
||||
@NotNull
|
||||
public abstract Ingredient toIngredient(ItemStack forItem);
|
||||
|
||||
/**
|
||||
* Gets a Generic Ingredient for this recipe item
|
||||
*/
|
||||
@NotNull
|
||||
public abstract Ingredient toIngredientGeneric();
|
||||
|
||||
/**
|
||||
* @return True if this recipeItem has one or more materials that could classify an item. if true, getMaterials() is NotNull
|
||||
*/
|
||||
public abstract boolean hasMaterials();
|
||||
|
||||
/**
|
||||
* @return List of one or more Materials this recipeItem uses.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract List<Material> getMaterials();
|
||||
|
||||
/**
|
||||
* @return The Id this Item uses in the config in the custom-items section
|
||||
*/
|
||||
@Nullable
|
||||
public String getConfigId() {
|
||||
return cfgId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Amount of this Item in a Recipe
|
||||
*/
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Amount of this Item in a Recipe
|
||||
* The amount can not be set on an existing item in a recipe or existing custom item.
|
||||
* To change amount you need to use getMutableCopy() and change the amount on the copy
|
||||
*
|
||||
* @param amount The new amount
|
||||
*/
|
||||
public void setAmount(int amount) {
|
||||
if (immutable) throw new IllegalStateException("Setting amount only possible on mutable copy");
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this Item immutable, for example when loaded from config. Used so if this is added to BIngredients,
|
||||
* it needs to be cloned before changing anything like amount
|
||||
*/
|
||||
public void makeImmutable() {
|
||||
immutable = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a shallow clone of this RecipeItem whose fields like amount can be changed.
|
||||
*
|
||||
* @return A mutable copy of this
|
||||
*/
|
||||
public RecipeItem getMutableCopy() {
|
||||
try {
|
||||
RecipeItem i = (RecipeItem) super.clone();
|
||||
i.immutable = false;
|
||||
return i;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find a matching RecipeItem for this item. It checks custom items and if it has found a unique custom item
|
||||
* it will return that. If there are multiple matching custom items, a new CustomItem with all item info is returned
|
||||
* If there is no matching CustomItem, it will return a SimpleItem with the items type
|
||||
*
|
||||
* @param item The Item for which to find a matching RecipeItem
|
||||
* @param acceptAll If true it will accept any item and return a SimpleItem even if not on the accepted list
|
||||
* If false it will return null if the item is not acceptable by the Cauldron
|
||||
* @return The Matched CustomItem, new CustomItem with all item info or SimpleItem
|
||||
*/
|
||||
@Nullable
|
||||
@Contract("_, true -> !null")
|
||||
public static RecipeItem getMatchingRecipeItem(ItemStack item, boolean acceptAll) {
|
||||
RecipeItem rItem = null;
|
||||
boolean multiMatch = false;
|
||||
for (RecipeItem ri : BCauldronRecipe.acceptedCustom) {
|
||||
// If we already have a multi match, only check if there is a PluginItem that matches more strictly
|
||||
if (!multiMatch || (ri instanceof PluginItem)) {
|
||||
if (ri.matches(item)) {
|
||||
// If we match a plugin item, thats a very strict match, so immediately return it
|
||||
if (ri instanceof PluginItem) {
|
||||
return ri;
|
||||
}
|
||||
if (rItem == null) {
|
||||
rItem = ri;
|
||||
} else {
|
||||
multiMatch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (multiMatch) {
|
||||
// We have multiple Custom Items matching, so just store all item info
|
||||
return new CustomItem(item);
|
||||
}
|
||||
if (rItem == null && (acceptAll || BCauldronRecipe.acceptedSimple.contains(item.getType()))) {
|
||||
// No Custom item found
|
||||
if (P.use1_13) {
|
||||
return new SimpleItem(item.getType());
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
return new SimpleItem(item.getType(), item.getDurability());
|
||||
}
|
||||
}
|
||||
return rItem;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static RecipeItem fromConfigCustom(ConfigurationSection cfg, String id) {
|
||||
RecipeItem rItem;
|
||||
if (cfg.getBoolean(id + ".matchAny", false)) {
|
||||
rItem = new CustomMatchAnyItem();
|
||||
} else {
|
||||
rItem = new CustomItem();
|
||||
}
|
||||
|
||||
rItem.cfgId = id;
|
||||
rItem.immutable = true;
|
||||
|
||||
List<Material> materials;
|
||||
List<String> names;
|
||||
List<String> lore;
|
||||
|
||||
List<String> load = null;
|
||||
String path = id + ".material";
|
||||
if (cfg.isString(path)) {
|
||||
load = new ArrayList<>(1);
|
||||
load.add(cfg.getString(path));
|
||||
} else if (cfg.isList(path)) {
|
||||
load = cfg.getStringList(path);
|
||||
}
|
||||
if (load != null && !load.isEmpty()) {
|
||||
if ((materials = loadMaterials(load)) == null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
materials = new ArrayList<>(0);
|
||||
}
|
||||
|
||||
load = null;
|
||||
path = id + ".name";
|
||||
if (cfg.isString(path)) {
|
||||
load = new ArrayList<>(1);
|
||||
load.add(cfg.getString(path));
|
||||
} else if (cfg.isList(path)) {
|
||||
load = cfg.getStringList(path);
|
||||
}
|
||||
if (load != null && !load.isEmpty()) {
|
||||
names = load.stream().map(l -> P.p.color(l)).collect(Collectors.toList());
|
||||
if (P.use1_13) {
|
||||
// In 1.13 trailing Color white is removed from display names
|
||||
names = names.stream().map(l -> l.startsWith("§f") ? l.substring(2) : l).collect(Collectors.toList());
|
||||
}
|
||||
} else {
|
||||
names = new ArrayList<>(0);
|
||||
}
|
||||
|
||||
load = null;
|
||||
path = id + ".lore";
|
||||
if (cfg.isString(path)) {
|
||||
load = new ArrayList<>(1);
|
||||
load.add(cfg.getString(path));
|
||||
} else if (cfg.isList(path)) {
|
||||
load = cfg.getStringList(path);
|
||||
}
|
||||
if (load != null && !load.isEmpty()) {
|
||||
lore = load.stream().map(l -> P.p.color(l)).collect(Collectors.toList());
|
||||
} else {
|
||||
lore = new ArrayList<>(0);
|
||||
}
|
||||
|
||||
if (materials.isEmpty() && names.isEmpty() && lore.isEmpty()) {
|
||||
P.p.errorLog("No Config Entries found for Custom Item");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (rItem instanceof CustomItem) {
|
||||
CustomItem cItem = ((CustomItem) rItem);
|
||||
if (!materials.isEmpty()) {
|
||||
cItem.setMat(materials.get(0));
|
||||
}
|
||||
if (!names.isEmpty()) {
|
||||
cItem.setName(names.get(0));
|
||||
}
|
||||
cItem.setLore(lore);
|
||||
} else {
|
||||
CustomMatchAnyItem maItem = (CustomMatchAnyItem) rItem;
|
||||
maItem.setMaterials(materials);
|
||||
maItem.setNames(names);
|
||||
maItem.setLore(lore);
|
||||
}
|
||||
|
||||
return rItem;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static List<Material> loadMaterials(List<String> ingredientsList) {
|
||||
List<Material> materials = new ArrayList<>(ingredientsList.size());
|
||||
for (String item : ingredientsList) {
|
||||
String[] ingredParts = item.split("/");
|
||||
if (ingredParts.length == 2) {
|
||||
P.p.errorLog("Item Amount can not be specified for Custom Items: " + item);
|
||||
return null;
|
||||
}
|
||||
Material mat = Material.matchMaterial(ingredParts[0]);
|
||||
|
||||
if (mat == null && BConfig.hasVault) {
|
||||
try {
|
||||
net.milkbowl.vault.item.ItemInfo vaultItem = net.milkbowl.vault.item.Items.itemByString(ingredParts[0]);
|
||||
if (vaultItem != null) {
|
||||
mat = vaultItem.getType();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
P.p.errorLog("Could not check vault for Item Name");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (mat != null) {
|
||||
materials.add(mat);
|
||||
} else {
|
||||
P.p.errorLog("Unknown Material: " + ingredParts[0]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return materials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof RecipeItem)) return false;
|
||||
RecipeItem that = (RecipeItem) o;
|
||||
return amount == that.amount &&
|
||||
immutable == that.immutable &&
|
||||
Objects.equals(cfgId, that.cfgId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(cfgId, amount, immutable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RecipeItem{(" + getClass().getSimpleName() + ") ID: " + getConfigId() + " Materials: " + (hasMaterials() ? getMaterials().size() : 0) + " Amount: " + getAmount();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user