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,176 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import com.dre.brewery.P;
|
||||
import com.dre.brewery.utility.PotionColor;
|
||||
import com.dre.brewery.utility.Tuple;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BCauldronRecipe {
|
||||
public static List<BCauldronRecipe> recipes = new ArrayList<>();
|
||||
public static List<RecipeItem> acceptedCustom = new ArrayList<>(); // All accepted custom and other items
|
||||
public static Set<Material> acceptedSimple = EnumSet.noneOf(Material.class); // All accepted simple items
|
||||
public static Set<Material> acceptedMaterials = EnumSet.noneOf(Material.class); // Fast cache for all accepted Materials
|
||||
|
||||
private String name;
|
||||
private List<RecipeItem> ingredients;
|
||||
//private List<String> particles
|
||||
private PotionColor color;
|
||||
private List<String> lore;
|
||||
|
||||
|
||||
@Nullable
|
||||
public static BCauldronRecipe fromConfig(ConfigurationSection cfg, String id) {
|
||||
BCauldronRecipe recipe = new BCauldronRecipe();
|
||||
|
||||
recipe.name = cfg.getString(id + ".name");
|
||||
if (recipe.name != null) {
|
||||
recipe.name = P.p.color(recipe.name);
|
||||
} else {
|
||||
P.p.errorLog("Missing name for Cauldron-Recipe: " + id);
|
||||
return null;
|
||||
}
|
||||
|
||||
recipe.ingredients = BRecipe.loadIngredients(cfg, id);
|
||||
if (recipe.ingredients == null || recipe.ingredients.isEmpty()) {
|
||||
P.p.errorLog("No ingredients for Cauldron-Recipe: " + recipe.name);
|
||||
return null;
|
||||
}
|
||||
|
||||
String col = cfg.getString(id + ".color");
|
||||
if (col != null) {
|
||||
recipe.color = PotionColor.fromString(col);
|
||||
} else {
|
||||
recipe.color = PotionColor.CYAN;
|
||||
}
|
||||
if (recipe.color == PotionColor.WATER && !col.equals("WATER")) {
|
||||
recipe.color = PotionColor.CYAN;
|
||||
// Don't throw error here as old mc versions will not know even the default colors
|
||||
//P.p.errorLog("Invalid Color '" + col + "' in Cauldron-Recipe: " + recipe.name);
|
||||
//return null;
|
||||
}
|
||||
|
||||
|
||||
List<Tuple<Integer,String>> lore = BRecipe.loadLore(cfg, id + ".lore");
|
||||
if (lore != null && !lore.isEmpty()) {
|
||||
recipe.lore = lore.stream().map(Tuple::second).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return recipe;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<RecipeItem> getIngredients() {
|
||||
return ingredients;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PotionColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getLore() {
|
||||
return lore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find how much these ingredients match the given ones from 0-10.
|
||||
* If any ingredient is missing, returns 0
|
||||
* If all Ingredients and their amounts are equal, returns 10
|
||||
* Returns something between 0 and 10 if all ingredients present, but differing amounts, depending on how much the amount differs.
|
||||
*/
|
||||
public float getIngredientMatch(List<Ingredient> items) {
|
||||
if (items.size() < ingredients.size()) {
|
||||
return 0;
|
||||
}
|
||||
float match = 10;
|
||||
search: for (RecipeItem recipeIng : ingredients) {
|
||||
for (Ingredient ing : items) {
|
||||
if (recipeIng.matches(ing)) {
|
||||
double difference = Math.abs(recipeIng.getAmount() - ing.getAmount());
|
||||
if (difference >= 1000) {
|
||||
return 0;
|
||||
}
|
||||
// The Item Amount is the determining part here, the higher the better.
|
||||
// But let the difference in amount to what the recipe expects have a tiny factor as well.
|
||||
// This way for the same amount, the recipe with the lower difference wins.
|
||||
double factor = ing.getAmount() * (1.0 - (difference / 1000.0)) ;
|
||||
//double mod = 0.1 + (0.9 * Math.exp(-0.03 * difference)); // logarithmic curve from 1 to 0.1
|
||||
double mod = 1 + (0.9 * -Math.exp(-0.03 * factor)); // logarithmic curve from 0.1 to 1, small for a low factor
|
||||
|
||||
P.p.debugLog("Mod for " + recipeIng + ": " + mod);
|
||||
|
||||
|
||||
|
||||
|
||||
match *= mod;
|
||||
continue search;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (items.size() > ingredients.size()) {
|
||||
// If there are too many items in the List, multiply the match by 0.1 per Item thats too much
|
||||
float tooMuch = items.size() - ingredients.size();
|
||||
float mod = 0.1f / tooMuch;
|
||||
match *= mod;
|
||||
}
|
||||
P.p.debugLog("Match for Cauldron Recipe " + name + ": " + match);
|
||||
return match;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BCauldronRecipe{" + name + '}';
|
||||
}
|
||||
|
||||
/*public static boolean acceptItem(ItemStack item) {
|
||||
if (acceptedMaterials.contains(item.getType())) {
|
||||
// Extremely fast way to check for most items
|
||||
return true;
|
||||
}
|
||||
if (!item.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
// If the Item is not on the list, but customized, we have to do more checks
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
if (meta.hasDisplayName() || meta.hasLore()) {
|
||||
for (BItem bItem : acceptedCustom) {
|
||||
if (bItem.matches(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static RecipeItem acceptItem(ItemStack item) {
|
||||
if (!acceptedMaterials.contains(item.getType()) && !item.hasItemMeta()) {
|
||||
// Extremely fast way to check for most items
|
||||
return null;
|
||||
}
|
||||
// If the Item is on the list, or customized, we have to do more checks
|
||||
for (RecipeItem rItem : acceptedItems) {
|
||||
if (rItem.matches(item)) {
|
||||
return rItem;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import com.dre.brewery.P;
|
||||
import com.dre.brewery.utility.BUtil;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
public class BEffect {
|
||||
|
||||
private PotionEffectType type;
|
||||
private short minlvl;
|
||||
private short maxlvl;
|
||||
private short minduration;
|
||||
private short maxduration;
|
||||
private boolean hidden = false;
|
||||
|
||||
|
||||
public BEffect(String effectString) {
|
||||
String[] effectSplit = effectString.split("/");
|
||||
String effect = effectSplit[0];
|
||||
if (effect.equalsIgnoreCase("WEAKNESS") ||
|
||||
effect.equalsIgnoreCase("INCREASE_DAMAGE") ||
|
||||
effect.equalsIgnoreCase("SLOW") ||
|
||||
effect.equalsIgnoreCase("SPEED") ||
|
||||
effect.equalsIgnoreCase("REGENERATION")) {
|
||||
// hide these effects as they put crap into lore
|
||||
// Dont write Regeneration into Lore, its already there storing data!
|
||||
hidden = true;
|
||||
} else if (effect.endsWith("X")) {
|
||||
hidden = true;
|
||||
effect = effect.substring(0, effect.length() - 1);
|
||||
}
|
||||
type = PotionEffectType.getByName(effect);
|
||||
if (type == null) {
|
||||
P.p.errorLog("Effect: " + effect + " does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (effectSplit.length == 3) {
|
||||
String[] range = effectSplit[1].split("-");
|
||||
if (type.isInstant()) {
|
||||
setLvl(range);
|
||||
} else {
|
||||
setLvl(range);
|
||||
range = effectSplit[2].split("-");
|
||||
setDuration(range);
|
||||
}
|
||||
} else if (effectSplit.length == 2) {
|
||||
String[] range = effectSplit[1].split("-");
|
||||
if (type.isInstant()) {
|
||||
setLvl(range);
|
||||
} else {
|
||||
setDuration(range);
|
||||
maxlvl = 3;
|
||||
minlvl = 1;
|
||||
}
|
||||
} else {
|
||||
maxduration = 20;
|
||||
minduration = 10;
|
||||
maxlvl = 3;
|
||||
minlvl = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void setLvl(String[] range) {
|
||||
if (range.length == 1) {
|
||||
maxlvl = (short) P.p.parseInt(range[0]);
|
||||
minlvl = 1;
|
||||
} else {
|
||||
maxlvl = (short) P.p.parseInt(range[1]);
|
||||
minlvl = (short) P.p.parseInt(range[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDuration(String[] range) {
|
||||
if (range.length == 1) {
|
||||
maxduration = (short) P.p.parseInt(range[0]);
|
||||
minduration = (short) (maxduration / 8);
|
||||
} else {
|
||||
maxduration = (short) P.p.parseInt(range[1]);
|
||||
minduration = (short) P.p.parseInt(range[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public PotionEffect generateEffect(int quality) {
|
||||
int duration = calcDuration(quality);
|
||||
int lvl = calcLvl(quality);
|
||||
|
||||
if (lvl < 1 || (duration < 1 && !type.isInstant())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
duration *= 20;
|
||||
if (!P.use1_14) {
|
||||
duration /= type.getDurationModifier();
|
||||
}
|
||||
return type.createEffect(duration, lvl - 1);
|
||||
}
|
||||
|
||||
public void apply(int quality, Player player) {
|
||||
PotionEffect effect = generateEffect(quality);
|
||||
if (effect != null) {
|
||||
BUtil.reapplyPotionEffect(player, effect, true);
|
||||
}
|
||||
}
|
||||
|
||||
public int calcDuration(float quality) {
|
||||
return (int) Math.round(minduration + ((maxduration - minduration) * (quality / 10.0)));
|
||||
}
|
||||
|
||||
public int calcLvl(float quality) {
|
||||
return (int) Math.round(minlvl + ((maxlvl - minlvl) * (quality / 10.0)));
|
||||
}
|
||||
|
||||
public void writeInto(PotionMeta meta, int quality) {
|
||||
if ((calcDuration(quality) > 0 || type.isInstant()) && calcLvl(quality) > 0) {
|
||||
meta.addCustomEffect(type.createEffect(0, 0), true);
|
||||
} else {
|
||||
meta.removeCustomEffect(type);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return type != null && minlvl >= 0 && maxlvl >= 0 && minduration >= 0 && maxduration >= 0;
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,517 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import com.dre.brewery.BIngredients;
|
||||
import com.dre.brewery.Brew;
|
||||
import com.dre.brewery.P;
|
||||
import com.dre.brewery.filedata.BConfig;
|
||||
import com.dre.brewery.utility.PotionColor;
|
||||
import com.dre.brewery.utility.Tuple;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BRecipe {
|
||||
|
||||
public static List<BRecipe> recipes = new ArrayList<>();
|
||||
|
||||
private String[] name;
|
||||
private List<RecipeItem> ingredients = new ArrayList<>(); // Items and amounts
|
||||
private int cookingTime; // time to cook in cauldron
|
||||
private byte distillruns; // runs through the brewer
|
||||
private int distillTime; // time for one distill run in seconds
|
||||
private byte wood; // type of wood the barrel has to consist of
|
||||
private int age; // time in minecraft days for the potions to age in barrels
|
||||
private PotionColor color; // color of the destilled/finished potion
|
||||
private int difficulty; // difficulty to brew the potion, how exact the instruction has to be followed
|
||||
private int alcohol; // Alcohol in perfect potion
|
||||
private List<Tuple<Integer, String>> lore; // Custom Lore on the Potion. The int is for Quality Lore, 0 = any, 1,2,3 = Bad,Middle,Good
|
||||
private ArrayList<BEffect> effects = new ArrayList<>(); // Special Effects when drinking
|
||||
|
||||
public BRecipe() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static BRecipe fromConfig(ConfigurationSection configSectionRecipes, String recipeId) {
|
||||
BRecipe recipe = new BRecipe();
|
||||
String nameList = configSectionRecipes.getString(recipeId + ".name");
|
||||
if (nameList != null) {
|
||||
String[] name = nameList.split("/");
|
||||
if (name.length > 2) {
|
||||
recipe.name = name;
|
||||
} else {
|
||||
recipe.name = new String[1];
|
||||
recipe.name[0] = name[0];
|
||||
}
|
||||
} else {
|
||||
P.p.errorLog(recipeId + ": Recipe Name missing or invalid!");
|
||||
return null;
|
||||
}
|
||||
if (recipe.getRecipeName() == null || recipe.getRecipeName().length() < 1) {
|
||||
P.p.errorLog(recipeId + ": Recipe Name invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
recipe.ingredients = loadIngredients(configSectionRecipes, recipeId);
|
||||
if (recipe.ingredients == null || recipe.ingredients.isEmpty()) {
|
||||
P.p.errorLog("No ingredients for: " + recipe.getRecipeName());
|
||||
return null;
|
||||
}
|
||||
recipe.cookingTime = configSectionRecipes.getInt(recipeId + ".cookingtime", 1);
|
||||
int dis = configSectionRecipes.getInt(recipeId + ".distillruns", 0);
|
||||
if (dis > Byte.MAX_VALUE) {
|
||||
recipe.distillruns = Byte.MAX_VALUE;
|
||||
} else {
|
||||
recipe.distillruns = (byte) dis;
|
||||
}
|
||||
recipe.distillTime = configSectionRecipes.getInt(recipeId + ".distilltime", 0) * 20;
|
||||
recipe.wood = (byte) configSectionRecipes.getInt(recipeId + ".wood", 0);
|
||||
recipe.age = configSectionRecipes.getInt(recipeId + ".age", 0);
|
||||
recipe.difficulty = configSectionRecipes.getInt(recipeId + ".difficulty", 0);
|
||||
recipe.alcohol = configSectionRecipes.getInt(recipeId + ".alcohol", 0);
|
||||
|
||||
String col = configSectionRecipes.getString(recipeId + ".color", "BLUE");
|
||||
recipe.color = PotionColor.fromString(col);
|
||||
if (recipe.color == PotionColor.WATER && !col.equals("WATER")) {
|
||||
P.p.errorLog("Invalid Color '" + col + "' in Recipe: " + recipe.getRecipeName());
|
||||
return null;
|
||||
}
|
||||
|
||||
recipe.lore = loadLore(configSectionRecipes, recipeId + ".lore");
|
||||
|
||||
List<String> effectStringList = configSectionRecipes.getStringList(recipeId + ".effects");
|
||||
if (effectStringList != null) {
|
||||
for (String effectString : effectStringList) {
|
||||
BEffect effect = new BEffect(effectString);
|
||||
if (effect.isValid()) {
|
||||
recipe.effects.add(effect);
|
||||
} else {
|
||||
P.p.errorLog("Error adding Effect to Recipe: " + recipe.getRecipeName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return recipe;
|
||||
}
|
||||
|
||||
public static List<RecipeItem> loadIngredients(ConfigurationSection cfg, String recipeId) {
|
||||
List<String> ingredientsList;
|
||||
if (cfg.isString(recipeId + ".ingredients")) {
|
||||
ingredientsList = new ArrayList<>(1);
|
||||
ingredientsList.add(cfg.getString(recipeId + ".ingredients", "x"));
|
||||
} else {
|
||||
ingredientsList = cfg.getStringList(recipeId + ".ingredients");
|
||||
}
|
||||
if (ingredientsList == null) {
|
||||
return null;
|
||||
}
|
||||
List<RecipeItem> ingredients = new ArrayList<>(ingredientsList.size());
|
||||
listLoop: for (String item : ingredientsList) {
|
||||
String[] ingredParts = item.split("/");
|
||||
int amount = 1;
|
||||
if (ingredParts.length == 2) {
|
||||
amount = P.p.parseInt(ingredParts[1]);
|
||||
if (amount < 1) {
|
||||
P.p.errorLog(recipeId + ": Invalid Item Amount: " + ingredParts[1]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
String[] matParts;
|
||||
if (ingredParts[0].contains(",")) {
|
||||
matParts = ingredParts[0].split(",");
|
||||
} else if (ingredParts[0].contains(";")) {
|
||||
matParts = ingredParts[0].split(";");
|
||||
} else {
|
||||
matParts = ingredParts[0].split("\\.");
|
||||
}
|
||||
|
||||
// Check if this is a Plugin Item
|
||||
String[] pluginItem = matParts[0].split(":");
|
||||
if (pluginItem.length > 1) {
|
||||
RecipeItem custom = PluginItem.fromConfig(pluginItem[0], pluginItem[1]);
|
||||
if (custom != null) {
|
||||
custom.setAmount(amount);
|
||||
custom.makeImmutable();
|
||||
ingredients.add(custom);
|
||||
BCauldronRecipe.acceptedCustom.add(custom);
|
||||
continue;
|
||||
} else {
|
||||
// TODO Maybe load later ie on first use of recipe?
|
||||
P.p.errorLog(recipeId + ": Could not Find Plugin: " + ingredParts[1]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to find this Ingredient as Custom Item
|
||||
for (RecipeItem custom : BConfig.customItems) {
|
||||
if (custom.getConfigId().equalsIgnoreCase(matParts[0])) {
|
||||
custom = custom.getMutableCopy();
|
||||
custom.setAmount(amount);
|
||||
custom.makeImmutable();
|
||||
ingredients.add(custom);
|
||||
if (custom.hasMaterials()) {
|
||||
BCauldronRecipe.acceptedMaterials.addAll(custom.getMaterials());
|
||||
}
|
||||
// Add it as acceptedCustom
|
||||
if (!BCauldronRecipe.acceptedCustom.contains(custom)) {
|
||||
BCauldronRecipe.acceptedCustom.add(custom);
|
||||
/*if (custom instanceof PluginItem || !custom.hasMaterials()) {
|
||||
BCauldronRecipe.acceptedCustom.add(custom);
|
||||
} else if (custom instanceof CustomMatchAnyItem) {
|
||||
CustomMatchAnyItem ma = (CustomMatchAnyItem) custom;
|
||||
if (ma.hasNames() || ma.hasLore()) {
|
||||
BCauldronRecipe.acceptedCustom.add(ma);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
continue listLoop;
|
||||
}
|
||||
}
|
||||
|
||||
Material mat = Material.matchMaterial(matParts[0]);
|
||||
short durability = -1;
|
||||
if (matParts.length == 2) {
|
||||
durability = (short) P.p.parseInt(matParts[1]);
|
||||
}
|
||||
if (mat == null && BConfig.hasVault) {
|
||||
try {
|
||||
net.milkbowl.vault.item.ItemInfo vaultItem = net.milkbowl.vault.item.Items.itemByString(matParts[0]);
|
||||
if (vaultItem != null) {
|
||||
mat = vaultItem.getType();
|
||||
if (durability == -1 && vaultItem.getSubTypeId() != 0) {
|
||||
durability = vaultItem.getSubTypeId();
|
||||
}
|
||||
if (mat.name().contains("LEAVES")) {
|
||||
if (durability > 3) {
|
||||
durability -= 4; // Vault has leaves with higher durability
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
P.p.errorLog("Could not check vault for Item Name");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (mat != null) {
|
||||
RecipeItem rItem;
|
||||
if (durability > -1) {
|
||||
rItem = new SimpleItem(mat, durability);
|
||||
} else {
|
||||
rItem = new SimpleItem(mat);
|
||||
}
|
||||
rItem.setAmount(amount);
|
||||
rItem.makeImmutable();
|
||||
ingredients.add(rItem);
|
||||
BCauldronRecipe.acceptedMaterials.add(mat);
|
||||
BCauldronRecipe.acceptedSimple.add(mat);
|
||||
} else {
|
||||
P.p.errorLog(recipeId + ": Unknown Material: " + ingredParts[0]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return ingredients;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static List<Tuple<Integer, String>> loadLore(ConfigurationSection cfg, String path) {
|
||||
List<String> load = null;
|
||||
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) {
|
||||
List<Tuple<Integer, String>> lore = new ArrayList<>(load.size());
|
||||
for (String line : load) {
|
||||
line = P.p.color(line);
|
||||
int plus = 0;
|
||||
if (line.startsWith("+++")) {
|
||||
plus = 3;
|
||||
line = line.substring(3);
|
||||
} else if (line.startsWith("++")) {
|
||||
plus = 2;
|
||||
line = line.substring(2);
|
||||
} else if (line.startsWith("+")) {
|
||||
plus = 1;
|
||||
line = line.substring(1);
|
||||
}
|
||||
if (line.startsWith(" ")) {
|
||||
line = line.substring(1);
|
||||
}
|
||||
if (!line.startsWith("§")) {
|
||||
line = "§9" + line;
|
||||
}
|
||||
lore.add(new Tuple<>(plus, line));
|
||||
}
|
||||
return lore;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// check every part of the recipe for validity
|
||||
public boolean isValid() {
|
||||
if (ingredients == null || ingredients.isEmpty()) {
|
||||
P.p.errorLog("No ingredients could be loaded for Recipe: " + getRecipeName());
|
||||
return false;
|
||||
}
|
||||
if (cookingTime < 1) {
|
||||
P.p.errorLog("Invalid cooking time '" + cookingTime + "' in Recipe: " + getRecipeName());
|
||||
return false;
|
||||
}
|
||||
if (distillruns < 0) {
|
||||
P.p.errorLog("Invalid distillruns '" + distillruns + "' in Recipe: " + getRecipeName());
|
||||
return false;
|
||||
}
|
||||
if (distillTime < 0) {
|
||||
P.p.errorLog("Invalid distilltime '" + distillTime + "' in Recipe: " + getRecipeName());
|
||||
return false;
|
||||
}
|
||||
if (wood < 0 || wood > 6) {
|
||||
P.p.errorLog("Invalid wood type '" + wood + "' in Recipe: " + getRecipeName());
|
||||
return false;
|
||||
}
|
||||
if (age < 0) {
|
||||
P.p.errorLog("Invalid age time '" + age + "' in Recipe: " + getRecipeName());
|
||||
return false;
|
||||
}
|
||||
if (difficulty < 0 || difficulty > 10) {
|
||||
P.p.errorLog("Invalid difficulty '" + difficulty + "' in Recipe: " + getRecipeName());
|
||||
return false;
|
||||
}
|
||||
if (alcohol < 0) {
|
||||
P.p.errorLog("Invalid alcohol '" + alcohol + "' in Recipe: " + getRecipeName());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// allowed deviation to the recipes count of ingredients at the given difficulty
|
||||
public int allowedCountDiff(int count) {
|
||||
if (count < 8) {
|
||||
count = 8;
|
||||
}
|
||||
int allowedCountDiff = Math.round((float) ((11.0 - difficulty) * (count / 10.0)));
|
||||
|
||||
if (allowedCountDiff == 0) {
|
||||
return 1;
|
||||
}
|
||||
return allowedCountDiff;
|
||||
}
|
||||
|
||||
// allowed deviation to the recipes cooking-time at the given difficulty
|
||||
public int allowedTimeDiff(int time) {
|
||||
if (time < 8) {
|
||||
time = 8;
|
||||
}
|
||||
int allowedTimeDiff = Math.round((float) ((11.0 - difficulty) * (time / 10.0)));
|
||||
|
||||
if (allowedTimeDiff == 0) {
|
||||
return 1;
|
||||
}
|
||||
return allowedTimeDiff;
|
||||
}
|
||||
|
||||
// difference between given and recipe-wanted woodtype
|
||||
public float getWoodDiff(float wood) {
|
||||
return Math.abs(wood - this.wood);
|
||||
}
|
||||
|
||||
public boolean isCookingOnly() {
|
||||
return age == 0 && distillruns == 0;
|
||||
}
|
||||
|
||||
public boolean needsDistilling() {
|
||||
return distillruns != 0;
|
||||
}
|
||||
|
||||
public boolean needsToAge() {
|
||||
return age != 0;
|
||||
}
|
||||
|
||||
// true if given list misses an ingredient
|
||||
public boolean isMissingIngredients(List<Ingredient> list) {
|
||||
if (list.size() < ingredients.size()) {
|
||||
return true;
|
||||
}
|
||||
for (RecipeItem rItem : ingredients) {
|
||||
boolean matches = false;
|
||||
for (Ingredient used : list) {
|
||||
if (rItem.matches(used)) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matches) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Potion from this Recipe with best values. Quality can be set, but will reset to 10 if put in a barrel
|
||||
*
|
||||
* @param quality The Quality of the Brew
|
||||
* @return The Created Item
|
||||
*/
|
||||
public ItemStack create(int quality) {
|
||||
return createBrew(quality).createItem(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Brew from this Recipe with best values. Quality can be set, but will reset to 10 if unset immutable and put in a barrel
|
||||
*
|
||||
* @param quality The Quality of the Brew
|
||||
* @return The created Brew
|
||||
*/
|
||||
public Brew createBrew(int quality) {
|
||||
List<Ingredient> list = new ArrayList<>(ingredients.size());
|
||||
for (RecipeItem rItem : ingredients) {
|
||||
Ingredient ing = rItem.toIngredientGeneric();
|
||||
ing.setAmount(rItem.getAmount());
|
||||
list.add(ing);
|
||||
}
|
||||
|
||||
BIngredients bIngredients = new BIngredients(list, cookingTime);
|
||||
|
||||
return new Brew(bIngredients, quality, distillruns, getAge(), wood, getRecipeName(), false, true, 0);
|
||||
}
|
||||
|
||||
|
||||
// Getter
|
||||
|
||||
// how many of a specific ingredient in the recipe
|
||||
public int amountOf(Ingredient ing) {
|
||||
for (RecipeItem rItem : ingredients) {
|
||||
if (rItem.matches(ing)) {
|
||||
return rItem.getAmount();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// how many of a specific ingredient in the recipe
|
||||
public int amountOf(ItemStack item) {
|
||||
for (RecipeItem rItem : ingredients) {
|
||||
if (rItem.matches(item)) {
|
||||
return rItem.getAmount();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Same as getName(5)
|
||||
public String getRecipeName() {
|
||||
return getName(5);
|
||||
}
|
||||
|
||||
// name that fits the quality
|
||||
public String getName(int quality) {
|
||||
if (name.length > 2) {
|
||||
if (quality <= 3) {
|
||||
return name[0];
|
||||
} else if (quality <= 7) {
|
||||
return name[1];
|
||||
} else {
|
||||
return name[2];
|
||||
}
|
||||
} else {
|
||||
return name[0];
|
||||
}
|
||||
}
|
||||
|
||||
// If one of the quality names equalIgnoreCase given name
|
||||
public boolean hasName(String name) {
|
||||
for (String test : this.name) {
|
||||
if (test.equalsIgnoreCase(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getCookingTime() {
|
||||
return cookingTime;
|
||||
}
|
||||
|
||||
public byte getDistillRuns() {
|
||||
return distillruns;
|
||||
}
|
||||
|
||||
public int getDistillTime() {
|
||||
return distillTime;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PotionColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
// get the woodtype
|
||||
public byte getWood() {
|
||||
return wood;
|
||||
}
|
||||
|
||||
public float getAge() {
|
||||
return (float) age;
|
||||
}
|
||||
|
||||
public int getDifficulty() {
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
public int getAlcohol() {
|
||||
return alcohol;
|
||||
}
|
||||
|
||||
public boolean hasLore() {
|
||||
return lore != null && !lore.isEmpty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<Tuple<Integer, String>> getLore() {
|
||||
return lore;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getLoreForQuality(int quality) {
|
||||
if (lore == null) return null;
|
||||
int plus;
|
||||
if (quality <= 3) {
|
||||
plus = 1;
|
||||
} else if (quality <= 7) {
|
||||
plus = 2;
|
||||
} else {
|
||||
plus = 3;
|
||||
}
|
||||
List<String> list = new ArrayList<>(lore.size());
|
||||
for (Tuple<Integer, String> line : lore) {
|
||||
if (line.first() == 0 || line.first() == plus) {
|
||||
list.add(line.second());
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public ArrayList<BEffect> getEffects() {
|
||||
return effects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BRecipe{" + getRecipeName() + '}';
|
||||
}
|
||||
|
||||
public static BRecipe get(String name) {
|
||||
for (BRecipe recipe : recipes) {
|
||||
if (recipe.getRecipeName().equalsIgnoreCase(name)) {
|
||||
return recipe;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Minecraft Item with custon name and lore.
|
||||
* Mostly used for Custom Items of the Config, but also for general custom items
|
||||
*/
|
||||
public class CustomItem extends RecipeItem implements Ingredient {
|
||||
|
||||
private Material mat;
|
||||
private String name;
|
||||
private List<String> lore;
|
||||
|
||||
public CustomItem() {
|
||||
}
|
||||
|
||||
public CustomItem(Material mat) {
|
||||
this.mat = mat;
|
||||
}
|
||||
|
||||
public CustomItem(Material mat, String name, List<String> lore) {
|
||||
this.mat = mat;
|
||||
this.name = name;
|
||||
this.lore = lore;
|
||||
}
|
||||
|
||||
public CustomItem(ItemStack item) {
|
||||
mat = item.getType();
|
||||
if (!item.hasItemMeta()) {
|
||||
return;
|
||||
}
|
||||
ItemMeta itemMeta = item.getItemMeta();
|
||||
assert itemMeta != null;
|
||||
if (itemMeta.hasDisplayName()) {
|
||||
name = itemMeta.getDisplayName();
|
||||
}
|
||||
if (itemMeta.hasLore()) {
|
||||
lore = itemMeta.getLore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaterials() {
|
||||
return mat != null;
|
||||
}
|
||||
|
||||
public boolean hasName() {
|
||||
return name != null;
|
||||
}
|
||||
|
||||
public boolean hasLore() {
|
||||
return lore != null && !lore.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Material> getMaterials() {
|
||||
List<Material> l = new ArrayList<>(1);
|
||||
l.add(mat);
|
||||
return l;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Material getMaterial() {
|
||||
return mat;
|
||||
}
|
||||
|
||||
protected void setMat(Material mat) {
|
||||
this.mat = mat;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
protected void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getLore() {
|
||||
return lore;
|
||||
}
|
||||
|
||||
protected void setLore(List<String> lore) {
|
||||
this.lore = lore;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ingredient toIngredient(ItemStack forItem) {
|
||||
return ((CustomItem) getMutableCopy());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ingredient toIngredientGeneric() {
|
||||
return ((CustomItem) getMutableCopy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Ingredient ingredient) {
|
||||
if (isSimilar(ingredient)) {
|
||||
return true;
|
||||
}
|
||||
if (ingredient instanceof RecipeItem) {
|
||||
RecipeItem rItem = ((RecipeItem) ingredient);
|
||||
if (rItem instanceof SimpleItem) {
|
||||
// If the recipe item is just a simple item, only match if we also only define material
|
||||
// If this is a custom item with more info, we don't want to match a simple item
|
||||
return hasMaterials() && !hasLore() && !hasName() && getMaterial() == ((SimpleItem) rItem).getMaterial();
|
||||
} else if (rItem instanceof CustomItem) {
|
||||
// If the other is a CustomItem as well and not Similar to ours, it might have more data and we still match
|
||||
CustomItem other = ((CustomItem) rItem);
|
||||
if (mat == null || mat == other.mat) {
|
||||
if (!hasName() || (other.name != null && name.equalsIgnoreCase(other.name))) {
|
||||
return !hasLore() || lore == other.lore || (other.hasLore() && matchLore(other.lore));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
if (mat != null) {
|
||||
if (item.getType() != mat) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (name == null && !hasLore()) {
|
||||
return true;
|
||||
}
|
||||
if (!item.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
if (name != null) {
|
||||
if (!meta.hasDisplayName() || !name.equalsIgnoreCase(meta.getDisplayName())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasLore()) {
|
||||
if (!meta.hasLore()) {
|
||||
return false;
|
||||
}
|
||||
return matchLore(meta.getLore());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this item has lore that matches the given lore.
|
||||
* It matches if our lore is contained in the given lore consecutively, ignoring color of the given lore.
|
||||
*
|
||||
* @param usedLore The given lore to match
|
||||
* @return True if the given lore contains our lore consecutively
|
||||
*/
|
||||
public boolean matchLore(List<String> usedLore) {
|
||||
if (lore == null) return true;
|
||||
int lastIndex = 0;
|
||||
boolean foundFirst = false;
|
||||
for (String line : lore) {
|
||||
do {
|
||||
if (lastIndex == usedLore.size()) {
|
||||
// There is more in lore than in usedLore, bad
|
||||
return false;
|
||||
}
|
||||
String usedLine = usedLore.get(lastIndex);
|
||||
if (line.equalsIgnoreCase(usedLine) || line.equalsIgnoreCase(ChatColor.stripColor(usedLine))) {
|
||||
// If the line is correct, we have found our first and we want all consecutive lines to also equal
|
||||
foundFirst = true;
|
||||
} else if (foundFirst) {
|
||||
// If a consecutive line is not equal, thats bad
|
||||
return false;
|
||||
}
|
||||
lastIndex++;
|
||||
// If we once found one correct line, iterate over 'lore' consecutively
|
||||
} while (!foundFirst);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// We don't compare id here
|
||||
@Override
|
||||
public boolean isSimilar(Ingredient item) {
|
||||
if (this == item) {
|
||||
return true;
|
||||
}
|
||||
if (item instanceof CustomItem) {
|
||||
CustomItem ci = ((CustomItem) item);
|
||||
return mat == ci.mat && Objects.equals(name, ci.name) && Objects.equals(lore, ci.lore);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!super.equals(obj)) return false;
|
||||
if (obj instanceof CustomItem) {
|
||||
return isSimilar(((CustomItem) obj));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), mat, name, lore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CustomItem{" +
|
||||
"id=" + getConfigId() +
|
||||
", mat=" + (mat != null ? mat.name().toLowerCase() : "null") +
|
||||
", name='" + name + '\'' +
|
||||
", loresize: " + (lore != null ? lore.size() : 0) +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveTo(DataOutputStream out) throws IOException {
|
||||
out.writeUTF("CI");
|
||||
if (mat != null) {
|
||||
out.writeBoolean(true);
|
||||
out.writeUTF(mat.name());
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
}
|
||||
if (name != null) {
|
||||
out.writeBoolean(true);
|
||||
out.writeUTF(name);
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
}
|
||||
if (lore != null) {
|
||||
short size = (short) Math.min(lore.size(), Short.MAX_VALUE);
|
||||
out.writeShort(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
out.writeUTF(lore.get(i));
|
||||
}
|
||||
} else {
|
||||
out.writeShort(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static CustomItem loadFrom(ItemLoader loader) {
|
||||
try {
|
||||
DataInputStream in = loader.getInputStream();
|
||||
CustomItem item = new CustomItem();
|
||||
if (in.readBoolean()) {
|
||||
item.mat = Material.getMaterial(in.readUTF());
|
||||
}
|
||||
if (in.readBoolean()) {
|
||||
item.name = in.readUTF();
|
||||
}
|
||||
short size = in.readShort();
|
||||
if (size > 0) {
|
||||
item.lore = new ArrayList<>(size);
|
||||
for (short i = 0; i < size; i++) {
|
||||
item.lore.add(in.readUTF());
|
||||
}
|
||||
}
|
||||
return item;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Needs to be called at Server start
|
||||
public static void registerItemLoader() {
|
||||
Ingredient.registerForItemLoader("CI", CustomItem::loadFrom);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Custom Item that matches any one of the given info.
|
||||
* Does not implement Ingredient, as it can not directly be added to an ingredient
|
||||
*/
|
||||
public class CustomMatchAnyItem extends RecipeItem {
|
||||
|
||||
private List<Material> materials;
|
||||
private List<String> names;
|
||||
private List<String> lore;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasMaterials() {
|
||||
return materials != null && !materials.isEmpty();
|
||||
}
|
||||
|
||||
public boolean hasNames() {
|
||||
return names != null && !names.isEmpty();
|
||||
}
|
||||
|
||||
public boolean hasLore() {
|
||||
return lore != null && !lore.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<Material> getMaterials() {
|
||||
return materials;
|
||||
}
|
||||
|
||||
protected void setMaterials(List<Material> materials) {
|
||||
this.materials = materials;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
protected void setNames(List<String> names) {
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getLore() {
|
||||
return lore;
|
||||
}
|
||||
|
||||
protected void setLore(List<String> lore) {
|
||||
this.lore = lore;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ingredient toIngredient(ItemStack forItem) {
|
||||
// We only use the one part of this item that actually matched the given item to add to ingredients
|
||||
Material mat = getMaterialMatch(forItem);
|
||||
if (mat != null) {
|
||||
return new CustomItem(mat);
|
||||
}
|
||||
String name = getNameMatch(forItem);
|
||||
if (name != null) {
|
||||
return new CustomItem(null, name, null);
|
||||
}
|
||||
String l = getLoreMatch(forItem);
|
||||
if (l != null) {
|
||||
List<String> lore = new ArrayList<>(1);
|
||||
lore.add(l);
|
||||
return new CustomItem(null, null, lore);
|
||||
}
|
||||
|
||||
// Shouldnt happen
|
||||
return new SimpleItem(Material.GOLDEN_HOE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ingredient toIngredientGeneric() {
|
||||
if (hasMaterials()) {
|
||||
return new CustomItem(materials.get(0));
|
||||
}
|
||||
if (hasNames()) {
|
||||
return new CustomItem(null, names.get(0), null);
|
||||
}
|
||||
if (hasLore()) {
|
||||
List<String> l = new ArrayList<>(1);
|
||||
l.add(lore.get(0));
|
||||
return new CustomItem(null, null, l);
|
||||
}
|
||||
|
||||
// Shouldnt happen
|
||||
return new SimpleItem(Material.GOLDEN_HOE);
|
||||
}
|
||||
|
||||
public Material getMaterialMatch(ItemStack item) {
|
||||
if (!hasMaterials()) return null;
|
||||
|
||||
Material usedMat = item.getType();
|
||||
for (Material mat : materials) {
|
||||
if (usedMat == mat) {
|
||||
return mat;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getNameMatch(ItemStack item) {
|
||||
if (!item.hasItemMeta() || !hasNames()) {
|
||||
return null;
|
||||
}
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
if (meta.hasDisplayName()) {
|
||||
return getNameMatch(meta.getDisplayName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getNameMatch(String usedName) {
|
||||
if (!hasNames()) return null;
|
||||
|
||||
for (String name : names) {
|
||||
if (name.equalsIgnoreCase(usedName)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getLoreMatch(ItemStack item) {
|
||||
if (!item.hasItemMeta() || !hasLore()) {
|
||||
return null;
|
||||
}
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
if (meta.hasLore()) {
|
||||
return getLoreMatch(meta.getLore());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getLoreMatch(List<String> usedLore) {
|
||||
if (!hasLore()) return null;
|
||||
|
||||
for (String line : this.lore) {
|
||||
for (String usedLine : usedLore) {
|
||||
if (line.equalsIgnoreCase(usedLine) || line.equalsIgnoreCase(ChatColor.stripColor(usedLine))) {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
if (getMaterialMatch(item) != null) {
|
||||
return true;
|
||||
}
|
||||
if (getNameMatch(item) != null) {
|
||||
return true;
|
||||
}
|
||||
return getLoreMatch(item) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Ingredient ingredient) {
|
||||
// Ingredient can not be CustomMatchAnyItem, so we don't need to/can't check for similarity.
|
||||
if (ingredient instanceof CustomItem) {
|
||||
// If the custom item has any of our data, we match
|
||||
CustomItem ci = ((CustomItem) ingredient);
|
||||
if (hasMaterials() && ci.hasMaterials()) {
|
||||
if (materials.contains(ci.getMaterial())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (hasNames() && ci.hasName()) {
|
||||
if (getNameMatch(ci.getName()) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (hasLore() && ci.hasLore()) {
|
||||
return getLoreMatch(ci.getLore()) != null;
|
||||
}
|
||||
} else if (ingredient instanceof SimpleItem) {
|
||||
// If we contain the Material of the Simple Item, we match
|
||||
SimpleItem si = (SimpleItem) ingredient;
|
||||
return hasMaterials() && materials.contains(si.getMaterial());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
CustomMatchAnyItem that = (CustomMatchAnyItem) o;
|
||||
return Objects.equals(materials, that.materials) &&
|
||||
Objects.equals(names, that.names) &&
|
||||
Objects.equals(lore, that.lore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), materials, names, lore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CustomMatchAnyItem{" +
|
||||
"id=" + getConfigId() +
|
||||
", materials: " + (materials != null ? materials.size() : 0) +
|
||||
", names:" + (names != null ? names.size() : 0) +
|
||||
", loresize: " + (lore != null ? lore.size() : 0) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Item used in a BIngredients, inside BCauldron or Brew.
|
||||
* Represents the Items used as ingredients in the Brewing process
|
||||
* Can be a copy of a recipe item
|
||||
* Will be saved and loaded with a DataStream
|
||||
* Each implementing class needs to register a static function as Item Loader
|
||||
*/
|
||||
public interface Ingredient {
|
||||
|
||||
Map<String, Function<ItemLoader, Ingredient>> LOADERS = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Register a Static function as function that takes an ItemLoader, containing a DataInputStream.
|
||||
* Using the Stream it constructs a corresponding Ingredient for the chosen SaveID
|
||||
*
|
||||
* @param saveID The SaveID should be a small identifier like "AB"
|
||||
* @param loadFct The Static Function that loads the Item, i.e.
|
||||
* public static AItem loadFrom(ItemLoader loader)
|
||||
*/
|
||||
static void registerForItemLoader(String saveID, Function<ItemLoader, Ingredient> loadFct) {
|
||||
LOADERS.put(saveID, loadFct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister the ItemLoader
|
||||
*
|
||||
* @param saveID the chosen SaveID
|
||||
*/
|
||||
static void unRegisterItemLoader(String saveID) {
|
||||
LOADERS.remove(saveID);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Saves this Ingredient to the DataOutputStream.
|
||||
* The first data HAS to be storing the SaveID like:
|
||||
* out.writeUTF("AB");
|
||||
* Amount will be saved automatically and does not have to be saved here.
|
||||
* Saving is done to Brew or for BCauldron into data.yml
|
||||
*
|
||||
* @param out The outputstream to write to
|
||||
* @throws IOException Any IOException
|
||||
*/
|
||||
void saveTo(DataOutputStream out) throws IOException;
|
||||
|
||||
int getAmount();
|
||||
|
||||
void setAmount(int amount);
|
||||
|
||||
/**
|
||||
* Does this Ingredient match the given ItemStack
|
||||
*
|
||||
* @param item The given ItemStack to match
|
||||
* @return true if all required data is contained on the item
|
||||
*/
|
||||
boolean matches(ItemStack item);
|
||||
|
||||
/*
|
||||
* Does this Item match the given RecipeItem.
|
||||
* An IngredientItem matches a RecipeItem if all required info of the RecipeItem are fulfilled on this IngredientItem
|
||||
* This does not imply that the same holds the other way round, as this item might have more info than needed
|
||||
*
|
||||
*
|
||||
* @param recipeItem The recipeItem whose requirements need to be fulfilled
|
||||
* @return True if this matches the required info of the recipeItem
|
||||
*/
|
||||
//boolean matches(RecipeItem recipeItem);
|
||||
|
||||
/**
|
||||
* The other Ingredient is Similar if it is equal except amount
|
||||
*
|
||||
* @param item The item to check similarity with
|
||||
* @return True if this is equal to item except for amount
|
||||
*/
|
||||
boolean isSimilar(Ingredient item);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
|
||||
public class ItemLoader {
|
||||
|
||||
private final int version;
|
||||
private final DataInputStream in;
|
||||
private final String saveID;
|
||||
|
||||
public ItemLoader(int version, DataInputStream in, String saveID) {
|
||||
this.version = version;
|
||||
this.in = in;
|
||||
this.saveID = saveID;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public DataInputStream getInputStream() {
|
||||
return in;
|
||||
}
|
||||
|
||||
public String getSaveID() {
|
||||
return saveID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An Item of a Recipe or as Ingredient in a Brew that corresponds to an item from another plugin.
|
||||
* See /integration/item for examples on how to extend this class.
|
||||
* This class stores items as name of the plugin and item id
|
||||
*/
|
||||
public abstract class PluginItem extends RecipeItem implements Ingredient {
|
||||
|
||||
private static Map<String, Supplier<PluginItem>> constructors = new HashMap<>();
|
||||
|
||||
private String plugin;
|
||||
private String itemId;
|
||||
|
||||
/**
|
||||
* New Empty PluginItem
|
||||
*/
|
||||
public PluginItem() {
|
||||
}
|
||||
|
||||
/**
|
||||
* New PluginItem with both fields already set
|
||||
*
|
||||
* @param plugin The name of the Plugin
|
||||
* @param itemId The ItemID
|
||||
*/
|
||||
public PluginItem(String plugin, String itemId) {
|
||||
this.plugin = plugin;
|
||||
this.itemId = itemId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasMaterials() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Material> getMaterials() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public String getItemId() {
|
||||
return itemId;
|
||||
}
|
||||
|
||||
protected void setPlugin(String plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
protected void setItemId(String itemId) {
|
||||
this.itemId = itemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after Loading this Plugin Item from Config, or (by default) from Ingredients.
|
||||
* Allows Override to define custom actions after an Item was constructed
|
||||
*/
|
||||
protected void onConstruct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this PluginItem Match the other Ingredient.
|
||||
* By default it matches exactly when they are similar, i.e. also a PluginItem with same parameters
|
||||
*
|
||||
* @param ingredient The ingredient that needs to fulfill the requirements
|
||||
* @return True if the ingredient matches the required info of this
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(Ingredient ingredient) {
|
||||
return isSimilar(ingredient);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ingredient toIngredient(ItemStack forItem) {
|
||||
return ((PluginItem) getMutableCopy());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ingredient toIngredientGeneric() {
|
||||
return ((PluginItem) getMutableCopy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimilar(Ingredient item) {
|
||||
if (item instanceof PluginItem) {
|
||||
return Objects.equals(plugin, ((PluginItem) item).plugin) && Objects.equals(itemId, ((PluginItem) item).itemId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
PluginItem item = (PluginItem) o;
|
||||
return Objects.equals(plugin, item.plugin) &&
|
||||
Objects.equals(itemId, item.itemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), plugin, itemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveTo(DataOutputStream out) throws IOException {
|
||||
out.writeUTF("PI");
|
||||
out.writeUTF(plugin);
|
||||
out.writeUTF(itemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when loading this Plugin Item from Ingredients (of a Brew)
|
||||
* The default loading is the same as loading from Config
|
||||
*
|
||||
* @param loader The ItemLoader from which to load the data, use loader.getInputStream()
|
||||
* @return The constructed PluginItem
|
||||
*/
|
||||
public static PluginItem loadFrom(ItemLoader loader) {
|
||||
try {
|
||||
DataInputStream in = loader.getInputStream();
|
||||
String plugin = in.readUTF();
|
||||
String itemId = in.readUTF();
|
||||
PluginItem item = fromConfig(plugin, itemId);
|
||||
if (item == null) {
|
||||
// Plugin not found when loading from Item, use a generic PluginItem that never matches other items
|
||||
item = new PluginItem(plugin, itemId) {
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
return item;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Needs to be called at Server start
|
||||
* Registers the chosen SaveID and the loading Method for loading from Brew or BCauldron
|
||||
*/
|
||||
public static void registerItemLoader() {
|
||||
Ingredient.registerForItemLoader("PI", PluginItem::loadFrom);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when loading trying to find a config defined Plugin Item, or by default also when loading from ingredients
|
||||
* Will call a registered constructor matching the given plugin identifier
|
||||
*
|
||||
* @param plugin The Identifier of the Plugin used in the config
|
||||
* @param itemId The Identifier of the Item belonging to this Plugin used in the config
|
||||
* @return The Plugin Item if found, or null if there is no plugin for the given String
|
||||
*/
|
||||
@Nullable
|
||||
public static PluginItem fromConfig(String plugin, String itemId) {
|
||||
plugin = plugin.toLowerCase();
|
||||
if (constructors.containsKey(plugin)) {
|
||||
PluginItem item = constructors.get(plugin).get();
|
||||
item.setPlugin(plugin);
|
||||
item.setItemId(itemId);
|
||||
item.onConstruct();
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This needs to be called at Server Start before Brewery loads its data.
|
||||
* When implementing this, put Brewery as softdepend in your plugin.yml!
|
||||
* Registers a Constructor that returns a new or cloned instance of a PluginItem
|
||||
* This Constructor will be called when loading a Plugin Item from Config or by default from ingredients
|
||||
* After the Constructor is called, the plugin and itemid will be set on the new instance
|
||||
* Finally the onConstruct is called.
|
||||
*
|
||||
* @param pluginId The ID to use in the config
|
||||
* @param constructor The constructor i.e. YourPluginItem::new
|
||||
*/
|
||||
public static void registerForConfig(String pluginId, Supplier<PluginItem> constructor) {
|
||||
constructors.put(pluginId.toLowerCase(), constructor);
|
||||
}
|
||||
|
||||
public static void unRegisterForConfig(String pluginId) {
|
||||
constructors.remove(pluginId.toLowerCase());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.dre.brewery.recipe;
|
||||
|
||||
import com.dre.brewery.P;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Simple Minecraft Item with just Material
|
||||
*/
|
||||
public class SimpleItem extends RecipeItem implements Ingredient {
|
||||
|
||||
private Material mat;
|
||||
private short dur; // Old Mc
|
||||
|
||||
|
||||
public SimpleItem(Material mat) {
|
||||
this(mat, (short) 0);
|
||||
}
|
||||
|
||||
public SimpleItem(Material mat, short dur) {
|
||||
this.mat = mat;
|
||||
this.dur = dur;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaterials() {
|
||||
return mat != null;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return mat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Material> getMaterials() {
|
||||
List<Material> l = new ArrayList<>(1);
|
||||
l.add(mat);
|
||||
return l;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ingredient toIngredient(ItemStack forItem) {
|
||||
return ((SimpleItem) getMutableCopy());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Ingredient toIngredientGeneric() {
|
||||
return ((SimpleItem) getMutableCopy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
if (!mat.equals(item.getType())) {
|
||||
return false;
|
||||
}
|
||||
//noinspection deprecation
|
||||
return P.use1_13 || dur == item.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Ingredient ingredient) {
|
||||
if (isSimilar(ingredient)) {
|
||||
return true;
|
||||
}
|
||||
if (ingredient instanceof RecipeItem) {
|
||||
if (!((RecipeItem) ingredient).hasMaterials()) {
|
||||
return false;
|
||||
}
|
||||
if (ingredient instanceof CustomItem) {
|
||||
// Only match if the Custom Item also only defines material
|
||||
// If the custom item has more info like name and lore, it is not supposed to match a simple item
|
||||
CustomItem ci = (CustomItem) ingredient;
|
||||
return !ci.hasLore() && !ci.hasName() && mat == ci.getMaterial();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimilar(Ingredient item) {
|
||||
if (this == item) {
|
||||
return true;
|
||||
}
|
||||
if (item instanceof SimpleItem) {
|
||||
SimpleItem si = ((SimpleItem) item);
|
||||
return si.mat == mat && si.dur == dur;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
SimpleItem item = (SimpleItem) o;
|
||||
return dur == item.dur &&
|
||||
mat == item.mat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), mat, dur);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SimpleItem{" +
|
||||
"mat=" + mat.name().toLowerCase() +
|
||||
" amount=" + getAmount() +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveTo(DataOutputStream out) throws IOException {
|
||||
out.writeUTF("SI");
|
||||
out.writeUTF(mat.name());
|
||||
out.writeShort(dur);
|
||||
}
|
||||
|
||||
public static SimpleItem loadFrom(ItemLoader loader) {
|
||||
try {
|
||||
DataInputStream in = loader.getInputStream();
|
||||
Material mat = Material.getMaterial(in.readUTF());
|
||||
if (mat != null) {
|
||||
SimpleItem item = new SimpleItem(mat, in.readShort());
|
||||
return item;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Needs to be called at Server start
|
||||
public static void registerItemLoader() {
|
||||
Ingredient.registerForItemLoader("SI", SimpleItem::loadFrom);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user