ingredients, int cookedTime, boolean legacy) {
+ this(ingredients, cookedTime);
+ if (legacy) {
+ this.id = lastId;
+ lastId++;
}
}
- // Add an ingredient to this
+ /**
+ * Force add an ingredient to this.
+ * Will not check if item is acceptable
+ *
+ * @param ingredient the item to add
+ */
public void add(ItemStack ingredient) {
- addMaterial(ingredient);
- for (ItemStack item : ingredients) {
- if (item.isSimilar(ingredient)) {
- item.setAmount(item.getAmount() + ingredient.getAmount());
+ for (Ingredient existing : ingredients) {
+ if (existing.matches(ingredient)) {
+ existing.setAmount(existing.getAmount() + 1);
return;
}
}
- ingredients.add(ingredient);
+
+ Ingredient ing = RecipeItem.getMatchingRecipeItem(ingredient, true).toIngredient(ingredient);
+ ing.setAmount(1);
+ ingredients.add(ing);
}
- private void addMaterial(ItemStack ingredient) {
- if (materials.containsKey(ingredient.getType())) {
- int newAmount = materials.get(ingredient.getType()) + ingredient.getAmount();
- materials.put(ingredient.getType(), newAmount);
- } else {
- materials.put(ingredient.getType(), ingredient.getAmount());
+ /**
+ * Add an ingredient to this with corresponding RecipeItem
+ *
+ * @param ingredient the item to add
+ * @param rItem the RecipeItem that matches the ingredient
+ */
+ public void add(ItemStack ingredient, RecipeItem rItem) {
+ Ingredient ingredientItem = rItem.toIngredient(ingredient);
+ for (Ingredient existing : ingredients) {
+ if (existing.isSimilar(ingredientItem)) {
+ existing.setAmount(existing.getAmount() + 1);
+ return;
+ }
}
+ ingredientItem.setAmount(1);
+ ingredients.add(ingredientItem);
}
- // returns an Potion item with cooked ingredients
+ /**
+ * returns an Potion item with cooked ingredients
+ */
public ItemStack cook(int state) {
ItemStack potion = new ItemStack(Material.POTION);
PotionMeta potionMeta = (PotionMeta) potion.getItemMeta();
+ assert potionMeta != null;
// cookedTime is always time in minutes, state may differ with number of ticks
cookedTime = state;
String cookedName = null;
BRecipe cookRecipe = getCookRecipe();
+ Brew brew;
- int uid = Brew.generateUID();
+ //int uid = Brew.generateUID();
if (cookRecipe != null) {
// Potion is best with cooking only
int quality = (int) Math.round((getIngredientQuality(cookRecipe) + getCookingQuality(cookRecipe, false)) / 2.0);
- P.p.debugLog("cooked potion has Quality: " + quality);
- Brew brew = new Brew(uid, quality, cookRecipe, this);
- Brew.addOrReplaceEffects(potionMeta, brew.getEffects(), brew.getQuality());
+ int alc = (int) Math.round(cookRecipe.getAlcohol() * ((float) quality / 10.0f));
+ P.p.debugLog("cooked potion has Quality: " + quality + ", Alc: " + alc);
+ brew = new Brew(quality, alc, cookRecipe, this);
+ BrewLore lore = new BrewLore(brew, potionMeta);
+ lore.updateQualityStars(false);
+ lore.updateCustomLore();
+ lore.updateAlc(false);
+ lore.addOrReplaceEffects(brew.getEffects(), brew.getQuality());
+ lore.write();
cookedName = cookRecipe.getName(quality);
- Brew.PotionColor.fromString(cookRecipe.getColor()).colorBrew(potionMeta, potion, false);
+ cookRecipe.getColor().colorBrew(potionMeta, potion, false);
} else {
// new base potion
- new Brew(uid, this);
+ brew = new Brew(this);
if (state <= 1) {
cookedName = P.p.languageReader.get("Brew_ThickBrew");
- Brew.PotionColor.BLUE.colorBrew(potionMeta, potion, false);
+ PotionColor.BLUE.colorBrew(potionMeta, potion, false);
} else {
- for (Material ingredient : materials.keySet()) {
- if (cookedNames.containsKey(ingredient)) {
- // if more than half of the ingredients is of one kind
- if (materials.get(ingredient) > (getIngredientsCount() / 2)) {
- cookedName = cookedNames.get(ingredient);
- Brew.PotionColor.CYAN.colorBrew(potionMeta, potion, true);
- }
+ BCauldronRecipe cauldronRecipe = getCauldronRecipe();
+ if (cauldronRecipe != null) {
+ P.p.debugLog("Found Cauldron Recipe: " + cauldronRecipe.getName());
+ cookedName = cauldronRecipe.getName();
+ if (cauldronRecipe.getLore() != null) {
+ BrewLore lore = new BrewLore(brew, potionMeta);
+ lore.addCauldronLore(cauldronRecipe.getLore());
+ lore.write();
}
+ cauldronRecipe.getColor().colorBrew(potionMeta, potion, true);
}
}
}
if (cookedName == null) {
// if no name could be found
cookedName = P.p.languageReader.get("Brew_Undefined");
- Brew.PotionColor.CYAN.colorBrew(potionMeta, potion, true);
+ PotionColor.CYAN.colorBrew(potionMeta, potion, true);
}
potionMeta.setDisplayName(P.p.color("&f" + cookedName));
- if (!P.use1_14) {
+ //if (!P.use1_14) {
// Before 1.14 the effects duration would strangely be only a quarter of what we tell it to be
// This is due to the Duration Modifier, that is removed in 1.14
- uid *= 4;
- }
+ // uid *= 4;
+ //}
// This effect stores the UID in its Duration
- potionMeta.addCustomEffect((PotionEffectType.REGENERATION).createEffect(uid, 0), true);
+ //potionMeta.addCustomEffect((PotionEffectType.REGENERATION).createEffect((uid * 4), 0), true);
+
+ brew.touch();
+ BrewModifyEvent modifyEvent = new BrewModifyEvent(brew, potionMeta, BrewModifyEvent.Type.FILL);
+ P.p.getServer().getPluginManager().callEvent(modifyEvent);
+ if (modifyEvent.isCancelled()) {
+ return null;
+ }
+ brew.save(potionMeta);
potion.setItemMeta(potionMeta);
+ P.p.metricsForCreate(false);
return potion;
}
- // returns amount of ingredients
- private int getIngredientsCount() {
+ /**
+ * returns amount of ingredients
+ */
+ public int getIngredientsCount() {
int count = 0;
- for (ItemStack item : ingredients) {
- count += item.getAmount();
+ for (Ingredient ing : ingredients) {
+ count += ing.getAmount();
}
return count;
}
@@ -137,8 +199,9 @@ public class BIngredients {
return cookedTime;
}
- // best recipe for current state of potion, STILL not always returns the
- // correct one...
+ /**
+ * best recipe for current state of potion, STILL not always returns the correct one...
+ */
public BRecipe getBestRecipe(float wood, float time, boolean distilled) {
float quality = 0;
int ingredientQuality;
@@ -146,7 +209,7 @@ public class BIngredients {
int woodQuality;
int ageQuality;
BRecipe bestRecipe = null;
- for (BRecipe recipe : recipes) {
+ for (BRecipe recipe : BRecipe.getAllRecipes()) {
ingredientQuality = getIngredientQuality(recipe);
cookingQuality = getCookingQuality(recipe, distilled);
@@ -179,8 +242,9 @@ public class BIngredients {
return bestRecipe;
}
- // returns recipe that is cooking only and matches the ingredients and
- // cooking time
+ /**
+ * returns recipe that is cooking only and matches the ingredients and cooking time
+ */
public BRecipe getCookRecipe() {
BRecipe bestRecipe = getBestRecipe(0, 0, false);
@@ -193,9 +257,31 @@ public class BIngredients {
return null;
}
- // returns the currently best matching recipe for distilling for the
- // ingredients and cooking time
- public BRecipe getdistillRecipe(float wood, float time) {
+ /**
+ * Get Cauldron Recipe that matches the contents of the cauldron
+ */
+ @Nullable
+ public BCauldronRecipe getCauldronRecipe() {
+ BCauldronRecipe best = null;
+ float bestMatch = 0;
+ float match;
+ for (BCauldronRecipe recipe : BCauldronRecipe.getAllRecipes()) {
+ match = recipe.getIngredientMatch(ingredients);
+ if (match >= 10) {
+ return recipe;
+ }
+ if (match > bestMatch) {
+ best = recipe;
+ bestMatch = match;
+ }
+ }
+ return best;
+ }
+
+ /**
+ * returns the currently best matching recipe for distilling for the ingredients and cooking time
+ */
+ public BRecipe getDistillRecipe(float wood, float time) {
BRecipe bestRecipe = getBestRecipe(wood, time, true);
// Check if best recipe needs to be destilled
@@ -207,8 +293,9 @@ public class BIngredients {
return null;
}
- // returns currently best matching recipe for ingredients, cooking- and
- // ageingtime
+ /**
+ * returns currently best matching recipe for ingredients, cooking- and ageingtime
+ */
public BRecipe getAgeRecipe(float wood, float time, boolean distilled) {
BRecipe bestRecipe = getBestRecipe(wood, time, distilled);
@@ -220,8 +307,9 @@ public class BIngredients {
return null;
}
- // returns the quality of the ingredients conditioning given recipe, -1 if
- // no recipe is near them
+ /**
+ * returns the quality of the ingredients conditioning given recipe, -1 if no recipe is near them
+ */
public int getIngredientQuality(BRecipe recipe) {
float quality = 10;
int count;
@@ -230,20 +318,9 @@ public class BIngredients {
// when ingredients are not complete
return -1;
}
- ArrayList mergedChecked = new ArrayList<>();
- for (ItemStack ingredient : ingredients) {
- if (mergedChecked.contains(ingredient.getType())) {
- // This ingredient type was already checked as part of a merged material
- continue;
- }
+ for (Ingredient ingredient : ingredients) {
int amountInRecipe = recipe.amountOf(ingredient);
- // If we dont consider durability for this ingredient, check the merged material
- if (recipe.hasExactData(ingredient)) {
- count = ingredient.getAmount();
- } else {
- mergedChecked.add(ingredient.getType());
- count = materials.get(ingredient.getType());
- }
+ count = ingredient.getAmount();
if (amountInRecipe == 0) {
// this ingredient doesnt belong into the recipe
if (count > (getIngredientsCount() / 2)) {
@@ -270,7 +347,9 @@ public class BIngredients {
return -1;
}
- // returns the quality regarding the cooking-time conditioning given Recipe
+ /**
+ * returns the quality regarding the cooking-time conditioning given Recipe
+ */
public int getCookingQuality(BRecipe recipe, boolean distilled) {
if (!recipe.needsDistilling() == distilled) {
return -1;
@@ -286,15 +365,19 @@ public class BIngredients {
return -1;
}
- // returns pseudo quality of distilling. 0 if doesnt match the need of the recipes distilling
- public int getDistillQuality(BRecipe recipe, int distillRuns) {
+ /**
+ * returns pseudo quality of distilling. 0 if doesnt match the need of the recipes distilling
+ */
+ public int getDistillQuality(BRecipe recipe, byte distillRuns) {
if (recipe.needsDistilling() != distillRuns > 0) {
return 0;
}
return 10 - Math.abs(recipe.getDistillRuns() - distillRuns);
}
- // returns the quality regarding the barrel wood conditioning given Recipe
+ /**
+ * returns the quality regarding the barrel wood conditioning given Recipe
+ */
public int getWoodQuality(BRecipe recipe, float wood) {
if (recipe.getWood() == 0) {
// type of wood doesnt matter
@@ -305,24 +388,100 @@ public class BIngredients {
return Math.max(quality, 0);
}
- // returns the quality regarding the ageing time conditioning given Recipe
+ /**
+ * returns the quality regarding the ageing time conditioning given Recipe
+ */
public int getAgeQuality(BRecipe recipe, float time) {
int quality = 10 - Math.round(Math.abs(time - recipe.getAge()) * ((float) recipe.getDifficulty() / 2));
return Math.max(quality, 0);
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof BIngredients)) return false;
+ BIngredients other = ((BIngredients) obj);
+ return cookedTime == other.cookedTime &&
+ ingredients.equals(other.ingredients);
+ }
+
// Creates a copy ingredients
- public BIngredients clone() {
+ public BIngredients copy() {
BIngredients copy = new BIngredients();
copy.ingredients.addAll(ingredients);
- copy.materials.putAll(materials);
copy.cookedTime = cookedTime;
return copy;
}
+ @Override
+ public String toString() {
+ return "BIngredients{" +
+ "cookedTime=" + cookedTime +
+ ", total ingredients: " + getIngredientsCount() + '}';
+ }
+
+ /*public void testStore(DataOutputStream out) throws IOException {
+ out.writeInt(cookedTime);
+ out.writeByte(ingredients.size());
+ for (ItemStack item : ingredients) {
+ out.writeUTF(item.getType().name());
+ out.writeShort(item.getDurability());
+ out.writeShort(item.getAmount());
+ }
+ }
+
+ public void testLoad(DataInputStream in) throws IOException {
+ if (in.readInt() != cookedTime) {
+ P.p.log("cookedtime wrong");
+ }
+ if (in.readUnsignedByte() != ingredients.size()) {
+ P.p.log("size wrong");
+ return;
+ }
+ for (ItemStack item : ingredients) {
+ if (!in.readUTF().equals(item.getType().name())) {
+ P.p.log("name wrong");
+ }
+ if (in.readShort() != item.getDurability()) {
+ P.p.log("dur wrong");
+ }
+ if (in.readShort() != item.getAmount()) {
+ P.p.log("amount wrong");
+ }
+ }
+ }*/
+
+ public void save(DataOutputStream out) throws IOException {
+ out.writeInt(cookedTime);
+ out.writeByte(ingredients.size());
+ for (Ingredient ing : ingredients) {
+ ing.saveTo(out);
+ out.writeShort(Math.min(ing.getAmount(), Short.MAX_VALUE));
+ }
+ }
+
+ public static BIngredients load(DataInputStream in, short dataVersion) throws IOException {
+ int cookedTime = in.readInt();
+ byte size = in.readByte();
+ List ing = new ArrayList<>(size);
+ for (; size > 0; size--) {
+ ItemLoader itemLoader = new ItemLoader(dataVersion, in, in.readUTF());
+ if (Ingredient.LOADERS.containsKey(itemLoader.getSaveID())) {
+ Ingredient loaded = Ingredient.LOADERS.get(itemLoader.getSaveID()).apply(itemLoader);
+ int amount = in.readShort();
+ if (loaded != null) {
+ loaded.setAmount(amount);
+ ing.add(loaded);
+ }
+ }
+ }
+ return new BIngredients(ing, cookedTime);
+ }
+
// saves data into main Ingredient section. Returns the save id
- public int save(ConfigurationSection config) {
+ // Only needed for legacy potions
+ public int saveLegacy(ConfigurationSection config) {
String path = "Ingredients." + id;
if (cookedTime != 0) {
config.set(path + ".cookedTime", cookedTime);
@@ -332,13 +491,26 @@ public class BIngredients {
}
//convert the ingredient Material to String
- public Map serializeIngredients() {
+ /*public Map serializeIngredients() {
Map mats = new HashMap<>();
for (ItemStack item : ingredients) {
String mat = item.getType().name() + "," + item.getDurability();
mats.put(mat, item.getAmount());
}
return mats;
+ }*/
+
+ // Serialize Ingredients to String for storing in yml, ie for Cauldrons
+ public String serializeIngredients() {
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ try (DataOutputStream out = new DataOutputStream(new Base91EncoderStream(byteStream))) {
+ out.writeByte(Brew.SAVE_VER);
+ save(out);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return "";
+ }
+ return byteStream.toString();
}
}
diff --git a/src/com/dre/brewery/BPlayer.java b/src/com/dre/brewery/BPlayer.java
index 14111b4..289fd7c 100644
--- a/src/com/dre/brewery/BPlayer.java
+++ b/src/com/dre/brewery/BPlayer.java
@@ -1,5 +1,12 @@
package com.dre.brewery;
+import com.dre.brewery.api.events.PlayerEffectEvent;
+import com.dre.brewery.api.events.PlayerPukeEvent;
+import com.dre.brewery.api.events.PlayerPushEvent;
+import com.dre.brewery.api.events.brew.BrewDrinkEvent;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.recipe.BEffect;
+import com.dre.brewery.utility.BUtil;
import org.apache.commons.lang.mutable.MutableInt;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -10,8 +17,11 @@ import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
+import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -24,20 +34,9 @@ public class BPlayer {
private static int taskId;
private static boolean modAge = true;
private static Random pukeRand;
- private static Method gh;
+ private static Method itemHandle;
private static Field age;
- // Settings
- public static Map drainItems = new HashMap<>();// DrainItem Material and Strength
- public static Material pukeItem;
- public static int pukeDespawntime;
- public static int hangoverTime;
- public static boolean overdrinkKick;
- public static boolean enableHome;
- public static boolean enableLoginDisallow;
- public static boolean enablePuke;
- public static String homeType;
-
private int quality = 0;// = quality of drunkeness * drunkeness
private int drunkeness = 0;// = amount of drunkeness
private int offlineDrunk = 0;// drunkeness when gone offline
@@ -55,14 +54,16 @@ public class BPlayer {
players.put(name, this);
}
+ @Nullable
public static BPlayer get(Player player) {
if (!players.isEmpty()) {
- return players.get(Util.playerString(player));
+ return players.get(BUtil.playerString(player));
}
return null;
}
// This method may be slow and should not be used if not needed
+ @Nullable
public static BPlayer getByName(String playerName) {
if (P.useUUID) {
for (Map.Entry entry : players.entrySet()) {
@@ -105,18 +106,18 @@ public class BPlayer {
}
public static boolean hasPlayer(Player player) {
- return players.containsKey(Util.playerString(player));
+ return players.containsKey(BUtil.playerString(player));
}
// Create a new BPlayer and add it to the list
public static BPlayer addPlayer(Player player) {
BPlayer bPlayer = new BPlayer();
- players.put(Util.playerString(player), bPlayer);
+ players.put(BUtil.playerString(player), bPlayer);
return bPlayer;
}
public static void remove(Player player) {
- players.remove(Util.playerString(player));
+ players.remove(BUtil.playerString(player));
}
public static int numDrunkPlayers() {
@@ -124,9 +125,10 @@ public class BPlayer {
}
public void remove() {
- for (Map.Entry entry : players.entrySet()) {
+ for (Iterator> iterator = players.entrySet().iterator(); iterator.hasNext(); ) {
+ Map.Entry entry = iterator.next();
if (entry.getValue() == this) {
- players.remove(entry.getKey());
+ iterator.remove();
return;
}
}
@@ -137,39 +139,58 @@ public class BPlayer {
}
// Drink a brew and apply effects, etc.
- public static void drink(Brew brew, Player player) {
- int brewAlc = brew.calcAlcohol();
- if (brewAlc == 0) {
- //no alcohol so we dont need to add a BPlayer
- addBrewEffects(brew, player);
- return;
- }
+ public static boolean drink(Brew brew, ItemMeta meta, Player player) {
BPlayer bPlayer = get(player);
if (bPlayer == null) {
bPlayer = addPlayer(player);
}
+ BrewDrinkEvent drinkEvent = new BrewDrinkEvent(brew, meta, player, bPlayer);
+ P.p.getServer().getPluginManager().callEvent(drinkEvent);
+ if (drinkEvent.isCancelled()) {
+ if (bPlayer.drunkeness <= 0) {
+ bPlayer.remove();
+ }
+ return false;
+ }
+
+ if (brew.hasRecipe()) {
+ brew.getCurrentRecipe().applyDrinkFeatures(player);
+ }
+ P.p.metricsForDrink(brew);
+
+ int brewAlc = drinkEvent.getAddedAlcohol();
+ int quality = drinkEvent.getQuality();
+ List effects = getBrewEffects(brew.getEffects(), quality);
+
+ if (brewAlc < 1) {
+ //no alcohol so we dont need to add a BPlayer
+ applyEffects(effects, player, PlayerEffectEvent.EffectType.DRINK);
+ if (bPlayer.drunkeness <= 0) {
+ bPlayer.remove();
+ }
+ return true;
+ }
+
bPlayer.drunkeness += brewAlc;
- if (brew.getQuality() > 0) {
- bPlayer.quality += brew.getQuality() * brewAlc;
+ if (quality > 0) {
+ bPlayer.quality += quality * brewAlc;
} else {
bPlayer.quality += brewAlc;
}
+ applyEffects(effects, player, PlayerEffectEvent.EffectType.DRINK);
+ applyEffects(getQualityEffects(quality, brewAlc), player, PlayerEffectEvent.EffectType.QUALITY);
- if (bPlayer.drunkeness <= 100) {
-
- addBrewEffects(brew, player);
- addQualityEffects(brew.getQuality(), brewAlc, player);
-
- } else {
+ if (bPlayer.drunkeness > 100) {
bPlayer.drinkCap(player);
}
+ return true;
}
// Player has drunken too much
public void drinkCap(Player player) {
quality = getQuality() * 100;
drunkeness = 100;
- if (overdrinkKick && !player.hasPermission("brewery.bypass.overdrink")) {
+ if (BConfig.overdrinkKick && !player.hasPermission("brewery.bypass.overdrink")) {
P.p.getServer().getScheduler().scheduleSyncDelayedTask(P.p, () -> passOut(player), 1);
} else {
addPuke(player, 60 + (int) (Math.random() * 60.0));
@@ -187,7 +208,7 @@ public class BPlayer {
// Eat something to drain the drunkeness
public void drainByItem(Player player, Material mat) {
- int strength = drainItems.get(mat);
+ int strength = BConfig.drainItems.get(mat);
if (drain(player, strength)) {
remove(player);
}
@@ -211,7 +232,7 @@ public class BPlayer {
}
quality = getQuality();
if (drunkeness <= -offlineDrunk) {
- return drunkeness <= -hangoverTime;
+ return drunkeness <= -BConfig.hangoverTime;
}
}
return false;
@@ -244,6 +265,13 @@ public class BPlayer {
push.setX(Math.random() - 0.5);
push.setZ(Math.random() - 0.5);
}
+ PlayerPushEvent pushEvent = new PlayerPushEvent(player, push, this);
+ P.p.getServer().getPluginManager().callEvent(pushEvent);
+ push = pushEvent.getPush();
+ if (pushEvent.isCancelled() || push.lengthSquared() <= 0) {
+ time = -10;
+ return;
+ }
player.setVelocity(push);
} else if (time < 0 && time > -10) {
// push him some more in the same direction
@@ -272,7 +300,7 @@ public class BPlayer {
if (drunkeness <= 70) {
return 0;
}
- if (!enableLoginDisallow) {
+ if (!BConfig.enableLoginDisallow) {
if (drunkeness <= 100) {
return 0;
} else {
@@ -302,24 +330,20 @@ public class BPlayer {
return;
}
// delayed login event as the player is not fully accessible pre login
- P.p.getServer().getScheduler().runTaskLater(P.p, new Runnable() {
- public void run() {
- login(player);
- }
- }, 1L);
+ P.p.getServer().getScheduler().runTaskLater(P.p, () -> login(player), 1L);
}
// he may be having a hangover
public void login(final Player player) {
if (drunkeness < 10) {
if (offlineDrunk > 60) {
- if (enableHome && !player.hasPermission("brewery.bypass.teleport")) {
+ if (BConfig.enableHome && !player.hasPermission("brewery.bypass.teleport")) {
goHome(player);
}
}
hangoverEffects(player);
// wird der spieler noch gebraucht?
- players.remove(Util.playerString(player));
+ players.remove(BUtil.playerString(player));
} else if (offlineDrunk - drunkeness >= 30) {
Location randomLoc = Wakeup.getRandom(player.getLocation());
@@ -339,6 +363,7 @@ public class BPlayer {
}
public void goHome(final Player player) {
+ String homeType = BConfig.homeType;
if (homeType != null) {
Location home = null;
if (homeType.equalsIgnoreCase("bed")) {
@@ -365,11 +390,11 @@ public class BPlayer {
public void drunkPuke(Player player) {
if (drunkeness >= 80) {
if (drunkeness >= 90) {
- if (Math.random() < 0.15 - (getQuality() / 100)) {
+ if (Math.random() < 0.15f - (getQuality() / 100f)) {
addPuke(player, 20 + (int) (Math.random() * 40));
}
} else {
- if (Math.random() < 0.08 - (getQuality() / 100)) {
+ if (Math.random() < 0.08f - (getQuality() / 100f)) {
addPuke(player, 10 + (int) (Math.random() * 30));
}
}
@@ -378,18 +403,20 @@ public class BPlayer {
// make a Player puke "count" items
public static void addPuke(Player player, int count) {
- if (!enablePuke) {
+ if (!BConfig.enablePuke) {
+ return;
+ }
+
+ PlayerPukeEvent event = new PlayerPukeEvent(player, count);
+ P.p.getServer().getPluginManager().callEvent(event);
+ if (event.isCancelled() || event.getCount() < 1) {
return;
}
if (pTasks.isEmpty()) {
- taskId = P.p.getServer().getScheduler().scheduleSyncRepeatingTask(P.p, new Runnable() {
- public void run() {
- pukeTask();
- }
- }, 1L, 1L);
+ taskId = P.p.getServer().getScheduler().scheduleSyncRepeatingTask(P.p, BPlayer::pukeTask, 1L, 1L);
}
- pTasks.put(player, new MutableInt(count));
+ pTasks.put(player, new MutableInt(event.getCount()));
}
public static void pukeTask() {
@@ -415,8 +442,8 @@ public class BPlayer {
if (pukeRand == null) {
pukeRand = new Random();
}
- if (pukeItem == null || pukeItem == Material.AIR) {
- pukeItem = Material.SOUL_SAND;
+ if (BConfig.pukeItem == null || BConfig.pukeItem == Material.AIR) {
+ BConfig.pukeItem = Material.SOUL_SAND;
}
Location loc = player.getLocation();
loc.setY(loc.getY() + 1.1);
@@ -425,19 +452,20 @@ public class BPlayer {
Vector direction = loc.getDirection();
direction.multiply(0.5);
loc.add(direction);
- Item item = player.getWorld().dropItem(loc, new ItemStack(pukeItem));
+ Item item = player.getWorld().dropItem(loc, new ItemStack(BConfig.pukeItem));
item.setVelocity(direction);
item.setPickupDelay(32767); // Item can never be picked up when pickup delay is 32767
//item.setTicksLived(6000 - pukeDespawntime); // Well this does not work...
if (modAge) {
+ int pukeDespawntime = BConfig.pukeDespawntime;
if (pukeDespawntime >= 5800) {
return;
}
try {
- if (gh == null) {
- gh = Class.forName(P.p.getServer().getClass().getPackage().getName() + ".entity.CraftItem").getMethod("getHandle", (Class>[]) null);
+ if (itemHandle == null) {
+ itemHandle = Class.forName(P.p.getServer().getClass().getPackage().getName() + ".entity.CraftItem").getMethod("getHandle", (Class>[]) null);
}
- Object entityItem = gh.invoke(item, (Object[]) null);
+ Object entityItem = itemHandle.invoke(item, (Object[]) null);
if (age == null) {
age = entityItem.getClass().getDeclaredField("age");
age.setAccessible(true);
@@ -459,13 +487,25 @@ public class BPlayer {
e.printStackTrace();
}
modAge = false;
- P.p.errorLog("Failed to set Despawn Time on item " + pukeItem.name());
+ P.p.errorLog("Failed to set Despawn Time on item " + BConfig.pukeItem.name());
}
}
// #### Effects ####
+ public static void applyEffects(List effects, Player player, PlayerEffectEvent.EffectType effectType) {
+ PlayerEffectEvent event = new PlayerEffectEvent(player, effectType, effects);
+ P.p.getServer().getPluginManager().callEvent(event);
+ effects = event.getEffects();
+ if (event.isCancelled() || effects == null) {
+ return;
+ }
+ for (PotionEffect effect : effects) {
+ BUtil.reapplyPotionEffect(player, effect, true);
+ }
+ }
+
public void drunkEffects(Player player) {
int duration = 10 - getQuality();
duration += drunkeness / 2;
@@ -478,10 +518,22 @@ public class BPlayer {
if (!P.use1_14) {
duration *= 4;
}
- PotionEffectType.CONFUSION.createEffect(duration, 0).apply(player);
+ List l = new ArrayList<>(1);
+ l.add(PotionEffectType.CONFUSION.createEffect(duration, 0));
+
+ PlayerEffectEvent event = new PlayerEffectEvent(player, PlayerEffectEvent.EffectType.ALCOHOL, l);
+ P.p.getServer().getPluginManager().callEvent(event);
+ l = event.getEffects();
+ if (event.isCancelled() || l == null) {
+ return;
+ }
+ for (PotionEffect effect : l) {
+ effect.apply(player);
+ }
}
- public static void addQualityEffects(int quality, int brewAlc, Player player) {
+ public static List getQualityEffects(int quality, int brewAlc) {
+ List out = new ArrayList<>(2);
int duration = 7 - quality;
if (quality == 0) {
duration *= 125;
@@ -497,7 +549,7 @@ public class BPlayer {
duration *= 4;
}
if (duration > 0) {
- Util.reapplyPotionEffect(player, PotionEffectType.POISON.createEffect(duration, 0), true);
+ out.add(PotionEffectType.POISON.createEffect(duration, 0));
}
if (brewAlc > 10) {
@@ -511,12 +563,39 @@ public class BPlayer {
if (!P.use1_14) {
duration *= 4;
}
- Util.reapplyPotionEffect(player, PotionEffectType.BLINDNESS.createEffect(duration, 0), true);
+ out.add(PotionEffectType.BLINDNESS.createEffect(duration, 0));
+ }
+ return out;
+ }
+
+ public static void addQualityEffects(int quality, int brewAlc, Player player) {
+ List list = getQualityEffects(quality, brewAlc);
+ PlayerEffectEvent event = new PlayerEffectEvent(player, PlayerEffectEvent.EffectType.QUALITY, list);
+ P.p.getServer().getPluginManager().callEvent(event);
+ list = event.getEffects();
+ if (event.isCancelled() || list == null) {
+ return;
+ }
+ for (PotionEffect effect : list) {
+ BUtil.reapplyPotionEffect(player, effect, true);
}
}
+ public static List getBrewEffects(List effects, int quality) {
+ List out = new ArrayList<>();
+ if (effects != null) {
+ for (BEffect effect : effects) {
+ PotionEffect e = effect.generateEffect(quality);
+ if (e != null) {
+ out.add(e);
+ }
+ }
+ }
+ return out;
+ }
+
public static void addBrewEffects(Brew brew, Player player) {
- ArrayList effects = brew.getEffects();
+ List effects = brew.getEffects();
if (effects != null) {
for (BEffect effect : effects) {
effect.apply(brew.getQuality(), player);
@@ -531,8 +610,19 @@ public class BPlayer {
}
int amplifier = getHangoverQuality() / 3;
- Util.reapplyPotionEffect(player, PotionEffectType.SLOW.createEffect(duration, amplifier), true);
- Util.reapplyPotionEffect(player, PotionEffectType.HUNGER.createEffect(duration, amplifier), true);
+ List list = new ArrayList<>(2);
+ list.add(PotionEffectType.SLOW.createEffect(duration, amplifier));
+ list.add(PotionEffectType.HUNGER.createEffect(duration, amplifier));
+
+ PlayerEffectEvent event = new PlayerEffectEvent(player, PlayerEffectEvent.EffectType.HANGOVER, list);
+ P.p.getServer().getPluginManager().callEvent(event);
+ list = event.getEffects();
+ if (event.isCancelled() || list == null) {
+ return;
+ }
+ for (PotionEffect effect : list) {
+ BUtil.reapplyPotionEffect(player, effect, true);
+ }
}
@@ -545,12 +635,12 @@ public class BPlayer {
if (bplayer.drunkeness > 30) {
if (bplayer.offlineDrunk == 0) {
- Player player = Util.getPlayerfromString(name);
+ Player player = BUtil.getPlayerfromString(name);
if (player != null) {
bplayer.drunkEffects(player);
- if (enablePuke) {
+ if (BConfig.enablePuke) {
bplayer.drunkPuke(player);
}
@@ -573,7 +663,7 @@ public class BPlayer {
// Prevent 0 drunkeness
soberPerMin++;
}
- if (bplayer.drain(Util.getPlayerfromString(name), soberPerMin)) {
+ if (bplayer.drain(BUtil.getPlayerfromString(name), soberPerMin)) {
iter.remove();
}
}
diff --git a/src/com/dre/brewery/BRecipe.java b/src/com/dre/brewery/BRecipe.java
deleted file mode 100644
index f0d997b..0000000
--- a/src/com/dre/brewery/BRecipe.java
+++ /dev/null
@@ -1,361 +0,0 @@
-package com.dre.brewery;
-
-import org.bukkit.Material;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.PotionMeta;
-import org.bukkit.potion.PotionEffectType;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class BRecipe {
-
- private String[] name;
- private ArrayList ingredients = new ArrayList<>(); // material and amount
- private int cookingTime; // time to cook in cauldron
- private int 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 String 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 ArrayList effects = new ArrayList<>(); // Special Effects when drinking
-
- public BRecipe(ConfigurationSection configSectionRecipes, String recipeId) {
- String nameList = configSectionRecipes.getString(recipeId + ".name");
- if (nameList != null) {
- String[] name = nameList.split("/");
- if (name.length > 2) {
- this.name = name;
- } else {
- this.name = new String[1];
- this.name[0] = name[0];
- }
- } else {
- return;
- }
- List ingredientsList = configSectionRecipes.getStringList(recipeId + ".ingredients");
- if (ingredientsList != null) {
- for (String item : ingredientsList) {
- String[] ingredParts = item.split("/");
- if (ingredParts.length == 2) {
- String[] matParts;
- if (ingredParts[0].contains(",")) {
- matParts = ingredParts[0].split(",");
- } else if (ingredParts[0].contains(":")) {
- matParts = ingredParts[0].split(":");
- } else if (ingredParts[0].contains(";")) {
- matParts = ingredParts[0].split(";");
- } else {
- matParts = ingredParts[0].split("\\.");
- }
- Material mat = Material.matchMaterial(matParts[0]);
- short durability = -1;
- if (matParts.length == 2) {
- durability = (short) P.p.parseInt(matParts[1]);
- }
- if (mat == null && P.p.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) {
- ItemStack stack = new ItemStack(mat, P.p.parseInt(ingredParts[1]), durability);
- this.ingredients.add(stack);
- BIngredients.possibleIngredients.add(mat);
- } else {
- P.p.errorLog("Unknown Material: " + ingredParts[0]);
- this.ingredients = null;
- return;
- }
- } else {
- return;
- }
- }
- }
- this.cookingTime = configSectionRecipes.getInt(recipeId + ".cookingtime", 1);
- this.distillruns = configSectionRecipes.getInt(recipeId + ".distillruns", 0);
- this.distillTime = configSectionRecipes.getInt(recipeId + ".distilltime", 0) * 20;
- this.wood = (byte) configSectionRecipes.getInt(recipeId + ".wood", 0);
- this.age = configSectionRecipes.getInt(recipeId + ".age", 0);
- this.color = configSectionRecipes.getString(recipeId + ".color");
- this.difficulty = configSectionRecipes.getInt(recipeId + ".difficulty", 0);
- this.alcohol = configSectionRecipes.getInt(recipeId + ".alcohol", 0);
-
- List effectStringList = configSectionRecipes.getStringList(recipeId + ".effects");
- if (effectStringList != null) {
- for (String effectString : effectStringList) {
- BEffect effect = new BEffect(effectString);
- if (effect.isValid()) {
- effects.add(effect);
- } else {
- P.p.errorLog("Error adding Effect to Recipe: " + getName(5));
- }
- }
- }
- }
-
- // check every part of the recipe for validity
- public boolean isValid() {
- if (name == null || name.length < 1) {
- P.p.errorLog("Recipe Name missing or invalid!");
- return false;
- }
- if (getName(5) == null || getName(5).length() < 1) {
- P.p.errorLog("Recipe Name invalid");
- return false;
- }
- if (ingredients == null || ingredients.isEmpty()) {
- P.p.errorLog("No ingredients could be loaded for Recipe: " + getName(5));
- return false;
- }
- if (cookingTime < 1) {
- P.p.errorLog("Invalid cooking time '" + cookingTime + "' in Recipe: " + getName(5));
- return false;
- }
- if (distillruns < 0) {
- P.p.errorLog("Invalid distillruns '" + distillruns + "' in Recipe: " + getName(5));
- return false;
- }
- if (distillTime < 0) {
- P.p.errorLog("Invalid distilltime '" + distillTime + "' in Recipe: " + getName(5));
- return false;
- }
- if (wood < 0 || wood > 6) {
- P.p.errorLog("Invalid wood type '" + wood + "' in Recipe: " + getName(5));
- return false;
- }
- if (age < 0) {
- P.p.errorLog("Invalid age time '" + age + "' in Recipe: " + getName(5));
- return false;
- }
- String c = getColor();
- if (!c.equals("WATER") && Brew.PotionColor.fromString(c) == Brew.PotionColor.WATER) {
- P.p.errorLog("Invalid Color '" + color + "' in Recipe: " + getName(5));
- return false;
- }
- if (difficulty < 0 || difficulty > 10) {
- P.p.errorLog("Invalid difficulty '" + difficulty + "' in Recipe: " + getName(5));
- return false;
- }
- if (alcohol < 0) {
- P.p.errorLog("Invalid alcohol '" + alcohol + "' in Recipe: " + getName(5));
- 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 list) {
- if (list.size() < ingredients.size()) {
- return true;
- }
- for (ItemStack ingredient : ingredients) {
- boolean matches = false;
- for (ItemStack used : list) {
- if (ingredientsMatch(used, ingredient)) {
- matches = true;
- break;
- }
- }
- if (!matches) {
- return true;
- }
- }
- return false;
- }
-
- // Returns true if this ingredient cares about durability
- public boolean hasExactData(ItemStack item) {
- for (ItemStack ingredient : ingredients) {
- if (ingredient.getType().equals(item.getType())) {
- return ingredient.getDurability() != -1;
- }
- }
- return true;
- }
-
- // Returns true if this item matches the item from a recipe
- public static boolean ingredientsMatch(ItemStack usedItem, ItemStack recipeItem) {
- if (!recipeItem.getType().equals(usedItem.getType())) {
- return false;
- }
- return recipeItem.getDurability() == -1 || recipeItem.getDurability() == usedItem.getDurability();
- }
-
- // Create a Potion from this Recipe with best values. Quality can be set, but will reset to 10 if put in a barrel
- public ItemStack create(int quality) {
- ItemStack potion = new ItemStack(Material.POTION);
- PotionMeta potionMeta = (PotionMeta) potion.getItemMeta();
-
- int uid = Brew.generateUID();
-
- ArrayList list = new ArrayList<>(ingredients.size());
- for (ItemStack item : ingredients) {
- if (item.getDurability() == -1) {
- list.add(new ItemStack(item.getType(), item.getAmount()));
- } else {
- list.add(item.clone());
- }
- }
-
- BIngredients bIngredients = new BIngredients(list, cookingTime);
-
- Brew brew = new Brew(uid, bIngredients, quality, distillruns, getAge(), wood, getName(5), false, false, true, 0);
-
- Brew.PotionColor.fromString(getColor()).colorBrew(potionMeta, potion, false);
- potionMeta.setDisplayName(P.p.color("&f" + getName(quality)));
- if (!P.use1_14) {
- // Before 1.14 the effects duration would strangely be only a quarter of what we tell it to be
- // This is due to the Duration Modifier, that is removed in 1.14
- uid *= 4;
- }
- // This effect stores the UID in its Duration
- potionMeta.addCustomEffect((PotionEffectType.REGENERATION).createEffect(uid, 0), true);
-
- brew.convertLore(potionMeta, false);
- Brew.addOrReplaceEffects(potionMeta, effects, quality);
- brew.touch();
-
- potion.setItemMeta(potionMeta);
- return potion;
- }
-
-
- // Getter
-
- // how many of a specific ingredient in the recipe
- public int amountOf(ItemStack item) {
- for (ItemStack ingredient : ingredients) {
- if (ingredientsMatch(item, ingredient)) {
- return ingredient.getAmount();
- }
- }
- return 0;
- }
-
- // 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 int getDistillRuns() {
- return distillruns;
- }
-
- public int getDistillTime() {
- return distillTime;
- }
-
- public String getColor() {
- if (color != null) {
- return color.toUpperCase();
- }
- return "BLUE";
- }
-
- // 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 ArrayList getEffects() {
- return effects;
- }
-
-}
diff --git a/src/com/dre/brewery/Barrel.java b/src/com/dre/brewery/Barrel.java
index fb3d603..e94a680 100644
--- a/src/com/dre/brewery/Barrel.java
+++ b/src/com/dre/brewery/Barrel.java
@@ -1,11 +1,19 @@
package com.dre.brewery;
-import com.dre.brewery.integration.CitadelBarrel;
-import com.dre.brewery.integration.GriefPreventionBarrel;
-import com.dre.brewery.integration.LWCBarrel;
-import com.dre.brewery.integration.LogBlockBarrel;
-import org.apache.commons.lang.ArrayUtils;
+import com.dre.brewery.api.events.barrel.BarrelAccessEvent;
+import com.dre.brewery.api.events.barrel.BarrelCreateEvent;
+import com.dre.brewery.api.events.barrel.BarrelDestroyEvent;
+import com.dre.brewery.api.events.barrel.BarrelRemoveEvent;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.integration.barrel.LogBlockBarrel;
+import com.dre.brewery.lore.BrewLore;
+import com.dre.brewery.utility.BUtil;
+import com.dre.brewery.utility.BoundingBox;
+import com.dre.brewery.utility.LegacyUtil;
+import org.bukkit.Location;
import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.SoundCategory;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.HumanEntity;
@@ -15,40 +23,47 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
-import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
+/**
+ * A Multi Block Barrel with Inventory
+ */
public class Barrel implements InventoryHolder {
- public static CopyOnWriteArrayList barrels = new CopyOnWriteArrayList<>();
- private static int check = 0;
+ public static List barrels = new ArrayList<>();
+ private static int check = 0; // Which Barrel was last checked
- private Block spigot;
- private int[] woodsloc = null; // location of wood Blocks
- private int[] stairsloc = null; // location of stair Blocks
- private byte signoffset;
- private boolean checked;
+ private final Block spigot;
+ private final BarrelBody body; // The Blocks that make up a Barrel in the World
+ private boolean checked; // Checked by the random BarrelCheck routine
private Inventory inventory;
private float time;
public Barrel(Block spigot, byte signoffset) {
this.spigot = spigot;
- this.signoffset = signoffset;
+ if (isLarge()) {
+ inventory = P.p.getServer().createInventory(this, 27, P.p.languageReader.get("Etc_Barrel"));
+ } else {
+ inventory = P.p.getServer().createInventory(this, 9, P.p.languageReader.get("Etc_Barrel"));
+ }
+ body = new BarrelBody(this, signoffset);
}
- // load from file
- public Barrel(Block spigot, byte sign, String[] st, String[] wo, Map items, float time) {
+ /**
+ * load from file
+ */
+ public Barrel(Block spigot, byte sign, BoundingBox bounds, Map items, float time) {
this.spigot = spigot;
- this.signoffset = sign;
if (isLarge()) {
- this.inventory = org.bukkit.Bukkit.createInventory(this, 27, P.p.languageReader.get("Etc_Barrel"));
+ this.inventory = P.p.getServer().createInventory(this, 27, P.p.languageReader.get("Etc_Barrel"));
} else {
- this.inventory = org.bukkit.Bukkit.createInventory(this, 9, P.p.languageReader.get("Etc_Barrel"));
+ this.inventory = P.p.getServer().createInventory(this, 9, P.p.languageReader.get("Etc_Barrel"));
}
if (items != null) {
for (String slot : items.keySet()) {
@@ -59,34 +74,7 @@ public class Barrel implements InventoryHolder {
}
this.time = time;
- int i = 0;
- if (wo.length > 1) {
- woodsloc = new int[wo.length];
- for (String wos : wo) {
- woodsloc[i] = P.p.parseInt(wos);
- i++;
- }
- i = 0;
- }
- if (st.length > 1) {
- stairsloc = new int[st.length];
- for (String sts : st) {
- stairsloc[i] = P.p.parseInt(sts);
- i++;
- }
- }
-
- if (woodsloc == null && stairsloc == null) {
- // If loading from old data, or block locations are missing, regenerate them
- // This will only be done in those extreme cases.
- Block broken = getBrokenBlock(true);
- if (broken != null) {
- remove(broken, null);
- return;
- }
- }
-
- barrels.add(this);
+ body = new BarrelBody(this, sign, bounds);
}
public static void onUpdate() {
@@ -94,13 +82,21 @@ public class Barrel implements InventoryHolder {
// Minecraft day is 20 min, so add 1/20 to the time every minute
barrel.time += (1.0 / 20.0);
}
- if (check == 0 && barrels.size() > 0) {
- Barrel random = barrels.get((int) Math.floor(Math.random() * barrels.size()));
+ int numBarrels = barrels.size();
+ if (check == 0 && numBarrels > 0) {
+ Barrel random = barrels.get((int) Math.floor(Math.random() * numBarrels));
if (random != null) {
// You have been selected for a random search
// We want to check at least one barrel every time
random.checked = false;
}
+ if (numBarrels > 50) {
+ Barrel randomInTheBack = barrels.get(numBarrels - 1 - (int) (Math.random() * (numBarrels >>> 2)));
+ if (randomInTheBack != null) {
+ // Prioritize checking one of the less recently used barrels as well
+ randomInTheBack.checked = false;
+ }
+ }
new BarrelCheck().runTaskTimer(P.p, 1, 1);
}
}
@@ -118,154 +114,36 @@ public class Barrel implements InventoryHolder {
}
}
- if (P.p.useWG) {
- Plugin plugin = P.p.getServer().getPluginManager().getPlugin("WorldGuard");
- if (plugin != null) {
- try {
- if (!P.p.wg.checkAccess(player, spigot, plugin)) {
- return false;
- }
- } catch (Throwable e) {
- P.p.errorLog("Failed to Check WorldGuard for Barrel Open Permissions!");
- P.p.errorLog("Brewery was tested with version 5.8, 6.1 to 7.0 of WorldGuard!");
- P.p.errorLog("Disable the WorldGuard support in the config and do /brew reload");
- e.printStackTrace();
- if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
- P.p.msg(player, "&cWorldGuard check Error, Brewery was tested with up to v7.0 of Worldguard");
- P.p.msg(player, "&cSet &7useWorldGuard: false &cin the config and /brew reload");
- } else {
- P.p.msg(player, "&cError opening Barrel, please report to an Admin!");
- }
- return false;
- }
- }
- }
-
- if (P.p.useGP) {
- if (P.p.getServer().getPluginManager().isPluginEnabled("GriefPrevention")) {
- try {
- if (!GriefPreventionBarrel.checkAccess(player, spigot)) {
- return false;
- }
- } catch (Throwable e) {
- P.p.errorLog("Failed to Check GriefPrevention for Barrel Open Permissions!");
- P.p.errorLog("Brewery was tested with GriefPrevention v14.5 - v16.9");
- P.p.errorLog("Disable the GriefPrevention support in the config and do /brew reload");
- e.printStackTrace();
- if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
- P.p.msg(player, "&cGriefPrevention check Error, Brewery was tested with up to v16.9 of GriefPrevention");
- P.p.msg(player, "&cSet &7useGriefPrevention: false &cin the config and /brew reload");
- } else {
- P.p.msg(player, "&cError opening Barrel, please report to an Admin!");
- }
- return false;
- }
- }
- }
-
- if (event != null && P.p.useLWC) {
- Plugin plugin = P.p.getServer().getPluginManager().getPlugin("LWC");
- if (plugin != null) {
-
- // If the Clicked Block was the Sign, LWC already knows and we dont need to do anything here
- if (!LegacyUtil.isSign(event.getClickedBlock().getType())) {
- Block sign = getSignOfSpigot();
- // If the Barrel does not have a Sign, it cannot be locked
- if (!sign.equals(event.getClickedBlock())) {
- try {
- return LWCBarrel.checkAccess(player, sign, event, plugin);
- } catch (Throwable e) {
- P.p.errorLog("Failed to Check LWC for Barrel Open Permissions!");
- P.p.errorLog("Brewery was tested with version 4.5.0 of LWC!");
- P.p.errorLog("Disable the LWC support in the config and do /brew reload");
- e.printStackTrace();
- if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
- P.p.msg(player, "&cLWC check Error, Brewery was tested with up to v4.5.0 of LWC");
- P.p.msg(player, "&cSet &7useLWC: false &cin the config and /brew reload");
- } else {
- P.p.msg(player, "&cError opening Barrel, please report to an Admin!");
- }
- return false;
- }
- }
- }
- }
- }
-
- if (event != null && P.p.useCitadel) {
- Plugin plugin = P.p.getServer().getPluginManager().getPlugin("Citadel");
- if (plugin != null) {
- try {
- if (LegacyUtil.isSign(event.getClickedBlock().getType())) {
- return CitadelBarrel.checkAccess(player, getSignOfSpigot());
- } else {
- return CitadelBarrel.checkAccess(player, spigot);
- }
- } catch (Throwable e) {
- P.p.errorLog("Failed to Check Citadel for Container Access Permissions!");
- P.p.errorLog("Brewery was tested with version 3.9.1 of Citadel!");
- P.p.errorLog("Disable Citadel support in the config and do /brew reload");
- e.printStackTrace();
- if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
- P.p.msg(player, "&cCitadel check Error, Brewery was tested with up to v3.9.1 of Citadel");
- } else {
- P.p.msg(player, "&cError opening Barrel, please report to an Admin!");
- }
- return false;
- }
- }
+ // Call event
+ BarrelAccessEvent accessEvent = new BarrelAccessEvent(this, player, event.getClickedBlock());
+ // Listened to by WGBarrel7, WGBarrelNew, WGBarrelOld, GriefPreventionBarrel (IntegrationListener)
+ P.p.getServer().getPluginManager().callEvent(accessEvent);
+ if (accessEvent.isCancelled()) {
+ return false;
}
return true;
}
- // Ask for permission to destroy barrel, remove protection if has
- public boolean hasPermsDestroy(Player player) {
- if (player == null) {
- willDestroy();
- return true;
- }
- if (P.p.useLWC) {
- try {
- return LWCBarrel.checkDestroy(player, this);
- } catch (Throwable e) {
- P.p.errorLog("Failed to Check LWC for Barrel Break Permissions!");
- P.p.errorLog("Brewery was tested with version 4.5.0 of LWC!");
- P.p.errorLog("Disable the LWC support in the config and do /brew reload");
- e.printStackTrace();
- if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
- P.p.msg(player, "&cLWC check Error, Brewery was tested with up to v4.5.0 of LWC");
- P.p.msg(player, "&cSet &7useLWC: false &cin the config and /brew reload");
- } else {
- P.p.msg(player, "&cError breaking Barrel, please report to an Admin!");
- }
- return false;
- }
- }
-
- return true;
+ /**
+ * Ask for permission to destroy barrel
+ */
+ public boolean hasPermsDestroy(Player player, Block block, BarrelDestroyEvent.Reason reason) {
+ // Listened to by LWCBarrel (IntegrationListener)
+ BarrelDestroyEvent destroyEvent = new BarrelDestroyEvent(this, block, reason, player);
+ P.p.getServer().getPluginManager().callEvent(destroyEvent);
+ return !destroyEvent.isCancelled();
}
- // If something other than the Player is destroying the barrel, inform protection plugins
- public void willDestroy() {
- if (P.p.useLWC) {
- try {
- LWCBarrel.remove(this);
- } catch (Throwable e) {
- P.p.errorLog("Failed to Remove LWC Lock from Barrel!");
- P.p.errorLog("Brewery was tested with version 4.5.0 of LWC!");
- e.printStackTrace();
- }
- }
- }
-
- // player opens the barrel
+ /**
+ * player opens the barrel
+ */
public void open(Player player) {
if (inventory == null) {
if (isLarge()) {
- inventory = org.bukkit.Bukkit.createInventory(this, 27, P.p.languageReader.get("Etc_Barrel"));
+ inventory = P.p.getServer().createInventory(this, 27, P.p.languageReader.get("Etc_Barrel"));
} else {
- inventory = org.bukkit.Bukkit.createInventory(this, 9, P.p.languageReader.get("Etc_Barrel"));
+ inventory = P.p.getServer().createInventory(this, 9, P.p.languageReader.get("Etc_Barrel"));
}
} else {
if (time > 0) {
@@ -273,7 +151,7 @@ public class Barrel implements InventoryHolder {
if (inventory.getViewers().isEmpty()) {
// if inventory contains potions
if (inventory.contains(Material.POTION)) {
- byte wood = getWood();
+ byte wood = body.getWood();
long loadTime = System.nanoTime();
for (ItemStack item : inventory.getContents()) {
if (item != null) {
@@ -293,7 +171,7 @@ public class Barrel implements InventoryHolder {
// reset barreltime, potions have new age
time = 0;
- if (P.p.useLB) {
+ if (BConfig.useLB) {
try {
LogBlockBarrel.openBarrel(player, inventory, spigot.getLocation());
} catch (Throwable e) {
@@ -305,78 +183,78 @@ public class Barrel implements InventoryHolder {
player.openInventory(inventory);
}
+ public void playOpeningSound() {
+ float randPitch = (float) (Math.random() * 0.1);
+ Location location = getSpigot().getLocation();
+ if (location.getWorld() == null) return;
+ if (isLarge()) {
+ location.getWorld().playSound(location, Sound.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.4f, 0.55f + randPitch);
+ //getSpigot().getWorld().playSound(getSpigot().getLocation(), Sound.ITEM_BUCKET_EMPTY, SoundCategory.BLOCKS, 0.5f, 0.6f + randPitch);
+ location.getWorld().playSound(location, Sound.BLOCK_BREWING_STAND_BREW, SoundCategory.BLOCKS, 0.4f, 0.45f + randPitch);
+ } else {
+ location.getWorld().playSound(location, Sound.BLOCK_BARREL_OPEN, SoundCategory.BLOCKS, 0.5f, 0.8f + randPitch);
+ }
+ }
+
+ public void playClosingSound() {
+ float randPitch = (float) (Math.random() * 0.1);
+ Location location = getSpigot().getLocation();
+ if (location.getWorld() == null) return;
+ if (isLarge()) {
+ location.getWorld().playSound(location, Sound.BLOCK_BARREL_CLOSE, SoundCategory.BLOCKS, 0.5f, 0.5f + randPitch);
+ location.getWorld().playSound(location, Sound.ITEM_BUCKET_EMPTY, SoundCategory.BLOCKS, 0.2f, 0.6f + randPitch);
+ } else {
+ location.getWorld().playSound(location, Sound.BLOCK_BARREL_CLOSE, SoundCategory.BLOCKS, 0.5f, 0.8f + randPitch);
+ }
+ }
+
@Override
+ @NotNull
public Inventory getInventory() {
return inventory;
}
+ @NotNull
public Block getSpigot() {
return spigot;
}
- // Returns true if this Block is part of this Barrel
+ @NotNull
+ public BarrelBody getBody() {
+ return body;
+ }
+
+ public float getTime() {
+ return time;
+ }
+
+ /**
+ * Returns true if this Block is part of this Barrel
+ */
public boolean hasBlock(Block block) {
- if (block != null) {
- if (LegacyUtil.isWoodPlanks(block.getType())) {
- return hasWoodBlock(block);
- } else if (LegacyUtil.isWoodStairs(block.getType())) {
- return hasStairsBlock(block);
- }
- }
- return false;
+ return body.hasBlock(block);
}
+ /**
+ * @deprecated just use hasBlock
+ */
+ @Deprecated
public boolean hasWoodBlock(Block block) {
- if (woodsloc != null) {
- if (spigot.getWorld() != null && spigot.getWorld().equals(block.getWorld())) {
- if (woodsloc.length > 2) {
- int x = block.getX();
- if (Math.abs(x - woodsloc[0]) < 10) {
- for (int i = 0; i < woodsloc.length - 2; i += 3) {
- if (woodsloc[i] == x) {
- if (woodsloc[i + 1] == block.getY()) {
- if (woodsloc[i + 2] == block.getZ()) {
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- return false;
+ return body.hasBlock(block);
}
+ /**
+ * @deprecated just use hasBlock
+ */
+ @Deprecated
public boolean hasStairsBlock(Block block) {
- if (stairsloc != null) {
- if (spigot.getWorld() != null && spigot.getWorld().equals(block.getWorld())) {
- if (stairsloc.length > 2) {
- int x = block.getX();
- if (Math.abs(x - stairsloc[0]) < 10) {
- for (int i = 0; i < stairsloc.length - 2; i += 3) {
- if (stairsloc[i] == x) {
- if (stairsloc[i + 1] == block.getY()) {
- if (stairsloc[i + 2] == block.getZ()) {
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- return false;
+ return body.hasBlock(block);
}
- // Returns true if the Offset of the clicked Sign matches the Barrel.
- // This prevents adding another sign to the barrel and clicking that.
- public boolean isSignOfBarrel(byte offset) {
- return offset == 0 || signoffset == 0 || signoffset == offset;
- }
-
- // Get the Barrel by Block, null if that block is not part of a barrel
+ /**
+ * Get the Barrel by Block, null if that block is not part of a barrel
+ */
+ @Nullable
public static Barrel get(Block block) {
if (block == null) {
return null;
@@ -384,57 +262,73 @@ public class Barrel implements InventoryHolder {
Material type = block.getType();
if (LegacyUtil.isFence(type) || LegacyUtil.isSign(type) ) {
return getBySpigot(block);
- } else if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
+ } else {
return getByWood(block);
}
- return null;
}
- // Get the Barrel by Sign or Spigot (Fastest)
+ /**
+ * Get the Barrel by Sign or Spigot (Fastest)
+ */
+ @Nullable
public static Barrel getBySpigot(Block sign) {
// convert spigot if neccessary
- Block spigot = getSpigotOfSign(sign);
+ Block spigot = BarrelBody.getSpigotOfSign(sign);
byte signoffset = 0;
if (!spigot.equals(sign)) {
signoffset = (byte) (sign.getY() - spigot.getY());
}
+ int i = 0;
for (Barrel barrel : barrels) {
- if (barrel.isSignOfBarrel(signoffset)) {
+ if (barrel.body.isSignOfBarrel(signoffset)) {
if (barrel.spigot.equals(spigot)) {
- if (barrel.signoffset == 0 && signoffset != 0) {
+ if (barrel.body.getSignoffset() == 0 && signoffset != 0) {
// Barrel has no signOffset even though we clicked a sign, may be old
- barrel.signoffset = signoffset;
+ barrel.body.setSignoffset(signoffset);
}
+ moveMRU(i);
return barrel;
}
}
+ i++;
}
return null;
}
- // Get the barrel by its corpus (Wood Planks, Stairs)
+ /**
+ * Get the barrel by its corpus (Wood Planks, Stairs)
+ */
+ @Nullable
public static Barrel getByWood(Block wood) {
- if (LegacyUtil.isWoodPlanks(wood.getType())) {
+ if (LegacyUtil.isWoodPlanks(wood.getType()) || LegacyUtil.isWoodStairs(wood.getType())) {
+ int i = 0;
for (Barrel barrel : barrels) {
- if (barrel.hasWoodBlock(wood)) {
- return barrel;
- }
- }
- } else if (LegacyUtil.isWoodStairs(wood.getType())) {
- for (Barrel barrel : Barrel.barrels) {
- if (barrel.hasStairsBlock(wood)) {
+ if (barrel.getSpigot().getWorld().equals(wood.getWorld()) && barrel.body.getBounds().contains(wood)) {
+ moveMRU(i);
return barrel;
}
+ i++;
}
}
return null;
}
- // creates a new Barrel out of a sign
+ // Move Barrel that was recently used more towards the front of the List
+ // Optimizes retrieve by Block over time
+ private static void moveMRU(int index) {
+ if (index > 0) {
+ // Swap entry at the index with the one next to it
+ barrels.set(index - 1, barrels.set(index, barrels.get(index - 1)));
+ }
+ }
+
+ /**
+ * creates a new Barrel out of a sign
+ */
public static boolean create(Block sign, Player player) {
- Block spigot = getSpigotOfSign(sign);
+ Block spigot = BarrelBody.getSpigotOfSign(sign);
byte signoffset = 0;
if (!spigot.equals(sign)) {
@@ -444,7 +338,7 @@ public class Barrel implements InventoryHolder {
Barrel barrel = getBySpigot(spigot);
if (barrel == null) {
barrel = new Barrel(spigot, signoffset);
- if (barrel.getBrokenBlock(true) == null) {
+ if (barrel.body.getBrokenBlock(true) == null) {
if (LegacyUtil.isSign(spigot.getType())) {
if (!player.hasPermission("brewery.createbarrel.small")) {
P.p.msg(player, P.p.languageReader.get("Perms_NoSmallBarrelCreate"));
@@ -456,29 +350,43 @@ public class Barrel implements InventoryHolder {
return false;
}
}
- barrels.add(barrel);
- return true;
+ BarrelCreateEvent createEvent = new BarrelCreateEvent(barrel, player);
+ P.p.getServer().getPluginManager().callEvent(createEvent);
+ if (!createEvent.isCancelled()) {
+ barrels.add(0, barrel);
+ return true;
+ }
}
} else {
- if (barrel.signoffset == 0 && signoffset != 0) {
- barrel.signoffset = signoffset;
+ if (barrel.body.getSignoffset() == 0 && signoffset != 0) {
+ barrel.body.setSignoffset(signoffset);
return true;
}
}
return false;
}
- // removes a barrel, throwing included potions to the ground
- public void remove(Block broken, Player breaker) {
+ /**
+ * Removes a barrel, throwing included potions to the ground
+ *
+ * @param broken The Block that was broken
+ * @param breaker The Player that broke it, or null if not known
+ * @param dropItems If the items in the barrels inventory should drop to the ground
+ */
+ public void remove(@Nullable Block broken, @Nullable Player breaker, boolean dropItems) {
+ BarrelRemoveEvent event = new BarrelRemoveEvent(this, dropItems);
+ // Listened to by LWCBarrel (IntegrationListener)
+ P.p.getServer().getPluginManager().callEvent(event);
+
if (inventory != null) {
- List viewers = new ArrayList(inventory.getViewers());
+ List viewers = new ArrayList<>(inventory.getViewers());
// Copy List to fix ConcModExc
for (HumanEntity viewer : viewers) {
viewer.closeInventory();
}
ItemStack[] items = inventory.getContents();
inventory.clear();
- if (P.p.useLB && breaker != null) {
+ if (BConfig.useLB && breaker != null) {
try {
LogBlockBarrel.breakBarrel(breaker, items, spigot.getLocation());
} catch (Throwable e) {
@@ -487,23 +395,27 @@ public class Barrel implements InventoryHolder {
e.printStackTrace();
}
}
- for (ItemStack item : items) {
- if (item != null) {
- Brew brew = Brew.get(item);
- if (brew != null) {
- // Brew before throwing
- brew.age(item, time, getWood());
- PotionMeta meta = (PotionMeta) item.getItemMeta();
- if (Brew.hasColorLore(meta)) {
- brew.convertLore(meta, false);
- item.setItemMeta(meta);
+ if (event.willDropItems()) {
+ for (ItemStack item : items) {
+ if (item != null) {
+ Brew brew = Brew.get(item);
+ if (brew != null) {
+ // Brew before throwing
+ brew.age(item, time, body.getWood());
+ PotionMeta meta = (PotionMeta) item.getItemMeta();
+ if (BrewLore.hasColorLore(meta)) {
+ BrewLore lore = new BrewLore(brew, meta);
+ lore.convertLore(false);
+ lore.write();
+ item.setItemMeta(meta);
+ }
+ }
+ // "broken" is the block that destroyed, throw them there!
+ if (broken != null) {
+ broken.getWorld().dropItem(broken.getLocation(), item);
+ } else {
+ spigot.getWorld().dropItem(spigot.getLocation(), item);
}
- }
- // "broken" is the block that destroyed, throw them there!
- if (broken != null) {
- broken.getWorld().dropItem(broken.getLocation(), item);
- } else {
- spigot.getWorld().dropItem(spigot.getLocation(), item);
}
}
}
@@ -512,23 +424,56 @@ public class Barrel implements InventoryHolder {
barrels.remove(this);
}
- //unloads barrels that are in a unloading world
+ /**
+ * is this a Large barrel?
+ */
+ public boolean isLarge() {
+ return !isSmall();
+ }
+
+ /**
+ * is this a Small barrel?
+ */
+ public boolean isSmall() {
+ return LegacyUtil.isSign(spigot.getType());
+ }
+
+ /**
+ * returns the Sign of a large barrel, the spigot if there is none
+ */
+ public Block getSignOfSpigot() {
+ return body.getSignOfSpigot();
+ }
+
+ /**
+ * returns the fence above/below a block, itself if there is none
+ */
+ public static Block getSpigotOfSign(Block block) {
+ return BarrelBody.getSpigotOfSign(block);
+ }
+
+ /**
+ * returns null if Barrel is correctly placed; the block that is missing when not.
+ * The barrel needs to be formed correctly
+ *
+ * @param force to also check even if chunk is not loaded
+ */
+ public Block getBrokenBlock(boolean force) {
+ return body.getBrokenBlock(force);
+ }
+
+ /**
+ * unloads barrels that are in a unloading world
+ */
public static void onUnload(String name) {
- for (Barrel barrel : barrels) {
- if (barrel.spigot.getWorld().getName().equals(name)) {
- barrels.remove(barrel);
- }
- }
+ barrels.removeIf(barrel -> barrel.spigot.getWorld().getName().equals(name));
}
- // If the Sign of a Large Barrel gets destroyed, set signOffset to 0
- public void destroySign() {
- signoffset = 0;
- }
-
- // Saves all data
+ /**
+ * Saves all data
+ */
public static void save(ConfigurationSection config, ConfigurationSection oldData) {
- Util.createWorldSections(config);
+ BUtil.createWorldSections(config);
if (!barrels.isEmpty()) {
int id = 0;
@@ -538,7 +483,7 @@ public class Barrel implements InventoryHolder {
String prefix;
if (worldName.startsWith("DXL_")) {
- prefix = Util.getDxlName(worldName) + "." + id;
+ prefix = BUtil.getDxlName(worldName) + "." + id;
} else {
prefix = barrel.spigot.getWorld().getUID().toString() + "." + id;
}
@@ -546,23 +491,8 @@ public class Barrel implements InventoryHolder {
// block: x/y/z
config.set(prefix + ".spigot", barrel.spigot.getX() + "/" + barrel.spigot.getY() + "/" + barrel.spigot.getZ());
- if (barrel.signoffset != 0) {
- config.set(prefix + ".sign", barrel.signoffset);
- }
- if (barrel.stairsloc != null && barrel.stairsloc.length > 0) {
- StringBuilder st = new StringBuilder();
- for (int i : barrel.stairsloc) {
- st.append(i).append(",");
- }
- config.set(prefix + ".st", st.substring(0, st.length() - 1));
- }
- if (barrel.woodsloc != null && barrel.woodsloc.length > 0) {
- StringBuilder wo = new StringBuilder();
- for (int i : barrel.woodsloc) {
- wo.append(i).append(",");
- }
- config.set(prefix + ".wo", wo.substring(0, wo.length() - 1));
- }
+ // save the body data into the section as well
+ barrel.body.save(config, prefix);
if (barrel.inventory != null) {
int slot = 0;
@@ -599,280 +529,6 @@ public class Barrel implements InventoryHolder {
}
}
- // direction of the barrel from the spigot
- public static int getDirection(Block spigot) {
- int direction = 0;// 1=x+ 2=x- 3=z+ 4=z-
- Material type = spigot.getRelative(0, 0, 1).getType();
- if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
- direction = 3;
- }
- type = spigot.getRelative(0, 0, -1).getType();
- if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
- if (direction == 0) {
- direction = 4;
- } else {
- return 0;
- }
- }
- type = spigot.getRelative(1, 0, 0).getType();
- if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
- if (direction == 0) {
- direction = 1;
- } else {
- return 0;
- }
- }
- type = spigot.getRelative(-1, 0, 0).getType();
- if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
- if (direction == 0) {
- direction = 2;
- } else {
- return 0;
- }
- }
- return direction;
- }
-
- // is this a Large barrel?
- public boolean isLarge() {
- return !LegacyUtil.isSign(spigot.getType());
- }
-
- // woodtype of the block the spigot is attached to
- public byte getWood() {
- Block wood;
- switch (getDirection(spigot)) { // 1=x+ 2=x- 3=z+ 4=z-
- case 0:
- return 0;
- case 1:
- wood = spigot.getRelative(1, 0, 0);
- break;
- case 2:
- wood = spigot.getRelative(-1, 0, 0);
- break;
- case 3:
- wood = spigot.getRelative(0, 0, 1);
- break;
- default:
- wood = spigot.getRelative(0, 0, -1);
- }
- try {
- return LegacyUtil.getWoodType(wood);
- } catch (NoSuchFieldError | NoClassDefFoundError noSuchFieldError) {
- // Using older minecraft versions some fields and classes do not exist
- return 0;
- }
- }
-
- // returns the Sign of a large barrel, the spigot if there is none
- public Block getSignOfSpigot() {
- if (signoffset != 0) {
- if (LegacyUtil.isSign(spigot.getType())) {
- return spigot;
- }
-
- if (LegacyUtil.isSign(spigot.getRelative(0, signoffset, 0).getType())) {
- return spigot.getRelative(0, signoffset, 0);
- } else {
- signoffset = 0;
- }
- }
- return spigot;
- }
-
- // returns the fence above/below a block, itself if there is none
- public static Block getSpigotOfSign(Block block) {
-
- int y = -2;
- while (y <= 1) {
- // Fence and Netherfence
- Block relative = block.getRelative(0, y, 0);
- if (LegacyUtil.isFence(relative.getType())) {
- return (relative);
- }
- y++;
- }
- return block;
- }
-
- // returns null if Barrel is correctly placed; the block that is missing when not
- // the barrel needs to be formed correctly
- // flag force to also check if chunk is not loaded
- public Block getBrokenBlock(boolean force) {
- if (force || Util.isChunkLoaded(spigot)) {
- spigot = getSpigotOfSign(spigot);
- if (LegacyUtil.isSign(spigot.getType())) {
- return checkSBarrel();
- } else {
- return checkLBarrel();
- }
- }
- return null;
- }
-
- public Block checkSBarrel() {
- int direction = getDirection(spigot);// 1=x+ 2=x- 3=z+ 4=z-
- if (direction == 0) {
- return spigot;
- }
- int startX;
- int startZ;
- int endX;
- int endZ;
-
- ArrayList stairs = new ArrayList<>();
-
- if (direction == 1) {
- startX = 1;
- endX = startX + 1;
- startZ = -1;
- endZ = 0;
- } else if (direction == 2) {
- startX = -2;
- endX = startX + 1;
- startZ = 0;
- endZ = 1;
- } else if (direction == 3) {
- startX = 0;
- endX = 1;
- startZ = 1;
- endZ = startZ + 1;
- } else {
- startX = -1;
- endX = 0;
- startZ = -2;
- endZ = startZ + 1;
- }
-
- Material type;
- int x = startX;
- int y = 0;
- int z = startZ;
- while (y <= 1) {
- while (x <= endX) {
- while (z <= endZ) {
- Block block = spigot.getRelative(x, y, z);
- type = block.getType();
-
- if (LegacyUtil.isWoodStairs(type)) {
- if (y == 0) {
- // stairs have to be upside down
- if (!LegacyUtil.areStairsInverted(block)) {
- return block;
- }
- }
- stairs.add(block.getX());
- stairs.add(block.getY());
- stairs.add(block.getZ());
- z++;
- } else {
- return spigot.getRelative(x, y, z);
- }
- }
- z = startZ;
- x++;
- }
- z = startZ;
- x = startX;
- y++;
- }
- stairsloc = ArrayUtils.toPrimitive(stairs.toArray(new Integer[0]));
- return null;
- }
-
- public Block checkLBarrel() {
- int direction = getDirection(spigot);// 1=x+ 2=x- 3=z+ 4=z-
- if (direction == 0) {
- return spigot;
- }
- int startX;
- int startZ;
- int endX;
- int endZ;
-
- ArrayList stairs = new ArrayList<>();
- ArrayList woods = new ArrayList<>();
-
- if (direction == 1) {
- startX = 1;
- endX = startX + 3;
- startZ = -1;
- endZ = 1;
- } else if (direction == 2) {
- startX = -4;
- endX = startX + 3;
- startZ = -1;
- endZ = 1;
- } else if (direction == 3) {
- startX = -1;
- endX = 1;
- startZ = 1;
- endZ = startZ + 3;
- } else {
- startX = -1;
- endX = 1;
- startZ = -4;
- endZ = startZ + 3;
- }
-
- Material type;
- int x = startX;
- int y = 0;
- int z = startZ;
- while (y <= 2) {
- while (x <= endX) {
- while (z <= endZ) {
- Block block = spigot.getRelative(x, y, z);
- type = block.getType();
- if (direction == 1 || direction == 2) {
- if (y == 1 && z == 0) {
- if (x == -1 || x == -4 || x == 1 || x == 4) {
- woods.add(block.getX());
- woods.add(block.getY());
- woods.add(block.getZ());
- }
- z++;
- continue;
- }
- } else {
- if (y == 1 && x == 0) {
- if (z == -1 || z == -4 || z == 1 || z == 4) {
- woods.add(block.getX());
- woods.add(block.getY());
- woods.add(block.getZ());
- }
- z++;
- continue;
- }
- }
- if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
- if (LegacyUtil.isWoodPlanks(type)) {
- woods.add(block.getX());
- woods.add(block.getY());
- woods.add(block.getZ());
- } else {
- stairs.add(block.getX());
- stairs.add(block.getY());
- stairs.add(block.getZ());
- }
- z++;
- } else {
- return block;
- }
- }
- z = startZ;
- x++;
- }
- z = startZ;
- x = startX;
- y++;
- }
- stairsloc = ArrayUtils.toPrimitive(stairs.toArray(new Integer[0]));
- woodsloc = ArrayUtils.toPrimitive(woods.toArray(new Integer[0]));
-
- return null;
- }
-
public static class BarrelCheck extends BukkitRunnable {
@Override
public void run() {
@@ -881,17 +537,17 @@ public class Barrel implements InventoryHolder {
if (check < barrels.size()) {
Barrel barrel = barrels.get(check);
if (!barrel.checked) {
- Block broken = barrel.getBrokenBlock(false);
+ Block broken = barrel.body.getBrokenBlock(false);
if (broken != null) {
- P.p.debugLog("Barrel at " + broken.getWorld().getName() + "/" + broken.getX() + "/" + broken.getY() + "/" + broken.getZ()
- + " has been destroyed unexpectedly, contents will drop");
+ P.p.debugLog("Barrel at "
+ + broken.getWorld().getName() + "/" + broken.getX() + "/" + broken.getY() + "/" + broken.getZ()
+ + " has been destroyed unexpectedly, contents will drop");
// remove the barrel if it was destroyed
- barrel.willDestroy();
- barrel.remove(broken, null);
+ barrel.remove(broken, null, true);
} else {
- // Dont check this barrel again, its enough to check it once after every restart
- // as now this is only the backup if we dont register the barrel breaking, as sample
- // when removing it with some world editor
+ // Dont check this barrel again, its enough to check it once after every restart (and when randomly chosen)
+ // as now this is only the backup if we dont register the barrel breaking,
+ // for example when removing it with some world editor
barrel.checked = true;
}
repeat = false;
diff --git a/src/com/dre/brewery/BarrelBody.java b/src/com/dre/brewery/BarrelBody.java
new file mode 100644
index 0000000..da0c617
--- /dev/null
+++ b/src/com/dre/brewery/BarrelBody.java
@@ -0,0 +1,384 @@
+package com.dre.brewery;
+
+import com.dre.brewery.utility.BUtil;
+import com.dre.brewery.utility.BoundingBox;
+import com.dre.brewery.utility.LegacyUtil;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.configuration.ConfigurationSection;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+
+/**
+ * The Blocks that make up a Barrel in the World
+ */
+public class BarrelBody {
+
+ private final Barrel barrel;
+ private final Block spigot;
+ private BoundingBox bounds;
+ private byte signoffset;
+
+ public BarrelBody(Barrel barrel, byte signoffset) {
+ this.barrel = barrel;
+ this.signoffset = signoffset;
+ spigot = barrel.getSpigot();
+ this.bounds = new BoundingBox(0, 0, 0, 0, 0, 0);
+ }
+
+ /**
+ * Loading from file
+ */
+ public BarrelBody(Barrel barrel, byte signoffset, BoundingBox bounds) {
+ this(barrel, signoffset);
+
+ if (bounds == null || bounds.area() > 64 ) {
+ // If loading from old data, or block locations are missing, or other error, regenerate BoundingBox
+ // This will only be done in those extreme cases.
+ Block broken = getBrokenBlock(true);
+ if (broken != null) {
+ barrel.remove(broken, null, true);
+ }
+ } else {
+ this.bounds = bounds;
+ }
+ }
+
+ public Barrel getBarrel() {
+ return barrel;
+ }
+
+ public Block getSpigot() {
+ return spigot;
+ }
+
+ @NotNull
+ public BoundingBox getBounds() {
+ return bounds;
+ }
+
+ public void setBounds(@NotNull BoundingBox bounds) {
+ Objects.requireNonNull(bounds);
+ this.bounds = bounds;
+ }
+
+ public byte getSignoffset() {
+ return signoffset;
+ }
+
+ public void setSignoffset(byte signoffset) {
+ this.signoffset = signoffset;
+ }
+
+ /**
+ * If the Sign of a Large Barrel gets destroyed, set signOffset to 0
+ */
+ public void destroySign() {
+ signoffset = 0;
+ }
+
+ /**
+ * direction of the barrel from the spigot
+ */
+ public static int getDirection(Block spigot) {
+ int direction = 0;// 1=x+ 2=x- 3=z+ 4=z-
+ Material type = spigot.getRelative(0, 0, 1).getType();
+ if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
+ direction = 3;
+ }
+ type = spigot.getRelative(0, 0, -1).getType();
+ if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
+ if (direction == 0) {
+ direction = 4;
+ } else {
+ return 0;
+ }
+ }
+ type = spigot.getRelative(1, 0, 0).getType();
+ if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
+ if (direction == 0) {
+ direction = 1;
+ } else {
+ return 0;
+ }
+ }
+ type = spigot.getRelative(-1, 0, 0).getType();
+ if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
+ if (direction == 0) {
+ direction = 2;
+ } else {
+ return 0;
+ }
+ }
+ return direction;
+ }
+
+ /**
+ * is this a Large barrel?
+ */
+ public boolean isLarge() {
+ return barrel.isLarge();
+ }
+
+ /**
+ * is this a Small barrel?
+ */
+ public boolean isSmall() {
+ return barrel.isSmall();
+ }
+
+ /**
+ * woodtype of the block the spigot is attached to
+ */
+ public byte getWood() {
+ Block wood;
+ switch (getDirection(spigot)) { // 1=x+ 2=x- 3=z+ 4=z-
+ case 0:
+ return 0;
+ case 1:
+ wood = spigot.getRelative(1, 0, 0);
+ break;
+ case 2:
+ wood = spigot.getRelative(-1, 0, 0);
+ break;
+ case 3:
+ wood = spigot.getRelative(0, 0, 1);
+ break;
+ default:
+ wood = spigot.getRelative(0, 0, -1);
+ }
+ try {
+ return LegacyUtil.getWoodType(wood);
+ } catch (NoSuchFieldError | NoClassDefFoundError noSuchFieldError) {
+ // Using older minecraft versions some fields and classes do not exist
+ return 0;
+ }
+ }
+
+ /**
+ * Returns true if this Block is part of this Barrel
+ *
+ * @param block the block to check
+ * @return true if the given block is part of this Barrel
+ */
+ public boolean hasBlock(Block block) {
+ if (block != null) {
+ if (spigot.equals(block)) {
+ return true;
+ }
+ if (spigot.getWorld().equals(block.getWorld())) {
+ return bounds != null && bounds.contains(block.getX(), block.getY(), block.getZ());
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the Offset of the clicked Sign matches the Barrel.
+ * This prevents adding another sign to the barrel and clicking that.
+ */
+ public boolean isSignOfBarrel(byte offset) {
+ return offset == 0 || signoffset == 0 || signoffset == offset;
+ }
+
+ /**
+ * returns the Sign of a large barrel, the spigot if there is none
+ */
+ public Block getSignOfSpigot() {
+ if (signoffset != 0) {
+ if (LegacyUtil.isSign(spigot.getType())) {
+ return spigot;
+ }
+
+ if (LegacyUtil.isSign(spigot.getRelative(0, signoffset, 0).getType())) {
+ return spigot.getRelative(0, signoffset, 0);
+ } else {
+ signoffset = 0;
+ }
+ }
+ return spigot;
+ }
+
+ /**
+ * returns the fence above/below a block, itself if there is none
+ */
+ public static Block getSpigotOfSign(Block block) {
+
+ int y = -2;
+ while (y <= 1) {
+ // Fence and Netherfence
+ Block relative = block.getRelative(0, y, 0);
+ if (LegacyUtil.isFence(relative.getType())) {
+ return (relative);
+ }
+ y++;
+ }
+ return block;
+ }
+
+ /**
+ * returns null if Barrel is correctly placed; the block that is missing when not.
+ *
the barrel needs to be formed correctly
+ *
+ * @param force to also check even if chunk is not loaded
+ */
+ public Block getBrokenBlock(boolean force) {
+ if (force || BUtil.isChunkLoaded(spigot)) {
+ //spigot = getSpigotOfSign(spigot);
+ if (LegacyUtil.isSign(spigot.getType())) {
+ return checkSBarrel();
+ } else {
+ return checkLBarrel();
+ }
+ }
+ return null;
+ }
+
+ public Block checkSBarrel() {
+ int direction = getDirection(spigot);// 1=x+ 2=x- 3=z+ 4=z-
+ if (direction == 0) {
+ return spigot;
+ }
+ int startX;
+ int startZ;
+ int endX;
+ int endZ;
+
+ if (direction == 1) {
+ startX = 1;
+ startZ = -1;
+ } else if (direction == 2) {
+ startX = -2;
+ startZ = 0;
+ } else if (direction == 3) {
+ startX = 0;
+ startZ = 1;
+ } else {
+ startX = -1;
+ startZ = -2;
+ }
+ endX = startX + 1;
+ endZ = startZ + 1;
+
+ Material type;
+ int x = startX;
+ int y = 0;
+ int z = startZ;
+ while (y <= 1) {
+ while (x <= endX) {
+ while (z <= endZ) {
+ Block block = spigot.getRelative(x, y, z);
+ type = block.getType();
+
+ if (LegacyUtil.isWoodStairs(type)) {
+ if (y == 0) {
+ // stairs have to be upside down
+ if (!LegacyUtil.areStairsInverted(block)) {
+ return block;
+ }
+ }
+ z++;
+ } else {
+ return spigot.getRelative(x, y, z);
+ }
+ }
+ z = startZ;
+ x++;
+ }
+ z = startZ;
+ x = startX;
+ y++;
+ }
+ bounds = new BoundingBox(
+ spigot.getX() + startX,
+ spigot.getY(),
+ spigot.getZ() + startZ,
+ spigot.getX() + endX,
+ spigot.getY() + 1,
+ spigot.getZ() + endZ);
+ return null;
+ }
+
+ public Block checkLBarrel() {
+ int direction = getDirection(spigot);// 1=x+ 2=x- 3=z+ 4=z-
+ if (direction == 0) {
+ return spigot;
+ }
+ int startX;
+ int startZ;
+ int endX;
+ int endZ;
+
+ if (direction == 1) {
+ startX = 1;
+ startZ = -1;
+ } else if (direction == 2) {
+ startX = -4;
+ startZ = -1;
+ } else if (direction == 3) {
+ startX = -1;
+ startZ = 1;
+ } else {
+ startX = -1;
+ startZ = -4;
+ }
+ if (direction == 1 || direction == 2) {
+ endX = startX + 3;
+ endZ = startZ + 2;
+ } else {
+ endX = startX + 2;
+ endZ = startZ + 3;
+ }
+
+ Material type;
+ int x = startX;
+ int y = 0;
+ int z = startZ;
+ while (y <= 2) {
+ while (x <= endX) {
+ while (z <= endZ) {
+ Block block = spigot.getRelative(x, y, z);
+ type = block.getType();
+ if (direction == 1 || direction == 2) {
+ if (y == 1 && z == 0) {
+ z++;
+ continue;
+ }
+ } else {
+ if (y == 1 && x == 0) {
+ z++;
+ continue;
+ }
+ }
+ if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)) {
+ z++;
+ } else {
+ return block;
+ }
+ }
+ z = startZ;
+ x++;
+ }
+ z = startZ;
+ x = startX;
+ y++;
+ }
+ bounds = new BoundingBox(
+ spigot.getX() + startX,
+ spigot.getY(),
+ spigot.getZ() + startZ,
+ spigot.getX() + endX,
+ spigot.getY() + 2,
+ spigot.getZ() + endZ);
+
+ return null;
+ }
+
+ public void save(ConfigurationSection config, String prefix) {
+ if (signoffset != 0) {
+ config.set(prefix + ".sign", signoffset);
+ }
+ config.set(prefix + ".bounds", bounds.serialize());
+ }
+}
diff --git a/src/com/dre/brewery/Brew.java b/src/com/dre/brewery/Brew.java
index 60994b4..429d9dc 100644
--- a/src/com/dre/brewery/Brew.java
+++ b/src/com/dre/brewery/Brew.java
@@ -1,106 +1,214 @@
package com.dre.brewery;
-import org.bukkit.Color;
+import com.dre.brewery.api.events.brew.BrewModifyEvent;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.filedata.ConfigUpdater;
+import com.dre.brewery.lore.*;
+import com.dre.brewery.recipe.BEffect;
+import com.dre.brewery.recipe.BRecipe;
+import com.dre.brewery.recipe.PotionColor;
+import com.dre.brewery.utility.BUtil;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.BrewerInventory;
-import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.potion.PotionType;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Nullable;
+import java.io.*;
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
-public class Brew {
-
- // represents the liquid in the brewed Potions
-
- public static Map potions = new HashMap<>();
+/**
+ * Represents the liquid in the brewed Potions
+ */
+public class Brew implements Cloneable {
+ public static final byte SAVE_VER = 1;
+ private static long saveSeed;
+ private static List prevSaveSeeds = new ArrayList<>(); // Save Seeds that have been used in the past, stored to decode brews made at that time
+ public static Map legacyPotions = new HashMap<>();
public static long installTime = System.currentTimeMillis(); // plugin install time in millis after epoch
- public static Boolean colorInBarrels; // color the Lore while in Barrels
- public static Boolean colorInBrewer; // color the Lore while in Brewer
private BIngredients ingredients;
private int quality;
- private int distillRuns;
+ private int alc;
+ private byte distillRuns;
private float ageTime;
private float wood;
- private BRecipe currentRecipe;
+ private BRecipe currentRecipe; // Recipe this Brew is currently Based off. May change between modifications and is often null when not modifying
private boolean unlabeled;
- private boolean persistent;
- private boolean stat; // static potions should not be changed
+ private boolean persistent; // Only for legacy
+ private boolean immutable; // static/immutable potions should not be changed
private int lastUpdate; // last update in hours after install time
+ private boolean needsSave; // There was a change that has not yet been saved
- public Brew(int uid, BIngredients ingredients) {
+ /**
+ * A new Brew with only ingredients
+ */
+ public Brew(BIngredients ingredients) {
this.ingredients = ingredients;
touch();
- potions.put(uid, this);
}
- // quality already set
- public Brew(int uid, int quality, BRecipe recipe, BIngredients ingredients) {
+ /**
+ * A Brew with quality, alc and recipe already set
+ */
+ public Brew(int quality, int alc, BRecipe recipe, BIngredients ingredients) {
this.ingredients = ingredients;
this.quality = quality;
+ this.alc = alc;
this.currentRecipe = recipe;
touch();
- potions.put(uid, this);
}
- // loading from file
- public Brew(int uid, BIngredients ingredients, int quality, int distillRuns, float ageTime, float wood, String recipe, boolean unlabeled, boolean persistent, boolean stat, int lastUpdate) {
- potions.put(uid, this);
+ /**
+ * Loading a Brew with all values set
+ */
+ public Brew(BIngredients ingredients, int quality, int alc, byte distillRuns, float ageTime, float wood, String recipe, boolean unlabeled, boolean immutable, int lastUpdate) {
this.ingredients = ingredients;
this.quality = quality;
+ this.alc = alc;
this.distillRuns = distillRuns;
this.ageTime = ageTime;
this.wood = wood;
this.unlabeled = unlabeled;
- this.persistent = persistent;
- this.stat = stat;
+ this.immutable = immutable;
this.lastUpdate = lastUpdate;
setRecipeFromString(recipe);
}
- // returns a Brew by its UID
+ // Loading from InputStream
+ private Brew() {
+ }
+
+ /**
+ * returns a Brew by ItemMeta
+ *
+ * @param meta The meta to get the brew from
+ * @return The Brew if meta is a brew, null if not
+ */
+ @Nullable
+ public static Brew get(ItemMeta meta) {
+ if (!P.useNBT && !meta.hasLore()) return null;
+
+ Brew brew = load(meta);
+
+ if (brew == null && meta instanceof PotionMeta && ((PotionMeta) meta).hasCustomEffect(PotionEffectType.REGENERATION)) {
+ // Load Legacy
+ return getFromPotionEffect(((PotionMeta) meta), false);
+ }
+ return brew;
+ }
+
+ /**
+ * returns a Brew by ItemStack
+ *
+ * @param item The Item to get the brew from
+ * @return The Brew if item is a brew, null if not
+ */
+ @Nullable
+ public static Brew get(ItemStack item) {
+ if (item.getType() != Material.POTION) return null;
+ if (!item.hasItemMeta()) return null;
+
+ ItemMeta meta = item.getItemMeta();
+ assert meta != null;
+ if (!P.useNBT && !meta.hasLore()) return null;
+
+ Brew brew = load(meta);
+
+ if (brew == null && meta instanceof PotionMeta && ((PotionMeta) meta).hasCustomEffect(PotionEffectType.REGENERATION)) {
+ // Load Legacy and convert
+ brew = getFromPotionEffect(((PotionMeta) meta), true);
+ if (brew == null) return null;
+ new BrewLore(brew, (PotionMeta) meta).removeLegacySpacing();
+ brew.save(meta);
+ item.setItemMeta(meta);
+ } else if (brew != null && brew.needsSave) {
+ // Brew needs saving from a previous format
+ if (P.useNBT) {
+ new BrewLore(brew, (PotionMeta) meta).removeLoreData();
+ P.p.debugLog("removed Data from Lore");
+ }
+ brew.save(meta);
+ item.setItemMeta(meta);
+ }
+ return brew;
+ }
+
+ // Legacy Brew Loading
+ private static Brew getFromPotionEffect(PotionMeta potionMeta, boolean remove) {
+ for (PotionEffect effect : potionMeta.getCustomEffects()) {
+ if (effect.getType().equals(PotionEffectType.REGENERATION)) {
+ if (effect.getDuration() < -1) {
+ if (remove) {
+ Brew b = legacyPotions.get(effect.getDuration());
+ if (b != null) {
+ potionMeta.removeCustomEffect(PotionEffectType.REGENERATION);
+ if (b.persistent) {
+ return b;
+ } else {
+ return legacyPotions.remove(effect.getDuration());
+ }
+ }
+ return null;
+ } else {
+ return legacyPotions.get(effect.getDuration());
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * returns a Brew by its UID
+ *
+ * @deprecated Does not work anymore with new save system
+ */
+ @Deprecated
public static Brew get(int uid) {
if (uid < -1) {
- if (!potions.containsKey(uid)) {
+ if (!legacyPotions.containsKey(uid)) {
P.p.errorLog("Database failure! unable to find UID " + uid + " of a custom Potion!");
return null;// throw some exception?
}
} else {
return null;
}
- return potions.get(uid);
+ return legacyPotions.get(uid);
}
- // returns a Brew by PotionMeta
- public static Brew get(PotionMeta meta) {
- return get(getUID(meta));
- }
-
- // returns a Brew by ItemStack
- public static Brew get(ItemStack item) {
- if (item.getType() == Material.POTION) {
- if (item.hasItemMeta()) {
- return get((PotionMeta) item.getItemMeta());
- }
- }
- return null;
- }
-
- // returns UID of custom Potion item
+ /**
+ * returns UID of custom Potion item
+ *
+ * @deprecated Does not work anymore with new save system
+ */
+ @Deprecated
public static int getUID(ItemStack item) {
return getUID((PotionMeta) item.getItemMeta());
}
// returns UID of custom Potion meta
+ // Does not work anymore with new save system
+
+ /**
+ * returns UID of custom Potion meta
+ *
+ * @deprecated Does not work anymore with new save system
+ */
+ @Deprecated
public static int getUID(PotionMeta potionMeta) {
if (potionMeta.hasCustomEffect(PotionEffectType.REGENERATION)) {
for (PotionEffect effect : potionMeta.getCustomEffects()) {
@@ -115,20 +223,22 @@ public class Brew {
}
// generate an UID
- public static int generateUID() {
+ /*public static int generateUID() {
int uid = -2;
while (potions.containsKey(uid)) {
uid -= 1;
}
return uid;
- }
+ }*/
- //returns the recipe with the given name, recalculates if not found
+ /**
+ * returns the recipe with the given name, recalculates if not found
+ */
public boolean setRecipeFromString(String name) {
currentRecipe = null;
if (name != null && !name.equals("")) {
- for (BRecipe recipe : BIngredients.recipes) {
- if (recipe.getName(5).equalsIgnoreCase(name)) {
+ for (BRecipe recipe : BRecipe.getAllRecipes()) {
+ if (recipe.getRecipeName().equalsIgnoreCase(name)) {
currentRecipe = recipe;
return true;
}
@@ -137,13 +247,13 @@ public class Brew {
if (quality > 0) {
currentRecipe = ingredients.getBestRecipe(wood, ageTime, distillRuns > 0);
if (currentRecipe != null) {
- if (!stat) {
+ /*if (!immutable) {
this.quality = calcQuality();
- }
- P.p.log("Brew was made from Recipe: '" + name + "' which could not be found. '" + currentRecipe.getName(5) + "' used instead!");
+ }*/
+ P.p.log("A Brew was made from Recipe: '" + name + "' which could not be found. '" + currentRecipe.getRecipeName() + "' used instead!");
return true;
} else {
- P.p.errorLog("Brew was made from Recipe: '" + name + "' which could not be found!");
+ P.p.errorLog("A Brew was made from Recipe: '" + name + "' which could not be found!");
}
}
}
@@ -151,11 +261,12 @@ public class Brew {
}
public boolean reloadRecipe() {
- return currentRecipe == null || setRecipeFromString(currentRecipe.getName(5));
+ return currentRecipe == null || setRecipeFromString(currentRecipe.getRecipeName());
}
// Copy a Brew with a new unique ID and return its item
- public ItemStack copy(ItemStack item) {
+ // Not needed anymore
+ /*public ItemStack copy(ItemStack item) {
ItemStack copy = item.clone();
int uid = generateUID();
clone(uid);
@@ -167,28 +278,64 @@ public class Brew {
meta.addCustomEffect((PotionEffectType.REGENERATION).createEffect(uid, 0), true);
copy.setItemMeta(meta);
return copy;
+ }*/
+
+ public boolean isSimilar(Brew brew) {
+ if (brew == null) return false;
+ if (equals(brew)) return true;
+ return quality == brew.quality &&
+ alc == brew.alc &&
+ distillRuns == brew.distillRuns &&
+ Float.compare(brew.ageTime, ageTime) == 0 &&
+ Float.compare(brew.wood, wood) == 0 &&
+ unlabeled == brew.unlabeled &&
+ persistent == brew.persistent &&
+ immutable == brew.immutable &&
+ ingredients.equals(brew.ingredients) &&
+ (Objects.equals(currentRecipe, brew.currentRecipe));
}
- // Clones this instance with a new unique ID
- public Brew clone(int uid) {
- Brew brew = new Brew(uid, quality, currentRecipe, ingredients);
- brew.distillRuns = distillRuns;
- brew.ageTime = ageTime;
- brew.unlabeled = unlabeled;
- if (!brew.persistent) {
- brew.stat = stat;
+ /**
+ * Clones this instance
+ */
+ @Override
+ public Brew clone() {
+ try {
+ Brew brew = (Brew) super.clone();
+ brew.ingredients = ingredients.copy();
+ return brew;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError(e);
}
- return brew;
+ }
+
+ @Override
+ public String toString() {
+ return "Brew{" +
+ ingredients + " ingredients" +
+ ", quality=" + quality +
+ ", alc=" + alc +
+ ", distillRuns=" + distillRuns +
+ ", ageTime=" + ageTime +
+ ", wood=" + wood +
+ ", currentRecipe=" + currentRecipe +
+ ", unlabeled=" + unlabeled +
+ ", immutable=" + immutable +
+ '}';
}
// remove potion from file (drinking, despawning, combusting, cmdDeleting, should be more!)
- public void remove(ItemStack item) {
+ // Not needed anymore
+ /*public void remove(ItemStack item) {
if (!persistent) {
potions.remove(getUID(item));
}
- }
+ }*/
- // calculate alcohol from recipe
+ /**
+ * calculate alcohol from recipe
+ */
+ @Contract(pure = true)
public int calcAlcohol() {
if (quality == 0) {
// Give bad potions some alc
@@ -215,13 +362,13 @@ public class Brew {
return 0;
}
// bad quality can decrease alc by up to 40%
- alc *= 1 - ((float) (10 - quality) * 0.04);
+ alc *= 1 - ((float) (10 - quality) * 0.04f);
// distillable Potions should have half alc after one and full alc after all needed distills
alc /= 2;
alc *= 1.0F + ((float) distillRuns / currentRecipe.getDistillRuns());
} else {
// quality decides 10% - 100%
- alc *= ((float) quality / 10.0);
+ alc *= ((float) quality / 10.0f);
}
if (alc > 0) {
return alc;
@@ -230,7 +377,10 @@ public class Brew {
return 0;
}
- // calculating quality
+ /**
+ * calculating quality
+ */
+ @Contract(pure = true)
public int calcQuality() {
// calculate quality from all of the factors
float quality = ingredients.getIngredientQuality(currentRecipe) + ingredients.getCookingQuality(currentRecipe, distillRuns > 0);
@@ -248,7 +398,7 @@ public class Brew {
}
public boolean canDistill() {
- if (stat) return false;
+ if (immutable) return false;
if (currentRecipe != null) {
return currentRecipe.getDistillRuns() > distillRuns;
} else {
@@ -256,35 +406,56 @@ public class Brew {
}
}
- // return special effect
- public ArrayList getEffects() {
+ /**
+ * Get Special Drink Effects
+ */
+ public List getEffects() {
if (currentRecipe != null && quality > 0) {
return currentRecipe.getEffects();
}
return null;
}
- // Set unlabeled to true to hide the numbers in Lore
+ /**
+ * Set unlabeled to true to hide the numbers in Lore
+ *
+ * @param item The Item this Brew is on
+ */
public void unLabel(ItemStack item) {
- PotionMeta meta = (PotionMeta) item.getItemMeta();
- if (meta.hasLore()) {
+ unlabeled = true;
+ ItemMeta meta = item.getItemMeta();
+ if (meta instanceof PotionMeta && meta.hasLore()) {
+ BrewLore lore = new BrewLore(this, ((PotionMeta) meta));
if (distillRuns > 0) {
- addOrReplaceLore(meta, P.p.color("&7"), P.p.languageReader.get("Brew_Distilled"));
+ lore.updateDistillLore(false);
}
if (ageTime >= 1) {
- addOrReplaceLore(meta, P.p.color("&7"), P.p.languageReader.get("Brew_BarrelRiped"));
+ lore.updateAgeLore(false);
}
+ lore.updateQualityStars(false);
+ lore.updateAlc(false);
+ lore.write();
item.setItemMeta(meta);
}
- unlabeled = true;
}
- // Do some regular updates
+ /**
+ * Do some regular updates.
+ * Not really used, apart from legacy potion timed purge
+ */
public void touch() {
lastUpdate = (int) ((double) (System.currentTimeMillis() - installTime) / 3600000D);
}
- public int getDistillRuns() {
+ public int getOrCalcAlc() {
+ return alc > 0 ? alc : (alc = calcAlcohol());
+ }
+
+ public void setAlc(int alc) {
+ this.alc = alc;
+ }
+
+ public byte getDistillRuns() {
return distillRuns;
}
@@ -292,36 +463,52 @@ public class Brew {
return ageTime;
}
+ public float getWood() {
+ return wood;
+ }
+
+ public BIngredients getIngredients() {
+ return ingredients;
+ }
+
+ public boolean hasRecipe() {
+ return currentRecipe != null;
+ }
+
public BRecipe getCurrentRecipe() {
return currentRecipe;
}
- public boolean isPersistent() {
- return persistent;
- }
-
- // Make a potion persistent to not delete it when drinking it
- public void makePersistent() {
- persistent = true;
- }
-
- // Remove the Persistence Flag from a brew, so it will be normally deleted when drinking it
- public void removePersistence() {
- persistent = false;
- }
-
public boolean isStatic() {
- return stat;
+ return immutable;
}
- // Set the Static flag, so potion is unchangeable
- public void setStatic(boolean stat, ItemStack potion) {
- this.stat = stat;
+ public boolean isImmutable() {
+ return immutable;
+ }
+
+ public boolean isUnlabeled() {
+ return unlabeled;
+ }
+
+ public boolean needsSave() {
+ return needsSave;
+ }
+
+ public void setNeedsSave(boolean needsSave) {
+ this.needsSave = needsSave;
+ }
+
+ /**
+ * Set the Static flag, so potion is unchangeable
+ */
+ public void setStatic(boolean immutable, ItemStack potion) {
+ this.immutable = immutable;
if (currentRecipe != null && canDistill()) {
- if (stat) {
- PotionColor.fromString(currentRecipe.getColor()).colorBrew(((PotionMeta) potion.getItemMeta()), potion, false);
+ if (immutable) {
+ currentRecipe.getColor().colorBrew(((PotionMeta) potion.getItemMeta()), potion, false);
} else {
- PotionColor.fromString(currentRecipe.getColor()).colorBrew(((PotionMeta) potion.getItemMeta()), potion, true);
+ currentRecipe.getColor().colorBrew(((PotionMeta) potion.getItemMeta()), potion, true);
}
}
}
@@ -332,7 +519,12 @@ public class Brew {
// Distilling section ---------------
- // distill all custom potions in the brewer
+ /**
+ * distill all custom potions in the brewer
+ *
+ * @param inv The Inventory of the Distiller
+ * @param contents The Brews in the 3 slots of the Inventory
+ */
public static void distillAll(BrewerInventory inv, Brew[] contents) {
for (int slot = 0; slot < 3; slot++) {
if (contents[slot] != null) {
@@ -343,42 +535,54 @@ public class Brew {
}
}
- // distill custom potion in given slot
+ /**
+ * distill custom potion in a distiller slot
+ *
+ * @param slotItem The item in the slot
+ * @param potionMeta The meta of the item
+ */
public void distillSlot(ItemStack slotItem, PotionMeta potionMeta) {
- if (stat) {
- return;
- }
+ if (immutable) return;
distillRuns += 1;
- BRecipe recipe = ingredients.getdistillRecipe(wood, ageTime);
+ BrewLore lore = new BrewLore(this, potionMeta);
+ BRecipe recipe = ingredients.getDistillRecipe(wood, ageTime);
if (recipe != null) {
// distillRuns will have an effect on the amount of alcohol, not the quality
currentRecipe = recipe;
quality = calcQuality();
- addOrReplaceEffects(potionMeta, getEffects(), quality);
+ lore.addOrReplaceEffects(getEffects(), quality);
potionMeta.setDisplayName(P.p.color("&f" + recipe.getName(quality)));
- PotionColor.fromString(recipe.getColor()).colorBrew(potionMeta, slotItem, canDistill());
+ recipe.getColor().colorBrew(potionMeta, slotItem, canDistill());
} else {
quality = 0;
- removeEffects(potionMeta);
+ lore.removeEffects();
potionMeta.setDisplayName(P.p.color("&f" + P.p.languageReader.get("Brew_DistillUndefined")));
PotionColor.GREY.colorBrew(potionMeta, slotItem, canDistill());
}
+ alc = calcAlcohol();
// Distill Lore
- if (currentRecipe != null) {
- if (colorInBrewer != hasColorLore(potionMeta)) {
- convertLore(potionMeta, colorInBrewer);
- }
+ if (currentRecipe != null && BConfig.colorInBrewer != BrewLore.hasColorLore(potionMeta)) {
+ lore.convertLore(BConfig.colorInBrewer);
+ } else {
+ lore.updateQualityStars(BConfig.colorInBrewer);
+ lore.updateCustomLore();
+ lore.updateDistillLore(BConfig.colorInBrewer);
}
- String prefix = P.p.color("&7");
- if (colorInBrewer && currentRecipe != null) {
- prefix = getQualityColor(ingredients.getDistillQuality(currentRecipe, distillRuns));
- }
- updateDistillLore(prefix, potionMeta);
+ lore.updateAlc(true);
+ lore.write();
touch();
+ BrewModifyEvent modifyEvent = new BrewModifyEvent(this, potionMeta, BrewModifyEvent.Type.DISTILL);
+ P.p.getServer().getPluginManager().callEvent(modifyEvent);
+ if (modifyEvent.isCancelled()) {
+ // As the brew and everything connected to it is only saved on the meta from now on,
+ // not saving the brew into potionMeta is enough to not change anything in case of cancel
+ return;
+ }
+ save(potionMeta);
slotItem.setItemMeta(potionMeta);
}
@@ -392,7 +596,7 @@ public class Brew {
return currentRecipe.getDistillTime();
}
- BRecipe recipe = ingredients.getdistillRecipe(wood, ageTime);
+ BRecipe recipe = ingredients.getDistillRecipe(wood, ageTime);
if (recipe != null) {
return recipe.getDistillTime();
}
@@ -402,11 +606,10 @@ public class Brew {
// Ageing Section ------------------
public void age(ItemStack item, float time, byte woodType) {
- if (stat) {
- return;
- }
-
+ if (immutable) return;
PotionMeta potionMeta = (PotionMeta) item.getItemMeta();
+
+ BrewLore lore = new BrewLore(this, potionMeta);
ageTime += time;
// if younger than half a day, it shouldnt get aged form
@@ -421,47 +624,59 @@ public class Brew {
currentRecipe = recipe;
quality = calcQuality();
- addOrReplaceEffects(potionMeta, getEffects(), quality);
+ lore.addOrReplaceEffects(getEffects(), quality);
potionMeta.setDisplayName(P.p.color("&f" + recipe.getName(quality)));
- PotionColor.fromString(recipe.getColor()).colorBrew(potionMeta, item, canDistill());
+ recipe.getColor().colorBrew(potionMeta, item, canDistill());
} else {
quality = 0;
- removeEffects(potionMeta);
+ lore.convertLore(false);
+ lore.removeEffects();
+ currentRecipe = null;
potionMeta.setDisplayName(P.p.color("&f" + P.p.languageReader.get("Brew_BadPotion")));
PotionColor.GREY.colorBrew(potionMeta, item, canDistill());
}
}
+ alc = calcAlcohol();
// Lore
- if (currentRecipe != null) {
- if (colorInBarrels != hasColorLore(potionMeta)) {
- convertLore(potionMeta, colorInBarrels);
- }
- }
- if (ageTime >= 1) {
- String prefix = P.p.color("&7");
- if (colorInBarrels && currentRecipe != null) {
- prefix = getQualityColor(ingredients.getAgeQuality(currentRecipe, ageTime));
- }
- updateAgeLore(prefix, potionMeta);
- }
- if (ageTime > 0.5) {
- if (colorInBarrels && !unlabeled && currentRecipe != null) {
- updateWoodLore(potionMeta);
+ if (currentRecipe != null && BConfig.colorInBarrels != BrewLore.hasColorLore(potionMeta)) {
+ lore.convertLore(BConfig.colorInBarrels);
+ } else {
+ if (ageTime >= 1) {
+ lore.updateAgeLore(BConfig.colorInBarrels);
+ }
+ if (ageTime > 0.5) {
+ if (BConfig.colorInBarrels) {
+ lore.updateWoodLore(true);
+ }
+ lore.updateQualityStars(BConfig.colorInBarrels);
+ lore.updateCustomLore();
+ lore.updateAlc(false);
}
}
+ lore.write();
touch();
+ BrewModifyEvent modifyEvent = new BrewModifyEvent(this, potionMeta, BrewModifyEvent.Type.AGE);
+ P.p.getServer().getPluginManager().callEvent(modifyEvent);
+ if (modifyEvent.isCancelled()) {
+ // As the brew and everything connected to it is only saved on the meta from now on,
+ // not saving the brew into potionMeta is enough to not change anything in case of cancel
+ return;
+ }
+ save(potionMeta);
item.setItemMeta(potionMeta);
}
- // Slowly shift the wood of the Brew to the new Type
+ /**
+ * Slowly shift the wood of the Brew to the new Type
+ */
public void woodShift(float time, byte to) {
- byte factor = 1;
+ float factor = 1;
if (ageTime > 5) {
factor = 2;
} else if (ageTime > 10) {
factor = 2;
- factor += Math.round(ageTime / 10);
+ factor += ageTime / 10F;
}
if (wood > to) {
wood -= time / factor;
@@ -476,182 +691,364 @@ public class Brew {
}
}
- // Lore -----------
-
- // Converts to/from qualitycolored Lore
- public void convertLore(PotionMeta meta, Boolean toQuality) {
- if (currentRecipe == null) {
- return;
- }
- meta.setLore(null);
- int quality;
- String prefix = P.p.color("&7");
- String lore;
-
- // Ingredients
- if (toQuality && !unlabeled) {
- quality = ingredients.getIngredientQuality(currentRecipe);
- prefix = getQualityColor(quality);
- lore = P.p.languageReader.get("Brew_Ingredients");
- addOrReplaceLore(meta, prefix, lore);
- }
-
- // Cooking
- if (toQuality && !unlabeled) {
- if (distillRuns > 0 == currentRecipe.needsDistilling()) {
- quality = ingredients.getCookingQuality(currentRecipe, distillRuns > 0);
- prefix = getQualityColor(quality) + ingredients.getCookedTime() + " " + P.p.languageReader.get("Brew_minute");
- if (ingredients.getCookedTime() > 1) {
- prefix = prefix + P.p.languageReader.get("Brew_MinutePluralPostfix");
- }
- lore = " " + P.p.languageReader.get("Brew_fermented");
- addOrReplaceLore(meta, prefix, lore);
- }
- }
-
- // Distilling
- if (distillRuns > 0) {
- if (toQuality) {
- quality = ingredients.getDistillQuality(currentRecipe, distillRuns);
- prefix = getQualityColor(quality);
- }
- updateDistillLore(prefix, meta);
- }
-
- // Ageing
- if (ageTime >= 1) {
- if (toQuality) {
- quality = ingredients.getAgeQuality(currentRecipe, ageTime);
- prefix = getQualityColor(quality);
- }
- updateAgeLore(prefix, meta);
- }
-
- // WoodType
- if (toQuality && !unlabeled) {
- if (ageTime > 0.5) {
- updateWoodLore(meta);
- }
- }
+ /**
+ * Create a new Item of this Brew. A BrewModifyEvent type CREATE will be called.
+ *
+ * @param recipe Recipe is required if the brew doesn't have a currentRecipe
+ * @return The created Item, null if the Event is cancelled
+ */
+ public ItemStack createItem(BRecipe recipe) {
+ return createItem(recipe, true);
}
- // sets the DistillLore. Prefix is the color to be used
- public void updateDistillLore(String prefix, PotionMeta meta) {
- if (!unlabeled) {
- if (distillRuns > 1) {
- prefix = prefix + distillRuns + P.p.languageReader.get("Brew_-times") + " ";
+ /**
+ * Create a new Item of this Brew.
+ *
+ * @param recipe Recipe is required if the brew doesn't have a currentRecipe
+ * @param event Set event to true if a BrewModifyEvent type CREATE should be called and may be cancelled. Only then may this method return null
+ * @return The created Item, null if the Event is cancelled
+ */
+ @Contract("_, false -> !null")
+ public ItemStack createItem(BRecipe recipe, boolean event) {
+ if (recipe == null) {
+ recipe = getCurrentRecipe();
+ }
+ if (recipe == null) {
+ throw new IllegalArgumentException("Argument recipe can't be null if the brew doesn't have a currentRecipe");
+ }
+ ItemStack potion = new ItemStack(Material.POTION);
+ PotionMeta potionMeta = (PotionMeta) potion.getItemMeta();
+
+ recipe.getColor().colorBrew(potionMeta, potion, false);
+ potionMeta.setDisplayName(P.p.color("&f" + recipe.getName(quality)));
+ //if (!P.use1_14) {
+ // Before 1.14 the effects duration would strangely be only a quarter of what we tell it to be
+ // This is due to the Duration Modifier, that is removed in 1.14
+ // uid *= 4;
+ //}
+ // This effect stores the UID in its Duration
+ //potionMeta.addCustomEffect((PotionEffectType.REGENERATION).createEffect((uid * 4), 0), true);
+
+ BrewLore lore = new BrewLore(this, potionMeta);
+ lore.convertLore(false);
+ lore.addOrReplaceEffects(recipe.getEffects(), quality);
+ lore.write();
+ touch();
+ if (event) {
+ BrewModifyEvent modifyEvent = new BrewModifyEvent(this, potionMeta, BrewModifyEvent.Type.CREATE);
+ P.p.getServer().getPluginManager().callEvent(modifyEvent);
+ if (modifyEvent.isCancelled()) {
+ return null;
}
}
- addOrReplaceLore(meta, prefix, P.p.languageReader.get("Brew_Distilled"));
+ save(potionMeta);
+ potion.setItemMeta(potionMeta);
+ P.p.metricsForCreate(true);
+ return potion;
}
- // sets the AgeLore. Prefix is the color to be used
- public void updateAgeLore(String prefix, PotionMeta meta) {
- if (!unlabeled) {
- if (ageTime >= 1 && ageTime < 2) {
- prefix = prefix + P.p.languageReader.get("Brew_OneYear") + " ";
- } else if (ageTime < 201) {
- prefix = prefix + (int) Math.floor(ageTime) + " " + P.p.languageReader.get("Brew_Years") + " ";
- } else {
- prefix = prefix + P.p.languageReader.get("Brew_HundredsOfYears") + " ";
+ /**
+ * Performant way of checking if this item is a Brew.
+ *
Does not give any guarantees that get() will return notnull for this item, i.e. if it is a brew but the data is corrupt
+ *
+ * @param item The Item to check
+ * @return True if the item is a brew
+ */
+ public static boolean isBrew(ItemStack item) {
+ if (item == null || item.getType() != Material.POTION) return false;
+ if (!item.hasItemMeta()) return false;
+
+ ItemMeta meta = item.getItemMeta();
+ assert meta != null;
+ if (!P.useNBT && !meta.hasLore()) return false;
+
+ if (P.useNBT) {
+ // Check for Data on PersistentDataContainer
+ if (NBTLoadStream.hasDataInMeta(meta)) {
+ return true;
}
}
- addOrReplaceLore(meta, prefix, P.p.languageReader.get("Brew_BarrelRiped"));
- }
-
- // updates/sets the color on WoodLore
- public void updateWoodLore(PotionMeta meta) {
- if (currentRecipe.getWood() > 0) {
- int quality = ingredients.getWoodQuality(currentRecipe, wood);
- addOrReplaceLore(meta, getQualityColor(quality), P.p.languageReader.get("Brew_Woodtype"));
- } else if (meta.hasLore()) {
- List existingLore = meta.getLore();
- int index = indexOfSubstring(existingLore, P.p.languageReader.get("Brew_Woodtype"));
- if (index > -1) {
- existingLore.remove(index);
- meta.setLore(existingLore);
- }
- }
- }
-
- // Adds or replaces a line of Lore. Searches for Substring lore and replaces it
- public static void addOrReplaceLore(PotionMeta meta, String prefix, String lore) {
+ // If either NBT is not supported or no data was found in NBT, try finding data in lore
if (meta.hasLore()) {
- List existingLore = meta.getLore();
- int index = indexOfSubstring(existingLore, lore);
- if (index > -1) {
- existingLore.set(index, prefix + lore);
- } else {
- existingLore.add(prefix + lore);
- }
- meta.setLore(existingLore);
- return;
+ // Find the Data Identifier in Lore
+ return BUtil.indexOfStart(meta.getLore(), LoreLoadStream.IDENTIFIER) > -1;
}
- List newLore = new ArrayList<>();
- newLore.add("");
- newLore.add(prefix + lore);
- meta.setLore(newLore);
+ return false;
}
- // Adds the Effect names to the Items description
- public static void addOrReplaceEffects(PotionMeta meta, ArrayList effects, int quality) {
- if (!P.use1_9 && effects != null) {
- for (BEffect effect : effects) {
- if (!effect.isHidden()) {
- effect.writeInto(meta, quality);
- }
+ private static Brew load(ItemMeta meta) {
+ InputStream itemLoadStream = null;
+ if (P.useNBT) {
+ // Try loading the Item Data from PersistentDataContainer
+ NBTLoadStream nbtStream = new NBTLoadStream(meta);
+ if (nbtStream.hasData()) {
+ itemLoadStream = nbtStream;
}
}
- }
-
- // Removes all effects except regeneration which stores data
- public static void removeEffects(PotionMeta meta) {
- if (meta.hasCustomEffects()) {
- for (PotionEffect effect : meta.getCustomEffects()) {
- PotionEffectType type = effect.getType();
- if (!type.equals(PotionEffectType.REGENERATION)) {
- meta.removeCustomEffect(type);
- }
+ if (itemLoadStream == null) {
+ // If either NBT is not supported or no data was found in NBT, try loading from Lore
+ try {
+ itemLoadStream = new Base91DecoderStream(new LoreLoadStream(meta, 0));
+ } catch (IllegalArgumentException ignored) {
+ // No Brew data found in Meta
+ return null;
}
}
- }
- // Returns the Index of a String from the list that contains this substring
- public static int indexOfSubstring(List list, String substring) {
- for (int index = 0; index < list.size(); index++) {
- String string = list.get(index);
- if (string.contains(substring)) {
- return index;
+ XORUnscrambleStream unscrambler = new XORUnscrambleStream(itemLoadStream, saveSeed, prevSaveSeeds);
+ try (DataInputStream in = new DataInputStream(unscrambler)) {
+ boolean parityFailed = false;
+ if (in.readByte() != 86) {
+ P.p.errorLog("Parity check failed on Brew while loading, trying to load anyways!");
+ parityFailed = true;
}
+ Brew brew = new Brew();
+ byte ver = in.readByte();
+ switch (ver) {
+ case 1:
+
+ unscrambler.start();
+ brew.loadFromStream(in, ver);
+
+ break;
+ default:
+ if (parityFailed) {
+ P.p.errorLog("Failed to load Brew. Maybe something corrupted the Lore of the Item?");
+ } else {
+ P.p.errorLog("Brew has data stored in v" + ver + " this Plugin version supports up to v1");
+ }
+ return null;
+ }
+
+ XORUnscrambleStream.SuccessType successType = unscrambler.getSuccessType();
+ if (successType == XORUnscrambleStream.SuccessType.PREV_SEED) {
+ P.p.debugLog("Converting Brew from previous Seed");
+ brew.setNeedsSave(true);
+ } else if (BConfig.enableEncode != (successType == XORUnscrambleStream.SuccessType.MAIN_SEED)) {
+ // We have either enabled encode and the data was not encoded or the other way round
+ P.p.debugLog("Converting Brew to new encode setting");
+ brew.setNeedsSave(true);
+ } else if (P.useNBT && itemLoadStream instanceof Base91DecoderStream) {
+ // We are on a version that supports nbt but the data is still in the lore of the item
+ // Just save it again so that it gets saved to nbt
+ P.p.debugLog("Converting Brew to NBT");
+ brew.setNeedsSave(true);
+ }
+ return brew;
+ } catch (IOException e) {
+ P.p.errorLog("IO Error while loading Brew");
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ P.p.errorLog("Failed to load Brew, has the data key 'encodeKey' in the config.yml been changed?");
+ e.printStackTrace();
}
- return -1;
+ return null;
}
- // True if the PotionMeta has colored Lore
- public static Boolean hasColorLore(PotionMeta meta) {
- return meta.hasLore() && (meta.getLore().size() > 1 && !meta.getLore().get(1).startsWith(P.p.color("&7")));
+ private void loadFromStream(DataInputStream in, byte dataVersion) throws IOException {
+ quality = in.readByte();
+ int bools = in.readUnsignedByte();
+ if ((bools & 64) != 0) {
+ alc = in.readShort();
+ }
+ if ((bools & 1) != 0) {
+ distillRuns = in.readByte();
+ }
+ if ((bools & 2) != 0) {
+ ageTime = in.readFloat();
+ }
+ if ((bools & 4) != 0) {
+ wood = in.readFloat();
+ }
+ String recipe = null;
+ if ((bools & 8) != 0) {
+ recipe = in.readUTF();
+ }
+ unlabeled = (bools & 16) != 0;
+ immutable = (bools & 32) != 0;
+ ingredients = BIngredients.load(in, dataVersion);
+ setRecipeFromString(recipe);
}
- // gets the Color that represents a quality in Lore
- public static String getQualityColor(int quality) {
- String color;
- if (quality > 8) {
- color = "&a";
- } else if (quality > 6) {
- color = "&e";
- } else if (quality > 4) {
- color = "&6";
- } else if (quality > 2) {
- color = "&c";
+ /**
+ * Save brew data into meta: lore/nbt.
+ * Should be called after any changes made to the brew
+ */
+ public void save(ItemMeta meta) {
+ OutputStream itemSaveStream;
+ if (P.useNBT) {
+ itemSaveStream = new NBTSaveStream(meta);
} else {
- color = "&4";
+ itemSaveStream = new Base91EncoderStream(new LoreSaveStream(meta, 0));
+ }
+ XORScrambleStream scrambler = new XORScrambleStream(itemSaveStream, saveSeed);
+ try (DataOutputStream out = new DataOutputStream(scrambler)) {
+ out.writeByte(86); // Parity/sanity
+ out.writeByte(SAVE_VER); // Version
+ if (BConfig.enableEncode) {
+ scrambler.start();
+ } else {
+ scrambler.startUnscrambled();
+ }
+ saveToStream(out);
+ } catch (IOException e) {
+ P.p.errorLog("IO Error while saving Brew");
+ e.printStackTrace();
}
- return P.p.color(color);
}
- // Saves all data
- public static void save(ConfigurationSection config) {
- for (Map.Entry entry : potions.entrySet()) {
+ /**
+ * Save brew data into the meta/lore of the specified item.
+ * The meta on the item changes, so to make further changes to the meta, item.getItemMeta() has to be called again after this
+ *
+ * @param item The item to save this brew into
+ */
+ public void save(ItemStack item) {
+ ItemMeta meta;
+ if (!item.hasItemMeta()) {
+ meta = P.p.getServer().getItemFactory().getItemMeta(item.getType());
+ } else {
+ meta = item.getItemMeta();
+ }
+ save(meta);
+ item.setItemMeta(meta);
+ }
+
+ public void saveToStream(DataOutputStream out) throws IOException {
+ if (quality > 10) {
+ quality = 10;
+ }
+ alc = Math.min(alc, Short.MAX_VALUE);
+ out.writeByte((byte) quality);
+ int bools = 0;
+ bools |= ((distillRuns != 0) ? 1 : 0);
+ bools |= (ageTime > 0 ? 2 : 0);
+ bools |= (wood != -1 ? 4 : 0);
+ bools |= (currentRecipe != null ? 8 : 0);
+ bools |= (unlabeled ? 16 : 0);
+ bools |= (immutable ? 32 : 0);
+ bools |= (alc > 0 ? 64 : 0);
+ out.writeByte(bools);
+ if (alc > 0) {
+ out.writeShort(alc);
+ }
+ if (distillRuns != 0) {
+ out.writeByte(distillRuns);
+ }
+ if (ageTime > 0) {
+ out.writeFloat(ageTime);
+ }
+ if (wood != -1) {
+ out.writeFloat(wood);
+ }
+ if (currentRecipe != null) {
+ out.writeUTF(currentRecipe.getRecipeName());
+ }
+ ingredients.save(out);
+ }
+
+ public static void loadPrevSeeds(ConfigurationSection section) {
+ if (section.contains("prevSaveSeeds")) {
+ prevSaveSeeds = section.getLongList("prevSaveSeeds");
+ if (!prevSaveSeeds.contains(saveSeed)) {
+ prevSaveSeeds.add(saveSeed);
+ }
+ }
+ }
+
+ public static void writePrevSeeds(ConfigurationSection section) {
+ if (!prevSaveSeeds.isEmpty()) {
+ section.set("prevSaveSeeds", prevSaveSeeds);
+ }
+ }
+
+ public static void loadSeed(ConfigurationSection config, File file) {
+ saveSeed = config.getLong("encodeKey", 0);
+ if (saveSeed == 0) {
+ while (saveSeed == 0) {
+ saveSeed = new SecureRandom().nextLong();
+ }
+ ConfigUpdater updater = new ConfigUpdater(file);
+ updater.setEncodeKey(saveSeed);
+ updater.saveConfig();
+ }
+ if (!prevSaveSeeds.contains(saveSeed)) {
+ prevSaveSeeds.add(saveSeed);
+ }
+ }
+
+ public static boolean noLegacy() {
+ return legacyPotions.isEmpty();
+ }
+
+ /**
+ * Load potion data from data file for backwards compatibility
+ */
+ public static void loadLegacy(BIngredients ingredients, int uid, int quality, int alc, byte distillRuns, float ageTime, float wood, String recipe, boolean unlabeled, boolean persistent, boolean stat, int lastUpdate) {
+ Brew brew = new Brew(ingredients, quality, alc, distillRuns, ageTime, wood, recipe, unlabeled, stat, lastUpdate);
+ brew.persistent = persistent;
+ if (brew.lastUpdate <= 0) {
+ // We failed to save the lastUpdate, restart the countdown
+ brew.touch();
+ }
+ legacyPotions.put(uid, brew);
+ }
+
+ /**
+ * remove legacy potiondata for an item
+ */
+ public static void removeLegacy(ItemStack item) {
+ if (legacyPotions.isEmpty()) return;
+ if (!item.hasItemMeta()) return;
+ ItemMeta meta = item.getItemMeta();
+ if (!(meta instanceof PotionMeta)) return;
+ getFromPotionEffect(((PotionMeta) meta), true);
+ }
+
+ public void convertPre1_9(ItemStack item) {
+ removeLegacy(item);
+ PotionMeta potionMeta = ((PotionMeta) item.getItemMeta());
+ assert potionMeta != null;
+
+ BrewLore lore = new BrewLore(this, potionMeta);
+ lore.removeEffects();
+
+ if (hasRecipe()) {
+ currentRecipe.getColor().colorBrew(potionMeta, item, canDistill());
+ } else {
+ PotionColor.GREY.colorBrew(potionMeta, item, canDistill());
+ }
+ lore.removeLegacySpacing();
+ save(potionMeta);
+ item.setItemMeta(potionMeta);
+ }
+
+ public void convertPre1_11(ItemStack item) {
+ removeLegacy(item);
+ PotionMeta potionMeta = ((PotionMeta) item.getItemMeta());
+ assert potionMeta != null;
+
+ potionMeta.setBasePotionData(new PotionData(PotionType.UNCRAFTABLE));
+ BrewLore lore = new BrewLore(this, potionMeta);
+ lore.removeEffects();
+
+ if (hasRecipe()) {
+ lore.addOrReplaceEffects(currentRecipe.getEffects(), getQuality());
+ currentRecipe.getColor().colorBrew(potionMeta, item, canDistill());
+ } else {
+ PotionColor.GREY.colorBrew(potionMeta, item, canDistill());
+ }
+ lore.removeLegacySpacing();
+ save(potionMeta);
+ item.setItemMeta(potionMeta);
+ }
+
+ /**
+ * Saves all data,
+ * Legacy method to save to data file.
+ */
+ public static void saveLegacy(ConfigurationSection config) {
+ for (Map.Entry entry : legacyPotions.entrySet()) {
int uid = entry.getKey();
Brew brew = entry.getValue();
ConfigurationSection idConfig = config.createSection("" + uid);
@@ -659,6 +1056,9 @@ public class Brew {
if (brew.quality != 0) {
idConfig.set("quality", brew.quality);
}
+ if (brew.alc > 0) {
+ idConfig.set("alc", brew.alc);
+ }
if (brew.distillRuns != 0) {
idConfig.set("distillRuns", brew.distillRuns);
}
@@ -669,7 +1069,7 @@ public class Brew {
idConfig.set("wood", brew.wood);
}
if (brew.currentRecipe != null) {
- idConfig.set("recipe", brew.currentRecipe.getName(5));
+ idConfig.set("recipe", brew.currentRecipe.getRecipeName());
}
if (brew.unlabeled) {
idConfig.set("unlabeled", true);
@@ -677,109 +1077,15 @@ public class Brew {
if (brew.persistent) {
idConfig.set("persist", true);
}
- if (brew.stat) {
+ if (brew.immutable) {
idConfig.set("stat", true);
}
if (brew.lastUpdate > 0) {
idConfig.set("lastUpdate", brew.lastUpdate);
}
// save the ingredients
- idConfig.set("ingId", brew.ingredients.save(config.getParent()));
+ idConfig.set("ingId", brew.ingredients.saveLegacy(config.getParent()));
}
}
- public static class PotionColor {
- public static final PotionColor PINK = new PotionColor(1, PotionType.REGEN, Color.FUCHSIA);
- public static final PotionColor CYAN = new PotionColor(2, PotionType.SPEED, Color.AQUA);
- public static final PotionColor ORANGE = new PotionColor(3, PotionType.FIRE_RESISTANCE, Color.ORANGE);
- public static final PotionColor GREEN = new PotionColor(4, PotionType.POISON, Color.GREEN);
- public static final PotionColor BRIGHT_RED = new PotionColor(5, PotionType.INSTANT_HEAL, Color.fromRGB(255,0,0));
- public static final PotionColor BLUE = new PotionColor(6, PotionType.NIGHT_VISION, Color.NAVY);
- public static final PotionColor BLACK = new PotionColor(8, PotionType.WEAKNESS, Color.BLACK);
- public static final PotionColor RED = new PotionColor(9, PotionType.STRENGTH, Color.fromRGB(196,0,0));
- public static final PotionColor GREY = new PotionColor(10, PotionType.SLOWNESS, Color.GRAY);
- public static final PotionColor WATER = new PotionColor(11, P.use1_9 ? PotionType.WATER_BREATHING : null, Color.BLUE);
- public static final PotionColor DARK_RED = new PotionColor(12, PotionType.INSTANT_DAMAGE, Color.fromRGB(128,0,0));
- public static final PotionColor BRIGHT_GREY = new PotionColor(14, PotionType.INVISIBILITY, Color.SILVER);
-
- private final int colorId;
- private final PotionType type;
- private final Color color;
-
- PotionColor(int colorId, PotionType type, Color color) {
- this.colorId = colorId;
- this.type = type;
- this.color = color;
- }
-
- public PotionColor(Color color) {
- colorId = -1;
- type = WATER.getType();
- this.color = color;
- }
-
- // gets the Damage Value, that sets a color on the potion
- // offset +32 is not accepted by brewer, so not further destillable
- public short getColorId(boolean destillable) {
- if (destillable) {
- return (short) (colorId + 64);
- }
- return (short) (colorId + 32);
- }
-
- public PotionType getType() {
- return type;
- }
-
- public Color getColor() {
- return color;
- }
-
- @SuppressWarnings("deprecation")
- public void colorBrew(PotionMeta meta, ItemStack potion, boolean destillable) {
- if (P.use1_9) {
- meta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS);
- if (P.use1_11) {
- // BasePotionData was only used for the Color, so starting with 1.12 we can use setColor instead
- meta.setColor(getColor());
- } else {
- meta.setBasePotionData(new PotionData(getType()));
- }
- } else {
- potion.setDurability(getColorId(destillable));
- }
- }
-
- public static PotionColor fromString(String string) {
- switch (string) {
- case "PINK": return PINK;
- case "CYAN": return CYAN;
- case "ORANGE": return ORANGE;
- case "GREEN": return GREEN;
- case "BRIGHT_RED": return BRIGHT_RED;
- case "BLUE": return BLUE;
- case "BLACK": return BLACK;
- case "RED": return RED;
- case "GREY": return GREY;
- case "WATER": return WATER;
- case "DARK_RED": return DARK_RED;
- case "BRIGHT_GREY": return BRIGHT_GREY;
- default:
- try{
- if (string.length() >= 7) {
- string = string.substring(1);
- }
- return new PotionColor(Color.fromRGB(
- Integer.parseInt(string.substring( 0, 2 ), 16 ),
- Integer.parseInt(string.substring( 2, 4 ), 16 ),
- Integer.parseInt(string.substring( 4, 6 ), 16 )
- ));
- } catch (Exception e) {
- return WATER;
- }
- }
- }
-
- }
-
}
diff --git a/src/com/dre/brewery/Words.java b/src/com/dre/brewery/DistortChat.java
similarity index 82%
rename from src/com/dre/brewery/Words.java
rename to src/com/dre/brewery/DistortChat.java
index 8301cf7..362faab 100644
--- a/src/com/dre/brewery/Words.java
+++ b/src/com/dre/brewery/DistortChat.java
@@ -1,5 +1,6 @@
package com.dre.brewery;
+import com.dre.brewery.api.events.PlayerChatDistortEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
@@ -9,11 +10,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-public class Words {
+public class DistortChat {
// represends Words and letters, that are replaced in drunk players messages
- public static ArrayList words = new ArrayList<>();
+ public static List words = new ArrayList<>();
public static List commands;
public static List ignoreText = new ArrayList<>();
public static Boolean doSigns;
@@ -27,7 +28,7 @@ public class Words {
private int alcohol = 1;
private int percentage = 100;
- public Words(Map, ?> part) {
+ public DistortChat(Map, ?> part) {
for (Map.Entry, ?> wordPart : part.entrySet()) {
String key = (String) wordPart.getKey();
@@ -79,9 +80,15 @@ public class Words {
P.p.log(P.p.languageReader.get("Player_TriedToSay", name, chat));
}
String message = chat.substring(command.length() + 1);
- message = distortMessage(message, bPlayer.getDrunkeness());
+ String distorted = distortMessage(message, bPlayer.getDrunkeness());
+ PlayerChatDistortEvent call = new PlayerChatDistortEvent(event.isAsynchronous(), event.getPlayer(), bPlayer, message, distorted);
+ P.p.getServer().getPluginManager().callEvent(call);
+ if (call.isCancelled()) {
+ return;
+ }
+ distorted = call.getDistortedMessage();
- event.setMessage(chat.substring(0, command.length() + 1) + message);
+ event.setMessage(chat.substring(0, command.length() + 1) + distorted);
waitPlayers.put(name, System.currentTimeMillis());
return;
}
@@ -101,12 +108,17 @@ public class Words {
int index = 0;
for (String message : event.getLines()) {
if (message.length() > 1) {
- message = distortMessage(message, bPlayer.getDrunkeness());
+ String distorted = distortMessage(message, bPlayer.getDrunkeness());
+ PlayerChatDistortEvent call = new PlayerChatDistortEvent(event.isAsynchronous(), event.getPlayer(), bPlayer, message, distorted);
+ P.p.getServer().getPluginManager().callEvent(call);
+ if (!call.isCancelled()) {
+ distorted = call.getDistortedMessage();
- if (message.length() > 15) {
- message = message.substring(0, 14);
+ if (distorted.length() > 15) {
+ distorted = distorted.substring(0, 14);
+ }
+ event.setLine(index, distorted);
}
- event.setLine(index, message);
}
index++;
}
@@ -123,7 +135,16 @@ public class Words {
if (log) {
P.p.log(P.p.languageReader.get("Player_TriedToSay", event.getPlayer().getName(), message));
}
- event.setMessage(distortMessage(message, bPlayer.getDrunkeness()));
+
+ String distorted = distortMessage(message, bPlayer.getDrunkeness());
+ PlayerChatDistortEvent call = new PlayerChatDistortEvent(event.isAsynchronous(), event.getPlayer(), bPlayer, message, distorted);
+ P.p.getServer().getPluginManager().callEvent(call);
+ if (call.isCancelled()) {
+ return;
+ }
+ distorted = call.getDistortedMessage();
+
+ event.setMessage(distorted);
}
}
}
@@ -164,7 +185,9 @@ public class Words {
// distorts a message without checking ignoreText letters
private static String distortString(String message, int drunkeness) {
if (message.length() > 1) {
- for (Words word : words) {
+ // Create our own reference to the words list, in case of config reload
+ List words = DistortChat.words;
+ for (DistortChat word : words) {
if (word.alcohol <= drunkeness) {
message = word.distort(message);
}
diff --git a/src/com/dre/brewery/MCBarrel.java b/src/com/dre/brewery/MCBarrel.java
index 4374b3e..6fda3c3 100644
--- a/src/com/dre/brewery/MCBarrel.java
+++ b/src/com/dre/brewery/MCBarrel.java
@@ -80,8 +80,7 @@ public class MCBarrel {
// This is the last viewer
for (ItemStack item : inv.getContents()) {
if (item != null) {
- Brew brew = Brew.get(item);
- if (brew != null) {
+ if (Brew.isBrew(item)) {
// We found a brew, so set time on this Barrel
if (inv.getHolder() instanceof org.bukkit.block.Barrel) {
Barrel barrel = (Barrel) inv.getHolder();
@@ -97,6 +96,26 @@ public class MCBarrel {
}
}
+ public void countBrews() {
+ brews = 0;
+ for (ItemStack item : inv.getContents()) {
+ if (item != null) {
+ if (Brew.isBrew(item)) {
+ brews++;
+ }
+ }
+ }
+ }
+
+ public Inventory getInventory() {
+ return inv;
+ }
+
+
+ public static void onUpdate() {
+ mcBarrelTime++;
+ }
+
// Used to visually stop Players from placing more than 6 (configurable) brews in the MC Barrels.
// There are still methods to place more Brews in that would be too tedious to catch.
// This is only for direct visual Notification, the age routine above will never age more than 6 brews in any case.
@@ -113,11 +132,9 @@ public class MCBarrel {
case SWAP_WITH_CURSOR:
// Placing Brew in MC Barrel
if (event.getCursor() != null && event.getClickedInventory() != null && event.getClickedInventory().getType() == InventoryType.BARREL && event.getCursor().getType() == Material.POTION) {
- Brew b = Brew.get(event.getCursor());
- if (b != null) {
+ if (Brew.isBrew(event.getCursor())) {
if (event.getAction() == InventoryAction.SWAP_WITH_CURSOR && event.getCurrentItem() != null && event.getCurrentItem().getType() == Material.POTION) {
- Brew bb = Brew.get(event.getCurrentItem());
- if (bb != null) {
+ if (Brew.isBrew(event.getCurrentItem())) {
// The item we are swapping with is also a brew, dont change the count and allow
break;
}
@@ -130,8 +147,7 @@ public class MCBarrel {
if (event.getCurrentItem() != null && event.getCurrentItem().getType() == Material.POTION && event.getClickedInventory() != null) {
if (event.getClickedInventory().getType() == InventoryType.BARREL) {
// Moving Brew out of MC Barrel
- Brew b = Brew.get(event.getCurrentItem());
- if (b != null) {
+ if (Brew.isBrew(event.getCurrentItem())) {
if (brews == -1) {
countBrews();
}
@@ -140,8 +156,7 @@ public class MCBarrel {
break;
} else if (event.getClickedInventory().getType() == InventoryType.PLAYER) {
// Moving Brew into MC Barrel
- Brew b = Brew.get(event.getCurrentItem());
- if (b != null) {
+ if (Brew.isBrew(event.getCurrentItem())) {
adding = true;
}
}
@@ -155,8 +170,7 @@ public class MCBarrel {
case COLLECT_TO_CURSOR:
// Pickup Brew from MC Barrel
if (event.getCurrentItem() != null && event.getClickedInventory() != null && event.getClickedInventory().getType() == InventoryType.BARREL && event.getCurrentItem().getType() == Material.POTION) {
- Brew b = Brew.get(event.getCurrentItem());
- if (b != null) {
+ if (Brew.isBrew(event.getCurrentItem())) {
if (brews == -1) {
countBrews();
}
@@ -184,24 +198,4 @@ public class MCBarrel {
}
}
- public void countBrews() {
- brews = 0;
- for (ItemStack item : inv.getContents()) {
- if (item != null) {
- Brew brew = Brew.get(item);
- if (brew != null) {
- brews++;
- }
- }
- }
- }
-
- public Inventory getInventory() {
- return inv;
- }
-
- public static void onUpdate() {
- mcBarrelTime++;
- }
-
}
diff --git a/src/com/dre/brewery/P.java b/src/com/dre/brewery/P.java
index f891907..e3020f5 100644
--- a/src/com/dre/brewery/P.java
+++ b/src/com/dre/brewery/P.java
@@ -1,62 +1,40 @@
package com.dre.brewery;
-import com.dre.brewery.filedata.ConfigUpdater;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.filedata.BData;
import com.dre.brewery.filedata.DataSave;
-import com.dre.brewery.filedata.DataUpdater;
import com.dre.brewery.filedata.LanguageReader;
import com.dre.brewery.filedata.UpdateChecker;
-import com.dre.brewery.integration.LogBlockBarrel;
-import com.dre.brewery.integration.WGBarrel;
-import com.dre.brewery.integration.WGBarrel7;
-import com.dre.brewery.integration.WGBarrelNew;
-import com.dre.brewery.integration.WGBarrelOld;
+import com.dre.brewery.integration.IntegrationListener;
+import com.dre.brewery.integration.barrel.LogBlockBarrel;
import com.dre.brewery.listeners.*;
+import com.dre.brewery.recipe.BCauldronRecipe;
+import com.dre.brewery.recipe.BRecipe;
+import com.dre.brewery.utility.BUtil;
+import com.dre.brewery.utility.LegacyUtil;
import org.apache.commons.lang.math.NumberUtils;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
-import org.bukkit.Location;
import org.bukkit.Material;
-import org.bukkit.World;
-import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
-import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.configuration.file.YamlConfiguration;
-import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.UUID;
public class P extends JavaPlugin {
public static P p;
- public static final String configVersion = "1.8";
public static boolean debug;
public static boolean useUUID;
+ public static boolean useNBT;
public static boolean use1_9;
public static boolean use1_11;
public static boolean use1_13;
public static boolean use1_14;
- public static boolean updateCheck;
-
- // Third Party Enabled
- public boolean useWG; //WorldGuard
- public WGBarrel wg;
- public boolean useLWC; //LWC
- public boolean useLB; //LogBlock
- public boolean useGP; //GriefPrevention
- public boolean hasVault; // Vault
- public boolean useCitadel; // CivCraft/DevotedMC Citadel
// Listeners
public BlockListener blockListener;
@@ -64,12 +42,16 @@ public class P extends JavaPlugin {
public EntityListener entityListener;
public InventoryListener inventoryListener;
public WorldListener worldListener;
+ public IntegrationListener integrationListener;
// Language
public String language;
public LanguageReader languageReader;
- private CommandSender reloader;
+ // Metrics
+ public int brewsCreated;
+ public int brewsCreatedCmd; // Created by command
+ public int exc, good, norm, bad, terr; // Brews drunken with quality
@Override
public void onEnable() {
@@ -83,81 +65,37 @@ public class P extends JavaPlugin {
use1_13 = !v.matches("(^|.*[^.\\d])1\\.1[0-2]([^\\d].*|$)") && !v.matches("(^|.*[^.\\d])1\\.[0-9]([^\\d].*|$)");
use1_14 = !v.matches("(^|.*[^.\\d])1\\.1[0-3]([^\\d].*|$)") && !v.matches("(^|.*[^.\\d])1\\.[0-9]([^\\d].*|$)");
- //P.p.log("§" + (use1_9 ? "a":"c") + "1.9 " + "§" + (use1_11 ? "a":"c") + "1.11 " + "§" + (use1_13 ? "a":"c") + "1.13 " + "§" + (use1_14 ? "a":"c") + "1.14");
+ //MC 1.13 uses a different NBT API than the newer versions..
+ // We decide here which to use, the new or the old or none at all
+ if (LegacyUtil.initNbt()) {
+ useNBT = true;
+ }
+
+ if (use1_14) {
+ // Campfires are weird
+ // Initialize once now so it doesn't lag later when we check for campfires under Cauldrons
+ getServer().createBlockData(Material.CAMPFIRE);
+ }
// load the Config
try {
- if (!readConfig()) {
+ FileConfiguration cfg = BConfig.loadConfigFile();
+ if (cfg == null) {
p = null;
getServer().getPluginManager().disablePlugin(this);
return;
}
+ BConfig.readConfig(cfg);
} catch (Exception e) {
e.printStackTrace();
p = null;
getServer().getPluginManager().disablePlugin(this);
return;
}
- readData();
+ BData.readData();
// Setup Metrics
- try {
- Metrics metrics = new Metrics(this);
- metrics.addCustomChart(new Metrics.SingleLineChart("drunk_players", BPlayer::numDrunkPlayers));
- metrics.addCustomChart(new Metrics.SingleLineChart("brews_in_existence", () -> Brew.potions.size()));
- metrics.addCustomChart(new Metrics.SingleLineChart("barrels_built", () -> Barrel.barrels.size()));
- metrics.addCustomChart(new Metrics.SingleLineChart("cauldrons_boiling", () -> BCauldron.bcauldrons.size()));
- metrics.addCustomChart(new Metrics.AdvancedPie("brew_quality", () -> {
- Map map = new HashMap<>(5);
- int exc = 0;
- int good = 0;
- int norm = 0;
- int bad = 0;
- int terr = 0;
- for (Brew brew : Brew.potions.values()) {
- if (brew.getQuality() >= 9) {
- exc++;
- } else if (brew.getQuality() >= 7) {
- good++;
- } else if (brew.getQuality() >= 5) {
- norm++;
- } else if (brew.getQuality() >= 3) {
- bad++;
- } else {
- terr++;
- }
- }
-
- map.put("excellent", exc);
- map.put("good", good);
- map.put("normal", norm);
- map.put("bad", bad);
- map.put("terrible", terr);
- return map;
- }));
- metrics.addCustomChart(new Metrics.SimplePie("number_of_recipes", () -> {
- int recipes = BIngredients.recipes.size();
- if (recipes < 7) {
- return "Less than 7";
- } else if (recipes < 11) {
- return "7-10";
- } else if (recipes == 11) {
- // There are 11 default recipes, so show this as its own slice
- return "11";
- } else if (recipes <= 31) {
- if (recipes % 2 == 0) {
- return recipes + "-" + (recipes + 1);
- } else {
- return (recipes - 1) + "-" + recipes;
- }
- } else {
- return "More than 31";
- }
-
- }));
- } catch (Throwable e) {
- e.printStackTrace();
- }
+ setupMetrics();
// Listeners
blockListener = new BlockListener();
@@ -165,14 +103,19 @@ public class P extends JavaPlugin {
entityListener = new EntityListener();
inventoryListener = new InventoryListener();
worldListener = new WorldListener();
- getCommand("Brewery").setExecutor(new CommandListener());
- getCommand("Brewery").setTabCompleter(new TabListener());
+ integrationListener = new IntegrationListener();
+ PluginCommand c = getCommand("Brewery");
+ if (c != null) {
+ c.setExecutor(new CommandListener());
+ c.setTabCompleter(new TabListener());
+ }
p.getServer().getPluginManager().registerEvents(blockListener, p);
p.getServer().getPluginManager().registerEvents(playerListener, p);
p.getServer().getPluginManager().registerEvents(entityListener, p);
p.getServer().getPluginManager().registerEvents(inventoryListener, p);
p.getServer().getPluginManager().registerEvents(worldListener, p);
+ p.getServer().getPluginManager().registerEvents(integrationListener, p);
if (use1_9) {
p.getServer().getPluginManager().registerEvents(new CauldronListener(), p);
}
@@ -181,7 +124,7 @@ public class P extends JavaPlugin {
p.getServer().getScheduler().runTaskTimer(p, new BreweryRunnable(), 650, 1200);
p.getServer().getScheduler().runTaskTimer(p, new DrunkRunnable(), 120, 120);
- if (updateCheck) {
+ if (BConfig.updateCheck) {
try {
p.getServer().getScheduler().runTaskLaterAsynchronously(p, new UpdateChecker(), 135);
} catch (Exception e) {
@@ -208,52 +151,28 @@ public class P extends JavaPlugin {
// save Data to Disk
DataSave.save(true);
- // save LanguageReader
- languageReader.save();
-
- // delete Data from Ram
- Barrel.barrels.clear();
- BCauldron.bcauldrons.clear();
- BIngredients.possibleIngredients.clear();
- BIngredients.recipes.clear();
- BIngredients.cookedNames.clear();
- BPlayer.clear();
- Brew.potions.clear();
- Wakeup.wakeups.clear();
- Words.words.clear();
- Words.ignoreText.clear();
- Words.commands = null;
+ // delete config data, in case this is a reload and to clear up some ram
+ clearConfigData();
this.log(this.getDescription().getName() + " disabled!");
}
public void reload(CommandSender sender) {
if (sender != null && !sender.equals(getServer().getConsoleSender())) {
- reloader = sender;
+ BConfig.reloader = sender;
}
+ FileConfiguration cfg = BConfig.loadConfigFile();
+ if (cfg == null) {
+ // Could not read yml file, do not proceed, error was printed
+ return;
+ }
+
// clear all existent config Data
- BIngredients.possibleIngredients.clear();
- BIngredients.recipes.clear();
- BIngredients.cookedNames.clear();
- Words.words.clear();
- Words.ignoreText.clear();
- Words.commands = null;
- BPlayer.drainItems.clear();
- if (useLB) {
- try {
- LogBlockBarrel.clear();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
+ clearConfigData();
// load the Config
try {
- if (!readConfig()) {
- p = null;
- getServer().getPluginManager().disablePlugin(this);
- return;
- }
+ BConfig.readConfig(cfg);
} catch (Exception e) {
e.printStackTrace();
p = null;
@@ -261,23 +180,179 @@ public class P extends JavaPlugin {
return;
}
- // save and load LanguageReader
- languageReader.save();
- languageReader = new LanguageReader(new File(p.getDataFolder(), "languages/" + language + ".yml"));
-
// Reload Recipes
boolean successful = true;
- for (Brew brew : Brew.potions.values()) {
+ for (Brew brew : Brew.legacyPotions.values()) {
if (!brew.reloadRecipe()) {
successful = false;
}
}
- if (!successful && sender != null) {
- msg(sender, p.languageReader.get("Error_Recipeload"));
+ if (sender != null) {
+ if (!successful) {
+ msg(sender, p.languageReader.get("Error_Recipeload"));
+ } else {
+ p.msg(sender, p.languageReader.get("CMD_Reload"));
+ }
}
- reloader = null;
+ BConfig.reloader = null;
}
+ private void clearConfigData() {
+ BRecipe.getConfigRecipes().clear();
+ BRecipe.numConfigRecipes = 0;
+ BCauldronRecipe.acceptedMaterials.clear();
+ BCauldronRecipe.acceptedCustom.clear();
+ BCauldronRecipe.acceptedSimple.clear();
+ BCauldronRecipe.getConfigRecipes().clear();
+ BCauldronRecipe.numConfigRecipes = 0;
+ BConfig.customItems.clear();
+ BConfig.hasSlimefun = null;
+ BConfig.hasMMOItems = null;
+ DistortChat.commands = null;
+ BConfig.drainItems.clear();
+ if (BConfig.useLB) {
+ try {
+ LogBlockBarrel.clear();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static P getInstance() {
+ return p;
+ }
+
+ private void setupMetrics() {
+ try {
+ Metrics metrics = new Metrics(this);
+ metrics.addCustomChart(new Metrics.SingleLineChart("drunk_players", BPlayer::numDrunkPlayers));
+ metrics.addCustomChart(new Metrics.SingleLineChart("brews_in_existence", () -> brewsCreated));
+ metrics.addCustomChart(new Metrics.SingleLineChart("barrels_built", () -> Barrel.barrels.size()));
+ metrics.addCustomChart(new Metrics.SingleLineChart("cauldrons_boiling", () -> BCauldron.bcauldrons.size()));
+ metrics.addCustomChart(new Metrics.AdvancedPie("brew_quality", () -> {
+ Map map = new HashMap<>(8);
+ map.put("excellent", exc);
+ map.put("good", good);
+ map.put("normal", norm);
+ map.put("bad", bad);
+ map.put("terrible", terr);
+ return map;
+ }));
+ metrics.addCustomChart(new Metrics.AdvancedPie("brews_created", () -> {
+ Map map = new HashMap<>(4);
+ map.put("by command", brewsCreatedCmd);
+ map.put("brewing", brewsCreated - brewsCreatedCmd);
+ return map;
+ }));
+
+ metrics.addCustomChart(new Metrics.SimplePie("number_of_recipes", () -> {
+ int recipes = BRecipe.getAllRecipes().size();
+ if (recipes < 7) {
+ return "Less than 7";
+ } else if (recipes < 11) {
+ return "7-10";
+ } else if (recipes == 11) {
+ // There are 11 default recipes, so show this as its own slice
+ return "11";
+ } else if (recipes <= 31) {
+ if (recipes % 2 == 0) {
+ return recipes + "-" + (recipes + 1);
+ } else {
+ return (recipes - 1) + "-" + recipes;
+ }
+ } else {
+ return "More than 31";
+ }
+
+ }));
+ metrics.addCustomChart(new Metrics.SimplePie("v2_mc_version", () -> {
+ String mcv = Bukkit.getBukkitVersion();
+ mcv = mcv.substring(0, mcv.indexOf('.', 2));
+ if (mcv.matches("^\\d\\.\\d{1,2}$")) {
+ // Start, digit, dot, 1-2 digits, end
+ return mcv;
+ } else {
+ return "undef";
+ }
+ }));
+ metrics.addCustomChart(new Metrics.DrilldownPie("plugin_mc_version", () -> {
+ Map> map = new HashMap<>(3);
+ String mcv = Bukkit.getBukkitVersion();
+ mcv = mcv.substring(0, mcv.indexOf('.', 2));
+ if (mcv.matches("^\\d\\.\\d{1,2}$")) {
+ // Start, digit, dot, 1-2 digits, end
+ mcv = "MC " + mcv;
+ } else {
+ mcv = "undef";
+ }
+ Map innerMap = new HashMap<>(3);
+ innerMap.put(mcv, 1);
+ map.put(getDescription().getVersion(), innerMap);
+ return map;
+ }));
+ metrics.addCustomChart(new Metrics.SimplePie("language", () -> language));
+ metrics.addCustomChart(new Metrics.SimplePie("config_scramble", () -> BConfig.enableEncode ? "enabled" : "disabled"));
+ metrics.addCustomChart(new Metrics.SimplePie("config_lore_color", () -> {
+ if (BConfig.colorInBarrels) {
+ if (BConfig.colorInBrewer) {
+ return "both";
+ } else {
+ return "in barrels";
+ }
+ } else {
+ if (BConfig.colorInBrewer) {
+ return "in distiller";
+ } else {
+ return "none";
+ }
+ }
+ }));
+ metrics.addCustomChart(new Metrics.SimplePie("config_always_show", () -> {
+ if (BConfig.alwaysShowQuality) {
+ if (BConfig.alwaysShowAlc) {
+ return "both";
+ } else {
+ return "quality stars";
+ }
+ } else {
+ if (BConfig.alwaysShowAlc) {
+ return "alc content";
+ } else {
+ return "none";
+ }
+ }
+ }));
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void metricsForCreate(boolean byCmd) {
+ if (brewsCreated == Integer.MAX_VALUE) return;
+ brewsCreated++;
+ if (byCmd) {
+ if (brewsCreatedCmd == Integer.MAX_VALUE) return;
+ brewsCreatedCmd++;
+ }
+ }
+
+ public void metricsForDrink(Brew brew) {
+ if (brew.getQuality() >= 9) {
+ exc++;
+ } else if (brew.getQuality() >= 7) {
+ good++;
+ } else if (brew.getQuality() >= 5) {
+ norm++;
+ } else if (brew.getQuality() >= 3) {
+ bad++;
+ } else {
+ terr++;
+ }
+ }
+
+ // Utility
+
public void msg(CommandSender sender, String msg) {
sender.sendMessage(color("&2[Brewery] &f" + msg));
}
@@ -294,507 +369,23 @@ public class P extends JavaPlugin {
public void errorLog(String msg) {
Bukkit.getConsoleSender().sendMessage(ChatColor.DARK_GREEN + "[Brewery] " + ChatColor.DARK_RED + "ERROR: " + ChatColor.RED + msg);
- if (reloader != null) {
- reloader.sendMessage(ChatColor.DARK_GREEN + "[Brewery] " + ChatColor.DARK_RED + "ERROR: " + ChatColor.RED + msg);
+ if (BConfig.reloader != null) {
+ BConfig.reloader.sendMessage(ChatColor.DARK_GREEN + "[Brewery] " + ChatColor.DARK_RED + "ERROR: " + ChatColor.RED + msg);
}
}
- public boolean readConfig() {
- File file = new File(p.getDataFolder(), "config.yml");
- if (!checkConfigs()) {
- return false;
- }
- FileConfiguration config = YamlConfiguration.loadConfiguration(file);
-
- // Set the Language
- language = config.getString("language", "en");
-
- // Load LanguageReader
- languageReader = new LanguageReader(new File(p.getDataFolder(), "languages/" + language + ".yml"));
-
- // Has to config still got old materials
- boolean oldMat = config.getBoolean("oldMat", false);
-
- // Check if config is the newest version
- String version = config.getString("version", null);
- if (version != null) {
- if (!version.equals(configVersion) || (oldMat && use1_13)) {
- copyDefaultConfigs(true);
- new ConfigUpdater(file).update(version, oldMat, language);
- P.p.log("Config Updated to version: " + configVersion);
- config = YamlConfiguration.loadConfiguration(file);
- }
- }
-
- // If the Update Checker should be enabled
- updateCheck = config.getBoolean("updateCheck", false);
-
- // Third-Party
- useWG = config.getBoolean("useWorldGuard", true) && getServer().getPluginManager().isPluginEnabled("WorldGuard");
- if (useWG) {
- Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldEdit");
- if (plugin != null) {
- String wgv = plugin.getDescription().getVersion();
- if (wgv.startsWith("6.")) {
- wg = new WGBarrelNew();
- } else if (wgv.startsWith("5.")) {
- wg = new WGBarrelOld();
- } else {
- wg = new WGBarrel7();
- }
- }
- if (wg == null) {
- P.p.errorLog("Failed loading WorldGuard Integration! Opening Barrels will NOT work!");
- P.p.errorLog("Brewery was tested with version 5.8, 6.1 and 7.0 of WorldGuard!");
- P.p.errorLog("Disable the WorldGuard support in the config and do /brew reload");
- }
- }
- useLWC = config.getBoolean("useLWC", true) && getServer().getPluginManager().isPluginEnabled("LWC");
- useGP = config.getBoolean("useGriefPrevention", true) && getServer().getPluginManager().isPluginEnabled("GriefPrevention");
- useLB = config.getBoolean("useLogBlock", false) && getServer().getPluginManager().isPluginEnabled("LogBlock");
- useCitadel = config.getBoolean("useCitadel", false) && getServer().getPluginManager().isPluginEnabled("Citadel");
- // The item util has been removed in Vault 1.7+
- hasVault = getServer().getPluginManager().isPluginEnabled("Vault")
- && Integer.parseInt(getServer().getPluginManager().getPlugin("Vault").getDescription().getVersion().split("\\.")[1]) <= 6;
-
- // various Settings
- DataSave.autosave = config.getInt("autosave", 3);
- debug = config.getBoolean("debug", false);
- BPlayer.pukeItem = Material.matchMaterial(config.getString("pukeItem", "SOUL_SAND"));
- BPlayer.hangoverTime = config.getInt("hangoverDays", 0) * 24 * 60;
- BPlayer.overdrinkKick = config.getBoolean("enableKickOnOverdrink", false);
- BPlayer.enableHome = config.getBoolean("enableHome", false);
- BPlayer.enableLoginDisallow = config.getBoolean("enableLoginDisallow", false);
- BPlayer.enablePuke = config.getBoolean("enablePuke", false);
- BPlayer.pukeDespawntime = config.getInt("pukeDespawntime", 60) * 20;
- BPlayer.homeType = config.getString("homeType", null);
- Brew.colorInBarrels = config.getBoolean("colorInBarrels", false);
- Brew.colorInBrewer = config.getBoolean("colorInBrewer", false);
- PlayerListener.openEverywhere = config.getBoolean("openLargeBarrelEverywhere", false);
- MCBarrel.maxBrews = config.getInt("maxBrewsInMCBarrels", 6);
-
- // loading recipes
- ConfigurationSection configSection = config.getConfigurationSection("recipes");
- if (configSection != null) {
- for (String recipeId : configSection.getKeys(false)) {
- BRecipe recipe = new BRecipe(configSection, recipeId);
- if (recipe.isValid()) {
- BIngredients.recipes.add(recipe);
- } else {
- errorLog("Loading the Recipe with id: '" + recipeId + "' failed!");
- }
- }
- }
-
- // loading cooked names and possible ingredients
- configSection = config.getConfigurationSection("cooked");
- if (configSection != null) {
- for (String ingredient : configSection.getKeys(false)) {
- Material mat = Material.matchMaterial(ingredient);
- if (mat == null && hasVault) {
- try {
- net.milkbowl.vault.item.ItemInfo vaultItem = net.milkbowl.vault.item.Items.itemByString(ingredient);
- if (vaultItem != null) {
- mat = vaultItem.getType();
- }
- } catch (Exception e) {
- P.p.errorLog("Could not check vault for Item Name");
- e.printStackTrace();
- }
- }
- if (mat != null) {
- BIngredients.cookedNames.put(mat, (configSection.getString(ingredient, null)));
- BIngredients.possibleIngredients.add(mat);
- } else {
- errorLog("Unknown Material: " + ingredient);
- }
- }
- }
-
- // loading drainItems
- List drainList = config.getStringList("drainItems");
- if (drainList != null) {
- for (String drainString : drainList) {
- String[] drainSplit = drainString.split("/");
- if (drainSplit.length > 1) {
- Material mat = Material.matchMaterial(drainSplit[0]);
- int strength = p.parseInt(drainSplit[1]);
- if (mat == null && hasVault && strength > 0) {
- try {
- net.milkbowl.vault.item.ItemInfo vaultItem = net.milkbowl.vault.item.Items.itemByString(drainSplit[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 && strength > 0) {
- BPlayer.drainItems.put(mat, strength);
- }
- }
- }
- }
-
- // Loading Words
- if (config.getBoolean("enableChatDistortion", false)) {
- for (Map, ?> map : config.getMapList("words")) {
- new Words(map);
- }
- for (String bypass : config.getStringList("distortBypass")) {
- Words.ignoreText.add(bypass.split(","));
- }
- Words.commands = config.getStringList("distortCommands");
- }
- Words.log = config.getBoolean("logRealChat", false);
- Words.doSigns = config.getBoolean("distortSignText", false);
-
- return true;
- }
-
- // load all Data
- public void readData() {
- File file = new File(p.getDataFolder(), "data.yml");
- if (file.exists()) {
-
- FileConfiguration data = YamlConfiguration.loadConfiguration(file);
-
- Brew.installTime = data.getLong("installTime", System.currentTimeMillis());
- MCBarrel.mcBarrelTime = data.getLong("MCBarrelTime", 0);
-
- // Check if data is the newest version
- String version = data.getString("Version", null);
- if (version != null) {
- if (!version.equals(DataSave.dataVersion)) {
- P.p.log("Data File is being updated...");
- new DataUpdater(data, file).update(version);
- data = YamlConfiguration.loadConfiguration(file);
- P.p.log("Data Updated to version: " + DataSave.dataVersion);
- }
- }
-
- // loading Ingredients into ingMap
- Map ingMap = new HashMap<>();
- ConfigurationSection section = data.getConfigurationSection("Ingredients");
- if (section != null) {
- for (String id : section.getKeys(false)) {
- ConfigurationSection matSection = section.getConfigurationSection(id + ".mats");
- if (matSection != null) {
- // matSection has all the materials + amount as Integers
- ArrayList ingredients = deserializeIngredients(matSection);
- ingMap.put(id, new BIngredients(ingredients, section.getInt(id + ".cookedTime", 0)));
- } else {
- errorLog("Ingredient id: '" + id + "' incomplete in data.yml");
- }
- }
- }
-
- // loading Brew
- section = data.getConfigurationSection("Brew");
- if (section != null) {
- // All sections have the UID as name
- for (String uid : section.getKeys(false)) {
- BIngredients ingredients = getIngredients(ingMap, section.getString(uid + ".ingId"));
- int quality = section.getInt(uid + ".quality", 0);
- int distillRuns = section.getInt(uid + ".distillRuns", 0);
- float ageTime = (float) section.getDouble(uid + ".ageTime", 0.0);
- float wood = (float) section.getDouble(uid + ".wood", -1.0);
- String recipe = section.getString(uid + ".recipe", null);
- boolean unlabeled = section.getBoolean(uid + ".unlabeled", false);
- boolean persistent = section.getBoolean(uid + ".persist", false);
- boolean stat = section.getBoolean(uid + ".stat", false);
- int lastUpdate = section.getInt("lastUpdate", 0);
-
- new Brew(parseInt(uid), ingredients, quality, distillRuns, ageTime, wood, recipe, unlabeled, persistent, stat, lastUpdate);
- }
- }
-
- // loading BPlayer
- section = data.getConfigurationSection("Player");
- if (section != null) {
- // keys have players name
- for (String name : section.getKeys(false)) {
- try {
- //noinspection ResultOfMethodCallIgnored
- UUID.fromString(name);
- if (!useUUID) {
- continue;
- }
- } catch (IllegalArgumentException e) {
- if (useUUID) {
- continue;
- }
- }
-
- int quality = section.getInt(name + ".quality");
- int drunk = section.getInt(name + ".drunk");
- int offDrunk = section.getInt(name + ".offDrunk", 0);
-
- new BPlayer(name, quality, drunk, offDrunk);
- }
- }
-
- for (World world : p.getServer().getWorlds()) {
- if (world.getName().startsWith("DXL_")) {
- loadWorldData(Util.getDxlName(world.getName()), world);
- } else {
- loadWorldData(world.getUID().toString(), world);
- }
- }
-
- } else {
- errorLog("No data.yml found, will create new one!");
- }
- }
-
- public ArrayList deserializeIngredients(ConfigurationSection matSection) {
- ArrayList ingredients = new ArrayList<>();
- for (String mat : matSection.getKeys(false)) {
- String[] matSplit = mat.split(",");
- Material m = Material.getMaterial(matSplit[0]);
- if (m == null && use1_13) {
- if (matSplit[0].equals("LONG_GRASS")) {
- m = Material.GRASS;
- } else {
- m = Material.matchMaterial(matSplit[0], true);
- }
- debugLog("converting Data Material from " + matSplit[0] + " to " + m);
- }
- if (m == null) continue;
- ItemStack item = new ItemStack(m, matSection.getInt(mat));
- if (matSplit.length == 2) {
- item.setDurability((short) P.p.parseInt(matSplit[1]));
- }
- ingredients.add(item);
- }
- return ingredients;
- }
-
- // returns Ingredients by id from the specified ingMap
- public BIngredients getIngredients(Map ingMap, String id) {
- if (!ingMap.isEmpty()) {
- if (ingMap.containsKey(id)) {
- return ingMap.get(id);
- }
- }
- errorLog("Ingredient id: '" + id + "' not found in data.yml");
- return new BIngredients();
- }
-
- // loads BIngredients from an ingredient section
- public BIngredients loadIngredients(ConfigurationSection section) {
- if (section != null) {
- return new BIngredients(deserializeIngredients(section), 0);
- } else {
- errorLog("Cauldron is missing Ingredient Section");
- }
- return new BIngredients();
- }
-
- // load Block locations of given world
- public void loadWorldData(String uuid, World world) {
-
- File file = new File(p.getDataFolder(), "data.yml");
- if (file.exists()) {
-
- FileConfiguration data = YamlConfiguration.loadConfiguration(file);
-
- // loading BCauldron
- if (data.contains("BCauldron." + uuid)) {
- ConfigurationSection section = data.getConfigurationSection("BCauldron." + uuid);
- for (String cauldron : section.getKeys(false)) {
- // block is splitted into x/y/z
- String block = section.getString(cauldron + ".block");
- if (block != null) {
- String[] splitted = block.split("/");
- if (splitted.length == 3) {
-
- Block worldBlock = world.getBlockAt(parseInt(splitted[0]), parseInt(splitted[1]), parseInt(splitted[2]));
- BIngredients ingredients = loadIngredients(section.getConfigurationSection(cauldron + ".ingredients"));
- int state = section.getInt(cauldron + ".state", 1);
-
- new BCauldron(worldBlock, ingredients, state);
- } else {
- errorLog("Incomplete Block-Data in data.yml: " + section.getCurrentPath() + "." + cauldron);
- }
- } else {
- errorLog("Missing Block-Data in data.yml: " + section.getCurrentPath() + "." + cauldron);
- }
- }
- }
-
- // loading Barrel
- if (data.contains("Barrel." + uuid)) {
- ConfigurationSection section = data.getConfigurationSection("Barrel." + uuid);
- for (String barrel : section.getKeys(false)) {
- // block spigot is splitted into x/y/z
- String spigot = section.getString(barrel + ".spigot");
- if (spigot != null) {
- String[] splitted = spigot.split("/");
- if (splitted.length == 3) {
-
- // load itemStacks from invSection
- ConfigurationSection invSection = section.getConfigurationSection(barrel + ".inv");
- Block block = world.getBlockAt(parseInt(splitted[0]), parseInt(splitted[1]), parseInt(splitted[2]));
- float time = (float) section.getDouble(barrel + ".time", 0.0);
- byte sign = (byte) section.getInt(barrel + ".sign", 0);
- String[] st = section.getString(barrel + ".st", "").split(",");
- String[] wo = section.getString(barrel + ".wo", "").split(",");
-
- if (invSection != null) {
- new Barrel(block, sign, st, wo, invSection.getValues(true), time);
- } else {
- // Barrel has no inventory
- new Barrel(block, sign, st, wo, null, time);
- }
-
- } else {
- errorLog("Incomplete Block-Data in data.yml: " + section.getCurrentPath() + "." + barrel);
- }
- } else {
- errorLog("Missing Block-Data in data.yml: " + section.getCurrentPath() + "." + barrel);
- }
- }
- }
-
- // loading Wakeup
- if (data.contains("Wakeup." + uuid)) {
- ConfigurationSection section = data.getConfigurationSection("Wakeup." + uuid);
- for (String wakeup : section.getKeys(false)) {
- // loc of wakeup is splitted into x/y/z/pitch/yaw
- String loc = section.getString(wakeup);
- if (loc != null) {
- String[] splitted = loc.split("/");
- if (splitted.length == 5) {
-
- double x = NumberUtils.toDouble(splitted[0]);
- double y = NumberUtils.toDouble(splitted[1]);
- double z = NumberUtils.toDouble(splitted[2]);
- float pitch = NumberUtils.toFloat(splitted[3]);
- float yaw = NumberUtils.toFloat(splitted[4]);
- Location location = new Location(world, x, y, z, yaw, pitch);
-
- Wakeup.wakeups.add(new Wakeup(location));
-
- } else {
- errorLog("Incomplete Location-Data in data.yml: " + section.getCurrentPath() + "." + wakeup);
- }
- }
- }
- }
-
- }
- }
-
- private boolean checkConfigs() {
- File cfg = new File(p.getDataFolder(), "config.yml");
- if (!cfg.exists()) {
- errorLog("No config.yml found, creating default file! You may want to choose a config according to your language!");
- errorLog("You can find them in plugins/Brewery/configs/");
- InputStream defconf = getResource("config/" + (use1_13 ? "v13/" : "v12/") + "en/config.yml");
- if (defconf == null) {
- errorLog("default config file not found, your jarfile may be corrupt. Disabling Brewery!");
- return false;
- }
- try {
- Util.saveFile(defconf, getDataFolder(), "config.yml", false);
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- }
- if (!cfg.exists()) {
- errorLog("default config file could not be copied, your jarfile may be corrupt. Disabling Brewery!");
- return false;
- }
-
- copyDefaultConfigs(false);
- return true;
- }
-
- private void copyDefaultConfigs(boolean overwrite) {
- File configs = new File(getDataFolder(), "configs");
- File languages = new File(getDataFolder(), "languages");
- for (String l : new String[] {"de", "en", "fr", "it", "zh", "tw"}) {
- File lfold = new File(configs, l);
- try {
- Util.saveFile(getResource("config/" + (use1_13 ? "v13/" : "v12/") + l + "/config.yml"), lfold, "config.yml", overwrite);
- Util.saveFile(getResource("languages/" + l + ".yml"), languages, l + ".yml", false); // Never overwrite languages for now
- } catch (IOException e) {
- if (!(l.equals("zh") || l.equals("tw"))) {
- e.printStackTrace();
- }
- }
- }
- }
-
- // Utility
-
public int parseInt(String string) {
return NumberUtils.toInt(string, 0);
}
-
- // Returns true if the Block can be destroyed by the Player or something else (null)
- public boolean blockDestroy(Block block, Player player) {
- Material type = block.getType();
- if (type == Material.CAULDRON) {
- // will only remove when existing
- BCauldron.remove(block);
- return true;
-
- } else if (LegacyUtil.isFence(type)) {
- // remove barrel and throw potions on the ground
- Barrel barrel = Barrel.getBySpigot(block);
- if (barrel != null) {
- if (barrel.hasPermsDestroy(player)) {
- barrel.remove(null, player);
- return true;
- } else {
- return false;
- }
- }
- return true;
-
- } else if (LegacyUtil.isSign(type)) {
- // remove small Barrels
- Barrel barrel2 = Barrel.getBySpigot(block);
- if (barrel2 != null) {
- if (!barrel2.isLarge()) {
- if (barrel2.hasPermsDestroy(player)) {
- barrel2.remove(null, player);
- return true;
- } else {
- return false;
- }
- } else {
- barrel2.destroySign();
- }
- }
- return true;
-
- } else if (LegacyUtil.isWoodPlanks(type) || LegacyUtil.isWoodStairs(type)){
- Barrel barrel3 = Barrel.getByWood(block);
- if (barrel3 != null) {
- if (barrel3.hasPermsDestroy(player)) {
- barrel3.remove(block, player);
- } else {
- return false;
- }
- }
- }
- return true;
- }
-
public String color(String msg) {
- return Util.color(msg);
+ return BUtil.color(msg);
}
// Runnables
- public class DrunkRunnable implements Runnable {
+ public static class DrunkRunnable implements Runnable {
@Override
public void run() {
if (!BPlayer.isEmpty()) {
@@ -806,17 +397,28 @@ public class P extends JavaPlugin {
public class BreweryRunnable implements Runnable {
@Override
public void run() {
- reloader = null;
- for (BCauldron cauldron : BCauldron.bcauldrons) {
+ long t1 = System.nanoTime();
+ BConfig.reloader = null;
+ for (BCauldron cauldron : BCauldron.bcauldrons.values()) {
cauldron.onUpdate();// runs every min to update cooking time
}
+ long t2 = System.nanoTime();
Barrel.onUpdate();// runs every min to check and update ageing time
+ long t3 = System.nanoTime();
if (use1_14) MCBarrel.onUpdate();
+ long t4 = System.nanoTime();
BPlayer.onUpdate();// updates players drunkeness
- debugLog("Update");
-
+ long t5 = System.nanoTime();
DataSave.autoSave();
+ long t6 = System.nanoTime();
+
+ debugLog("BreweryRunnable: " +
+ "t1: " + (t2 - t1) / 1000000.0 + "ms" +
+ " | t2: " + (t3 - t2) / 1000000.0 + "ms" +
+ " | t3: " + (t4 - t3) / 1000000.0 + "ms" +
+ " | t4: " + (t5 - t4) / 1000000.0 + "ms" +
+ " | t5: " + (t6 - t5) / 1000000.0 + "ms" );
}
}
diff --git a/src/com/dre/brewery/Util.java b/src/com/dre/brewery/Util.java
deleted file mode 100644
index bc7cf4a..0000000
--- a/src/com/dre/brewery/Util.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package com.dre.brewery;
-
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.World;
-import org.bukkit.block.Block;
-import org.bukkit.command.CommandSender;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.entity.Player;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.ListIterator;
-import java.util.UUID;
-
-public class Util {
-
- /********** Bukkit Utils **********/
-
- // Check if the Chunk of a Block is loaded !without loading it in the process!
- public static boolean isChunkLoaded(Block block) {
- return block.getWorld().isChunkLoaded(block.getX() >> 4, block.getZ() >> 4);
- }
-
- public static String color(String msg) {
- if (msg != null) {
- msg = ChatColor.translateAlternateColorCodes('&', msg);
- }
- return msg;
- }
-
- // Returns either uuid or Name of player, depending on bukkit version
- public static String playerString(Player player) {
- if (P.useUUID) {
- return player.getUniqueId().toString();
- } else {
- return player.getName();
- }
- }
-
- // returns the Player if online
- public static Player getPlayerfromString(String name) {
- if (P.useUUID) {
- try {
- return Bukkit.getPlayer(UUID.fromString(name));
- } catch (Exception e) {
- return Bukkit.getPlayerExact(name);
- }
- }
- return Bukkit.getPlayerExact(name);
- }
-
- // Apply a Potion Effect, if player already has this effect, overwrite the existing effect.
- // Optionally only overwrite if the new one is stronger, i.e. has higher level or longer duration
- public static void reapplyPotionEffect(Player player, PotionEffect effect, boolean onlyIfStronger) {
- final PotionEffectType type = effect.getType();
- if (player.hasPotionEffect(type)) {
- PotionEffect plEffect;
- if (P.use1_11) {
- plEffect = player.getPotionEffect(type);
- } else {
- plEffect = player.getActivePotionEffects().stream().filter(e -> e.getType().equals(type)).findAny().get();
- }
- if (plEffect.getAmplifier() < effect.getAmplifier() || (plEffect.getAmplifier() == effect.getAmplifier() && plEffect.getDuration() < effect.getDuration())) {
- player.removePotionEffect(type);
- } else {
- return;
- }
- }
- effect.apply(player);
- }
-
- /********** Other Utils **********/
-
- // prints a list of Strings at the specified page
- public static void list(CommandSender sender, ArrayList strings, int page) {
- int pages = (int) Math.ceil(strings.size() / 7F);
- if (page > pages || page < 1) {
- page = 1;
- }
-
- sender.sendMessage(color("&7-------------- &f" + P.p.languageReader.get("Etc_Page") + " &6" + page + "&f/&6" + pages + " &7--------------"));
-
- ListIterator iter = strings.listIterator((page - 1) * 7);
-
- for (int i = 0; i < 7; i++) {
- if (iter.hasNext()) {
- sender.sendMessage(color(iter.next()));
- } else {
- break;
- }
- }
- }
-
- // gets the Name of a DXL World
- public static String getDxlName(String worldName) {
- File dungeonFolder = new File(worldName);
- if (dungeonFolder.isDirectory()) {
- for (File file : dungeonFolder.listFiles()) {
- if (!file.isDirectory()) {
- if (file.getName().startsWith(".id_")) {
- return file.getName().substring(1).toLowerCase();
- }
- }
- }
- }
- return worldName;
- }
-
- // create empty World save Sections
- public static void createWorldSections(ConfigurationSection section) {
- for (World world : P.p.getServer().getWorlds()) {
- String worldName = world.getName();
- if (worldName.startsWith("DXL_")) {
- worldName = getDxlName(worldName);
- } else {
- worldName = world.getUID().toString();
- }
- section.createSection(worldName);
- }
- }
-
- @SuppressWarnings("ResultOfMethodCallIgnored")
- public static void saveFile(InputStream in, File dest, String name, boolean overwrite) throws IOException {
- if (in == null) return;
- if (!dest.exists()) {
- dest.mkdirs();
- }
- File result = new File(dest, name);
- if (result.exists()) {
- if (overwrite) {
- result.delete();
- } else {
- return;
- }
- }
-
- OutputStream out = new FileOutputStream(result);
- byte[] buffer = new byte[1024];
-
- int length;
- //copy the file content in bytes
- while ((length = in.read(buffer)) > 0){
- out.write(buffer, 0, length);
- }
-
- in.close();
- out.close();
- }
-
-}
diff --git a/src/com/dre/brewery/Wakeup.java b/src/com/dre/brewery/Wakeup.java
index 78aed34..46e2906 100644
--- a/src/com/dre/brewery/Wakeup.java
+++ b/src/com/dre/brewery/Wakeup.java
@@ -1,16 +1,18 @@
package com.dre.brewery;
+import com.dre.brewery.utility.BUtil;
+import org.bukkit.Location;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.entity.Player;
+
import java.util.ArrayList;
import java.util.Iterator;
-
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.command.CommandSender;
-import org.bukkit.Location;
-import org.bukkit.entity.Player;
+import java.util.List;
public class Wakeup {
- public static ArrayList wakeups = new ArrayList<>();
+ public static List wakeups = new ArrayList<>();
public static P p = P.p;
public static int checkId = -1;
public static Player checkPlayer = null;
@@ -140,7 +142,7 @@ public class Wakeup {
locs.add("&6" + s + id + "&f" + s + ": " + world + " " + x + "," + y + "," + z);
}
}
- Util.list(sender, locs, page);
+ BUtil.list(sender, locs, page);
}
public static void check(CommandSender sender, int id, boolean all) {
@@ -228,7 +230,7 @@ public class Wakeup {
public static void save(ConfigurationSection section, ConfigurationSection oldData) {
- Util.createWorldSections(section);
+ BUtil.createWorldSections(section);
// loc is saved as a String in world sections with format x/y/z/pitch/yaw
if (!wakeups.isEmpty()) {
@@ -245,7 +247,7 @@ public class Wakeup {
String prefix;
if (worldName.startsWith("DXL_")) {
- prefix = Util.getDxlName(worldName) + "." + id;
+ prefix = BUtil.getDxlName(worldName) + "." + id;
} else {
prefix = wakeup.loc.getWorld().getUID().toString() + "." + id;
}
diff --git a/src/com/dre/brewery/api/BreweryApi.java b/src/com/dre/brewery/api/BreweryApi.java
new file mode 100644
index 0000000..b53def9
--- /dev/null
+++ b/src/com/dre/brewery/api/BreweryApi.java
@@ -0,0 +1,372 @@
+package com.dre.brewery.api;
+
+import com.dre.brewery.BCauldron;
+import com.dre.brewery.BPlayer;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.recipe.BCauldronRecipe;
+import com.dre.brewery.recipe.BRecipe;
+import com.dre.brewery.Barrel;
+import com.dre.brewery.Brew;
+import org.apache.commons.lang.NotImplementedException;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * Convenience methods to get common objects or do common things.
+ * Contains shortcuts and collects of some of the main functions of this Plugin
+ *
+ *
Next to this there are lots of public Methods in many Objects
+ * like Brew, Barrel, BCauldron, BRecipe, etc
+ *
In the api package, you can also find custom Events.
+ */
+public class BreweryApi {
+
+ /**
+ * Remove any data that this Plugin may associate with the given Block.
+ *
Currently Cauldrons and Barrels (Cauldron, Wood, Woodstairs, Fence, Sign)
+ *
Does not remove any actual Blocks
+ *
Returns true if anything was removed
+ *
+ * @return true if anything was removed
+ */
+ public static boolean removeAny(Block block) {
+ if (removeCauldron(block)) return true;
+ return removeBarrel(block, true);
+ }
+
+ /**
+ *
Like removeAny() but removes data as if the given player broke the Block.
+ *
Currently only makes a difference for Logging
+ */
+ public static boolean removeAnyByPlayer(Block block, Player player) {
+ if (removeCauldron(block)) return true;
+ return removeBarrelByPlayer(block, player, true);
+ }
+
+
+ // # # # # # # # # # # # #
+ // # # # # # Player # # # # #
+ // # # # # # # # # # # # #
+
+ /**
+ * Get the BPlayer for the given Player, containing drunkeness and hangover data.
+ */
+ public static BPlayer getBPlayer(Player player) {
+ return BPlayer.get(player);
+ }
+
+ /**
+ * Set the Players drunkeness state.
+ *
+ * @param player The Player to set the drunkeness on
+ * @param drunkeness The amount of drunkeness 0-100 to apply to the player
+ * @param quality The Quality 1-10 the drunkeness of the player should have.
+ *
zero Quality keeps the players current quality
+ */
+ public static void setPlayerDrunk(Player player, int drunkeness, int quality) {
+ if (drunkeness < 0) {
+ throw new IllegalArgumentException("Drunkeness can not be <0");
+ }
+ if (quality > 10) {
+ throw new IllegalArgumentException("Quality can not be >10");
+ }
+ BPlayer bPlayer = BPlayer.get(player);
+ if (bPlayer == null && player != null) {
+ if (drunkeness == 0) {
+ return;
+ }
+ bPlayer = BPlayer.addPlayer(player);
+ }
+ if (bPlayer == null) {
+ return;
+ }
+
+ if (drunkeness == 0) {
+ bPlayer.remove();
+ } else {
+ bPlayer.setData(drunkeness, quality);
+ }
+
+ if (drunkeness > 100) {
+ if (player != null) {
+ bPlayer.drinkCap(player);
+ } else {
+ if (!BConfig.overdrinkKick) {
+ bPlayer.setData(100, 0);
+ }
+ }
+ }
+ }
+
+
+ // # # # # # # # # # # # #
+ // # # # # # Brew # # # # #
+ // # # # # # # # # # # # #
+
+ /**
+ * Get a Brew from an ItemStack.
+ *
Reads the Brew data from the saved data on the item
+ *
Checks if item is actually a Brew
+ *
Returns null if item is not a Brew
+ */
+ @Nullable
+ public static Brew getBrew(ItemStack item) {
+ return Brew.get(item);
+ }
+
+ /**
+ * Get a Brew from an ItemMeta.
+ *
Reads the Brew data from the saved data in the Meta
+ *
Checks if meta has a Brew saved
+ *
Returns null if meta is not a Brew
+ */
+ @Nullable
+ public static Brew getBrew(ItemMeta meta) {
+ return Brew.get(meta);
+ }
+
+ /**
+ * Performant way to check if an item is a brew.
+ *
Does not give any guarantees that getBrew() will return notnull for this item, i.e. if it is a brew but couldn't be loaded
+ */
+ public static boolean isBrew(ItemStack item) {
+ return Brew.isBrew(item);
+ }
+
+ /**
+ * Create a Brew from the given Recipe.
+ *
+ * @param recipe The Recipe to create a brew from
+ * @return The Brew that was created. Can use brew.createItem() to get an ItemStack
+ */
+ public static Brew createBrew(BRecipe recipe, int quality) {
+ return recipe.createBrew(quality);
+ }
+
+
+ // # # # # # # # # # # # #
+ // # # # # # Barrel # # # # #
+ // # # # # # # # # # # # #
+
+ /**
+ * Get a Barrel from a Block.
+ *
May be any Wood, Fence, Sign that is part of a Barrel
+ *
Returns null if block is not part of a Barrel
+ */
+ @Nullable
+ public static Barrel getBarrel(Block block) {
+ return Barrel.get(block);
+ }
+
+ /**
+ * Get the Inventory of a Block part of a Barrel.
+ *
May be any Wood, Fence or Sign that is part of a Barrel
+ *
Returns null if block is not part of a Barrel
+ */
+ @Nullable
+ public static Inventory getBarrelInventory(Block block) {
+ Barrel barrel = Barrel.get(block);
+ if (barrel != null) {
+ return barrel.getInventory();
+ }
+ return null;
+ }
+
+ /**
+ * Remove any Barrel that this Block may be Part of.
+ * Does not remove any actual Block
+ *
+ * @param block The Block thats part of the barrel, potions will drop there
+ * @param dropItems If the items in the barrels inventory should drop to the ground
+ * @return True if a Barrel was removed
+ */
+ public static boolean removeBarrel(Block block, boolean dropItems) {
+ return removeBarrelByPlayer(block, null, dropItems);
+ }
+
+ /**
+ * Remove any Barrel that this Block may be Part of, as if broken by the Player.
+ * Does not remove any actual Block from the World
+ *
+ * @param block The Block thats part of the barrel, potions will drop there
+ * @param player The Player that broke the Block
+ * @param dropItems If the items in the barrels inventory should drop to the ground
+ * @return True if a Barrel was removed
+ */
+ public static boolean removeBarrelByPlayer(Block block, Player player, boolean dropItems) {
+ Barrel barrel = Barrel.get(block);
+ if (barrel != null) {
+ barrel.remove(block, player, dropItems);
+ return true;
+ }
+ return false;
+ }
+
+ // # # # # # # # # # # # #
+ // # # # # # Cauldron # # # # #
+ // # # # # # # # # # # # #
+
+ /**
+ * Get a BCauldron from a Block.
+ *
Returns null if block is not a BCauldron
+ */
+ @Nullable
+ public static BCauldron getCauldron(Block block) {
+ return BCauldron.get(block);
+ }
+
+ /**
+ * Remove any data associated with a Cauldron at that given Block.
+ *
Returns true if a Cauldron was removed
+ *
Does not remove the Block from the World
+ */
+ public static boolean removeCauldron(Block block) {
+ return BCauldron.remove(block);
+ }
+
+
+ // # # # # # # # # # # # #
+ // # # # # # Recipe # # # # #
+ // # # # # # # # # # # # #
+
+ /**
+ * Get a BRecipe by its name.
+ *
The name is the middle one of the three if three are set in the config
+ *
Returns null if recipe with that name does not exist
+ */
+ @Nullable
+ public static BRecipe getRecipe(String name) {
+ return BRecipe.get(name);
+ }
+
+ /**
+ * Add a New Recipe.
+ *
Brews can be made out of this Recipe.
+ *
The recipe can be changed or removed later.
+ *
+ * @param recipe The Recipe to add
+ * @param saveForever Not Implemented yet.
+ *
If the recipe should be saved forever, even after the Server restarts
+ *
If True: Recipe will be saved until removed manually
+ *
If False: Recipe will be removed when the Server restarts, existing potions using
+ *
this Recipe will become bad after continued aging, if the recipe is not added again.
+ */
+ public static void addRecipe(BRecipe recipe, boolean saveForever) {
+ //recipe.setSaveInData(saveForever);
+ if (saveForever) {
+ throw new NotImplementedException("SaveForever is not implemented yet");
+ }
+ BRecipe.getAddedRecipes().add(recipe);
+ recipe.updateAcceptedLists();
+ }
+
+ /**
+ * Removes a Recipe from the List of all Recipes.
+ *
This can also remove Recipes that were loaded from config, though these will be readded when reloading the config
+ *
+ * @param name The name of the recipe to remove
+ * @return The Recipe that was removed, null if none was removed
+ */
+ @Nullable
+ public static BRecipe removeRecipe(String name) {
+ List recipes = BRecipe.getAllRecipes();
+ for (int i = 0; i < recipes.size(); i++) {
+ if (recipes.get(i).getRecipeName().equalsIgnoreCase(name)) {
+ BRecipe remove = recipes.remove(i);
+ if (i < BRecipe.numConfigRecipes) {
+ // We removed one of the Config Recipes
+ BRecipe.numConfigRecipes--;
+ }
+ return remove;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Create a New Recipe with a Recipe Builder.
+ *
+ * @param recipeNames Either 1 or 3 names. Sets the Name for Quality (Bad, Normal, Good)
+ * @return A Recipe Builder
+ */
+ public static BRecipe.Builder recipeBuilder(String... recipeNames) {
+ return new BRecipe.Builder(recipeNames);
+ }
+
+
+
+ // # # # # # # # # # # # #
+ // # # # # # Cauldron Recipe # # # # #
+ // # # # # # # # # # # # #
+
+ /**
+ * Get A BCauldronRecipe by its name.
+ * Returns null if recipe with that name does not exist
+ */
+ @Nullable
+ public static BCauldronRecipe getCauldronRecipe(String name) {
+ return BCauldronRecipe.get(name);
+ }
+
+ /**
+ * Add a New Cauldron Recipe.
+ *
Base Brews coming out of the Cauldron can be made from this recipe
+ *
The recipe can be changed or removed later.
+ *
+ * @param recipe The Cauldron Recipe to add
+ * @param saveForever Not Implemented yet.
+ *
If the recipe should be saved forever, even after the Server restarts
+ *
If True: Recipe will be saved until removed manually
+ *
If False: Recipe will be removed when the Server restarts
+ */
+ public static void addCauldronRecipe(BCauldronRecipe recipe, boolean saveForever) {
+ //recipe.setSaveInData(saveForever);
+ if (saveForever) {
+ throw new NotImplementedException();
+ }
+ BCauldronRecipe.getAddedRecipes().add(recipe);
+ recipe.updateAcceptedLists();
+ }
+
+ /**
+ * Removes a Cauldron Recipe from the List of all Cauldron Recipes.
+ *
This can also remove Cauldron Recipes that were loaded from config,
+ * though these will be readded when reloading the config
+ *
+ * @param name The name of the cauldron recipe to remove
+ * @return The Cauldron Recipe that was removed, null if none was removed
+ */
+ @Nullable
+ public static BCauldronRecipe removeCauldronRecipe(String name) {
+ List recipes = BCauldronRecipe.getAllRecipes();
+ for (int i = 0; i < recipes.size(); i++) {
+ if (recipes.get(i).getName().equalsIgnoreCase(name)) {
+ BCauldronRecipe remove = recipes.remove(i);
+ if (i < BCauldronRecipe.numConfigRecipes) {
+ // We removed one of the Config Recipes
+ BCauldronRecipe.numConfigRecipes--;
+ }
+ return remove;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Create a New Cauldron Recipe with a Recipe Builder.
+ *
+ * @param name The name of the new Cauldron Recipe
+ * @return A Cauldron Recipe Builder
+ */
+ public static BCauldronRecipe.Builder cauldronRecipeBuilder(String name) {
+ return new BCauldronRecipe.Builder(name);
+ }
+
+
+}
diff --git a/src/com/dre/brewery/api/events/ConfigLoadEvent.java b/src/com/dre/brewery/api/events/ConfigLoadEvent.java
new file mode 100644
index 0000000..e4ea2af
--- /dev/null
+++ b/src/com/dre/brewery/api/events/ConfigLoadEvent.java
@@ -0,0 +1,49 @@
+package com.dre.brewery.api.events;
+
+import com.dre.brewery.api.BreweryApi;
+import com.dre.brewery.recipe.BCauldronRecipe;
+import com.dre.brewery.recipe.BRecipe;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * The Brewery Config was reloaded.
+ * The Recipes added by a Plugin to the Added Recipes will not be reloaded and stay where they are.
+ */
+public class ConfigLoadEvent extends Event {
+ private static final HandlerList handlers = new HandlerList();
+
+ /**
+ * Removes a Recipe, can also remove config recipes.
+ * One of the things one might need to do after reloading.
+ *
+ * @param name Name of the Recipe to remove
+ * @return The Recipe that was removed, null if none was removed
+ */
+ public BRecipe removeRecipe(String name) {
+ return BreweryApi.removeRecipe(name);
+ }
+
+ /**
+ * Removes a Cauldron Recipe, can also remove config recipes.
+ * One of the things one might need to do after reloading.
+ *
+ * @param name Name of the Cauldron Recipe to remove
+ * @return The Cauldron Recipe that was removed, null if none was removed
+ */
+ public BCauldronRecipe removeCauldronRecipe(String name) {
+ return BreweryApi.removeCauldronRecipe(name);
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/com/dre/brewery/api/events/IngedientAddEvent.java b/src/com/dre/brewery/api/events/IngedientAddEvent.java
new file mode 100644
index 0000000..37461f3
--- /dev/null
+++ b/src/com/dre/brewery/api/events/IngedientAddEvent.java
@@ -0,0 +1,147 @@
+package com.dre.brewery.api.events;
+
+import com.dre.brewery.BCauldron;
+import com.dre.brewery.recipe.RecipeItem;
+import com.dre.brewery.utility.LegacyUtil;
+import org.bukkit.block.Block;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.block.data.Levelled;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Player adding an ingredient to a cauldron.
+ *
Always one item added at a time.
+ *
If needed use the caudrons add method to manually add more Items
+ */
+public class IngedientAddEvent extends PlayerEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private final Block block;
+ private final BCauldron cauldron;
+ private ItemStack ingredient;
+ private RecipeItem rItem;
+ private boolean cancelled;
+ private boolean takeItem = true;
+
+ public IngedientAddEvent(Player who, Block block, BCauldron bCauldron, ItemStack ingredient, RecipeItem rItem) {
+ super(who);
+ this.block = block;
+ cauldron = bCauldron;
+ this.rItem = rItem;
+ this.ingredient = ingredient;
+ }
+
+ public Block getBlock() {
+ return block;
+ }
+
+ public BCauldron getCauldron() {
+ return cauldron;
+ }
+
+ /**
+ * The Recipe item that matches the ingredient.
+ *
This might not be the only recipe item that will match the ingredient
+ *
Will be recalculated if the Ingredient is changed with the setIngredient Method
+ */
+ public RecipeItem getRecipeItem() {
+ return rItem;
+ }
+
+ /**
+ * Get the item currently being added to the cauldron by the player.
+ *
Can be changed directly (mutable) or with the setter Method
+ *
The amount is ignored and always one added
+ *
+ * @return The item being added
+ */
+ public ItemStack getIngredient() {
+ return ingredient;
+ }
+
+ /**
+ * Set the ingredient added to the cauldron to something else.
+ *
Will always be accepted, even when not in a recipe or the cooked lis
+ *
The amount is ignored and always one added
+ *
This also recalculates the recipeItem!
+ *
+ * @param ingredient The item to add instead
+ */
+ public void setIngredient(ItemStack ingredient) {
+ this.ingredient = ingredient;
+ // The Ingredient has been changed. Recalculate RecipeItem!
+ rItem = RecipeItem.getMatchingRecipeItem(ingredient, true);
+ }
+
+ /**
+ * If the amount of the item in the players hand should be decreased.
+ * (Default true)
+ */
+ public boolean willTakeItem() {
+ return takeItem;
+ }
+
+ /**
+ * Set if the amount of the item in the players hand should be decreased.
+ *
+ * @param takeItem if the item amount in the hand should be decreased
+ */
+ public void setTakeItem(boolean takeItem) {
+ this.takeItem = takeItem;
+ }
+
+ /**
+ * Get the BlockData of the Cauldron.
+ *
May be null if the Cauldron does not exist anymore
+ *
+ * @return The BlockData of the cauldron
+ */
+ @Nullable
+ public Levelled getCauldronData() {
+ BlockData data = block.getBlockData();
+ if (data instanceof Levelled) {
+ return (Levelled) data;
+ }
+ return null;
+ }
+
+ /**
+ * Get the water fill level of the Cauldron.
+ *
0 = empty, 1 = something in, 2 = full
+ *
Can use BCauldron.EMPTY, BCauldron.SOME, BCauldron.FULL
+ *
+ * @return The fill level as a byte 0-2
+ */
+ public byte getFillLevel() {
+ return LegacyUtil.getFillLevel(block);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ /**
+ * If the event is cancelled, no item will be added or taken from the player.
+ */
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/com/dre/brewery/api/events/PlayerChatDistortEvent.java b/src/com/dre/brewery/api/events/PlayerChatDistortEvent.java
new file mode 100644
index 0000000..15e7dfc
--- /dev/null
+++ b/src/com/dre/brewery/api/events/PlayerChatDistortEvent.java
@@ -0,0 +1,95 @@
+package com.dre.brewery.api.events;
+
+import com.dre.brewery.BPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+
+/**
+ * The Player writes something in Chat or on a Sign and his words are distorted.
+ *
+ *
This Event may be Async if the Chat Event is Async!
+ */
+public class PlayerChatDistortEvent extends Event implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+
+ private final Player player;
+ private final BPlayer bPlayer;
+ private final String prevMsg;
+ private String distortMsg;
+ private boolean cancelled;
+
+ public PlayerChatDistortEvent(boolean async, Player player, BPlayer bPlayer, String prevMsg, String distortMsg) {
+ super(async);
+ this.player = player;
+ this.bPlayer = bPlayer;
+ this.prevMsg = prevMsg;
+ this.distortMsg = distortMsg;
+ }
+
+ @NotNull
+ public Player getPlayer() {
+ return player;
+ }
+
+ @NotNull
+ public BPlayer getbPlayer() {
+ return bPlayer;
+ }
+
+ /**
+ * @return The Message the Player had actually written
+ */
+ @NotNull
+ public String getWrittenMessage() {
+ return prevMsg;
+ }
+
+ /**
+ * @return The message after it was distorted
+ */
+ @NotNull
+ public String getDistortedMessage() {
+ return distortMsg;
+ }
+
+ /**
+ * @return The drunkeness of the player that is writing the message
+ */
+ public int getDrunkeness() {
+ return bPlayer.getDrunkeness();
+ }
+
+ /**
+ * Set the Message that the player will say instead of what he wrote
+ */
+ public void setDistortedMessage(String distortMsg) {
+ this.distortMsg = Objects.requireNonNull(distortMsg);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/com/dre/brewery/api/events/PlayerEffectEvent.java b/src/com/dre/brewery/api/events/PlayerEffectEvent.java
new file mode 100644
index 0000000..3d1b432
--- /dev/null
+++ b/src/com/dre/brewery/api/events/PlayerEffectEvent.java
@@ -0,0 +1,98 @@
+package com.dre.brewery.api.events;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.potion.PotionEffect;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * A List of effects is applied to the player.
+ *
This happens for various reasons like Alcohol level, Brew quality, Brew effects, etc.
+ *
+ *
Can be changed or cancelled
+ */
+public class PlayerEffectEvent extends PlayerEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private final EffectType effectType;
+ private List effects;
+ private boolean cancelled;
+
+ public PlayerEffectEvent(Player who, EffectType effectType, List effects) {
+ super(who);
+ this.effectType = effectType;
+ this.effects = effects;
+ }
+
+ /**
+ * @return The effects being applied. Effects can be added or removed from this list.
+ */
+ public List getEffects() {
+ return effects;
+ }
+
+ public void setEffects(List effects) {
+ this.effects = effects;
+ }
+
+ /**
+ * @return What type of effects are applied, see EffectType
+ */
+ public EffectType getEffectType() {
+ return effectType;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+
+
+ /**
+ * The Type of Effect, or why an effect is being added to the player.
+ */
+ public enum EffectType {
+ /**
+ * The Alcohol level demands its toll.
+ * Regularly applied depending on the players alcohol level
+ *
By default it is just one Confusion effect
+ */
+ ALCOHOL,
+
+ /**
+ * Effects of a Brew are applied to the player (drinking the Brew).
+ *
These depend on alcohol and quality of the brew
+ */
+ DRINK,
+
+ /**
+ * When drinking a Brew with low Quality, these effects are applied.
+ */
+ QUALITY,
+
+ /**
+ * When logging in after drinking, Hangover Effects are applied.
+ */
+ HANGOVER
+
+ }
+}
diff --git a/src/com/dre/brewery/api/events/PlayerPukeEvent.java b/src/com/dre/brewery/api/events/PlayerPukeEvent.java
new file mode 100644
index 0000000..05f3bbc
--- /dev/null
+++ b/src/com/dre/brewery/api/events/PlayerPukeEvent.java
@@ -0,0 +1,69 @@
+package com.dre.brewery.api.events;
+
+import com.dre.brewery.BPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * The player pukes (throws puke items to the ground).
+ *
Those items can never be picked up and despawn after the time set in the config
+ *
Number of items to drop can be changed with count
+ */
+public class PlayerPukeEvent extends PlayerEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private int count;
+ private boolean cancelled;
+ private BPlayer bPlayer;
+
+
+ public PlayerPukeEvent(Player who, int count) {
+ super(who);
+ this.count = count;
+ }
+
+ /**
+ * Get the Amount of items being dropped this time
+ */
+ public int getCount() {
+ return count;
+ }
+
+ /**
+ * Set the amount of items being dropped this time
+ */
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public BPlayer getBPlayer() {
+ if (bPlayer == null) {
+ bPlayer = BPlayer.get(player);
+ }
+ return bPlayer;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+
+}
diff --git a/src/com/dre/brewery/api/events/PlayerPushEvent.java b/src/com/dre/brewery/api/events/PlayerPushEvent.java
new file mode 100644
index 0000000..03290fe
--- /dev/null
+++ b/src/com/dre/brewery/api/events/PlayerPushEvent.java
@@ -0,0 +1,75 @@
+package com.dre.brewery.api.events;
+
+import com.dre.brewery.BPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * The Players movement is hindered because of drunkeness.
+ *
Called each time before pushing the Player with the Vector push 10 times
+ *
The Push Vector can be changed or multiplied
+ */
+public class PlayerPushEvent extends PlayerEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private final BPlayer bPlayer;
+ private Vector push;
+ private boolean cancelled;
+
+ public PlayerPushEvent(Player who, Vector push, BPlayer bPlayer) {
+ super(who);
+ this.push = push;
+ this.bPlayer = bPlayer;
+ }
+
+ public BPlayer getBPlayer() {
+ return bPlayer;
+ }
+
+ /**
+ * Get the Vector in which direction and magnitude the player is pushed.
+ *
Can be changed directly or through setPush
+ *
+ * @return The current push vector
+ */
+ public Vector getPush() {
+ return push;
+ }
+
+ /**
+ * Set the Push vector.
+ *
+ * @param push The new push vector, not null
+ */
+ public void setPush(@NotNull Vector push) {
+ if (push == null) {
+ throw new NullPointerException("Push Vector is null");
+ }
+ this.push = push;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+
+}
diff --git a/src/com/dre/brewery/api/events/barrel/BarrelAccessEvent.java b/src/com/dre/brewery/api/events/barrel/BarrelAccessEvent.java
new file mode 100644
index 0000000..b3c853d
--- /dev/null
+++ b/src/com/dre/brewery/api/events/barrel/BarrelAccessEvent.java
@@ -0,0 +1,59 @@
+package com.dre.brewery.api.events.barrel;
+
+import com.dre.brewery.Barrel;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A Player opens a Barrel by rightclicking it.
+ *
The PlayerInteractEvent on the Barrel may be cancelled. In that case this never gets called
+ *
Can be cancelled to silently deny opening the Barrel
+ */
+public class BarrelAccessEvent extends BarrelEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private final Player player;
+ private final Block clickedBlock;
+ private boolean isCancelled;
+
+ public BarrelAccessEvent(Barrel barrel, Player player, Block clickedBlock) {
+ super(barrel);
+ this.player = player;
+ this.clickedBlock = clickedBlock;
+ }
+
+ /**
+ * Gets the Block that was actually clicked.
+ *
For access Permissions getSpigot() should be used
+ */
+ public Block getClickedBlock() {
+ return clickedBlock;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return isCancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ isCancelled = cancelled;
+ }
+
+ public Player getPlayer() {
+ return player;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/com/dre/brewery/api/events/barrel/BarrelCreateEvent.java b/src/com/dre/brewery/api/events/barrel/BarrelCreateEvent.java
new file mode 100644
index 0000000..ef9129e
--- /dev/null
+++ b/src/com/dre/brewery/api/events/barrel/BarrelCreateEvent.java
@@ -0,0 +1,47 @@
+package com.dre.brewery.api.events.barrel;
+
+import com.dre.brewery.Barrel;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Called when a Barrel is created by a Player by placing a Sign.
+ *
Cancelling this will silently fail the Barrel creation
+ */
+public class BarrelCreateEvent extends BarrelEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private final Player player;
+ private boolean cancelled;
+
+ public BarrelCreateEvent(Barrel barrel, Player player) {
+ super(barrel);
+ this.player = player;
+ }
+
+ public Player getPlayer() {
+ return player;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/com/dre/brewery/api/events/barrel/BarrelDestroyEvent.java b/src/com/dre/brewery/api/events/barrel/BarrelDestroyEvent.java
new file mode 100644
index 0000000..45ee763
--- /dev/null
+++ b/src/com/dre/brewery/api/events/barrel/BarrelDestroyEvent.java
@@ -0,0 +1,114 @@
+package com.dre.brewery.api.events.barrel;
+
+import com.dre.brewery.Barrel;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * A Barrel is being destroyed by something, may not be by a Player.
+ *
A BarrelRemoveEvent will be called after this, if this is not cancelled
+ *
Use the BarrelRemoveEvent to monitor any and all barrels being removed in a non cancellable way
+ *
Cancelling the Event will stop the barrel from being destroyed
+*/
+public class BarrelDestroyEvent extends BarrelEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private final Block broken;
+ private final Reason reason;
+ private final Player player;
+ private boolean cancelled;
+
+ public BarrelDestroyEvent(Barrel barrel, Block broken, Reason reason, Player player) {
+ super(barrel);
+ this.broken = broken;
+ this.player = player;
+ this.reason = reason;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ /**
+ * Cancelling the Event will stop the barrel from being destroyed.
+ * Any Blocks that are part of the barrel will not be destroyed
+ */
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ /**
+ * @return The Block of the Barrel that was broken
+ */
+ public Block getBroken() {
+ return broken;
+ }
+
+ /**
+ * @return The Reason of destruction of this barrel, see Reason
+ */
+ public Reason getReason() {
+ return reason;
+ }
+
+ /**
+ * If a Player was recorded destroying the barrel
+ */
+ public boolean hasPlayer() {
+ return player != null;
+ }
+
+ /**
+ * @return The Player, Null if no Player is involved
+ */
+ @Nullable
+ public Player getPlayerOptional() {
+ return player;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+
+ /**
+ * The Reason why the Barrel is being destroyed.
+ */
+ public enum Reason {
+ /**
+ * A Player Broke the Barrel
+ */
+ PLAYER,
+
+ /**
+ * A Block was broken by something
+ */
+ BROKEN,
+
+ /**
+ * A Block burned away
+ */
+ BURNED,
+
+ /**
+ * The Barrel exploded somehow
+ */
+ EXPLODED,
+
+ /**
+ * The Barrel was broken somehow else
+ */
+ UNKNOWN
+ }
+}
diff --git a/src/com/dre/brewery/api/events/barrel/BarrelEvent.java b/src/com/dre/brewery/api/events/barrel/BarrelEvent.java
new file mode 100644
index 0000000..871b085
--- /dev/null
+++ b/src/com/dre/brewery/api/events/barrel/BarrelEvent.java
@@ -0,0 +1,29 @@
+package com.dre.brewery.api.events.barrel;
+
+import com.dre.brewery.Barrel;
+import org.bukkit.block.Block;
+import org.bukkit.event.Event;
+import org.bukkit.inventory.Inventory;
+
+public abstract class BarrelEvent extends Event {
+ protected final Barrel barrel;
+
+ public BarrelEvent(Barrel barrel) {
+ this.barrel = barrel;
+ }
+
+ public Barrel getBarrel() {
+ return barrel;
+ }
+
+ public Inventory getInventory() {
+ return barrel.getInventory();
+ }
+
+ /**
+ * @return The Spigot Block of the Barrel, usually Sign or a Fence
+ */
+ public Block getSpigot() {
+ return barrel.getSpigot();
+ }
+}
diff --git a/src/com/dre/brewery/api/events/barrel/BarrelRemoveEvent.java b/src/com/dre/brewery/api/events/barrel/BarrelRemoveEvent.java
new file mode 100644
index 0000000..827d6de
--- /dev/null
+++ b/src/com/dre/brewery/api/events/barrel/BarrelRemoveEvent.java
@@ -0,0 +1,42 @@
+package com.dre.brewery.api.events.barrel;
+
+import com.dre.brewery.Barrel;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A Barrel is being removed.
+ *
There may have been a BarrelDestroyEvent before this.
+ * If not, Worldedit, other Plugins etc may be the cause for unexpected removal
+ */
+public class BarrelRemoveEvent extends BarrelEvent {
+ private static final HandlerList handlers = new HandlerList();
+ private boolean dropItems;
+
+ public BarrelRemoveEvent(Barrel barrel, boolean dropItems) {
+ super(barrel);
+ this.dropItems = dropItems;
+ }
+
+ public boolean willDropItems() {
+ return dropItems;
+ }
+
+ /**
+ * @param dropItems Should the Items contained in this Barrel drop to the ground?
+ */
+ public void setShouldDropItems(boolean dropItems) {
+ this.dropItems = dropItems;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/com/dre/brewery/api/events/brew/BrewDrinkEvent.java b/src/com/dre/brewery/api/events/brew/BrewDrinkEvent.java
new file mode 100644
index 0000000..49f3378
--- /dev/null
+++ b/src/com/dre/brewery/api/events/brew/BrewDrinkEvent.java
@@ -0,0 +1,79 @@
+package com.dre.brewery.api.events.brew;
+
+import com.dre.brewery.BPlayer;
+import com.dre.brewery.Brew;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A Player Drinks a Brew.
+ *
The amount of alcohol and quality that will be added to the player can be get/set here
+ *
If cancelled the drinking will fail silently
+ */
+public class BrewDrinkEvent extends BrewEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private final Player player;
+ private final BPlayer bPlayer;
+ private int alc;
+ private int quality;
+ private boolean cancelled;
+
+ public BrewDrinkEvent(Brew brew, ItemMeta meta, Player player, BPlayer bPlayer) {
+ super(brew, meta);
+ this.player = player;
+ this.bPlayer = bPlayer;
+ alc = brew.getOrCalcAlc();
+ quality = brew.getQuality();
+ }
+
+ public Player getPlayer() {
+ return player;
+ }
+
+ public BPlayer getbPlayer() {
+ return bPlayer;
+ }
+
+ public int getAddedAlcohol() {
+ return alc;
+ }
+
+ public void setAddedAlcohol(int alc) {
+ this.alc = alc;
+ }
+
+ public int getQuality() {
+ return quality;
+ }
+
+ public void setQuality(int quality) {
+ if (quality > 10 || quality < 0) {
+ throw new IllegalArgumentException("Quality must be in range from 0 to 10");
+ }
+ this.quality = quality;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/com/dre/brewery/api/events/brew/BrewEvent.java b/src/com/dre/brewery/api/events/brew/BrewEvent.java
new file mode 100644
index 0000000..aa76e7e
--- /dev/null
+++ b/src/com/dre/brewery/api/events/brew/BrewEvent.java
@@ -0,0 +1,29 @@
+package com.dre.brewery.api.events.brew;
+
+import com.dre.brewery.Brew;
+import org.bukkit.event.Event;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class BrewEvent extends Event {
+ protected final Brew brew;
+ protected final ItemMeta meta;
+
+ public BrewEvent(@NotNull Brew brew, @NotNull ItemMeta meta) {
+ this.brew = brew;
+ this.meta = meta;
+ }
+
+ @NotNull
+ public Brew getBrew() {
+ return brew;
+ }
+
+ /**
+ * Gets the Meta of the Item this Brew is attached to
+ */
+ @NotNull
+ public ItemMeta getItemMeta() {
+ return meta;
+ }
+}
diff --git a/src/com/dre/brewery/api/events/brew/BrewModifyEvent.java b/src/com/dre/brewery/api/events/brew/BrewModifyEvent.java
new file mode 100644
index 0000000..74bed88
--- /dev/null
+++ b/src/com/dre/brewery/api/events/brew/BrewModifyEvent.java
@@ -0,0 +1,109 @@
+package com.dre.brewery.api.events.brew;
+
+import com.dre.brewery.Brew;
+import com.dre.brewery.lore.BrewLore;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.PotionMeta;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A Brew has been created or modified.
+ *
Usually happens on filling from cauldron, distilling and aging.
+ *
Modifications to the Brew or the PotionMeta can be done now
+ *
Cancelling reverts the Brew to the state it was before the modification
+ */
+public class BrewModifyEvent extends BrewEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+ private final Type type;
+ private boolean cancelled;
+
+
+ public BrewModifyEvent(@NotNull Brew brew, @NotNull ItemMeta meta, @NotNull Type type) {
+ super(brew, meta);
+ this.type = type;
+ }
+
+ /**
+ * Get the Type of modification being applied to the Brew.
+ */
+ @NotNull
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Get the BrewLore to modify lore on the Brew
+ */
+ @NotNull
+ public BrewLore getLore() {
+ return new BrewLore(getBrew(), (PotionMeta) getItemMeta());
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ /**
+ * Setting the Event cancelled cancels all modificatons to the brew.
+ *
Modifications to the Brew or ItemMeta will not be applied
+ */
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ // Required by Bukkit
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+
+ /**
+ * The Type of Modification being applied to the Brew.
+ */
+ public enum Type {
+ /**
+ * A new Brew is created with arbitrary ways, like the create command.
+ *
Cancelling this will disallow the creation
+ */
+ CREATE,
+
+ /**
+ * Filled from a Cauldron into a new Brew.
+ */
+ FILL,
+
+ /**
+ * Distilled in the Brewing stand.
+ */
+ DISTILL,
+
+ /**
+ * Aged in a Barrel.
+ */
+ AGE,
+
+ /**
+ * Unlabeling Brew with command.
+ */
+ UNLABEL,
+
+ /**
+ * Making Brew static with command.
+ */
+ STATIC,
+
+ /**
+ * Unknown modification, unused.
+ */
+ UNKNOWN
+ }
+}
diff --git a/src/com/dre/brewery/filedata/BConfig.java b/src/com/dre/brewery/filedata/BConfig.java
new file mode 100644
index 0000000..5588440
--- /dev/null
+++ b/src/com/dre/brewery/filedata/BConfig.java
@@ -0,0 +1,331 @@
+package com.dre.brewery.filedata;
+
+import com.dre.brewery.Brew;
+import com.dre.brewery.DistortChat;
+import com.dre.brewery.MCBarrel;
+import com.dre.brewery.P;
+import com.dre.brewery.api.events.ConfigLoadEvent;
+import com.dre.brewery.integration.barrel.WGBarrel;
+import com.dre.brewery.integration.barrel.WGBarrel5;
+import com.dre.brewery.integration.barrel.WGBarrel6;
+import com.dre.brewery.integration.barrel.WGBarrel7;
+import com.dre.brewery.integration.item.BreweryPluginItem;
+import com.dre.brewery.integration.item.MMOItemsPluginItem;
+import com.dre.brewery.integration.item.SlimefunPluginItem;
+import com.dre.brewery.recipe.BCauldronRecipe;
+import com.dre.brewery.recipe.BRecipe;
+import com.dre.brewery.recipe.PluginItem;
+import com.dre.brewery.recipe.RecipeItem;
+import com.dre.brewery.utility.BUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class BConfig {
+
+ public static final String configVersion = "2.0";
+ public static boolean updateCheck;
+ public static CommandSender reloader;
+
+ // Third Party Enabled
+ public static boolean useWG; //WorldGuard
+ public static WGBarrel wg;
+ public static boolean useLWC; //LWC
+ public static boolean useLB; //LogBlock
+ public static boolean useGP; //GriefPrevention
+ public static boolean hasVault; // Vault
+ public static boolean useCitadel; // CivCraft/DevotedMC Citadel
+ public static boolean useGMInventories; // GamemodeInventories
+ public static Boolean hasSlimefun = null; // Slimefun ; Null if not checked
+ public static Boolean hasMMOItems = null; // MMOItems ; Null if not checked
+
+ // Barrel
+ public static boolean openEverywhere;
+
+ //BPlayer
+ public static Map drainItems = new HashMap<>();// DrainItem Material and Strength
+ public static Material pukeItem;
+ public static int pukeDespawntime;
+ public static int hangoverTime;
+ public static boolean overdrinkKick;
+ public static boolean enableHome;
+ public static boolean enableLoginDisallow;
+ public static boolean enablePuke;
+ public static String homeType;
+
+ //Brew
+ public static boolean colorInBarrels; // color the Lore while in Barrels
+ public static boolean colorInBrewer; // color the Lore while in Brewer
+ public static boolean enableEncode;
+ public static boolean alwaysShowQuality; // Always show quality stars
+ public static boolean alwaysShowAlc; // Always show alc%
+
+ //Item
+ public static List customItems = new ArrayList<>();
+
+ public static P p = P.p;
+
+ private static boolean checkConfigs() {
+ File cfg = new File(p.getDataFolder(), "config.yml");
+ if (!cfg.exists()) {
+ p.log("§1§lNo config.yml found, creating default file! You may want to choose a config according to your language!");
+ p.log("§1§lYou can find them in plugins/Brewery/configs/");
+ p.log("§1§lJust copy the config for your language into the Brewery folder and /brew reload");
+ InputStream defconf = p.getResource("config/" + (P.use1_13 ? "v13/" : "v12/") + "en/config.yml");
+ if (defconf == null) {
+ p.errorLog("default config file not found, your jarfile may be corrupt. Disabling Brewery!");
+ return false;
+ }
+ try {
+ BUtil.saveFile(defconf, p.getDataFolder(), "config.yml", false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ if (!cfg.exists()) {
+ p.errorLog("default config file could not be copied, your jarfile may be corrupt. Disabling Brewery!");
+ return false;
+ }
+
+ copyDefaultConfigs(false);
+ return true;
+ }
+
+ private static void copyDefaultConfigs(boolean overwrite) {
+ File configs = new File(p.getDataFolder(), "configs");
+ File languages = new File(p.getDataFolder(), "languages");
+ for (String l : new String[] {"de", "en", "fr", "it", "zh", "tw"}) {
+ File lfold = new File(configs, l);
+ try {
+ BUtil.saveFile(p.getResource("config/" + (P.use1_13 ? "v13/" : "v12/") + l + "/config.yml"), lfold, "config.yml", overwrite);
+ BUtil.saveFile(p.getResource("languages/" + l + ".yml"), languages, l + ".yml", false); // Never overwrite languages, they get updated with their updater
+ } catch (IOException e) {
+ if (!(l.equals("zh") || l.equals("tw"))) {
+ // zh and tw not available for some versions
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static FileConfiguration loadConfigFile() {
+ File file = new File(P.p.getDataFolder(), "config.yml");
+ if (!checkConfigs()) {
+ return null;
+ }
+
+ try {
+ YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
+ if (cfg.contains("version") && cfg.contains("language")) {
+ return cfg;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // Failed to load
+ if (p.languageReader != null) {
+ P.p.errorLog(p.languageReader.get("Error_YmlRead"));
+ } else {
+ P.p.errorLog("Could not read file config.yml, please make sure the file is in valid yml format (correct spaces etc.)");
+ }
+ return null;
+ }
+
+ public static void readConfig(FileConfiguration config) {
+ // Set the Language
+ p.language = config.getString("language", "en");
+
+ // Load LanguageReader
+ p.languageReader = new LanguageReader(new File(p.getDataFolder(), "languages/" + p.language + ".yml"), "languages/" + p.language + ".yml");
+
+ // Has to config still got old materials
+ boolean oldMat = config.getBoolean("oldMat", false);
+
+ // Check if config is the newest version
+ String version = config.getString("version", null);
+ if (version != null) {
+ if (!version.equals(configVersion) || (oldMat && P.use1_13)) {
+ File file = new File(P.p.getDataFolder(), "config.yml");
+ copyDefaultConfigs(true);
+ new ConfigUpdater(file).update(version, oldMat, p.language, config);
+ P.p.log("Config Updated to version: " + configVersion);
+ config = YamlConfiguration.loadConfiguration(file);
+ }
+ }
+
+ // If the Update Checker should be enabled
+ updateCheck = config.getBoolean("updateCheck", false);
+
+ PluginManager plMan = p.getServer().getPluginManager();
+
+ // Third-Party
+ useWG = config.getBoolean("useWorldGuard", true) && plMan.isPluginEnabled("WorldGuard");
+
+ if (useWG) {
+ Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldEdit");
+ if (plugin != null) {
+ String wgv = plugin.getDescription().getVersion();
+ if (wgv.startsWith("6.")) {
+ wg = new WGBarrel6();
+ } else if (wgv.startsWith("5.")) {
+ wg = new WGBarrel5();
+ } else {
+ wg = new WGBarrel7();
+ }
+ }
+ if (wg == null) {
+ P.p.errorLog("Failed loading WorldGuard Integration! Opening Barrels will NOT work!");
+ P.p.errorLog("Brewery was tested with version 5.8, 6.1 and 7.0 of WorldGuard!");
+ P.p.errorLog("Disable the WorldGuard support in the config and do /brew reload");
+ }
+ }
+ useLWC = config.getBoolean("useLWC", true) && plMan.isPluginEnabled("LWC");
+ useGP = config.getBoolean("useGriefPrevention", true) && plMan.isPluginEnabled("GriefPrevention");
+ useLB = config.getBoolean("useLogBlock", false) && plMan.isPluginEnabled("LogBlock");
+ useGMInventories = config.getBoolean("useGMInventories", false);
+ useCitadel = config.getBoolean("useCitadel", false) && plMan.isPluginEnabled("Citadel");
+ // The item util has been removed in Vault 1.7+
+ hasVault = plMan.isPluginEnabled("Vault")
+ && Integer.parseInt(plMan.getPlugin("Vault").getDescription().getVersion().split("\\.")[1]) <= 6;
+
+ // various Settings
+ DataSave.autosave = config.getInt("autosave", 3);
+ P.debug = config.getBoolean("debug", false);
+ pukeItem = Material.matchMaterial(config.getString("pukeItem", "SOUL_SAND"));
+ hangoverTime = config.getInt("hangoverDays", 0) * 24 * 60;
+ overdrinkKick = config.getBoolean("enableKickOnOverdrink", false);
+ enableHome = config.getBoolean("enableHome", false);
+ enableLoginDisallow = config.getBoolean("enableLoginDisallow", false);
+ enablePuke = config.getBoolean("enablePuke", false);
+ pukeDespawntime = config.getInt("pukeDespawntime", 60) * 20;
+ homeType = config.getString("homeType", null);
+ colorInBarrels = config.getBoolean("colorInBarrels", false);
+ colorInBrewer = config.getBoolean("colorInBrewer", false);
+ alwaysShowQuality = config.getBoolean("alwaysShowQuality", false);
+ alwaysShowAlc = config.getBoolean("alwaysShowAlc", false);
+ enableEncode = config.getBoolean("enableEncode", false);
+ openEverywhere = config.getBoolean("openLargeBarrelEverywhere", false);
+ MCBarrel.maxBrews = config.getInt("maxBrewsInMCBarrels", 6);
+
+ Brew.loadSeed(config, new File(P.p.getDataFolder(), "config.yml"));
+
+ PluginItem.registerForConfig("brewery", BreweryPluginItem::new);
+ PluginItem.registerForConfig("mmoitems", MMOItemsPluginItem::new);
+ PluginItem.registerForConfig("slimefun", SlimefunPluginItem::new);
+ PluginItem.registerForConfig("exoticgarden", SlimefunPluginItem::new);
+
+ // Loading custom items
+ ConfigurationSection configSection = config.getConfigurationSection("customItems");
+ if (configSection != null) {
+ for (String custId : configSection.getKeys(false)) {
+ RecipeItem custom = RecipeItem.fromConfigCustom(configSection, custId);
+ if (custom != null) {
+ custom.makeImmutable();
+ customItems.add(custom);
+ } else {
+ p.errorLog("Loading the Custom Item with id: '" + custId + "' failed!");
+ }
+ }
+ }
+
+ // loading recipes
+ configSection = config.getConfigurationSection("recipes");
+ if (configSection != null) {
+ List configRecipes = BRecipe.getConfigRecipes();
+ for (String recipeId : configSection.getKeys(false)) {
+ BRecipe recipe = BRecipe.fromConfig(configSection, recipeId);
+ if (recipe != null && recipe.isValid()) {
+ configRecipes.add(recipe);
+ } else {
+ p.errorLog("Loading the Recipe with id: '" + recipeId + "' failed!");
+ }
+ }
+ BRecipe.numConfigRecipes = configRecipes.size();
+ }
+
+ // Loading Cauldron Recipes
+ configSection = config.getConfigurationSection("cauldron");
+ if (configSection != null) {
+ List configRecipes = BCauldronRecipe.getConfigRecipes();
+ for (String id : configSection.getKeys(false)) {
+ BCauldronRecipe recipe = BCauldronRecipe.fromConfig(configSection, id);
+ if (recipe != null) {
+ configRecipes.add(recipe);
+ } else {
+ p.errorLog("Loading the Cauldron-Recipe with id: '" + id + "' failed!");
+ }
+ }
+ BCauldronRecipe.numConfigRecipes = configRecipes.size();
+ }
+
+ // Recalculating Cauldron-Accepted Items for non-config recipes
+ for (BRecipe recipe : BRecipe.getAddedRecipes()) {
+ recipe.updateAcceptedLists();
+ }
+ for (BCauldronRecipe recipe : BCauldronRecipe.getAddedRecipes()) {
+ recipe.updateAcceptedLists();
+ }
+
+ // loading drainItems
+ List drainList = config.getStringList("drainItems");
+ if (drainList != null) {
+ for (String drainString : drainList) {
+ String[] drainSplit = drainString.split("/");
+ if (drainSplit.length > 1) {
+ Material mat = Material.matchMaterial(drainSplit[0]);
+ int strength = p.parseInt(drainSplit[1]);
+ if (mat == null && hasVault && strength > 0) {
+ try {
+ net.milkbowl.vault.item.ItemInfo vaultItem = net.milkbowl.vault.item.Items.itemByString(drainSplit[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 && strength > 0) {
+ drainItems.put(mat, strength);
+ }
+ }
+ }
+ }
+
+ // Loading Words
+ DistortChat.words = new ArrayList<>();
+ DistortChat.ignoreText = new ArrayList<>();
+ if (config.getBoolean("enableChatDistortion", false)) {
+ for (Map, ?> map : config.getMapList("words")) {
+ new DistortChat(map);
+ }
+ for (String bypass : config.getStringList("distortBypass")) {
+ DistortChat.ignoreText.add(bypass.split(","));
+ }
+ DistortChat.commands = config.getStringList("distortCommands");
+ }
+ DistortChat.log = config.getBoolean("logRealChat", false);
+ DistortChat.doSigns = config.getBoolean("distortSignText", false);
+
+ // The Config was reloaded, call Event
+ ConfigLoadEvent event = new ConfigLoadEvent();
+ P.p.getServer().getPluginManager().callEvent(event);
+
+
+ }
+}
diff --git a/src/com/dre/brewery/filedata/BData.java b/src/com/dre/brewery/filedata/BData.java
new file mode 100644
index 0000000..37e4263
--- /dev/null
+++ b/src/com/dre/brewery/filedata/BData.java
@@ -0,0 +1,393 @@
+package com.dre.brewery.filedata;
+
+import com.dre.brewery.*;
+import com.dre.brewery.lore.Base91DecoderStream;
+import com.dre.brewery.recipe.CustomItem;
+import com.dre.brewery.recipe.Ingredient;
+import com.dre.brewery.recipe.PluginItem;
+import com.dre.brewery.recipe.SimpleItem;
+import com.dre.brewery.utility.BUtil;
+import com.dre.brewery.utility.BoundingBox;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+public class BData {
+
+
+ // load all Data
+ public static void readData() {
+ File file = new File(P.p.getDataFolder(), "data.yml");
+ if (file.exists()) {
+
+ long t1 = System.currentTimeMillis();
+
+ FileConfiguration data = YamlConfiguration.loadConfiguration(file);
+
+ long t2 = System.currentTimeMillis();
+
+ if (t2 - t1 > 8000) {
+ // Spigot is very slow at loading inventories from yml. Notify Admin that loading Data took long
+ P.p.log("Bukkit took " + (t2 - t1) / 1000.0 + "s to load the Data File,");
+ P.p.log("consider switching to Paper, or have less items in Barrels");
+ } else {
+ P.p.debugLog("Loading data.yml: " + (t2 - t1) + "ms");
+ }
+
+ Brew.installTime = data.getLong("installTime", System.currentTimeMillis());
+ MCBarrel.mcBarrelTime = data.getLong("MCBarrelTime", 0);
+
+ Brew.loadPrevSeeds(data);
+
+ List brewsCreated = data.getIntegerList("brewsCreated");
+ if (brewsCreated != null && brewsCreated.size() == 7) {
+ int hash = data.getInt("brewsCreatedH");
+ // Check the hash to prevent tampering with statistics
+ if (brewsCreated.hashCode() == hash) {
+ P.p.brewsCreated = brewsCreated.get(0);
+ P.p.brewsCreatedCmd = brewsCreated.get(1);
+ P.p.exc = brewsCreated.get(2);
+ P.p.good = brewsCreated.get(3);
+ P.p.norm = brewsCreated.get(4);
+ P.p.bad = brewsCreated.get(5);
+ P.p.terr = brewsCreated.get(6);
+ }
+ }
+
+ // Check if data is the newest version
+ String version = data.getString("Version", null);
+ if (version != null) {
+ if (!version.equals(DataSave.dataVersion)) {
+ P.p.log("Data File is being updated...");
+ new DataUpdater(data, file).update(version);
+ data = YamlConfiguration.loadConfiguration(file);
+ P.p.log("Data Updated to version: " + DataSave.dataVersion);
+ }
+ }
+
+ // Register Item Loaders
+ CustomItem.registerItemLoader();
+ SimpleItem.registerItemLoader();
+ PluginItem.registerItemLoader();
+
+ // loading Ingredients into ingMap
+ // Only for Legacy Brews
+ Map ingMap = new HashMap<>();
+ ConfigurationSection section = data.getConfigurationSection("Ingredients");
+ if (section != null) {
+ for (String id : section.getKeys(false)) {
+ if (section.isConfigurationSection(id + ".mats")) {
+ // Old way of saving
+ ConfigurationSection matSection = section.getConfigurationSection(id + ".mats");
+ if (matSection != null) {
+ // matSection has all the materials + amount as Integers
+ List ingredients = oldDeserializeIngredients(matSection);
+ ingMap.put(id, new BIngredients(ingredients, section.getInt(id + ".cookedTime", 0), true));
+ } else {
+ P.p.errorLog("Ingredient id: '" + id + "' incomplete in data.yml");
+ }
+ } else {
+ // New way of saving ingredients
+ ingMap.put(id, deserializeIngredients(section.getString(id + ".mats")));
+ }
+ }
+ }
+
+ // loading Brew legacy
+ section = data.getConfigurationSection("Brew");
+ if (section != null) {
+ // All sections have the UID as name
+ for (String uid : section.getKeys(false)) {
+ BIngredients ingredients = getIngredients(ingMap, section.getString(uid + ".ingId"));
+ int quality = section.getInt(uid + ".quality", 0);
+ int alc = section.getInt(uid + ".alc", 0);
+ byte distillRuns = (byte) section.getInt(uid + ".distillRuns", 0);
+ float ageTime = (float) section.getDouble(uid + ".ageTime", 0.0);
+ float wood = (float) section.getDouble(uid + ".wood", -1.0);
+ String recipe = section.getString(uid + ".recipe", null);
+ boolean unlabeled = section.getBoolean(uid + ".unlabeled", false);
+ boolean persistent = section.getBoolean(uid + ".persist", false);
+ boolean stat = section.getBoolean(uid + ".stat", false);
+ int lastUpdate = section.getInt(uid + ".lastUpdate", 0);
+
+ Brew.loadLegacy(ingredients, P.p.parseInt(uid), quality, alc, distillRuns, ageTime, wood, recipe, unlabeled, persistent, stat, lastUpdate);
+ }
+ }
+
+ // Store how many legacy brews were created
+ if (P.p.brewsCreated <= 0) {
+ P.p.brewsCreated = 0;
+ P.p.brewsCreatedCmd = 0;
+ P.p.exc = 0;
+ P.p.good = 0;
+ P.p.norm = 0;
+ P.p.bad = 0;
+ P.p.terr = 0;
+ if (!Brew.noLegacy()) {
+ for (Brew brew : Brew.legacyPotions.values()) {
+ P.p.metricsForCreate(false);
+ }
+ }
+ }
+
+ // Remove Legacy Potions that haven't been touched in a long time, these may have been lost
+ if (!Brew.noLegacy()) {
+ int currentHoursAfterInstall = (int) ((double) (System.currentTimeMillis() - Brew.installTime) / 3600000D);
+ int purgeTime = currentHoursAfterInstall - (24 * 30 * 4); // Purge Time is 4 Months ago
+ if (purgeTime > 0) {
+ int removed = 0;
+ for (Iterator iterator = Brew.legacyPotions.values().iterator(); iterator.hasNext(); ) {
+ Brew brew = iterator.next();
+ if (brew.getLastUpdate() < purgeTime) {
+ iterator.remove();
+ removed++;
+ }
+ }
+ if (removed > 0) {
+ P.p.log("Removed " + removed + " Legacy Brews older than 3 months");
+ }
+ }
+ }
+
+ // loading BPlayer
+ section = data.getConfigurationSection("Player");
+ if (section != null) {
+ // keys have players name
+ for (String name : section.getKeys(false)) {
+ try {
+ //noinspection ResultOfMethodCallIgnored
+ UUID.fromString(name);
+ if (!P.useUUID) {
+ continue;
+ }
+ } catch (IllegalArgumentException e) {
+ if (P.useUUID) {
+ continue;
+ }
+ }
+
+ int quality = section.getInt(name + ".quality");
+ int drunk = section.getInt(name + ".drunk");
+ int offDrunk = section.getInt(name + ".offDrunk", 0);
+
+ new BPlayer(name, quality, drunk, offDrunk);
+ }
+ }
+
+ for (World world : P.p.getServer().getWorlds()) {
+ if (world.getName().startsWith("DXL_")) {
+ loadWorldData(BUtil.getDxlName(world.getName()), world, data);
+ } else {
+ loadWorldData(world.getUID().toString(), world, data);
+ }
+ }
+
+ } else {
+ P.p.log("No data.yml found, will create new one!");
+ }
+ }
+
+ public static BIngredients deserializeIngredients(String mat) {
+ try (DataInputStream in = new DataInputStream(new Base91DecoderStream(new ByteArrayInputStream(mat.getBytes())))) {
+ byte ver = in.readByte();
+ return BIngredients.load(in, ver);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return new BIngredients();
+ }
+ }
+
+ // Loading from the old way of saving ingredients
+ public static List oldDeserializeIngredients(ConfigurationSection matSection) {
+ List ingredients = new ArrayList<>();
+ for (String mat : matSection.getKeys(false)) {
+ String[] matSplit = mat.split(",");
+ Material m = Material.getMaterial(matSplit[0]);
+ if (m == null && P.use1_13) {
+ if (matSplit[0].equals("LONG_GRASS")) {
+ m = Material.GRASS;
+ } else {
+ m = Material.matchMaterial(matSplit[0], true);
+ }
+ P.p.debugLog("converting Data Material from " + matSplit[0] + " to " + m);
+ }
+ if (m == null) continue;
+ SimpleItem item;
+ if (matSplit.length == 2) {
+ item = new SimpleItem(m, (short) P.p.parseInt(matSplit[1]));
+ } else {
+ item = new SimpleItem(m);
+ }
+ item.setAmount(matSection.getInt(mat));
+ ingredients.add(item);
+ }
+ return ingredients;
+ }
+
+ // returns Ingredients by id from the specified ingMap
+ public static BIngredients getIngredients(Map ingMap, String id) {
+ if (!ingMap.isEmpty()) {
+ if (ingMap.containsKey(id)) {
+ return ingMap.get(id);
+ }
+ }
+ P.p.errorLog("Ingredient id: '" + id + "' not found in data.yml");
+ return new BIngredients();
+ }
+
+ // loads BIngredients from an ingredient section
+ public static BIngredients loadCauldronIng(ConfigurationSection section, String path) {
+ if (section.isConfigurationSection(path)) {
+ // Old way of saving
+ ConfigurationSection matSection = section.getConfigurationSection(path);
+ if (matSection != null) {
+ // matSection has all the materials + amount as Integers
+ return new BIngredients(oldDeserializeIngredients(section), 0);
+ } else {
+ P.p.errorLog("Cauldron is missing Ingredient Section");
+ return new BIngredients();
+ }
+ } else {
+ // New way of saving ingredients
+ return deserializeIngredients(section.getString(path));
+ }
+ }
+
+ // load Block locations of given world
+ public static void loadWorldData(String uuid, World world, FileConfiguration data) {
+
+ if (data == null) {
+ File file = new File(P.p.getDataFolder(), "data.yml");
+ if (file.exists()) {
+ data = YamlConfiguration.loadConfiguration(file);
+ } else {
+ return;
+ }
+ }
+
+ // loading BCauldron
+ if (data.contains("BCauldron." + uuid)) {
+ ConfigurationSection section = data.getConfigurationSection("BCauldron." + uuid);
+ for (String cauldron : section.getKeys(false)) {
+ // block is splitted into x/y/z
+ String block = section.getString(cauldron + ".block");
+ if (block != null) {
+ String[] splitted = block.split("/");
+ if (splitted.length == 3) {
+
+ Block worldBlock = world.getBlockAt(P.p.parseInt(splitted[0]), P.p.parseInt(splitted[1]), P.p.parseInt(splitted[2]));
+ BIngredients ingredients = loadCauldronIng(section, cauldron + ".ingredients");
+ int state = section.getInt(cauldron + ".state", 1);
+
+ new BCauldron(worldBlock, ingredients, state);
+ } else {
+ P.p.errorLog("Incomplete Block-Data in data.yml: " + section.getCurrentPath() + "." + cauldron);
+ }
+ } else {
+ P.p.errorLog("Missing Block-Data in data.yml: " + section.getCurrentPath() + "." + cauldron);
+ }
+ }
+ }
+
+ // loading Barrel
+ if (data.contains("Barrel." + uuid)) {
+ ConfigurationSection section = data.getConfigurationSection("Barrel." + uuid);
+ for (String barrel : section.getKeys(false)) {
+ // block spigot is splitted into x/y/z
+ String spigot = section.getString(barrel + ".spigot");
+ if (spigot != null) {
+ String[] splitted = spigot.split("/");
+ if (splitted.length == 3) {
+
+ // load itemStacks from invSection
+ ConfigurationSection invSection = section.getConfigurationSection(barrel + ".inv");
+ Block block = world.getBlockAt(P.p.parseInt(splitted[0]), P.p.parseInt(splitted[1]), P.p.parseInt(splitted[2]));
+ float time = (float) section.getDouble(barrel + ".time", 0.0);
+ byte sign = (byte) section.getInt(barrel + ".sign", 0);
+
+ BoundingBox box = null;
+ if (section.contains(barrel + ".bounds")) {
+ String[] bds = section.getString(barrel + ".bounds", "").split(",");
+ if (bds.length == 6) {
+ box = new BoundingBox(P.p.parseInt(bds[0]), P.p.parseInt(bds[1]), P.p.parseInt(bds[2]), P.p.parseInt(bds[3]), P.p.parseInt(bds[4]), P.p.parseInt(bds[5]));
+ }
+ } else if (section.contains(barrel + ".st")) {
+ // Convert from Stair and Wood Locations to BoundingBox
+ String[] st = section.getString(barrel + ".st", "").split(",");
+ String[] wo = section.getString(barrel + ".wo", "").split(",");
+ int woLength = wo.length;
+ if (woLength <= 1) {
+ woLength = 0;
+ }
+ String[] points = new String[st.length + woLength];
+ System.arraycopy(st, 0, points, 0, st.length);
+ if (woLength > 1) {
+ System.arraycopy(wo, 0, points, st.length, woLength);
+ }
+ int[] locs = ArrayUtils.toPrimitive(Arrays.stream(points).map(s -> P.p.parseInt(s)).toArray(Integer[]::new));
+ box = BoundingBox.fromPoints(locs);
+ }
+
+ Barrel b;
+ if (invSection != null) {
+ b = new Barrel(block, sign, box, invSection.getValues(true), time);
+ } else {
+ // Barrel has no inventory
+ b = new Barrel(block, sign, box, null, time);
+ }
+
+ // In case Barrel Block locations were missing and could not be recreated: do not add the barrel
+
+ if (b.getBody().getBounds() != null) {
+ Barrel.barrels.add(b);
+ }
+
+ } else {
+ P.p.errorLog("Incomplete Block-Data in data.yml: " + section.getCurrentPath() + "." + barrel);
+ }
+ } else {
+ P.p.errorLog("Missing Block-Data in data.yml: " + section.getCurrentPath() + "." + barrel);
+ }
+ }
+ }
+
+ // loading Wakeup
+ if (data.contains("Wakeup." + uuid)) {
+ ConfigurationSection section = data.getConfigurationSection("Wakeup." + uuid);
+ for (String wakeup : section.getKeys(false)) {
+ // loc of wakeup is splitted into x/y/z/pitch/yaw
+ String loc = section.getString(wakeup);
+ if (loc != null) {
+ String[] splitted = loc.split("/");
+ if (splitted.length == 5) {
+
+ double x = NumberUtils.toDouble(splitted[0]);
+ double y = NumberUtils.toDouble(splitted[1]);
+ double z = NumberUtils.toDouble(splitted[2]);
+ float pitch = NumberUtils.toFloat(splitted[3]);
+ float yaw = NumberUtils.toFloat(splitted[4]);
+ Location location = new Location(world, x, y, z, yaw, pitch);
+
+ Wakeup.wakeups.add(new Wakeup(location));
+
+ } else {
+ P.p.errorLog("Incomplete Location-Data in data.yml: " + section.getCurrentPath() + "." + wakeup);
+ }
+ }
+ }
+ }
+
+ }
+}
diff --git a/src/com/dre/brewery/filedata/ConfigUpdater.java b/src/com/dre/brewery/filedata/ConfigUpdater.java
index ed2d0af..d4fbba7 100644
--- a/src/com/dre/brewery/filedata/ConfigUpdater.java
+++ b/src/com/dre/brewery/filedata/ConfigUpdater.java
@@ -1,17 +1,16 @@
package com.dre.brewery.filedata;
-import com.dre.brewery.LegacyUtil;
import com.dre.brewery.P;
+import com.dre.brewery.utility.LegacyUtil;
import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
+import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
public class ConfigUpdater {
@@ -49,6 +48,25 @@ public class ConfigUpdater {
config.addAll(index, Arrays.asList(newLines));
}
+ public void removeLine(int index) {
+ config.remove(index);
+ }
+
+ public void addLinesAt(String[] search, int offset, String... newLines) {
+ int index = indexOfStart(search[0]);
+ int s = 1;
+ while (index == -1 && s < search.length) {
+ index = indexOfStart(search[s]);
+ s++;
+ }
+
+ if (index != -1) {
+ addLines(index + offset, newLines);
+ } else {
+ appendLines(newLines);
+ }
+ }
+
public void saveConfig() {
StringBuilder stringBuilder = new StringBuilder();
for (String line : config) {
@@ -82,10 +100,35 @@ public class ConfigUpdater {
+ // ---- Updating Scramble Seed ----
+
+ public void setEncodeKey(long key) {
+ int index = indexOfStart("encodeKey:");
+ if (index != -1) {
+ setLine(index, "encodeKey: " + key);
+ return;
+ }
+
+ // Old key not present
+ index = indexOfStart("enableEncode:");
+ if (index == -1) {
+ index = indexOfStart("# So enable this if you want to make recipe cheating harder");
+ }
+ if (index == -1) {
+ index = indexOfStart("version:");
+ }
+ if (index != -1) {
+ addLines(index + 1, "encodeKey: " + key);
+ } else {
+ addLines(1, "encodeKey: " + key);
+ }
+
+ }
+
// ---- Updating to newer Versions ----
// Update from a specified Config version and language to the newest version
- public void update(String fromVersion, boolean oldMat, String lang) {
+ public void update(String fromVersion, boolean oldMat, String lang, FileConfiguration yml) {
if (fromVersion.equals("0.5")) {
// Version 0.5 was only released for de, but with en as setting, so default to de
if (!lang.equals("de")) {
@@ -162,12 +205,24 @@ public class ConfigUpdater {
fromVersion = "1.8";
}
+ if (fromVersion.equals("1.8")) {
+ if (de) {
+ update18de(yml);
+ } else if (lang.equals("fr")) {
+ update18fr(yml);
+ } else {
+ update18en(yml);
+ }
+ updateVersion(BConfig.configVersion);
+ fromVersion = BConfig.configVersion;
+ }
+
if (P.use1_13 && oldMat) {
updateMaterials(true);
updateMaterialDescriptions(de);
}
- if (!fromVersion.equals("1.8")) {
+ if (!fromVersion.equals(BConfig.configVersion)) {
P.p.log(P.p.languageReader.get("Error_ConfigUpdate", fromVersion));
return;
}
@@ -526,12 +581,12 @@ public class ConfigUpdater {
if (index != -1) {
index = indexOfStart("# (WEAKNESS, INCREASE_DAMAGE, SLOW und SPEED sind immer verborgen.) Mögliche Effekte:");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
}
index = indexOfStart("# Bei Effekten mit sofortiger Wirkung ");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
}
@@ -625,12 +680,12 @@ public class ConfigUpdater {
if (index != -1) {
index = indexOfStart("# (WEAKNESS, INCREASE_DAMAGE, SLOW and SPEED are always hidden.) Possible Effects:");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
}
index = indexOfStart("# instant effects ");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
}
@@ -693,7 +748,7 @@ public class ConfigUpdater {
int index = indexOfStart("# SamplePlugin = installiertes home plugin. Unterstützt: ManagerXL.");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# Ob der Spieler nach etwas kürzerem Ausloggen an einem zufälligen Ort \"aufwacht\" (diese müssen durch '/br Wakeup add");
@@ -815,7 +870,7 @@ public class ConfigUpdater {
int index = indexOfStart("# SamplePlugin = installed home plugin. Supports: ManagerXL.");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# If the player \"wakes up\" at a random place when offline for some time while drinking (the places have to be defined with '/br Wakeup add'");
@@ -1221,13 +1276,360 @@ public class ConfigUpdater {
if (P.use1_13) updateMaterialDescriptions(false);
}
+ private void update18de(FileConfiguration yml) {
+ int index = indexOfStart("# Löschen einzelner Einstellungen");
+ if (index != -1) {
+ removeLine(index);
+ }
+
+ addLinesAt(new String[] {"colorInBrewer:", "colorInBarrels:", "hangoverDays:", "language:"}, 1, "",
+ "# Ob in den Iteminformationen immer 1-5 Sterne für die Qualität angezeigt werden sollen, oder nur beim brauen [true]",
+ "alwaysShowQuality: true",
+ "",
+ "# Ob in den Iteminformationen immer der Alkoholgehalt angezeigt weden soll, oder nur im Braustand [false]",
+ "alwaysShowAlc: false");
+
+ addLinesAt(new String[] {"maxBrewsInMCBarrels:", "openLargeBarrelEverywhere:", "language:"}, 1, "",
+ "# Benutzte Zutaten und andere Brau-Daten werden in allen Brewery Tränken gespeichert. Um zu verhindern,",
+ "# dass gehackte clients diese Daten auslesen um Rezepte herauszufinden, können diese encodiert werden.",
+ "# Einziger Nachteil: Tränke können nur auf Servern mit dem gleichen encodeKey benutzt werden.",
+ "# Dies kann also aktiviert werden um Rezept-cheating schwerer zu machen, aber keine Tränke per World Download, Schematic, o.ä. geteilt werden. [false]",
+ "enableEncode: false",
+ "encodeKey: 0");
+
+ if (indexOfStart("debug:") == -1) {
+ addLinesAt(new String[]{"autosave:", "version:"}, 1, "",
+ "# Debug Nachrichten im Log anzeigen [false]",
+ "debug: false");
+ }
+
+ index = indexOfStart("oldMat:") + 1;
+ if (index == 0) {
+ index = indexOfStart("version:") + 1;
+ if (index == 0) {
+ index = 2;
+ }
+ }
+ // Custom Items and start of cauldron section
+ applyPatch("config/patches/de18.txt", index);
+
+ index = indexOfStart("%%%%MAT1%%%%");
+ if (index != -1) {
+ if (P.use1_13) {
+ setLine(index, " material: Barrier");
+ } else {
+ setLine(index, " material: BEDROCK");
+ }
+ }
+ index = indexOfStart("%%%%MAT2%%%%");
+ if (index != -1) {
+ removeLine(index);
+ if (P.use1_13) {
+ addLines(index, " material:",
+ " - Acacia_Door",
+ " - Oak_Door",
+ " - Spruce_Door");
+ } else {
+ addLines(index, " material:",
+ " - WOODEN_DOOR",
+ " - IRON_DOOR");
+ }
+ }
+
+ index = indexOfStart("# -- Eine Zutat:");
+ if (index == -1) {
+ index = indexOfStart("cauldron:");
+ if (index == -1) {
+ // Patch failed
+ index = indexOfStart("version:");
+ if (index == -1) {
+ index = 0;
+ }
+ addLines(index + 1, "cauldron:");
+ index ++;
+ }
+ }
+ convertCookedSection(yml, index + 1);
+
+ addLinesAt(new String[]{"# Eine Liste von allen Materialien", "# ingredients:"}, 1,
+ "# Plugin Items mit 'Plugin:Id' (Im Moment ExoticGarden, Slimefun, MMOItems, Brewery)",
+ "# Oder ein oben definiertes Custom Item");
+
+ addLinesAt(new String[]{"# alcohol:", "# difficulty:", "# ingredients:", "# -- Rezepte"}, 1,
+ "# lore: Auflistung von zusätzlichem Text auf dem fertigen Trank. (Farbcodes möglich: z.b. &6)",
+ "# Lore nur für bestimmte Qualität möglich mit + Schlecht, ++ Mittel, +++ Gut, vorne anhängen.",
+ "# servercommands: Liste von Befehlen ausgeführt vom Server wenn der Trank getrunken wird",
+ "# playercommands: Liste von Befehlen ausgeführt vom Spieler wenn der Trank getrunken wird",
+ "# drinkmessage: Nachricht im Chat beim trinken des Trankes",
+ "# drinktitle: Nachricht als Titel auf dem Bildschirm an den Spieler beim trinken des Trankes");
+
+ addLinesAt(new String[]{"useGriefPrevention:", "useWorldGuard:", "# -- Plugin Kompatiblit"}, 1, "useGMInventories: true");
+
+ index = indexOfStart("# cooked:");
+ if (index != -1) {
+ removeLine(index);
+ }
+ index = indexOfStart("# [Beispiel] MATERIAL:");
+ if (index != -1) {
+ removeLine(index);
+ }
+
+ }
+
+ private void update18fr(FileConfiguration yml) {
+ int index = indexOfStart("# Supprimer un para");
+ if (index != -1) {
+ removeLine(index);
+ }
+
+ addLinesAt(new String[] {"colorInBrewer:", "colorInBarrels:", "hangoverDays:", "language:"}, 1, "\n" +
+ "# Toujours montrer les 1-5 étoiles sur les objets en fonction de leur qualité. S'ils sont faux, ils n'apparaîtront que lors de l'infusion. [true]",
+ "alwaysShowQuality: true",
+ "",
+ "# Toujours indiquer la teneur en alcool sur les objets. S'il est false, il n'apparaîtra que dans le stand de brassage. [false]",
+ "alwaysShowAlc: false");
+
+ addLinesAt(new String[] {"maxBrewsInMCBarrels:", "openLargeBarrelEverywhere:", "language:"}, 1, "",
+ "# Les ingrédients et autres données de brassage utilisés sont sauvegardés dans tous les articles de brasserie. [false]",
+ "# Pour empêcher les clients piratés de lire exactement ce qui a été utilisé pour infuser un élément, les données peuvent être encodées/brouillées.",
+ "# Il s'agit d'un processus rapide pour empêcher les joueurs de pirater des recettes, une fois qu'ils mettent la main sur une bière.",
+ "# Seul inconvénient: Les boissons brassicoles ne peuvent être utilisés que sur un autre serveur avec la même clé de chiffrement.",
+ "# Activez cette option si vous voulez rendre la tricherie des recettes plus difficile, mais ne partagez pas les infusions par téléchargement mondial, schémas ou autres moyens.",
+ "enableEncode: false",
+ "encodeKey: 0");
+
+ if (indexOfStart("debug:") == -1) {
+ addLinesAt(new String[]{"autosave:", "version:"}, 1, "",
+ "# Show debug messages in log [false]",
+ "debug: false");
+ }
+
+ index = indexOfStart("oldMat:") + 1;
+ if (index == 0) {
+ index = indexOfStart("version:") + 1;
+ if (index == 0) {
+ index = 2;
+ }
+ }
+ // Custom Items and start of cauldron section
+ applyPatch("config/patches/fr18.txt", index);
+
+ index = indexOfStart("%%%%MAT1%%%%");
+ if (index != -1) {
+ if (P.use1_13) {
+ setLine(index, " material: Barrier");
+ } else {
+ setLine(index, " material: BEDROCK");
+ }
+ }
+ index = indexOfStart("%%%%MAT2%%%%");
+ if (index != -1) {
+ removeLine(index);
+ if (P.use1_13) {
+ addLines(index, " material:",
+ " - Acacia_Door",
+ " - Oak_Door",
+ " - Spruce_Door");
+ } else {
+ addLines(index, " material:",
+ " - WOODEN_DOOR",
+ " - IRON_DOOR");
+ }
+ }
+
+ index = indexOfStart(" # -- Un ingr");
+ if (index == -1) {
+ index = indexOfStart("cauldron:");
+ if (index == -1) {
+ // Patch failed
+ index = indexOfStart("version:");
+ if (index == -1) {
+ index = 0;
+ }
+ addLines(index + 1, "cauldron:");
+ index ++;
+ }
+ }
+ convertCookedSection(yml, index + 1);
+
+ addLinesAt(new String[]{"# Une liste des mat", "# ingredients:"}, 1,
+ "# Plugin items avec 'plugin:id' (Actuellement supporté ExoticGarden, Slimefun, MMOItems, Brewery)",
+ "# Ou un élément personnalisé défini ci-dessus");
+
+ addLinesAt(new String[]{"# alcohol:", "# difficulty:", "# ingredients:", "# -- Recette "}, 1,
+ "# lore: Liste des textes supplémentaires sur le breuvage fini. (Codes de formatage possibles : tels que &6)",
+ "# Texte spécifique de qualité possible, en utilisant + mauvais, ++ normal, +++ bon, ajouté à l'avant de la ligne.",
+ "# servercommands: Liste des commandes exécutées par le serveur lors de la consommation de la potion",
+ "# playercommands: Liste des commandes exécutées par le joueur lors de la consommation de la potion",
+ "# drinkmessage: Chat-message au joueur lorsqu'il boit la potion",
+ "# drinktitle: Titre à l'écran du joueur lorsqu'il boit la potion");
+
+ addLinesAt(new String[]{"useGriefPrevention:", "useWorldGuard:", "# -- Plugin Compatibility"}, 1, "useGMInventories: true");
+
+ index = indexOfStart("# cooked:");
+ if (index != -1) {
+ removeLine(index);
+ }
+ index = indexOfStart("# [Exemple] MATERIEL");
+ if (index != -1) {
+ removeLine(index);
+ }
+
+ }
+
+ private void update18en(FileConfiguration yml) {
+ int index = indexOfStart("# Deleting of single settings");
+ if (index != -1) {
+ removeLine(index);
+ }
+
+ addLinesAt(new String[] {"colorInBrewer:", "colorInBarrels:", "hangoverDays:", "language:"}, 1, "",
+ "# Always show the 1-5 stars on the item depending on the quality. If false, they will only appear when brewing [true]",
+ "alwaysShowQuality: true",
+ "",
+ "# Always show the alcohol content on the item. If false, it will only show in the brewing stand [false]",
+ "alwaysShowAlc: false");
+
+ addLinesAt(new String[] {"maxBrewsInMCBarrels:", "openLargeBarrelEverywhere:", "language:"}, 1, "",
+ "# The used Ingredients and other brewing-data is saved to all Brewery Items. To prevent",
+ "# hacked clients from reading what exactly was used to brew an item, the data can be encoded/scrambled.",
+ "# This is a fast process to stop players from hacking out recipes, once they get hold of a brew.",
+ "# Only drawback: brew items can only be used on another server with the same encodeKey.",
+ "# So enable this if you want to make recipe cheating harder, but don't share any brews by world download, schematics, or other means. [false]",
+ "enableEncode: false",
+ "encodeKey: 0");
+
+ if (indexOfStart("debug:") == -1) {
+ addLinesAt(new String[]{"autosave:", "version:"}, 1, "",
+ "# Show debug messages in log [false]",
+ "debug: false");
+ }
+
+ index = indexOfStart("oldMat:") + 1;
+ if (index == 0) {
+ index = indexOfStart("version:") + 1;
+ if (index == 0) {
+ index = 2;
+ }
+ }
+ // Custom Items and start of cauldron section
+ applyPatch("config/patches/en18.txt", index);
+
+ index = indexOfStart("%%%%MAT1%%%%");
+ if (index != -1) {
+ if (P.use1_13) {
+ setLine(index, " material: Barrier");
+ } else {
+ setLine(index, " material: BEDROCK");
+ }
+ }
+ index = indexOfStart("%%%%MAT2%%%%");
+ if (index != -1) {
+ removeLine(index);
+ if (P.use1_13) {
+ addLines(index, " material:",
+ " - Acacia_Door",
+ " - Oak_Door",
+ " - Spruce_Door");
+ } else {
+ addLines(index, " material:",
+ " - WOODEN_DOOR",
+ " - IRON_DOOR");
+ }
+ }
+
+ index = indexOfStart(" # -- One Ingredient");
+ if (index == -1) {
+ index = indexOfStart("cauldron:");
+ if (index == -1) {
+ // Patch failed
+ index = indexOfStart("version:");
+ if (index == -1) {
+ index = 0;
+ }
+ addLines(index + 1, "cauldron:");
+ index ++;
+ }
+ }
+ convertCookedSection(yml, index + 1);
+
+ addLinesAt(new String[]{"# A list of materials", "# ingredients:"}, 1,
+ "# Plugin items with 'plugin:id' (Currently supporting ExoticGarden, Slimefun, MMOItems, Brewery)",
+ "# Or a custom item defined above");
+
+ addLinesAt(new String[]{"# alcohol:", "# difficulty:", "# ingredients:", "# -- Recipes"}, 1,
+ "# lore: List of additional text on the finished brew. (Formatting codes possible: such as &6)",
+ "# Specific lore for quality possible, using + bad, ++ normal, +++ good, added to the front of the line.",
+ "# servercommands: List of Commands executed by the Server when drinking the brew",
+ "# playercommands: List of Commands executed by the Player when drinking the brew",
+ "# drinkmessage: Chat-message to the Player when drinking the Brew",
+ "# drinktitle: Title on Screen to the Player when drinking the Brew");
+
+ addLinesAt(new String[]{"useGriefPrevention:", "useWorldGuard:", "# -- Plugin Compatibility"}, 1, "useGMInventories: true");
+
+ index = indexOfStart("# cooked:");
+ if (index != -1) {
+ removeLine(index);
+ }
+ index = indexOfStart("# [Example] MATERIAL:");
+ if (index != -1) {
+ removeLine(index);
+ }
+
+ }
+
+
+
+ private void convertCookedSection(FileConfiguration yml, int toLine) {
+ ConfigurationSection cookedSection = yml.getConfigurationSection("cooked");
+ if (cookedSection != null) {
+ for (String ing : cookedSection.getKeys(false)) {
+ String name = cookedSection.getString(ing);
+ addLines(toLine,
+ " " + ing.toLowerCase() + ":",
+ " name: " + name,
+ " ingredients:",
+ " - " + ing,
+ "");
+ toLine += 5;
+ }
+
+ int index = indexOfStart("cooked:");
+ if (index != -1) {
+ int size = cookedSection.getKeys(false).size();
+ while (size >= 0) {
+ removeLine(index);
+ size--;
+ }
+ }
+ }
+
+
+ }
+
+ public void applyPatch(String resourcePath, int toLine) {
+ try {
+ List patch = new ArrayList<>();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(P.p.getResource(resourcePath), "Resource not found")));
+ String currentLine;
+ while((currentLine = reader.readLine()) != null) {
+ patch.add(currentLine);
+ }
+ reader.close();
+ config.addAll(toLine, patch);
+ } catch (IOException | NullPointerException e) {
+ P.p.errorLog("Could not apply Patch: " + resourcePath);
+ e.printStackTrace();
+ }
+ }
+
// Update all Materials to Minecraft 1.13
private void updateMaterials(boolean toMC113) {
int index;
if (toMC113) {
index = indexOfStart("oldMat:");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
} else {
index = indexOfStart("version:");
@@ -1286,6 +1688,29 @@ public class ConfigUpdater {
index++;
}
}
+
+ index = indexOfStart("cauldron:");
+ if (index != -1) {
+ index++;
+ int endIndex = indexOfStart("recipes:");
+ if (endIndex < index) {
+ endIndex = indexOfStart(" cookingtime:");
+ }
+ if (endIndex < index) {
+ endIndex = indexOfStart("useWorldGuard:");
+ }
+ while (index < endIndex) {
+ if (config.get(index).matches("^\\s+ingredients:.*")) {
+ index++;
+ while (config.get(index).matches("^\\s+- .+")) {
+ line = config.get(index);
+ setLine(index, convertMaterial(line, "^\\s+- ", "(,.*|)/.*", toMC113));
+ index++;
+ }
+ }
+ index++;
+ }
+ }
}
private String convertMaterial(String line, String regexPrefix, String regexPostfix, boolean toMC113) {
@@ -1337,33 +1762,33 @@ public class ConfigUpdater {
index = indexOfStart("# Es kann ein Data-Wert (durability) angegeben werden");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# Wenn Vault installiert ist");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# Vault erkennt Namen wie");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# - Jungle Leaves/64 # Nur mit Vault");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# - Green Dye/6 # Nur mit Vault");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# Ein 'X' an den Namen");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# Effekte sind ab der 1.9 immer verborgen");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
} else {
index = indexOfStart("# ingredients: List of 'material,data/amount'");
@@ -1373,33 +1798,33 @@ public class ConfigUpdater {
index = indexOfStart("# You can specify a data (durability) value");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# If Vault is installed normal names can be used");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# Vault will recognize things");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# - Jungle Leaves/64 # Only with Vault");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# - Green Dye/6 # Only with Vault");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# Suffix name with 'X' to hide effect");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
index = indexOfStart("# Effects are always hidden in 1.9 and newer");
if (index != -1) {
- config.remove(index);
+ removeLine(index);
}
}
}
diff --git a/src/com/dre/brewery/filedata/DataSave.java b/src/com/dre/brewery/filedata/DataSave.java
index ffd9043..5c3dfa3 100644
--- a/src/com/dre/brewery/filedata/DataSave.java
+++ b/src/com/dre/brewery/filedata/DataSave.java
@@ -1,22 +1,16 @@
package com.dre.brewery.filedata;
-import java.io.File;
-
-import com.dre.brewery.MCBarrel;
-import com.dre.brewery.Util;
+import com.dre.brewery.*;
+import com.dre.brewery.utility.BUtil;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.scheduler.BukkitRunnable;
-import com.dre.brewery.BCauldron;
-import com.dre.brewery.BPlayer;
-import com.dre.brewery.Barrel;
-import com.dre.brewery.Brew;
-import com.dre.brewery.P;
-import com.dre.brewery.Wakeup;
+import java.util.ArrayList;
+import java.util.List;
public class DataSave extends BukkitRunnable {
@@ -39,6 +33,7 @@ public class DataSave extends BukkitRunnable {
@Override
public void run() {
+ long saveTime = System.nanoTime();
FileConfiguration oldData;
if (read != null) {
if (!read.done) {
@@ -64,8 +59,21 @@ public class DataSave extends BukkitRunnable {
configFile.set("installTime", Brew.installTime);
configFile.set("MCBarrelTime", MCBarrel.mcBarrelTime);
- if (!Brew.potions.isEmpty()) {
- Brew.save(configFile.createSection("Brew"));
+ Brew.writePrevSeeds(configFile);
+
+ List brewsCreated = new ArrayList<>(7);
+ brewsCreated.add(P.p.brewsCreated);
+ brewsCreated.add(P.p.brewsCreatedCmd);
+ brewsCreated.add(P.p.exc);
+ brewsCreated.add(P.p.good);
+ brewsCreated.add(P.p.norm);
+ brewsCreated.add(P.p.bad);
+ brewsCreated.add(P.p.terr);
+ configFile.set("brewsCreated", brewsCreated);
+ configFile.set("brewsCreatedH", brewsCreated.hashCode());
+
+ if (!Brew.legacyPotions.isEmpty()) {
+ Brew.saveLegacy(configFile.createSection("Brew"));
}
if (!BCauldron.bcauldrons.isEmpty() || oldData.contains("BCauldron")) {
@@ -88,6 +96,9 @@ public class DataSave extends BukkitRunnable {
configFile.set("Version", dataVersion);
collected = true;
+
+ P.p.debugLog("saving: " + ((System.nanoTime() - saveTime) / 1000000.0) + "ms");
+
if (P.p.isEnabled()) {
P.p.getServer().getScheduler().runTaskAsynchronously(P.p, new WriteData(configFile));
} else {
@@ -111,7 +122,6 @@ public class DataSave extends BukkitRunnable {
// Save all data. Takes a boolean whether all data should be collected in instantly
public static void save(boolean collectInstant) {
- long time = System.nanoTime();
if (running != null) {
P.p.log("Another Save was started while a Save was in Progress");
if (collectInstant) {
@@ -119,24 +129,17 @@ public class DataSave extends BukkitRunnable {
}
return;
}
- File datafile = new File(P.p.getDataFolder(), "data.yml");
- if (datafile.exists()) {
- ReadOldData read = new ReadOldData();
- if (collectInstant) {
- read.run();
- running = new DataSave(read);
- running.run();
- } else {
- read.runTaskAsynchronously(P.p);
- running = new DataSave(read);
- running.runTaskTimer(P.p, 1, 2);
- }
- } else {
- running = new DataSave(null);
+ ReadOldData read = new ReadOldData();
+ if (collectInstant) {
+ read.run();
+ running = new DataSave(read);
running.run();
+ } else {
+ read.runTaskAsynchronously(P.p);
+ running = new DataSave(read);
+ running.runTaskTimer(P.p, 1, 2);
}
- P.p.debugLog("saving: " + ((System.nanoTime() - time) / 1000000.0) + "ms");
}
public static void autoSave() {
@@ -154,7 +157,7 @@ public class DataSave extends BukkitRunnable {
for (World world : P.p.getServer().getWorlds()) {
String worldName = world.getName();
if (worldName.startsWith("DXL_")) {
- worldName = Util.getDxlName(worldName);
+ worldName = BUtil.getDxlName(worldName);
root.set("Worlds." + worldName, 0);
} else {
worldName = world.getUID().toString();
diff --git a/src/com/dre/brewery/filedata/DataUpdater.java b/src/com/dre/brewery/filedata/DataUpdater.java
index 0bacfe1..fc84159 100644
--- a/src/com/dre/brewery/filedata/DataUpdater.java
+++ b/src/com/dre/brewery/filedata/DataUpdater.java
@@ -1,107 +1,106 @@
-package com.dre.brewery.filedata;
-
-import com.dre.brewery.LegacyUtil;
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.bukkit.Material;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.configuration.file.FileConfiguration;
-
-import com.dre.brewery.P;
-
-public class DataUpdater {
-
- private FileConfiguration data;
- private File file;
-
- public DataUpdater(FileConfiguration data, File file) {
- this.data = data;
- this.file = file;
- }
-
-
-
- public void update(String fromVersion) {
- if (fromVersion.equalsIgnoreCase("1.0")) {
- update10();
- //fromVersion = "1.1";
- }
-
- try {
- data.save(file);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
-
-
-
- @SuppressWarnings("deprecation")
- public void update10() {
-
- data.set("Version", DataSave.dataVersion);
-
- ConfigurationSection section = data.getConfigurationSection("Ingredients");
- try {
- if (section != null) {
- for (String id : section.getKeys(false)) {
- ConfigurationSection matSection = section.getConfigurationSection(id + ".mats");
- if (matSection != null) {
- // matSection has all the materials + amount as Integers
- Map ingredients = new HashMap<>();
- for (String ingredient : matSection.getKeys(false)) {
- // convert to Material
- Material mat = LegacyUtil.getMaterial(P.p.parseInt(ingredient));
- if (mat != null) {
- ingredients.put(mat.name(), matSection.getInt(ingredient));
- }
- }
- section.set(id + ".mats", ingredients);
- } else {
- P.p.errorLog("Ingredient id: '" + id + "' incomplete in data.yml");
- }
- }
- }
- } catch (Exception e) {
- // Getting Material by id may not work in the future
- P.p.errorLog("Error Converting Ingredient Section of the Data File, newer versions of Bukkit may not support the old Save File anymore:");
- e.printStackTrace();
- }
-
- section = data.getConfigurationSection("BCauldron");
- if (section != null) {
- try {
- for (String uuid : section.getKeys(false)) {
- ConfigurationSection cauldrons = section.getConfigurationSection(uuid);
- if (cauldrons != null) {
- for (String id : cauldrons.getKeys(false)) {
- ConfigurationSection ingredientSection = cauldrons.getConfigurationSection(id + ".ingredients");
- if (ingredientSection != null) {
- // has all the materials + amount as Integers
- Map ingredients = new HashMap<>();
- for (String ingredient : ingredientSection.getKeys(false)) {
- // convert to Material
- Material mat = LegacyUtil.getMaterial(P.p.parseInt(ingredient));
- if (mat != null) {
- ingredients.put(mat.name(), ingredientSection.getInt(ingredient));
- }
- }
- cauldrons.set(id + ".ingredients", ingredients);
- } else {
- P.p.errorLog("BCauldron " + id + " is missing Ingredient Section");
- }
- }
- }
- }
- } catch (Exception e) {
- // Getting Material by id may not work in the future
- P.p.errorLog("Error Converting Ingredient Section of Cauldrons, newer versions of Bukkit may not support the old Save File anymore:");
- e.printStackTrace();
- }
- }
- }
-}
+package com.dre.brewery.filedata;
+
+import com.dre.brewery.utility.LegacyUtil;
+import com.dre.brewery.P;
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class DataUpdater {
+
+ private FileConfiguration data;
+ private File file;
+
+ public DataUpdater(FileConfiguration data, File file) {
+ this.data = data;
+ this.file = file;
+ }
+
+
+
+ public void update(String fromVersion) {
+ if (fromVersion.equalsIgnoreCase("1.0")) {
+ update10();
+ //fromVersion = "1.1";
+ }
+
+ try {
+ data.save(file);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+
+
+ @SuppressWarnings("deprecation")
+ public void update10() {
+
+ data.set("Version", DataSave.dataVersion);
+
+ ConfigurationSection section = data.getConfigurationSection("Ingredients");
+ try {
+ if (section != null) {
+ for (String id : section.getKeys(false)) {
+ ConfigurationSection matSection = section.getConfigurationSection(id + ".mats");
+ if (matSection != null) {
+ // matSection has all the materials + amount as Integers
+ Map ingredients = new HashMap<>();
+ for (String ingredient : matSection.getKeys(false)) {
+ // convert to Material
+ Material mat = LegacyUtil.getMaterial(P.p.parseInt(ingredient));
+ if (mat != null) {
+ ingredients.put(mat.name(), matSection.getInt(ingredient));
+ }
+ }
+ section.set(id + ".mats", ingredients);
+ } else {
+ P.p.errorLog("Ingredient id: '" + id + "' incomplete in data.yml");
+ }
+ }
+ }
+ } catch (Exception e) {
+ // Getting Material by id may not work in the future
+ P.p.errorLog("Error Converting Ingredient Section of the Data File, newer versions of Bukkit may not support the old Save File anymore:");
+ e.printStackTrace();
+ }
+
+ section = data.getConfigurationSection("BCauldron");
+ if (section != null) {
+ try {
+ for (String uuid : section.getKeys(false)) {
+ ConfigurationSection cauldrons = section.getConfigurationSection(uuid);
+ if (cauldrons != null) {
+ for (String id : cauldrons.getKeys(false)) {
+ ConfigurationSection ingredientSection = cauldrons.getConfigurationSection(id + ".ingredients");
+ if (ingredientSection != null) {
+ // has all the materials + amount as Integers
+ Map ingredients = new HashMap<>();
+ for (String ingredient : ingredientSection.getKeys(false)) {
+ // convert to Material
+ Material mat = LegacyUtil.getMaterial(P.p.parseInt(ingredient));
+ if (mat != null) {
+ ingredients.put(mat.name(), ingredientSection.getInt(ingredient));
+ }
+ }
+ cauldrons.set(id + ".ingredients", ingredients);
+ } else {
+ P.p.errorLog("BCauldron " + id + " is missing Ingredient Section");
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // Getting Material by id may not work in the future
+ P.p.errorLog("Error Converting Ingredient Section of Cauldrons, newer versions of Bukkit may not support the old Save File anymore:");
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/src/com/dre/brewery/filedata/LanguageReader.java b/src/com/dre/brewery/filedata/LanguageReader.java
index e1cb2f1..2f5e2a7 100644
--- a/src/com/dre/brewery/filedata/LanguageReader.java
+++ b/src/com/dre/brewery/filedata/LanguageReader.java
@@ -1,24 +1,26 @@
package com.dre.brewery.filedata;
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
+import com.dre.brewery.P;
+import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
public class LanguageReader {
- private Map entries = new TreeMap<>();
- private Map defaults = new TreeMap<>();
+ private Map entries = new HashMap<>(128);
private File file;
- private boolean changed;
-
- public LanguageReader(File file) {
- this.setDefaults();
+ public LanguageReader(File file, String defaultPath) {
/* Load */
this.file = file;
@@ -30,149 +32,55 @@ public class LanguageReader {
}
/* Check */
- this.check();
+ check(defaultPath);
}
- private void setDefaults() {
-
- /* Player */
- defaults.put("Player_BarrelCreated", "Barrel created");
- defaults.put("Player_BarrelFull", "&cThis barrel can''t hold any more drinks");
- defaults.put("Player_CauldronInfo1", "This cauldron has been boiling for &v1 minutes.");
- defaults.put("Player_CauldronInfo2", "This cauldron has just started boiling.");
- defaults.put("Player_CantDrink", "You can't drink any more.");
- defaults.put("Player_DrunkPassOut", "You drank too much and passed out.");
- defaults.put("Player_LoginDeny", "Your character tries to log in, but is too drunk to find the server. Try again!");
- defaults.put("Player_LoginDenyLong", "Your character is really drunk and has passed out. Try again in 10 minutes!");
- defaults.put("Player_Wake", "Ohh no! I cannot remember how I got here...");
- defaults.put("Player_WakeCreated", "&aWakeup Point with id: &6&v1 &awas created successfully!");
- defaults.put("Player_WakeNotExist", "&cThe Wakeup Point with the id: &6&v1 &cdoesn't exist!");
- defaults.put("Player_WakeDeleted", "&aThe Wakeup Point with the id: &6&v1 &awas successfully deleted!");
- defaults.put("Player_WakeAlreadyDeleted", "&cThe Wakeup Point with the id: &6&v1 &chas already been deleted!");
- defaults.put("Player_WakeFilled", "&cThe Wakeup Point with the id: &6&v1&c at position &6&v2 &v3, &v4, &v5&c is filled with Blocks!");
- defaults.put("Player_WakeNoPoints", "&cThere are no Wakeup Points!");
- defaults.put("Player_WakeLast", "&aThis was the last Wakeup Point");
- defaults.put("Player_WakeTeleport", "Teleport to Wakeup Point with the id: &6&v1&f At position: &6&v2 &v3, &v4, &v5");
- defaults.put("Player_WakeHint1", "To Next Wakeup Point: Punch your fist in the air");
- defaults.put("Player_WakeHint2", "To Cancel: &9/br wakeup cancel");
- defaults.put("Player_WakeCancel", "&6Wakeup Point Check was cancelled");
- defaults.put("Player_WakeNoCheck", "&cNo Wakeup Point Check is currently active");
- defaults.put("Player_TriedToSay", "&v1 tried to say: &0&v2");
-
- /* Brew */
- defaults.put("Brew_Distilled", "Distilled");
- defaults.put("Brew_BarrelRiped", "Barrel aged");
- defaults.put("Brew_Undefined", "Indefinable Brew");
- defaults.put("Brew_DistillUndefined", "Indefinable Distillate");
- defaults.put("Brew_BadPotion", "Ruined Potion");
- defaults.put("Brew_Ingredients", "Ingredients");
- defaults.put("Brew_minute", "minute");
- defaults.put("Brew_MinutePluralPostfix", "s");
- defaults.put("Brew_fermented", "fermented");
- defaults.put("Brew_-times", "-times");
- defaults.put("Brew_OneYear", "One Year");
- defaults.put("Brew_Years", "Years");
- defaults.put("Brew_HundredsOfYears", "Hundreds of Years");
- defaults.put("Brew_Woodtype", "Woodtype");
- defaults.put("Brew_ThickBrew", "Muddy Brew");
-
- /* Commands */
- defaults.put("CMD_Reload", "&aConfig was successfully reloaded");
- defaults.put("CMD_Configname", "&aName for the Config is: &f&v1");
- defaults.put("CMD_Configname_Error", "&cCould not find item in your hand");
- defaults.put("CMD_Player", "&a&v1 is now &6&v2% &adrunk, with a quality of &6&v3");
- defaults.put("CMD_Player_Error", "&cThe quality has to be between 1 and 10!");
- defaults.put("CMD_Info_NotDrunk", "&v1 is not drunk");
- defaults.put("CMD_Info_Drunk", "&v1 is &6&v2% &fdrunk, with a quality of &6&v3");
- defaults.put("CMD_UnLabel", "&aLabel removed!");
- defaults.put("CMD_Persistent", "&aPotion is now Persistent and Static and may now be copied like any other item. You can remove the persistence with the same command.");
- defaults.put("CMD_PersistRemove", "&cPersistent Brews cannot be removed from the Database. It would render any copies of them useless!");
- defaults.put("CMD_UnPersist", "&aPersistence and static Removed. &eEvery Potential copy NOT made with '/brew copy' could become useless now!");
- defaults.put("CMD_Copy_Error", "&6&v1 &cPotions did not fit into your inventory");
- defaults.put("CMD_CopyNotPersistent", "&eThese copies of this Brew will not be persistent or static!");
- defaults.put("CMD_Static", "&aPotion is now static and will not change in barrels or brewing stands.");
- defaults.put("CMD_NonStatic", "&ePotion is not static anymore and will normally age in barrels.");
-
- /* Error */
- defaults.put("Error_UnknownCommand", "Unknown Command");
- defaults.put("Error_ShowHelp", "Use &6/brew help &fto display the help");
- defaults.put("Error_PlayerCommand", "&cThis command can only be executed as a player!");
- defaults.put("Error_ItemNotPotion", "&cThe item in your hand could not be identified as a potion!");
- defaults.put("Error_NoBrewName", "&cNo Recipe with Name: '&v1&c' found!");
- defaults.put("Error_Recipeload", "&cNot all recipes could be restored: More information in the server log!");
- defaults.put("Error_ConfigUpdate", "Unknown Brewery config version: v&v1, config was not updated!");
- defaults.put("Error_PersistStatic", "&cPersistent potions are always static!");
-
- /* Permissions */
- defaults.put("Error_NoPermissions", "&cYou don't have permissions to do this!");
- defaults.put("Error_NoBarrelAccess", "&cYou don't have permissions to access this barrel!");
- defaults.put("Perms_NoBarrelCreate", "&cYou don't have permissions to create barrels!");
- defaults.put("Perms_NoSmallBarrelCreate", "&cYou don't have permissions to create small barrels!");
- defaults.put("Perms_NoBigBarrelCreate", "&cYou don't have permissions to create big barrels!");
- defaults.put("Perms_NoCauldronInsert", "&cYou don't have permissions to put ingredients into cauldrons!");
- defaults.put("Perms_NoCauldronFill", "&cYou don't have permissions to fill bottles from this cauldron!");
-
- /* Help */
- defaults.put("Help_Help", "&6/brew help [Page] &9Shows a specific help-page");
- defaults.put("Help_Player", "&6/brew <%Drunkeness> [Quality]&9 Sets Drunkeness (and Quality) of a Player");
- defaults.put("Help_Info", "&6/brew info&9 Displays your current Drunkeness and Quality");
- defaults.put("Help_UnLabel", "&6/brew unlabel &9Removes the detailled label of a potion");
- defaults.put("Help_Copy", "&6/brew copy [Quantity]>&9 Copies the potion in your hand");
- defaults.put("Help_Delete", "&6/brew delete &9Deletes the potion in your hand");
- defaults.put("Help_InfoOther", "&6/brew info [Player]&9 Displays the current Drunkeness and Quality of [Player]");
- defaults.put("Help_Wakeup", "&6/brew wakeup list &9 Lists all wakeup points");
- defaults.put("Help_WakeupList", "&6/brew wakeup list [World]&9 Lists all wakeup points of [world]");
- defaults.put("Help_WakeupCheck", "&6/brew wakeup check &9Teleports to all wakeup points");
- defaults.put("Help_WakeupCheckSpecific", "&6/brew wakeup check &9Teleports to the wakeup point with ");
- defaults.put("Help_WakeupAdd", "&6/brew wakeup add &9Adds a wakeup point at your current position");
- defaults.put("Help_WakeupRemove", "&6/brew wakeup remove &9Removes the wakeup point with ");
- defaults.put("Help_Reload", "&6/brew reload &9Reload config");
- defaults.put("Help_Configname", "&6/brew ItemName &9Display name of item in hand for the config");
- defaults.put("Help_Persist", "&6/brew persist &9Make Brew persistent -> copyable by any plugin and technique");
- defaults.put("Help_Static", "&6/brew static &9Make Brew static -> No further ageing or distilling");
- defaults.put("Help_Create", "&6/brew create [Quality] [Player] &9Create a Brew with optional quality (1-10)");
-
- /* Etc. */
- defaults.put("Etc_Usage", "Usage:");
- defaults.put("Etc_Page", "Page");
- defaults.put("Etc_Barrel", "Barrel");
- }
-
- private void check() {
- for (String defaultEntry : defaults.keySet()) {
- if (!entries.containsKey(defaultEntry)) {
- entries.put(defaultEntry, defaults.get(defaultEntry));
- changed = true;
+ private void check(String defaultPath) {
+ FileConfiguration defaults = null;
+ ConfigUpdater updater = null;
+ String line;
+ InputStream resource = P.p.getResource(defaultPath);
+ if (resource == null) return;
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource))) {
+ while ((line = reader.readLine()) != null) {
+ int index = line.indexOf(':');
+ if (index != -1) {
+ String key = line.substring(0, index);
+ if (!entries.containsKey(key)) {
+ if (defaults == null) {
+ defaults = new YamlConfiguration();
+ defaults.load(new BufferedReader(new InputStreamReader(Objects.requireNonNull(P.p.getResource(defaultPath)))));
+ updater = new ConfigUpdater(file);
+ updater.appendLines("", "# Updated");
+ }
+ entries.put(key, defaults.getString(key));
+ updater.appendLines(line);
+ }
+ }
}
+ if (updater != null) {
+ createBackup();
+ updater.saveConfig();
+ P.p.log("Language file updated");
+ }
+ } catch (IOException | InvalidConfigurationException e) {
+ e.printStackTrace();
+ P.p.errorLog("Language File could not be updated");
}
}
@SuppressWarnings("ResultOfMethodCallIgnored")
- public void save() {
- if (changed) {
- /* Copy old File */
- File source = new File(file.getPath());
- String filePath = file.getPath();
- File temp = new File(filePath.substring(0, filePath.length() - 4) + "_old.yml");
+ private void createBackup() {
+ /* Copy old File */
+ File source = new File(file.getPath());
+ String filePath = file.getPath();
+ File backup = new File(filePath.substring(0, filePath.length() - 4) + "_old.yml");
- if (temp.exists())
- temp.delete();
-
- source.renameTo(temp);
-
- /* Save */
- FileConfiguration configFile = new YamlConfiguration();
-
- for (String key : entries.keySet()) {
- configFile.set(key, entries.get(key));
- }
-
- try {
- configFile.save(file);
- } catch (IOException e) {
- e.printStackTrace();
- }
+ if (backup.exists()) {
+ backup.delete();
}
+
+ source.renameTo(backup);
}
public String get(String key, String... args) {
diff --git a/src/com/dre/brewery/filedata/ReadOldData.java b/src/com/dre/brewery/filedata/ReadOldData.java
index ef04b7e..e24e065 100644
--- a/src/com/dre/brewery/filedata/ReadOldData.java
+++ b/src/com/dre/brewery/filedata/ReadOldData.java
@@ -18,6 +18,12 @@ public class ReadOldData extends BukkitRunnable {
@Override
public void run() {
File datafile = new File(P.p.getDataFolder(), "data.yml");
+ if (!datafile.exists()) {
+ data = new YamlConfiguration();
+ done = true;
+ return;
+ }
+
data = YamlConfiguration.loadConfiguration(datafile);
if (DataSave.lastBackup > 10) {
diff --git a/src/com/dre/brewery/filedata/WriteData.java b/src/com/dre/brewery/filedata/WriteData.java
index c624851..a1f5a44 100644
--- a/src/com/dre/brewery/filedata/WriteData.java
+++ b/src/com/dre/brewery/filedata/WriteData.java
@@ -8,6 +8,9 @@ import org.bukkit.configuration.file.FileConfiguration;
import com.dre.brewery.P;
+/**
+ * Writes the collected Data to file in Async Thread
+ */
public class WriteData implements Runnable {
private FileConfiguration data;
diff --git a/src/com/dre/brewery/integration/CitadelBarrel.java b/src/com/dre/brewery/integration/CitadelBarrel.java
deleted file mode 100644
index cb36a80..0000000
--- a/src/com/dre/brewery/integration/CitadelBarrel.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.dre.brewery.integration;
-
-import org.bukkit.block.Block;
-import org.bukkit.entity.Player;
-
-import com.dre.brewery.P;
-
-import vg.civcraft.mc.citadel.Citadel;
-import vg.civcraft.mc.citadel.ReinforcementManager;
-import vg.civcraft.mc.citadel.reinforcement.NullReinforcement;
-import vg.civcraft.mc.citadel.reinforcement.PlayerReinforcement;
-import vg.civcraft.mc.citadel.reinforcement.Reinforcement;
-
-/**
- * Basic Citadel support to prevent randos from stealing your barrel aging brews
- *
- * @author ProgrammerDan
- */
-public class CitadelBarrel {
- static P brewery = P.p;
-
- public static boolean checkAccess(Player player, Block sign) {
- ReinforcementManager manager = Citadel.getReinforcementManager();
-
- Reinforcement rein = manager.getReinforcement(sign);
-
- if (rein == null) return true; // no protections in place.
-
- if (rein instanceof PlayerReinforcement) {
- PlayerReinforcement prein = (PlayerReinforcement) rein;
- if (prein.canAccessChests(player)) {
- return true;
- }
- } else if (rein instanceof NullReinforcement) {
- return true;
- }
- // no support for multiblock atm, would require namelayer support.
-
- // special locked, or no access.
- brewery.msg(player, brewery.languageReader.get("Error_NoBarrelAccess"));
- return false;
- }
-}
diff --git a/src/com/dre/brewery/integration/IntegrationListener.java b/src/com/dre/brewery/integration/IntegrationListener.java
new file mode 100644
index 0000000..c4c8a19
--- /dev/null
+++ b/src/com/dre/brewery/integration/IntegrationListener.java
@@ -0,0 +1,251 @@
+package com.dre.brewery.integration;
+
+import com.dre.brewery.Barrel;
+import com.dre.brewery.P;
+import com.dre.brewery.api.events.barrel.BarrelAccessEvent;
+import com.dre.brewery.api.events.barrel.BarrelDestroyEvent;
+import com.dre.brewery.api.events.barrel.BarrelRemoveEvent;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.integration.barrel.GriefPreventionBarrel;
+import com.dre.brewery.integration.barrel.LWCBarrel;
+import com.dre.brewery.integration.barrel.LogBlockBarrel;
+import com.dre.brewery.integration.item.MMOItemsPluginItem;
+import com.dre.brewery.recipe.BCauldronRecipe;
+import com.dre.brewery.recipe.RecipeItem;
+import com.dre.brewery.utility.LegacyUtil;
+import net.Indyuce.mmoitems.MMOItems;
+import net.Indyuce.mmoitems.api.item.NBTItem;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.plugin.Plugin;
+
+public class IntegrationListener implements Listener {
+
+ @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
+ public void onBarrelAccessLowest(BarrelAccessEvent event) {
+ if (BConfig.useWG) {
+ Plugin plugin = P.p.getServer().getPluginManager().getPlugin("WorldGuard");
+ if (plugin != null) {
+ try {
+ if (!BConfig.wg.checkAccess(event.getPlayer(), event.getSpigot(), plugin)) {
+ event.setCancelled(true);
+ P.p.msg(event.getPlayer(), P.p.languageReader.get("Error_NoBarrelAccess"));
+ }
+ } catch (Throwable e) {
+ event.setCancelled(true);
+ P.p.errorLog("Failed to Check WorldGuard for Barrel Open Permissions!");
+ P.p.errorLog("Brewery was tested with version 5.8, 6.1 to 7.0 of WorldGuard!");
+ P.p.errorLog("Disable the WorldGuard support in the config and do /brew reload");
+ e.printStackTrace();
+ Player player = event.getPlayer();
+ if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
+ P.p.msg(player, "&cWorldGuard check Error, Brewery was tested with up to v7.0 of Worldguard");
+ P.p.msg(player, "&cSet &7useWorldGuard: false &cin the config and /brew reload");
+ } else {
+ P.p.msg(player, "&cError opening Barrel, please report to an Admin!");
+ }
+ }
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void onBarrelAccess(BarrelAccessEvent event) {
+ if (BConfig.useGMInventories) {
+ Plugin pl = P.p.getServer().getPluginManager().getPlugin("GameModeInventories");
+ if (pl != null && pl.isEnabled()) {
+ try {
+ if (pl.getConfig().getBoolean("restrict_creative")) {
+ Player player = event.getPlayer();
+ if (player.getGameMode() == GameMode.CREATIVE) {
+ if (!pl.getConfig().getBoolean("bypass.inventories") || (!player.hasPermission("gamemodeinventories.bypass") && !player.isOp())) {
+ event.setCancelled(true);
+ if (!pl.getConfig().getBoolean("dont_spam_chat")) {
+ P.p.msg(event.getPlayer(), P.p.languageReader.get("Error_NoBarrelAccess"));
+ }
+ return;
+ }
+ }
+ }
+ } catch (Throwable e) {
+ P.p.errorLog("Failed to Check GameModeInventories for Barrel Open Permissions!");
+ P.p.errorLog("Players will be able to open Barrel with GameMode Creative");
+ e.printStackTrace();
+ BConfig.useGMInventories = false;
+ }
+ } else {
+ BConfig.useGMInventories = false;
+ }
+ }
+ if (BConfig.useGP) {
+ if (P.p.getServer().getPluginManager().isPluginEnabled("GriefPrevention")) {
+ try {
+ if (!GriefPreventionBarrel.checkAccess(event)) {
+ P.p.msg(event.getPlayer(), P.p.languageReader.get("Error_NoBarrelAccess"));
+ event.setCancelled(true);
+ return;
+ }
+ } catch (Throwable e) {
+ event.setCancelled(true);
+ P.p.errorLog("Failed to Check GriefPrevention for Barrel Open Permissions!");
+ P.p.errorLog("Brewery was tested with GriefPrevention v14.5 - v16.9");
+ P.p.errorLog("Disable the GriefPrevention support in the config and do /brew reload");
+ e.printStackTrace();
+ Player player = event.getPlayer();
+ if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
+ P.p.msg(player, "&cGriefPrevention check Error, Brewery was tested with up to v16.9 of GriefPrevention");
+ P.p.msg(player, "&cSet &7useGriefPrevention: false &cin the config and /brew reload");
+ } else {
+ P.p.msg(player, "&cError opening Barrel, please report to an Admin!");
+ }
+ }
+ }
+ }
+
+ if (BConfig.useLWC) {
+ Plugin plugin = P.p.getServer().getPluginManager().getPlugin("LWC");
+ if (plugin != null) {
+
+ // If the Clicked Block was the Sign, LWC already knows and we dont need to do anything here
+ if (!LegacyUtil.isSign(event.getClickedBlock().getType())) {
+ Block sign = event.getBarrel().getBody().getSignOfSpigot();
+ // If the Barrel does not have a Sign, it cannot be locked
+ if (!sign.equals(event.getClickedBlock())) {
+ Player player = event.getPlayer();
+ try {
+ if (!LWCBarrel.checkAccess(player, sign, plugin)) {
+ P.p.msg(event.getPlayer(), P.p.languageReader.get("Error_NoBarrelAccess"));
+ event.setCancelled(true);
+ }
+ } catch (Throwable e) {
+ event.setCancelled(true);
+ P.p.errorLog("Failed to Check LWC for Barrel Open Permissions!");
+ P.p.errorLog("Brewery was tested with version 4.5.0 of LWC!");
+ P.p.errorLog("Disable the LWC support in the config and do /brew reload");
+ e.printStackTrace();
+ if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
+ P.p.msg(player, "&cLWC check Error, Brewery was tested with up to v4.5.0 of LWC");
+ P.p.msg(player, "&cSet &7useLWC: false &cin the config and /brew reload");
+ } else {
+ P.p.msg(player, "&cError opening Barrel, please report to an Admin!");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
+ public void onBarrelDestroy(BarrelDestroyEvent event) {
+ if (!BConfig.useLWC) return;
+
+ if (event.hasPlayer()) {
+ try {
+ if (LWCBarrel.denyDestroy(event.getPlayerOptional(), event.getBarrel())) {
+ event.setCancelled(true);
+ }
+ } catch (Throwable e) {
+ event.setCancelled(true);
+ P.p.errorLog("Failed to Check LWC for Barrel Break Permissions!");
+ P.p.errorLog("Brewery was tested with version 4.5.0 of LWC!");
+ P.p.errorLog("Disable the LWC support in the config and do /brew reload");
+ e.printStackTrace();
+ Player player = event.getPlayerOptional();
+ if (player.hasPermission("brewery.admin") || player.hasPermission("brewery.mod")) {
+ P.p.msg(player, "&cLWC check Error, Brewery was tested with up to v4.5.0 of LWC");
+ P.p.msg(player, "&cSet &7useLWC: false &cin the config and /brew reload");
+ } else {
+ P.p.msg(player, "&cError breaking Barrel, please report to an Admin!");
+ }
+ }
+ } else {
+ try {
+ if (event.getReason() == BarrelDestroyEvent.Reason.EXPLODED) {
+ if (LWCBarrel.denyExplosion(event.getBarrel())) {
+ event.setCancelled(true);
+ }
+ } else {
+ if (LWCBarrel.denyDestroyOther(event.getBarrel())) {
+ event.setCancelled(true);
+ }
+ }
+ } catch (Throwable e) {
+ event.setCancelled(true);
+ P.p.errorLog("Failed to Check LWC on Barrel Destruction!");
+ P.p.errorLog("Brewery was tested with version 4.5.0 of LWC!");
+ P.p.errorLog("Disable the LWC support in the config and do /brew reload");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @EventHandler
+ public void onBarrelRemove(BarrelRemoveEvent event) {
+ if (!BConfig.useLWC) return;
+
+ try {
+ LWCBarrel.remove(event.getBarrel());
+ } catch (Throwable e) {
+ P.p.errorLog("Failed to Remove LWC Lock from Barrel!");
+ P.p.errorLog("Brewery was tested with version 4.5.0 of LWC!");
+ e.printStackTrace();
+ }
+ }
+
+ @EventHandler
+ public void onInventoryClose(InventoryCloseEvent event) {
+ if (BConfig.useLB) {
+ if (event.getInventory().getHolder() instanceof Barrel) {
+ try {
+ LogBlockBarrel.closeBarrel(event.getPlayer(), event.getInventory());
+ } catch (Exception e) {
+ P.p.errorLog("Failed to Log Barrel to LogBlock!");
+ P.p.errorLog("Brewery was tested with version 1.94 of LogBlock!");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void onInteract(PlayerInteractEvent event) {
+ // Cancel the Interact Event early, so MMOItems does not act before us and consume the item when trying to add item to Cauldron
+ if (!P.use1_9) return;
+ if (BConfig.hasMMOItems == null) {
+ BConfig.hasMMOItems = P.p.getServer().getPluginManager().isPluginEnabled("MMOItems");
+ }
+ if (!BConfig.hasMMOItems) return;
+ try {
+ if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasItem() && event.getHand() == EquipmentSlot.HAND) {
+ if (event.getClickedBlock() != null && event.getClickedBlock().getType() == Material.CAULDRON) {
+ NBTItem item = MMOItems.plugin.getNMS().getNBTItem(event.getItem());
+ if (item.hasType()) {
+ for (RecipeItem rItem : BCauldronRecipe.acceptedCustom) {
+ if (rItem instanceof MMOItemsPluginItem) {
+ MMOItemsPluginItem mmo = ((MMOItemsPluginItem) rItem);
+ if (mmo.matches(event.getItem())) {
+ event.setCancelled(true);
+ P.p.playerListener.onPlayerInteract(event);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (Throwable e) {
+ P.p.errorLog("Could not check MMOItems for Item");
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/com/dre/brewery/integration/GriefPreventionBarrel.java b/src/com/dre/brewery/integration/barrel/GriefPreventionBarrel.java
similarity index 66%
rename from src/com/dre/brewery/integration/GriefPreventionBarrel.java
rename to src/com/dre/brewery/integration/barrel/GriefPreventionBarrel.java
index 85edf76..9337bed 100644
--- a/src/com/dre/brewery/integration/GriefPreventionBarrel.java
+++ b/src/com/dre/brewery/integration/barrel/GriefPreventionBarrel.java
@@ -1,18 +1,19 @@
-package com.dre.brewery.integration;
+package com.dre.brewery.integration.barrel;
import com.dre.brewery.P;
+import com.dre.brewery.api.events.barrel.BarrelAccessEvent;
import me.ryanhamshire.GriefPrevention.Claim;
import me.ryanhamshire.GriefPrevention.GriefPrevention;
import me.ryanhamshire.GriefPrevention.PlayerData;
-import org.bukkit.block.Block;
import org.bukkit.entity.Player;
public class GriefPreventionBarrel {
- static P brewery = P.p;
- static GriefPrevention griefPrevention = GriefPrevention.instance;
+ private static P brewery = P.p;
- public static boolean checkAccess(Player player, Block sign) {
+ public static boolean checkAccess(BarrelAccessEvent event) {
+ GriefPrevention griefPrevention = GriefPrevention.instance;
+ Player player = event.getPlayer();
PlayerData playerData = griefPrevention.dataStore.getPlayerData(player.getUniqueId());
if (!griefPrevention.claimsEnabledForWorld(player.getWorld()) || playerData.ignoreClaims || !griefPrevention.config_claims_preventTheft) {
@@ -21,17 +22,15 @@ public class GriefPreventionBarrel {
// block container use during pvp combat
if (playerData.inPvpCombat()) {
- brewery.msg(player, brewery.languageReader.get("Error_NoBarrelAccess"));
return false;
}
// check permissions for the claim the Barrel is in
- Claim claim = griefPrevention.dataStore.getClaimAt(sign.getLocation(), false, playerData.lastClaim);
+ Claim claim = griefPrevention.dataStore.getClaimAt(event.getSpigot().getLocation(), false, playerData.lastClaim);
if (claim != null) {
playerData.lastClaim = claim;
String noContainersReason = claim.allowContainers(player);
if (noContainersReason != null) {
- brewery.msg(player, brewery.languageReader.get("Error_NoBarrelAccess") + " " + noContainersReason);
return false;
}
}
diff --git a/src/com/dre/brewery/integration/LWCBarrel.java b/src/com/dre/brewery/integration/barrel/LWCBarrel.java
similarity index 76%
rename from src/com/dre/brewery/integration/LWCBarrel.java
rename to src/com/dre/brewery/integration/barrel/LWCBarrel.java
index b3ee6f5..cad18b5 100644
--- a/src/com/dre/brewery/integration/LWCBarrel.java
+++ b/src/com/dre/brewery/integration/barrel/LWCBarrel.java
@@ -1,12 +1,4 @@
-package com.dre.brewery.integration;
-
-import org.bukkit.block.Block;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventException;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.player.PlayerInteractEvent;
-import org.bukkit.plugin.Plugin;
-import org.bukkit.plugin.RegisteredListener;
+package com.dre.brewery.integration.barrel;
import com.dre.brewery.Barrel;
import com.dre.brewery.P;
@@ -15,13 +7,24 @@ import com.griefcraft.lwc.LWC;
import com.griefcraft.model.Flag;
import com.griefcraft.model.Protection;
import com.griefcraft.scripting.event.LWCProtectionDestroyEvent;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventException;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.RegisteredListener;
public class LWCBarrel {
- public static boolean checkDestroy(Player player, Barrel barrel) {
+ public static boolean denyDestroy(Player player, Barrel barrel) {
LWC lwc = LWC.getInstance();
- Block sign = barrel.getSignOfSpigot();
+ Block sign = barrel.getBody().getSignOfSpigot();
//if (!Boolean.parseBoolean(lwc.resolveProtectionConfiguration(sign, "ignoreBlockDestruction"))) {
Protection protection = lwc.findProtection(sign);
if (protection != null) {
@@ -33,21 +36,21 @@ public class LWCBarrel {
lwc.getModuleLoader().dispatchEvent(evt);
if (evt.isCancelled()) {
- return false;
+ return true;
}
} catch (Exception e) {
lwc.sendLocale(player, "protection.internalerror", "id", "BLOCK_BREAK");
P.p.errorLog("Failed to dispatch LWCProtectionDestroyEvent");
e.printStackTrace();
- return false;
+ return true;
}
}
//}
- return true;
+ return false;
}
- public static boolean checkAccess(Player player, Block sign, PlayerInteractEvent event, Plugin plugin) {
+ public static boolean checkAccess(Player player, Block sign, Plugin plugin) {
LWC lwc = LWC.getInstance();
// Disallow Chest Access with these permissions
@@ -57,7 +60,7 @@ public class LWCBarrel {
}
// We just fake a BlockInteractEvent on the Sign for LWC, it handles it nicely. Otherwise we could copy LWCs listener in here...
- PlayerInteractEvent lwcEvent = new PlayerInteractEvent(player, event.getAction(), event.getItem(), sign, event.getBlockFace());
+ PlayerInteractEvent lwcEvent = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, new ItemStack(Material.AIR), sign, BlockFace.EAST);
for (RegisteredListener listener : HandlerList.getRegisteredListeners(plugin)) {
if (listener.getListener() instanceof LWCPlayerListener) {
try {
@@ -79,26 +82,21 @@ public class LWCBarrel {
// If a Barrel is destroyed without player
public static void remove(Barrel barrel) {
- Protection protection = LWC.getInstance().findProtection(barrel.getSignOfSpigot());
+ Protection protection = LWC.getInstance().findProtection(barrel.getBody().getSignOfSpigot());
if (protection != null) {
protection.remove();
}
}
// Returns true if the block that exploded should not be removed
- public static boolean blockExplosion(Barrel barrel, Block block) {
- Protection protection = LWC.getInstance().findProtection(barrel.getSignOfSpigot());
+ public static boolean denyExplosion(Barrel barrel) {
+ Protection protection = LWC.getInstance().findProtection(barrel.getBody().getSignOfSpigot());
- if (protection == null) {
- barrel.remove(block, null);
- return false;
- }
+ return protection != null && !protection.hasFlag(Flag.Type.ALLOWEXPLOSIONS);
+ }
- if (protection.hasFlag(Flag.Type.ALLOWEXPLOSIONS)) {
- protection.remove();
- barrel.remove(block, null);
- return false;
- }
- return true;
+ // Returns true if the block that was destroyed should not be removed
+ public static boolean denyDestroyOther(Barrel barrel) {
+ return LWC.getInstance().findProtection(barrel.getBody().getSignOfSpigot()) != null;
}
}
diff --git a/src/com/dre/brewery/integration/LogBlockBarrel.java b/src/com/dre/brewery/integration/barrel/LogBlockBarrel.java
similarity index 98%
rename from src/com/dre/brewery/integration/LogBlockBarrel.java
rename to src/com/dre/brewery/integration/barrel/LogBlockBarrel.java
index 4d368a8..6602d66 100644
--- a/src/com/dre/brewery/integration/LogBlockBarrel.java
+++ b/src/com/dre/brewery/integration/barrel/LogBlockBarrel.java
@@ -1,6 +1,6 @@
-package com.dre.brewery.integration;
+package com.dre.brewery.integration.barrel;
-import com.dre.brewery.LegacyUtil;
+import com.dre.brewery.utility.LegacyUtil;
import com.dre.brewery.P;
import de.diddiz.LogBlock.Actor;
diff --git a/src/com/dre/brewery/integration/WGBarrel.java b/src/com/dre/brewery/integration/barrel/WGBarrel.java
similarity index 81%
rename from src/com/dre/brewery/integration/WGBarrel.java
rename to src/com/dre/brewery/integration/barrel/WGBarrel.java
index 25e29b9..033124b 100644
--- a/src/com/dre/brewery/integration/WGBarrel.java
+++ b/src/com/dre/brewery/integration/barrel/WGBarrel.java
@@ -1,4 +1,4 @@
-package com.dre.brewery.integration;
+package com.dre.brewery.integration.barrel;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
diff --git a/src/com/dre/brewery/integration/WGBarrelOld.java b/src/com/dre/brewery/integration/barrel/WGBarrel5.java
similarity index 91%
rename from src/com/dre/brewery/integration/WGBarrelOld.java
rename to src/com/dre/brewery/integration/barrel/WGBarrel5.java
index 8699a7a..0d0ebd1 100644
--- a/src/com/dre/brewery/integration/WGBarrelOld.java
+++ b/src/com/dre/brewery/integration/barrel/WGBarrel5.java
@@ -1,4 +1,4 @@
-package com.dre.brewery.integration;
+package com.dre.brewery.integration.barrel;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -17,13 +17,13 @@ import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
-public class WGBarrelOld implements WGBarrel {
+public class WGBarrel5 implements WGBarrel {
private Method allows;
private Method canBuild;
private Method getApplicableRegions;
- public WGBarrelOld() {
+ public WGBarrel5() {
try {
allows = ApplicableRegionSet.class.getMethod("allows", StateFlag.class, LocalPlayer.class);
canBuild = ApplicableRegionSet.class.getMethod("canBuild", LocalPlayer.class);
@@ -48,7 +48,6 @@ public class WGBarrelOld implements WGBarrel {
if (!(Boolean) allows.invoke(region, DefaultFlag.CHEST_ACCESS, localPlayer)) {
if (!(Boolean) canBuild.invoke(region, localPlayer)) {
- P.p.msg(player, P.p.languageReader.get("Error_NoBarrelAccess"));
return false;
}
}
diff --git a/src/com/dre/brewery/integration/WGBarrelNew.java b/src/com/dre/brewery/integration/barrel/WGBarrel6.java
similarity index 70%
rename from src/com/dre/brewery/integration/WGBarrelNew.java
rename to src/com/dre/brewery/integration/barrel/WGBarrel6.java
index 4503b3d..d3b243b 100644
--- a/src/com/dre/brewery/integration/WGBarrelNew.java
+++ b/src/com/dre/brewery/integration/barrel/WGBarrel6.java
@@ -1,17 +1,15 @@
-package com.dre.brewery.integration;
+package com.dre.brewery.integration.barrel;
-import org.bukkit.block.Block;
-import org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
-
-import com.dre.brewery.P;
import com.sk89q.worldguard.bukkit.RegionQuery;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
-public class WGBarrelNew implements WGBarrel {
+public class WGBarrel6 implements WGBarrel {
public boolean checkAccess(Player player, Block spigot, Plugin plugin) {
WorldGuardPlugin wg = (WorldGuardPlugin) plugin;
@@ -21,12 +19,8 @@ public class WGBarrelNew implements WGBarrel {
RegionQuery query = wg.getRegionContainer().createQuery();
- if (!query.testBuild(spigot.getLocation(), player, DefaultFlag.USE, DefaultFlag.CHEST_ACCESS)) {
- P.p.msg(player, P.p.languageReader.get("Error_NoBarrelAccess"));
- return false;
- }
+ return query.testBuild(spigot.getLocation(), player, DefaultFlag.USE, DefaultFlag.CHEST_ACCESS);
- return true;
}
}
diff --git a/src/com/dre/brewery/integration/WGBarrel7.java b/src/com/dre/brewery/integration/barrel/WGBarrel7.java
similarity index 87%
rename from src/com/dre/brewery/integration/WGBarrel7.java
rename to src/com/dre/brewery/integration/barrel/WGBarrel7.java
index 7c2ef25..e06dc29 100644
--- a/src/com/dre/brewery/integration/WGBarrel7.java
+++ b/src/com/dre/brewery/integration/barrel/WGBarrel7.java
@@ -1,4 +1,4 @@
-package com.dre.brewery.integration;
+package com.dre.brewery.integration.barrel;
import org.bukkit.block.Block;
@@ -55,12 +55,7 @@ public class WGBarrel7 implements WGBarrel {
RegionQuery query = platform.getRegionContainer().createQuery();
- if (!query.testBuild(new Location(world, spigot.getX(), spigot.getY(), spigot.getZ()), wg.wrapPlayer(player), Flags.USE, Flags.CHEST_ACCESS)) {
- P.p.msg(player, P.p.languageReader.get("Error_NoBarrelAccess"));
- return false;
- }
-
- return true;
+ return query.testBuild(new Location(world, spigot.getX(), spigot.getY(), spigot.getZ()), wg.wrapPlayer(player), Flags.USE, Flags.CHEST_ACCESS);
}
}
diff --git a/src/com/dre/brewery/integration/item/BreweryPluginItem.java b/src/com/dre/brewery/integration/item/BreweryPluginItem.java
new file mode 100644
index 0000000..a815612
--- /dev/null
+++ b/src/com/dre/brewery/integration/item/BreweryPluginItem.java
@@ -0,0 +1,30 @@
+package com.dre.brewery.integration.item;
+
+import com.dre.brewery.Brew;
+import com.dre.brewery.recipe.BRecipe;
+import com.dre.brewery.recipe.PluginItem;
+import org.bukkit.ChatColor;
+import org.bukkit.inventory.ItemStack;
+
+/**
+ * For recipes that use Brewery Items as input
+ */
+public class BreweryPluginItem extends PluginItem {
+
+// When implementing this, put Brewery as softdepend in your plugin.yml!
+// We're calling this as server start:
+// PluginItem.registerForConfig("brewery", BreweryPluginItem::new);
+
+ @Override
+ public boolean matches(ItemStack item) {
+ Brew brew = Brew.get(item);
+ if (brew != null) {
+ BRecipe recipe = brew.getCurrentRecipe();
+ if (recipe != null) {
+ return recipe.getRecipeName().equalsIgnoreCase(getItemId()) || recipe.getName(10).equalsIgnoreCase(getItemId());
+ }
+ return ChatColor.stripColor(item.getItemMeta().getDisplayName()).equalsIgnoreCase(getItemId());
+ }
+ return false;
+ }
+}
diff --git a/src/com/dre/brewery/integration/item/MMOItemsPluginItem.java b/src/com/dre/brewery/integration/item/MMOItemsPluginItem.java
new file mode 100644
index 0000000..d4df22e
--- /dev/null
+++ b/src/com/dre/brewery/integration/item/MMOItemsPluginItem.java
@@ -0,0 +1,32 @@
+package com.dre.brewery.integration.item;
+
+import com.dre.brewery.P;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.recipe.PluginItem;
+import net.Indyuce.mmoitems.MMOItems;
+import net.Indyuce.mmoitems.api.item.NBTItem;
+import org.bukkit.inventory.ItemStack;
+
+public class MMOItemsPluginItem extends PluginItem {
+
+// When implementing this, put Brewery as softdepend in your plugin.yml!
+// We're calling this as server start:
+// PluginItem.registerForConfig("mmoitems", MMOItemsPluginItem::new);
+
+ @Override
+ public boolean matches(ItemStack item) {
+ if (BConfig.hasMMOItems == null) {
+ BConfig.hasMMOItems = P.p.getServer().getPluginManager().isPluginEnabled("MMOItems");
+ }
+ if (!BConfig.hasMMOItems) return false;
+
+ try {
+ NBTItem nbtItem = MMOItems.plugin.getNMS().getNBTItem(item);
+ return nbtItem.hasType() && nbtItem.getString("MMOITEMS_ITEM_ID").equalsIgnoreCase(getItemId());
+ } catch (Throwable e) {
+ e.printStackTrace();
+ P.p.errorLog("Could not check MMOItems for Item ID");
+ return false;
+ }
+ }
+}
diff --git a/src/com/dre/brewery/integration/item/SlimefunPluginItem.java b/src/com/dre/brewery/integration/item/SlimefunPluginItem.java
new file mode 100644
index 0000000..fe33094
--- /dev/null
+++ b/src/com/dre/brewery/integration/item/SlimefunPluginItem.java
@@ -0,0 +1,35 @@
+package com.dre.brewery.integration.item;
+
+import com.dre.brewery.P;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.recipe.PluginItem;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
+import org.bukkit.inventory.ItemStack;
+
+public class SlimefunPluginItem extends PluginItem {
+
+// When implementing this, put Brewery as softdepend in your plugin.yml!
+// We're calling this as server start:
+// PluginItem.registerForConfig("slimefun", SlimefunPluginItem::new);
+// PluginItem.registerForConfig("exoticgarden", SlimefunPluginItem::new);
+
+ @Override
+ public boolean matches(ItemStack item) {
+ if (BConfig.hasSlimefun == null) {
+ BConfig.hasSlimefun = P.p.getServer().getPluginManager().isPluginEnabled("Slimefun");
+ }
+ if (!BConfig.hasSlimefun) return false;
+
+ try {
+ SlimefunItem sfItem = SlimefunItem.getByItem(item);
+ if (sfItem != null) {
+ return sfItem.getID().equalsIgnoreCase(getItemId());
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ P.p.errorLog("Could not check Slimefun for Item ID");
+ return false;
+ }
+ return false;
+ }
+}
diff --git a/src/com/dre/brewery/listeners/BlockListener.java b/src/com/dre/brewery/listeners/BlockListener.java
index 8263d7b..37a5a4a 100644
--- a/src/com/dre/brewery/listeners/BlockListener.java
+++ b/src/com/dre/brewery/listeners/BlockListener.java
@@ -1,78 +1,81 @@
-package com.dre.brewery.listeners;
-
-import org.bukkit.block.Block;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.block.BlockBurnEvent;
-import org.bukkit.event.block.BlockPistonExtendEvent;
-import org.bukkit.event.block.BlockPistonRetractEvent;
-import org.bukkit.event.block.SignChangeEvent;
-import org.bukkit.event.block.BlockBreakEvent;
-
-import com.dre.brewery.Barrel;
-import com.dre.brewery.BPlayer;
-import com.dre.brewery.Words;
-import com.dre.brewery.P;
-
-public class BlockListener implements Listener {
-
- @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
- public void onSignChange(SignChangeEvent event) {
- String[] lines = event.getLines();
-
- if (lines[0].equalsIgnoreCase("Barrel") || lines[0].equalsIgnoreCase(P.p.languageReader.get("Etc_Barrel"))) {
- Player player = event.getPlayer();
- if (!player.hasPermission("brewery.createbarrel.small") && !player.hasPermission("brewery.createbarrel.big")) {
- P.p.msg(player, P.p.languageReader.get("Perms_NoBarrelCreate"));
- return;
- }
- if (Barrel.create(event.getBlock(), player)) {
- P.p.msg(player, P.p.languageReader.get("Player_BarrelCreated"));
- }
- }
- }
-
- @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
- public void onSignChangeLow(SignChangeEvent event) {
- if (Words.doSigns) {
- if (BPlayer.hasPlayer(event.getPlayer())) {
- Words.signWrite(event);
- }
- }
- }
-
- @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
- public void onBlockBreak(BlockBreakEvent event) {
- if (!P.p.blockDestroy(event.getBlock(), event.getPlayer())) {
- event.setCancelled(true);
- }
- }
-
- @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
- public void onBlockBurn(BlockBurnEvent event) {
- P.p.blockDestroy(event.getBlock(), null);
- }
-
- @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
- public void onPistonRetract(BlockPistonRetractEvent event) {
- if (event.isSticky()) {
- Block block = event.getRetractLocation().getBlock();
-
- if (Barrel.get(block) != null) {
- event.setCancelled(true);
- }
- }
- }
-
- @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
- public void onPistonExtend(BlockPistonExtendEvent event) {
- for (Block block : event.getBlocks()) {
- if (Barrel.get(block) != null) {
- event.setCancelled(true);
- return;
- }
- }
- }
-}
+package com.dre.brewery.listeners;
+
+import com.dre.brewery.BPlayer;
+import com.dre.brewery.utility.BUtil;
+import com.dre.brewery.Barrel;
+import com.dre.brewery.P;
+import com.dre.brewery.DistortChat;
+import com.dre.brewery.api.events.barrel.BarrelDestroyEvent;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockBurnEvent;
+import org.bukkit.event.block.BlockPistonExtendEvent;
+import org.bukkit.event.block.BlockPistonRetractEvent;
+import org.bukkit.event.block.SignChangeEvent;
+
+public class BlockListener implements Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onSignChange(SignChangeEvent event) {
+ String[] lines = event.getLines();
+
+ if (lines[0].equalsIgnoreCase("Barrel") || lines[0].equalsIgnoreCase(P.p.languageReader.get("Etc_Barrel"))) {
+ Player player = event.getPlayer();
+ if (!player.hasPermission("brewery.createbarrel.small") && !player.hasPermission("brewery.createbarrel.big")) {
+ P.p.msg(player, P.p.languageReader.get("Perms_NoBarrelCreate"));
+ return;
+ }
+ if (Barrel.create(event.getBlock(), player)) {
+ P.p.msg(player, P.p.languageReader.get("Player_BarrelCreated"));
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void onSignChangeLow(SignChangeEvent event) {
+ if (DistortChat.doSigns) {
+ if (BPlayer.hasPlayer(event.getPlayer())) {
+ DistortChat.signWrite(event);
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onBlockBreak(BlockBreakEvent event) {
+ if (!BUtil.blockDestroy(event.getBlock(), event.getPlayer(), BarrelDestroyEvent.Reason.PLAYER)) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockBurn(BlockBurnEvent event) {
+ if (!BUtil.blockDestroy(event.getBlock(), null, BarrelDestroyEvent.Reason.BURNED)) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void onPistonRetract(BlockPistonRetractEvent event) {
+ if (event.isSticky()) {
+ Block block = event.getRetractLocation().getBlock();
+
+ if (Barrel.get(block) != null) {
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void onPistonExtend(BlockPistonExtendEvent event) {
+ for (Block block : event.getBlocks()) {
+ if (Barrel.get(block) != null) {
+ event.setCancelled(true);
+ return;
+ }
+ }
+ }
+}
diff --git a/src/com/dre/brewery/listeners/CommandListener.java b/src/com/dre/brewery/listeners/CommandListener.java
index 60a6ece..9a3c3c7 100644
--- a/src/com/dre/brewery/listeners/CommandListener.java
+++ b/src/com/dre/brewery/listeners/CommandListener.java
@@ -1,29 +1,28 @@
package com.dre.brewery.listeners;
-import java.util.ArrayList;
-import java.util.Locale;
-
-import com.dre.brewery.Util;
+import com.dre.brewery.*;
+import com.dre.brewery.api.events.brew.BrewModifyEvent;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.recipe.BRecipe;
+import com.dre.brewery.utility.BUtil;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.jetbrains.annotations.NotNull;
-import com.dre.brewery.BIngredients;
-import com.dre.brewery.BRecipe;
-import com.dre.brewery.P;
-import com.dre.brewery.Wakeup;
-import com.dre.brewery.BPlayer;
-import com.dre.brewery.Brew;
+import java.util.ArrayList;
+import java.util.Locale;
public class CommandListener implements CommandExecutor {
public P p = P.p;
@Override
- public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
String cmd = "help";
if (args.length > 0) {
@@ -38,7 +37,6 @@ public class CommandListener implements CommandExecutor {
if (sender.hasPermission("brewery.cmd.reload")) {
p.reload(sender);
- p.msg(sender, p.languageReader.get("CMD_Reload"));
} else {
p.msg(sender, p.languageReader.get("Error_NoPermissions"));
}
@@ -103,14 +101,6 @@ public class CommandListener implements CommandExecutor {
p.msg(sender, p.languageReader.get("Error_NoPermissions"));
}
- } else if (cmd.equalsIgnoreCase("persist") || cmd.equalsIgnoreCase("persistent")) {
-
- if (sender.hasPermission("brewery.cmd.persist")) {
- cmdPersist(sender);
- } else {
- p.msg(sender, p.languageReader.get("Error_NoPermissions"));
- }
-
} else if (cmd.equalsIgnoreCase("static")) {
if (sender.hasPermission("brewery.cmd.static")) {
@@ -167,7 +157,7 @@ public class CommandListener implements CommandExecutor {
p.msg(sender, "&6" + p.getDescription().getName() + " v" + p.getDescription().getVersion());
}
- Util.list(sender, commands, page);
+ BUtil.list(sender, commands, page);
}
@@ -188,18 +178,19 @@ public class CommandListener implements CommandExecutor {
cmds.add (p.languageReader.get("Help_UnLabel"));
}
- if (sender.hasPermission("brewery.cmd.copy")) {
- cmds.add (p.languageReader.get("Help_Copy"));
- }
-
- if (sender.hasPermission("brewery.cmd.delete")) {
- cmds.add (p.languageReader.get("Help_Delete"));
- }
-
if (sender.hasPermission("brewery.cmd.infoOther")) {
cmds.add (p.languageReader.get("Help_InfoOther"));
}
+ if (sender.hasPermission("brewery.cmd.create")) {
+ cmds.add(p.languageReader.get("Help_Create"));
+ }
+
+ if (sender.hasPermission("brewery.cmd.reload")) {
+ cmds.add(p.languageReader.get("Help_Configname"));
+ cmds.add(p.languageReader.get("Help_Reload"));
+ }
+
if (sender.hasPermission("brewery.cmd.wakeup")) {
cmds.add(p.languageReader.get("Help_Wakeup"));
cmds.add(p.languageReader.get("Help_WakeupList"));
@@ -209,21 +200,16 @@ public class CommandListener implements CommandExecutor {
cmds.add(p.languageReader.get("Help_WakeupRemove"));
}
- if (sender.hasPermission("brewery.cmd.reload")) {
- cmds.add(p.languageReader.get("Help_Configname"));
- cmds.add(p.languageReader.get("Help_Reload"));
- }
-
- if (sender.hasPermission("brewery.cmd.persist")) {
- cmds.add(p.languageReader.get("Help_Persist"));
- }
-
if (sender.hasPermission("brewery.cmd.static")) {
cmds.add(p.languageReader.get("Help_Static"));
}
- if (sender.hasPermission("brewery.cmd.create")) {
- cmds.add(p.languageReader.get("Help_Create"));
+ if (sender.hasPermission("brewery.cmd.copy")) {
+ cmds.add (p.languageReader.get("Help_Copy"));
+ }
+
+ if (sender.hasPermission("brewery.cmd.delete")) {
+ cmds.add (p.languageReader.get("Help_Delete"));
}
return cmds;
@@ -328,7 +314,7 @@ public class CommandListener implements CommandExecutor {
if (player != null) {
bPlayer.drinkCap(player);
} else {
- if (!BPlayer.overdrinkKick) {
+ if (!BConfig.overdrinkKick) {
bPlayer.setData(100, 0);
}
}
@@ -365,162 +351,138 @@ public class CommandListener implements CommandExecutor {
}
public void cmdItemName(CommandSender sender) {
- if (sender instanceof Player) {
-
- Player player = (Player) sender;
- ItemStack hand = P.use1_9 ? player.getInventory().getItemInMainHand() : player.getItemInHand();
- if (hand != null) {
- p.msg(sender, p.languageReader.get("CMD_Configname", hand.getType().name().toLowerCase(Locale.ENGLISH)));
- } else {
- p.msg(sender, p.languageReader.get("CMD_Configname_Error"));
- }
-
- } else {
+ if (!(sender instanceof Player)) {
p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
+ return;
}
+
+ Player player = (Player) sender;
+ ItemStack hand = P.use1_9 ? player.getInventory().getItemInMainHand() : player.getItemInHand();
+ if (hand != null) {
+ p.msg(sender, p.languageReader.get("CMD_Configname", hand.getType().name().toLowerCase(Locale.ENGLISH)));
+ } else {
+ p.msg(sender, p.languageReader.get("CMD_Configname_Error"));
+ }
+
}
- @SuppressWarnings("deprecation")
+ @Deprecated
public void cmdCopy(CommandSender sender, int count) {
- if (sender instanceof Player) {
- if (count < 1 || count > 36) {
- p.msg(sender, p.languageReader.get("Etc_Usage"));
- p.msg(sender, p.languageReader.get("Help_Copy"));
+ if (!(sender instanceof Player)) {
+ p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
+ return;
+ }
+ if (count < 1 || count > 36) {
+ p.msg(sender, p.languageReader.get("Etc_Usage"));
+ p.msg(sender, p.languageReader.get("Help_Copy"));
+ return;
+ }
+ Player player = (Player) sender;
+ ItemStack hand = player.getItemInHand();
+ if (hand != null) {
+ if (Brew.isBrew(hand)) {
+ while (count > 0) {
+ ItemStack item = hand.clone();
+ if (!(player.getInventory().addItem(item)).isEmpty()) {
+ p.msg(sender, p.languageReader.get("CMD_Copy_Error", "" + count));
+ return;
+ }
+ count--;
+ }
return;
}
- Player player = (Player) sender;
- ItemStack hand = player.getItemInHand();
- if (hand != null) {
- Brew brew = Brew.get(hand);
- if (brew != null) {
- while (count > 0) {
- ItemStack item = brew.copy(hand);
- if (!(player.getInventory().addItem(item)).isEmpty()) {
- p.msg(sender, p.languageReader.get("CMD_Copy_Error", "" + count));
- return;
- }
- count--;
- }
- if (brew.isPersistent()) {
- p.msg(sender, p.languageReader.get("CMD_CopyNotPersistent"));
- }
- return;
- }
- }
-
- p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
-
- } else {
- p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
}
+ p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
+
}
- @SuppressWarnings("deprecation")
+ @Deprecated
public void cmdDelete(CommandSender sender) {
- if (sender instanceof Player) {
- Player player = (Player) sender;
- ItemStack hand = player.getItemInHand();
- if (hand != null) {
- Brew brew = Brew.get(hand);
- if (brew != null) {
- if (brew.isPersistent()) {
- p.msg(sender, p.languageReader.get("CMD_PersistRemove"));
- } else {
- brew.remove(hand);
- player.setItemInHand(new ItemStack(Material.AIR));
- }
- return;
- }
- }
- p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
- } else {
+ if (!(sender instanceof Player)) {
p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
+ return;
}
-
- }
-
- @SuppressWarnings("deprecation")
- public void cmdPersist(CommandSender sender) {
-
- if (sender instanceof Player) {
- Player player = (Player) sender;
- ItemStack hand = player.getItemInHand();
- if (hand != null) {
- Brew brew = Brew.get(hand);
- if (brew != null) {
- if (brew.isPersistent()) {
- brew.removePersistence();
- brew.setStatic(false, hand);
- p.msg(sender, p.languageReader.get("CMD_UnPersist"));
- } else {
- brew.makePersistent();
- brew.setStatic(true, hand);
- p.msg(sender, p.languageReader.get("CMD_Persistent"));
- }
- brew.touch();
- return;
- }
+ Player player = (Player) sender;
+ ItemStack hand = player.getItemInHand();
+ if (hand != null) {
+ if (Brew.isBrew(hand)) {
+ player.setItemInHand(new ItemStack(Material.AIR));
+ return;
}
- p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
- } else {
- p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
}
+ p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
}
@SuppressWarnings("deprecation")
public void cmdStatic(CommandSender sender) {
- if (sender instanceof Player) {
- Player player = (Player) sender;
- ItemStack hand = player.getItemInHand();
- if (hand != null) {
- Brew brew = Brew.get(hand);
- if (brew != null) {
- if (brew.isStatic()) {
- if (!brew.isPersistent()) {
- brew.setStatic(false, hand);
- p.msg(sender, p.languageReader.get("CMD_NonStatic"));
- } else {
- p.msg(sender, p.languageReader.get("Error_PersistStatic"));
- }
- } else {
- brew.setStatic(true, hand);
- p.msg(sender, p.languageReader.get("CMD_Static"));
- }
- brew.touch();
+ if (!(sender instanceof Player)) {
+ p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
+ return;
+ }
+ Player player = (Player) sender;
+ ItemStack hand = player.getItemInHand();
+ if (hand != null) {
+ Brew brew = Brew.get(hand);
+ if (brew != null) {
+ if (brew.isStatic()) {
+ brew.setStatic(false, hand);
+ p.msg(sender, p.languageReader.get("CMD_NonStatic"));
+ } else {
+ brew.setStatic(true, hand);
+ p.msg(sender, p.languageReader.get("CMD_Static"));
+ }
+ brew.touch();
+ ItemMeta meta = hand.getItemMeta();
+ assert meta != null;
+ BrewModifyEvent modifyEvent = new BrewModifyEvent(brew, meta, BrewModifyEvent.Type.STATIC);
+ P.p.getServer().getPluginManager().callEvent(modifyEvent);
+ if (modifyEvent.isCancelled()) {
return;
}
+ brew.save(meta);
+ hand.setItemMeta(meta);
+ return;
}
- p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
- } else {
- p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
}
+ p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
}
@SuppressWarnings("deprecation")
public void cmdUnlabel(CommandSender sender) {
- if (sender instanceof Player) {
- Player player = (Player) sender;
- ItemStack hand = player.getItemInHand();
- if (hand != null) {
- Brew brew = Brew.get(hand);
- if (brew != null) {
- brew.unLabel(hand);
- brew.touch();
- p.msg(sender, p.languageReader.get("CMD_UnLabel"));
+ if (!(sender instanceof Player)) {
+ p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
+ return;
+ }
+ Player player = (Player) sender;
+ ItemStack hand = player.getItemInHand();
+ if (hand != null) {
+ Brew brew = Brew.get(hand);
+ if (brew != null) {
+ ItemMeta origMeta = hand.getItemMeta();
+ brew.unLabel(hand);
+ brew.touch();
+ ItemMeta meta = hand.getItemMeta();
+ assert meta != null;
+ BrewModifyEvent modifyEvent = new BrewModifyEvent(brew, meta, BrewModifyEvent.Type.UNLABEL);
+ P.p.getServer().getPluginManager().callEvent(modifyEvent);
+ if (modifyEvent.isCancelled()) {
+ hand.setItemMeta(origMeta);
return;
}
+ brew.save(meta);
+ hand.setItemMeta(meta);
+ p.msg(sender, p.languageReader.get("CMD_UnLabel"));
+ return;
}
- p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
- } else {
- p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
}
+ p.msg(sender, p.languageReader.get("Error_ItemNotPotion"));
}
@@ -555,51 +517,56 @@ public class CommandListener implements CommandExecutor {
player = p.getServer().getPlayer(pName);
}
- if (sender instanceof Player || player != null) {
- if (player == null) {
- player = ((Player) sender);
- }
- int stringLength = args.length - 1;
- if (pName != null) {
- stringLength--;
- }
- if (hasQuality) {
- stringLength--;
- }
-
- String name;
- if (stringLength > 1) {
- StringBuilder builder = new StringBuilder(args[1]);
-
- for (int i = 2; i < stringLength + 1; i++) {
- builder.append(" ").append(args[i]);
- }
- name = builder.toString();
- } else {
- name = args[1];
- }
-
- if (player.getInventory().firstEmpty() == -1) {
- p.msg(sender, p.languageReader.get("CMD_Copy_Error", "1"));
- return;
- }
-
- BRecipe recipe = null;
- for (BRecipe r : BIngredients.recipes) {
- if (r.hasName(name)) {
- recipe = r;
- break;
- }
- }
- if (recipe != null) {
- player.getInventory().addItem(recipe.create(quality));
- } else {
- p.msg(sender, p.languageReader.get("Error_NoBrewName", name));
- }
-
- } else {
+ if (!(sender instanceof Player) && player == null) {
p.msg(sender, p.languageReader.get("Error_PlayerCommand"));
+ return;
}
+
+ if (player == null) {
+ player = ((Player) sender);
+ }
+ int stringLength = args.length - 1;
+ if (pName != null) {
+ stringLength--;
+ }
+ if (hasQuality) {
+ stringLength--;
+ }
+
+ String name;
+ if (stringLength > 1) {
+ StringBuilder builder = new StringBuilder(args[1]);
+
+ for (int i = 2; i < stringLength + 1; i++) {
+ builder.append(" ").append(args[i]);
+ }
+ name = builder.toString();
+ } else {
+ name = args[1];
+ }
+
+ if (player.getInventory().firstEmpty() == -1) {
+ p.msg(sender, p.languageReader.get("CMD_Copy_Error", "1"));
+ return;
+ }
+
+ BRecipe recipe = null;
+ for (BRecipe r : BRecipe.getAllRecipes()) {
+ if (r.hasName(name)) {
+ recipe = r;
+ break;
+ }
+ }
+ if (recipe != null) {
+ ItemStack item = recipe.create(quality);
+ if (item != null) {
+ player.getInventory().addItem(item);
+ p.msg(sender, p.languageReader.get("CMD_Created"));
+ }
+ } else {
+ p.msg(sender, p.languageReader.get("Error_NoBrewName", name));
+ }
+
}
}
diff --git a/src/com/dre/brewery/listeners/EntityListener.java b/src/com/dre/brewery/listeners/EntityListener.java
index 0947802..6fd00b9 100644
--- a/src/com/dre/brewery/listeners/EntityListener.java
+++ b/src/com/dre/brewery/listeners/EntityListener.java
@@ -1,51 +1,48 @@
package com.dre.brewery.listeners;
-import java.util.ListIterator;
-
-import org.bukkit.Material;
-import org.bukkit.block.Block;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.entity.EntityChangeBlockEvent;
-import org.bukkit.event.entity.EntityExplodeEvent;
-import org.bukkit.event.entity.ItemDespawnEvent;
-import org.bukkit.event.entity.EntityCombustEvent;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.EntityType;
-import org.bukkit.entity.Item;
-import org.bukkit.inventory.ItemStack;
-
import com.dre.brewery.Barrel;
import com.dre.brewery.Brew;
import com.dre.brewery.P;
-import com.dre.brewery.integration.LWCBarrel;
+import com.dre.brewery.api.events.barrel.BarrelDestroyEvent;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Item;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityChangeBlockEvent;
+import org.bukkit.event.entity.EntityCombustEvent;
+import org.bukkit.event.entity.EntityExplodeEvent;
+import org.bukkit.event.entity.ItemDespawnEvent;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
public class EntityListener implements Listener {
- // Remove the Potion from Brew when it despawns
+ // Legacy Brew removal
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemDespawn(ItemDespawnEvent event) {
+ if (Brew.noLegacy()) return;
ItemStack item = event.getEntity().getItemStack();
if (item.getType() == Material.POTION) {
- Brew brew = Brew.get(item);
- if (brew != null) {
- brew.remove(item);
- }
+ Brew.removeLegacy(item);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityCombust(EntityCombustEvent event) {
+ if (Brew.noLegacy()) return;
Entity entity = event.getEntity();
if (entity.getType() == EntityType.DROPPED_ITEM) {
if (entity instanceof Item) {
ItemStack item = ((Item) entity).getItemStack();
if (item.getType() == Material.POTION) {
- Brew brew = Brew.get(item);
- if (brew != null) {
- brew.remove(item);
- }
+ Brew.removeLegacy(item);
}
}
}
@@ -56,31 +53,33 @@ public class EntityListener implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onExplode(EntityExplodeEvent event) {
ListIterator iter = event.blockList().listIterator();
- Barrel barrel = null;
- boolean removedBarrel = false;
- while (iter.hasNext()) {
- Block block = iter.next();
- if (barrel == null || !barrel.hasBlock(block)) {
- barrel = Barrel.get(block);
- removedBarrel = false;
- }
- if (!removedBarrel) {
- if (barrel != null) {
- if (P.p.useLWC) {
- try {
- if (LWCBarrel.blockExplosion(barrel, block)) {
- iter.remove();
- } else {
- removedBarrel = true;
- }
- } catch (Exception e) {
- P.p.errorLog("Failed to Check LWC on Barrel Explosion!");
- e.printStackTrace();
- removedBarrel = true;
+ if (!iter.hasNext()) return;
+ List breakEvents = new ArrayList<>(6);
+ Block block;
+ blocks: while (iter.hasNext()) {
+ block = iter.next();
+ if (!breakEvents.isEmpty()) {
+ for (BarrelDestroyEvent breakEvent : breakEvents) {
+ if (breakEvent.getBarrel().hasBlock(block)) {
+ if (breakEvent.isCancelled()) {
+ iter.remove();
}
+ continue blocks;
}
}
}
+ Barrel barrel = Barrel.get(block);
+ if (barrel != null) {
+ BarrelDestroyEvent breakEvent = new BarrelDestroyEvent(barrel, block, BarrelDestroyEvent.Reason.EXPLODED, null);
+ // Listened to by LWCBarrel (IntegrationListener)
+ P.p.getServer().getPluginManager().callEvent(breakEvent);
+ breakEvents.add(breakEvent);
+ if (breakEvent.isCancelled()) {
+ iter.remove();
+ } else {
+ barrel.remove(block, null, true);
+ }
+ }
}
}
diff --git a/src/com/dre/brewery/listeners/InventoryListener.java b/src/com/dre/brewery/listeners/InventoryListener.java
index 7df7504..a27283f 100644
--- a/src/com/dre/brewery/listeners/InventoryListener.java
+++ b/src/com/dre/brewery/listeners/InventoryListener.java
@@ -1,63 +1,36 @@
package com.dre.brewery.listeners;
-import com.dre.brewery.BPlayer;
-import com.dre.brewery.BRecipe;
+import com.dre.brewery.BDistiller;
import com.dre.brewery.Barrel;
import com.dre.brewery.Brew;
import com.dre.brewery.MCBarrel;
import com.dre.brewery.P;
-import com.dre.brewery.integration.LogBlockBarrel;
-import org.bukkit.Bukkit;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.lore.BrewLore;
import org.bukkit.Material;
-import org.bukkit.Sound;
-import org.bukkit.SoundCategory;
-import org.bukkit.block.Block;
-import org.bukkit.block.BlockState;
-import org.bukkit.block.BrewingStand;
import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
-import org.bukkit.event.inventory.BrewEvent;
-import org.bukkit.event.inventory.ClickType;
-import org.bukkit.event.inventory.InventoryAction;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.inventory.InventoryCloseEvent;
-import org.bukkit.event.inventory.InventoryDragEvent;
-import org.bukkit.event.inventory.InventoryOpenEvent;
-import org.bukkit.event.inventory.InventoryPickupItemEvent;
-import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.event.inventory.*;
import org.bukkit.inventory.BrewerInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
-import org.bukkit.scheduler.BukkitRunnable;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.UUID;
-/**
- * Updated for 1.9 to replicate the "Brewing" process for distilling.
- * Because of how metadata has changed, the brewer no longer triggers as previously described.
- * So, I've added some event tracking and manual forcing of the brewing "animation" if the
- * set of ingredients in the brewer can be distilled.
- * Nothing here should interfere with vanilla brewing.
- *
- * @author ProgrammerDan (1.9 distillation update only)
- */
public class InventoryListener implements Listener {
/* === Recreating manually the prior BrewEvent behavior. === */
private HashSet trackedBrewmen = new HashSet<>();
- private HashMap trackedBrewers = new HashMap<>();
- private static final int DISTILLTIME = 400;
/**
* Start tracking distillation for a person when they open the brewer window.
- * @param event
*/
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBrewerOpen(InventoryOpenEvent event) {
@@ -72,7 +45,6 @@ public class InventoryListener implements Listener {
/**
* Stop tracking distillation for a person when they close the brewer window.
- * @param event
*/
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBrewerClose(InventoryCloseEvent event) {
@@ -96,14 +68,13 @@ public class InventoryListener implements Listener {
/**
* Clicking can either start or stop the new brew distillation tracking.
- * Note that server restart will halt any ongoing brewing processes and
+ * Note that server restart will halt any ongoing brewing processes and
* they will _not_ restart until a new click event.
- *
- * @param event the Click event.
*/
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBrewerClick(InventoryClickEvent event) {
if (!P.use1_9) return;
+
HumanEntity player = event.getWhoClicked();
Inventory inv = event.getInventory();
if (player == null || !(inv instanceof BrewerInventory)) return;
@@ -114,171 +85,22 @@ public class InventoryListener implements Listener {
if (InventoryType.BREWING != inv.getType()) return;
if (event.getAction() == InventoryAction.NOTHING) return; // Ignore clicks that do nothing
- BrewerInventory brewer = (BrewerInventory) inv;
- final Block brewery = brewer.getHolder().getBlock();
-
- // If we were already tracking the brewer, cancel any ongoing event due to the click.
- Integer curTask = trackedBrewers.get(brewery);
- if (curTask != null) {
- Bukkit.getScheduler().cancelTask(curTask); // cancel prior
- brewer.getHolder().setBrewingTime(0); // Fixes brewing continuing without fuel for normal potions
- brewer.getHolder().update();
- }
- final int fuel = brewer.getHolder().getFuelLevel();
-
- // Now check if we should bother to track it.
- trackedBrewers.put(brewery, new BukkitRunnable() {
- private int runTime = -1;
- private int brewTime = -1;
- @Override
- public void run() {
- BlockState now = brewery.getState();
- if (now instanceof BrewingStand) {
- BrewingStand stand = (BrewingStand) now;
- if (brewTime == -1) { // only check at the beginning (and end) for distillables
- switch (hasCustom(stand.getInventory())) {
- case 1:
- // Custom potion but not for distilling. Stop any brewing and cancel this task
- if (stand.getBrewingTime() > 0) {
- if (P.use1_11) {
- // The trick below doesnt work in 1.11, but we dont need it anymore
- // This should only happen with older Brews that have been made with the old Potion Color System
- stand.setBrewingTime(Short.MAX_VALUE);
- } else {
- // Brewing time is sent and stored as short
- // This sends a negative short value to the Client
- // In the client the Brewer will look like it is not doing anything
- stand.setBrewingTime(Short.MAX_VALUE << 1);
- }
- stand.setFuelLevel(fuel);
- stand.update();
- }
- case 0:
- // No custom potion, cancel and ignore
- this.cancel();
- trackedBrewers.remove(brewery);
- P.p.debugLog("nothing to distill");
- return;
- default:
- runTime = getLongestDistillTime(stand.getInventory());
- brewTime = runTime;
- P.p.debugLog("using brewtime: " + runTime);
-
- }
- }
-
- brewTime--; // count down.
- stand.setBrewingTime((int) ((float) brewTime / ((float) runTime / (float) DISTILLTIME)) + 1);
-
- if (brewTime <= 1) { // Done!
- stand.setBrewingTime(0);
- stand.update();
- BrewerInventory brewer = stand.getInventory();
- if (!runDistill(brewer)) {
- this.cancel();
- trackedBrewers.remove(brewery);
- P.p.debugLog("All done distilling");
- } else {
- brewTime = -1; // go again.
- P.p.debugLog("Can distill more! Continuing.");
- }
- } else {
- stand.update();
- }
- } else {
- this.cancel();
- trackedBrewers.remove(brewery);
- P.p.debugLog("The block was replaced; not a brewing stand.");
- }
- }
- }.runTaskTimer(P.p, 2L, 1L).getTaskId());
- }
-
- // Returns a Brew or null for every Slot in the BrewerInventory
- private Brew[] getDistillContents(BrewerInventory inv) {
- ItemStack item;
- Brew[] contents = new Brew[3];
- for (int slot = 0; slot < 3; slot++) {
- item = inv.getItem(slot);
- if (item != null) {
- contents[slot] = Brew.get(item);
- }
- }
- return contents;
- }
-
- private byte hasCustom(BrewerInventory brewer) {
- ItemStack item = brewer.getItem(3); // ingredient
- boolean glowstone = (item != null && Material.GLOWSTONE_DUST == item.getType()); // need dust in the top slot.
- byte customFound = 0;
- for (Brew brew : getDistillContents(brewer)) {
- if (brew != null) {
- if (!glowstone) {
- return 1;
- }
- if (brew.canDistill()) {
- return 2;
- } else {
- customFound = 1;
- }
- }
- }
- return customFound;
+ BDistiller.distillerClick(event);
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBrew(BrewEvent event) {
if (P.use1_9) {
- if (hasCustom(event.getContents()) != 0) {
+ if (BDistiller.hasBrew(event.getContents(), BDistiller.getDistillContents(event.getContents())) != 0) {
event.setCancelled(true);
}
return;
}
- if (runDistill(event.getContents())) {
+ if (BDistiller.runDistill(event.getContents(), BDistiller.getDistillContents(event.getContents()))) {
event.setCancelled(true);
}
}
- private boolean runDistill(BrewerInventory inv) {
- boolean custom = false;
- Brew[] contents = getDistillContents(inv);
- for (int slot = 0; slot < 3; slot++) {
- if (contents[slot] == null) continue;
- if (contents[slot].canDistill()) {
- // is further distillable
- custom = true;
- } else {
- contents[slot] = null;
- }
- }
- if (custom) {
- Brew.distillAll(inv, contents);
- return true;
- }
- return false;
- }
-
- private int getLongestDistillTime(BrewerInventory inv) {
- int bestTime = 0;
- int time;
- Brew[] contents = getDistillContents(inv);
- for (int slot = 0; slot < 3; slot++) {
- if (contents[slot] == null) continue;
- time = contents[slot].getDistillTimeNextRun();
- if (time == 0) {
- // Undefined Potion needs 40 seconds
- time = 800;
- }
- if (time > bestTime) {
- bestTime = time;
- }
- }
- if (bestTime > 0) {
- return bestTime;
- }
- return 800;
- }
-
// Clicked a Brew somewhere, do some updating
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = false)
public void onInventoryClickLow(InventoryClickEvent event) {
@@ -286,18 +108,33 @@ public class InventoryListener implements Listener {
ItemStack item = event.getCurrentItem();
if (item.hasItemMeta()) {
PotionMeta potion = ((PotionMeta) item.getItemMeta());
- Brew brew = Brew.get(potion);
- if (brew != null) {
- // convert potions from 1.8 to 1.9 for color and to remove effect descriptions
- if (P.use1_9 && !potion.hasItemFlag(ItemFlag.HIDE_POTION_EFFECTS)) {
- BRecipe recipe = brew.getCurrentRecipe();
- if (recipe != null) {
- Brew.removeEffects(potion);
- Brew.PotionColor.fromString(recipe.getColor()).colorBrew(potion, item, brew.canDistill());
- item.setItemMeta(potion);
+ assert potion != null;
+ if (P.use1_11) {
+ // Convert potions from 1.10 to 1.11 for new color
+ if (potion.getColor() == null) {
+ Brew brew = Brew.get(potion);
+ if (brew != null) {
+ brew.convertPre1_11(item);
}
}
- brew.touch();
+ } else {
+ // convert potions from 1.8 to 1.9 for color and to remove effect descriptions
+ if (P.use1_9 && !potion.hasItemFlag(ItemFlag.HIDE_POTION_EFFECTS)) {
+ Brew brew = Brew.get(potion);
+ if (brew != null) {
+ brew.convertPre1_9(item);
+ }
+ }
+ }
+ //long t1 = System.nanoTime();
+ Brew brew = Brew.get(item);
+ //long t2 = System.nanoTime();
+ if (brew != null) {
+ P.p.log(brew.toString());
+
+ //P.p.log("Brew.get(): " + (t2 - t1) / 1000000.0 + "ms");
+
+ //brew.touch();
}
}
}
@@ -315,15 +152,28 @@ public class InventoryListener implements Listener {
}
ItemStack item = event.getCurrentItem();
- if (item != null) {
- if (item.getType() == Material.POTION) {
- if (item.hasItemMeta()) {
- PotionMeta meta = (PotionMeta) item.getItemMeta();
- Brew brew = Brew.get(meta);
- if (brew != null) {
- if (Brew.hasColorLore(meta)) {
- brew.convertLore(meta, false);
- item.setItemMeta(meta);
+ if (item != null && item.getType() == Material.POTION && item.hasItemMeta()) {
+ PotionMeta meta = (PotionMeta) item.getItemMeta();
+ assert meta != null;
+ Brew brew = Brew.get(meta);
+ if (brew != null) {
+ BrewLore lore = null;
+ if (BrewLore.hasColorLore(meta)) {
+ lore = new BrewLore(brew, meta);
+ lore.convertLore(false);
+ } else if (!BConfig.alwaysShowAlc && event.getInventory().getType() == InventoryType.BREWING) {
+ lore = new BrewLore(brew, meta);
+ lore.updateAlc(false);
+ }
+ if (lore != null) {
+ lore.write();
+ item.setItemMeta(meta);
+ if (event.getWhoClicked() instanceof Player) {
+ switch (event.getAction()) {
+ case MOVE_TO_OTHER_INVENTORY:
+ case HOTBAR_SWAP:
+ // Fix a Graphical glitch of item still showing colors until clicking it
+ P.p.getServer().getScheduler().runTask(P.p, () -> ((Player) event.getWhoClicked()).updateInventory());
}
}
}
@@ -332,7 +182,7 @@ public class InventoryListener implements Listener {
}
// Check if the player tries to add more than the allowed amount of brews into an mc-barrel
- @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onInventoryClickMCBarrel(InventoryClickEvent event) {
if (!P.use1_14) return;
if (event.getInventory().getType() != InventoryType.BARREL) return;
@@ -351,6 +201,27 @@ public class InventoryListener implements Listener {
//public static boolean opening = false;
+ @SuppressWarnings("deprecation")
+ @EventHandler(ignoreCancelled = false)
+ public void onInventoryOpenLegacyConvert(InventoryOpenEvent event) {
+ if (Brew.noLegacy()) {
+ return;
+ }
+ if (event.getInventory().getType() == InventoryType.PLAYER) {
+ return;
+ }
+ for (ItemStack item : event.getInventory().getContents()) {
+ if (item != null && item.getType() == Material.POTION) {
+ int uid = Brew.getUID(item);
+ // Check if the uid exists first, otherwise it will log that it can't find the id
+ if (uid < 0 && Brew.legacyPotions.containsKey(uid)) {
+ // This will convert the Brew
+ Brew.get(item);
+ }
+ }
+ }
+ }
+
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryOpen(InventoryOpenEvent event) {
if (!P.use1_14) return;
@@ -383,38 +254,53 @@ public class InventoryListener implements Listener {
// block the pickup of items where getPickupDelay is > 1000 (puke)
@EventHandler(ignoreCancelled = true)
- public void onInventoryPickupItem(InventoryPickupItemEvent event){
- if (event.getItem().getPickupDelay() > 1000 && event.getItem().getItemStack().getType() == BPlayer.pukeItem) {
+ public void onHopperPickupPuke(InventoryPickupItemEvent event){
+ if (event.getItem().getPickupDelay() > 1000 && event.getItem().getItemStack().getType() == BConfig.pukeItem) {
event.setCancelled(true);
}
}
+ // Block taking out items from running distillers,
+ // Convert Color Lore from MC Barrels back into normal color on taking out
+ @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
+ public void onHopperMove(InventoryMoveItemEvent event){
+ if (event.getSource() instanceof BrewerInventory) {
+ if (BDistiller.isTrackingDistiller(((BrewerInventory) event.getSource()).getHolder().getBlock())) {
+ event.setCancelled(true);
+ }
+ return;
+ }
+
+ if (!P.use1_14) return;
+
+ if (event.getSource().getType() == InventoryType.BARREL) {
+ ItemStack item = event.getItem();
+ if (item.getType() == Material.POTION && Brew.isBrew(item)) {
+ PotionMeta meta = (PotionMeta) item.getItemMeta();
+ assert meta != null;
+ if (BrewLore.hasColorLore(meta)) {
+ // has color lore, convert lore back to normal
+ Brew brew = Brew.get(meta);
+ if (brew != null) {
+ BrewLore lore = new BrewLore(brew, meta);
+ lore.convertLore(false);
+ lore.write();
+ item.setItemMeta(meta);
+ event.setItem(item);
+ }
+ }
+ }
+ }
+ }
+
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
- if (P.p.useLB) {
- if (event.getInventory().getHolder() instanceof Barrel) {
- try {
- LogBlockBarrel.closeBarrel(event.getPlayer(), event.getInventory());
- } catch (Exception e) {
- P.p.errorLog("Failed to Log Barrel to LogBlock!");
- P.p.errorLog("Brewery was tested with version 1.94 of LogBlock!");
- e.printStackTrace();
- }
- }
- }
-
if (!P.use1_14) return;
// Barrel Closing Sound
if (event.getInventory().getHolder() instanceof Barrel) {
Barrel barrel = ((Barrel) event.getInventory().getHolder());
- float randPitch = (float) (Math.random() * 0.1);
- if (barrel.isLarge()) {
- barrel.getSpigot().getWorld().playSound(barrel.getSpigot().getLocation(), Sound.BLOCK_BARREL_CLOSE, SoundCategory.BLOCKS, 0.5f, 0.5f + randPitch);
- barrel.getSpigot().getWorld().playSound(barrel.getSpigot().getLocation(), Sound.ITEM_BUCKET_EMPTY, SoundCategory.BLOCKS, 0.2f, 0.6f + randPitch);
- } else {
- barrel.getSpigot().getWorld().playSound(barrel.getSpigot().getLocation(), Sound.BLOCK_BARREL_CLOSE, SoundCategory.BLOCKS, 0.5f, 0.8f + randPitch);
- }
+ barrel.playClosingSound();
}
// Check for MC Barrel
diff --git a/src/com/dre/brewery/listeners/PlayerListener.java b/src/com/dre/brewery/listeners/PlayerListener.java
index e902122..ab1d99c 100644
--- a/src/com/dre/brewery/listeners/PlayerListener.java
+++ b/src/com/dre/brewery/listeners/PlayerListener.java
@@ -1,13 +1,12 @@
package com.dre.brewery.listeners;
import com.dre.brewery.*;
+import com.dre.brewery.filedata.BConfig;
import com.dre.brewery.filedata.UpdateChecker;
+import com.dre.brewery.utility.LegacyUtil;
import org.bukkit.GameMode;
import org.bukkit.Material;
-import org.bukkit.Sound;
-import org.bukkit.SoundCategory;
import org.bukkit.block.Block;
-import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -18,219 +17,93 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-
public class PlayerListener implements Listener {
- public static boolean openEverywhere;
- private static Set interacted = new HashSet<>();
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
Block clickedBlock = event.getClickedBlock();
+ if (clickedBlock == null) return;
- if (clickedBlock != null) {
- if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
- Player player = event.getPlayer();
- if (!player.isSneaking()) {
- Material type = clickedBlock.getType();
+ if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
- // Interacting with a Cauldron
- if (type == Material.CAULDRON) {
- Material materialInHand = event.getMaterial();
- ItemStack item = event.getItem();
+ Player player = event.getPlayer();
+ if (player.isSneaking()) return;
- if (materialInHand == null || materialInHand == Material.BUCKET) {
- return;
+ Material type = clickedBlock.getType();
- } else if (materialInHand == LegacyUtil.CLOCK) {
- BCauldron.printTime(player, clickedBlock);
- return;
+ // Interacting with a Cauldron
+ if (type == Material.CAULDRON) {
+ // Handle the Cauldron Interact
+ // The Event might get cancelled in here
+ BCauldron.clickCauldron(event);
+ return;
+ }
- // fill a glass bottle with potion
- } else if (materialInHand == Material.GLASS_BOTTLE) {
- if (player.getInventory().firstEmpty() != -1 || item.getAmount() == 1) {
- if (BCauldron.fill(player, clickedBlock)) {
- event.setCancelled(true);
- if (player.hasPermission("brewery.cauldron.fill")) {
- if (item.getAmount() > 1) {
- item.setAmount(item.getAmount() - 1);
- } else {
- setItemInHand(event, Material.AIR, false);
- }
- }
- }
- } else {
- event.setCancelled(true);
- }
- return;
+ // Do not process Off Hand for Barrel interaction
+ if (P.use1_9 && event.getHand() != EquipmentSlot.HAND) {
+ return;
+ }
- // reset cauldron when refilling to prevent unlimited source of potions
- } else if (materialInHand == Material.WATER_BUCKET) {
- if (!P.use1_9) {
- // We catch >=1.9 cases in the Cauldron Listener
- if (LegacyUtil.getFillLevel(clickedBlock) == 1) {
- // will only remove when existing
- BCauldron.remove(clickedBlock);
- }
- }
- return;
- }
-
- // Check if fire alive below cauldron when adding ingredients
- Block down = clickedBlock.getRelative(BlockFace.DOWN);
- if (LegacyUtil.isFireForCauldron(down)) {
-
- event.setCancelled(true);
- boolean handSwap = false;
-
- // Interact event is called twice!!!?? in 1.9, once for each hand.
- // Certain Items in Hand cause one of them to be cancelled or not called at all sometimes.
- // We mark if a player had the event for the main hand
- // If not, we handle the main hand in the event for the off hand
- if (P.use1_9) {
- if (event.getHand() == EquipmentSlot.HAND) {
- final UUID id = player.getUniqueId();
- interacted.add(id);
- P.p.getServer().getScheduler().runTask(P.p, new Runnable() {
- @Override
- public void run() {
- interacted.remove(id);
- }
- });
- } else if (event.getHand() == EquipmentSlot.OFF_HAND) {
- if (!interacted.remove(player.getUniqueId())) {
- item = player.getInventory().getItemInMainHand();
- if (item != null && item.getType() != Material.AIR) {
- materialInHand = item.getType();
- handSwap = true;
- } else {
- item = event.getItem();
- }
- }
- }
- }
- if (item == null) return;
-
- // add ingredient to cauldron that meet the previous conditions
- if (BIngredients.possibleIngredients.contains(materialInHand)) {
-
- if (player.hasPermission("brewery.cauldron.insert")) {
- if (BCauldron.ingredientAdd(clickedBlock, item)) {
- boolean isBucket = item.getType().equals(Material.WATER_BUCKET)
- || item.getType().equals(Material.LAVA_BUCKET)
- || item.getType().equals(Material.MILK_BUCKET);
- if (item.getAmount() > 1) {
- item.setAmount(item.getAmount() - 1);
-
- if (isBucket) {
- BCauldron.giveItem(player, new ItemStack(Material.BUCKET));
- }
- } else {
- if (isBucket) {
- setItemInHand(event, Material.BUCKET, handSwap);
- } else {
- setItemInHand(event, Material.AIR, handSwap);
- }
- }
- }
- } else {
- P.p.msg(player, P.p.languageReader.get("Perms_NoCauldronInsert"));
- }
- }
- }
- return;
- }
-
- if (P.use1_9 && event.getHand() != EquipmentSlot.HAND) {
- return;
- }
-
- // Access a Barrel
- Barrel barrel = null;
- if (LegacyUtil.isWoodPlanks(type)) {
- if (openEverywhere) {
- barrel = Barrel.get(clickedBlock);
- }
- } else if (LegacyUtil.isWoodStairs(type)) {
- for (Barrel barrel2 : Barrel.barrels) {
- if (barrel2.hasStairsBlock(clickedBlock)) {
- if (openEverywhere || !barrel2.isLarge()) {
- barrel = barrel2;
- }
- break;
- }
- }
- } else if (LegacyUtil.isFence(type) || LegacyUtil.isSign(type)) {
- barrel = Barrel.getBySpigot(clickedBlock);
- }
-
- if (barrel != null) {
- event.setCancelled(true);
-
- if (!barrel.hasPermsOpen(player, event)) {
- return;
- }
-
- barrel.open(player);
-
- if (P.use1_14) {
-
- // When right clicking a normal Block in 1.14 with a potion or any edible item in hand,
- // even when cancelled the consume animation will continue playing while opening the Barrel inventory.
- // The Animation and sound will play endlessly while the inventory is open, though no item is consumed.
- // This seems to be a client bug.
- // This workaround switches the currently selected slot to another for a short time, it needs to be a slot with a different item in it.
- // This seems to make the client stop animating a consumption
- // If there is a better way to do this please let me know
- Material hand = event.getMaterial();
- if ((hand == Material.POTION || hand.isEdible()) && !LegacyUtil.isSign(type)) {
- PlayerInventory inv = player.getInventory();
- final int held = inv.getHeldItemSlot();
- int useSlot = -1;
- for (int i = 0; i < 9; i++) {
- ItemStack item = inv.getItem(i);
- if (item == null || item.getType() == Material.AIR) {
- useSlot = i;
- break;
- } else if (useSlot == -1 && item.getType() != hand) {
- useSlot = i;
- }
- }
- if (useSlot != -1) {
- inv.setHeldItemSlot(useSlot);
- P.p.getServer().getScheduler().scheduleSyncDelayedTask(P.p, () -> player.getInventory().setHeldItemSlot(held), 2);
- }
- }
-
- // Barrel opening Sound
- float randPitch = (float) (Math.random() * 0.1);
- if (barrel.isLarge()) {
- barrel.getSpigot().getWorld().playSound(barrel.getSpigot().getLocation(), Sound.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.4f, 0.55f + randPitch);
- //barrel.getSpigot().getWorld().playSound(barrel.getSpigot().getLocation(), Sound.ITEM_BUCKET_EMPTY, SoundCategory.BLOCKS, 0.5f, 0.6f + randPitch);
- barrel.getSpigot().getWorld().playSound(barrel.getSpigot().getLocation(), Sound.BLOCK_BREWING_STAND_BREW, SoundCategory.BLOCKS, 0.4f, 0.45f + randPitch);
- } else {
- barrel.getSpigot().getWorld().playSound(barrel.getSpigot().getLocation(), Sound.BLOCK_BARREL_OPEN, SoundCategory.BLOCKS, 0.5f, 0.8f + randPitch);
- }
- }
- }
+ // Access a Barrel
+ Barrel barrel = null;
+ if (LegacyUtil.isWoodPlanks(type)) {
+ if (BConfig.openEverywhere) {
+ barrel = Barrel.getByWood(clickedBlock);
+ }
+ } else if (LegacyUtil.isWoodStairs(type)) {
+ barrel = Barrel.getByWood(clickedBlock);
+ if (barrel != null) {
+ if (!BConfig.openEverywhere && barrel.isLarge()) {
+ barrel = null;
}
}
+ } else if (LegacyUtil.isFence(type) || LegacyUtil.isSign(type)) {
+ barrel = Barrel.getBySpigot(clickedBlock);
}
- }
- @SuppressWarnings("deprecation")
- public void setItemInHand(PlayerInteractEvent event, Material mat, boolean swapped) {
- if (P.use1_9) {
- if ((event.getHand() == EquipmentSlot.OFF_HAND) != swapped) {
- event.getPlayer().getInventory().setItemInOffHand(new ItemStack(mat));
- } else {
- event.getPlayer().getInventory().setItemInMainHand(new ItemStack(mat));
+ if (barrel != null) {
+ event.setCancelled(true);
+
+ P.p.debugLog("Barrel has area of: " + barrel.getBody().getBounds().area());
+
+ if (!barrel.hasPermsOpen(player, event)) {
+ return;
+ }
+
+ barrel.open(player);
+
+ if (P.use1_14) {
+
+ // When right clicking a normal Block in 1.14 with a potion or any edible item in hand,
+ // even when cancelled, the consume animation will continue playing while opening the Barrel inventory.
+ // The Animation and sound will play endlessly while the inventory is open, though no item is consumed.
+ // This seems to be a client bug.
+ // This workaround switches the currently selected slot to another for a short time, it needs to be a slot with a different item in it.
+ // This seems to make the client stop animating a consumption
+ // If there is a better way to do this please let me know
+ Material hand = event.getMaterial();
+ if ((hand == Material.POTION || hand.isEdible()) && !LegacyUtil.isSign(type)) {
+ PlayerInventory inv = player.getInventory();
+ final int held = inv.getHeldItemSlot();
+ int useSlot = -1;
+ for (int i = 0; i < 9; i++) {
+ ItemStack item = inv.getItem(i);
+ if (item == null || item.getType() == Material.AIR) {
+ useSlot = i;
+ break;
+ } else if (useSlot == -1 && item.getType() != hand) {
+ useSlot = i;
+ }
+ }
+ if (useSlot != -1) {
+ inv.setHeldItemSlot(useSlot);
+ P.p.getServer().getScheduler().scheduleSyncDelayedTask(P.p, () -> player.getInventory().setHeldItemSlot(held), 2);
+ }
+ }
+
+ barrel.playOpeningSound();
}
- } else {
- event.getPlayer().setItemInHand(new ItemStack(mat));
}
}
@@ -256,10 +129,13 @@ public class PlayerListener implements Listener {
if (item.getType() == Material.POTION) {
Brew brew = Brew.get(item);
if (brew != null) {
- BPlayer.drink(brew, player);
- if (player.getGameMode() != GameMode.CREATIVE) {
- brew.remove(item);
+ if (!BPlayer.drink(brew, item.getItemMeta(), player)) {
+ event.setCancelled(true);
+ return;
}
+ /*if (player.getGameMode() != org.bukkit.GameMode.CREATIVE) {
+ brew.remove(item);
+ }*/
if (P.use1_9) {
if (player.getGameMode() != GameMode.CREATIVE) {
// replace the potion with an empty potion to avoid effects
@@ -270,7 +146,7 @@ public class PlayerListener implements Listener {
}
}
}
- } else if (BPlayer.drainItems.containsKey(item.getType())) {
+ } else if (BConfig.drainItems.containsKey(item.getType())) {
BPlayer bplayer = BPlayer.get(player);
if (bplayer != null) {
bplayer.drainByItem(player, item.getType());
@@ -303,13 +179,13 @@ public class PlayerListener implements Listener {
// player talks while drunk, but he cant speak very well
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerChat(AsyncPlayerChatEvent event) {
- Words.playerChat(event);
+ DistortChat.playerChat(event);
}
// player commands while drunk, distort chat commands
@EventHandler(priority = EventPriority.LOWEST)
public void onCommandPreProcess(PlayerCommandPreprocessEvent event) {
- Words.playerCommand(event);
+ DistortChat.playerCommand(event);
}
// player joins while passed out
diff --git a/src/com/dre/brewery/listeners/WorldListener.java b/src/com/dre/brewery/listeners/WorldListener.java
index fde093c..b19b03c 100644
--- a/src/com/dre/brewery/listeners/WorldListener.java
+++ b/src/com/dre/brewery/listeners/WorldListener.java
@@ -2,8 +2,8 @@ package com.dre.brewery.listeners;
import com.dre.brewery.BCauldron;
import com.dre.brewery.Barrel;
-import com.dre.brewery.P;
-import com.dre.brewery.Util;
+import com.dre.brewery.utility.BUtil;
+import com.dre.brewery.filedata.BData;
import com.dre.brewery.filedata.DataSave;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
@@ -19,9 +19,9 @@ public class WorldListener implements Listener {
World world = event.getWorld();
if (world.getName().startsWith("DXL_")) {
- P.p.loadWorldData(Util.getDxlName(world.getName()), world);
+ BData.loadWorldData(BUtil.getDxlName(world.getName()), world, null);
} else {
- P.p.loadWorldData(world.getUID().toString(), world);
+ BData.loadWorldData(world.getUID().toString(), world, null);
}
}
diff --git a/src/com/dre/brewery/lore/Base91DecoderStream.java b/src/com/dre/brewery/lore/Base91DecoderStream.java
new file mode 100644
index 0000000..7dbbb1f
--- /dev/null
+++ b/src/com/dre/brewery/lore/Base91DecoderStream.java
@@ -0,0 +1,147 @@
+package com.dre.brewery.lore;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class Base91DecoderStream extends FilterInputStream {
+
+ private final basE91 decoder = new basE91();
+ private byte[] decbuf = new byte[32];
+ private byte[] buf = new byte[32];
+ private int reader = 0;
+ private int count = 0;
+ private byte[] markBuf = null;
+
+ public Base91DecoderStream(InputStream in) {
+ super(in);
+ }
+
+ private void decode() throws IOException {
+ reader = 0;
+ count = in.read(decbuf);
+ if (count < 1) {
+ count = decoder.decEnd(buf);
+ if (count < 1) {
+ count = -1;
+ }
+ return;
+ }
+ count = decoder.decode(decbuf, count, buf);
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (count == -1) return -1;
+ if (count == 0 || reader == count) {
+ decode();
+ return read();
+ }
+ return buf[reader++] & 0xFF;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (b == null) throw new NullPointerException();
+ if (off < 0 || len < 0 || len > b.length - off) throw new IndexOutOfBoundsException();
+ if (len == 0) return 0;
+
+ if (count == -1) return -1;
+ if (count == 0 || reader == count) {
+ decode();
+ if (count == -1) return -1;
+ }
+
+ if (count > 0 && count - reader >= len) {
+ // enough data in buffer, copy it out directly
+ System.arraycopy(buf, reader, b, off, len);
+ reader += len;
+ return len;
+ }
+
+ int out = 0;
+ int writeSize;
+ while (count > 0) {
+ // Not enough data in buffer, write all out, decode and repeat
+ writeSize = Math.min(len, count - reader);
+ System.arraycopy(buf, reader, b, off + out, writeSize);
+ out += writeSize;
+ len -= writeSize;
+ if (len > 0) {
+ decode();
+ } else {
+ reader += writeSize;
+ break;
+ }
+ }
+ return out;
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ if (count == -1) return 0;
+ if (count > 0 && count - reader >= n) {
+ reader += n;
+ return n;
+ }
+ long skipped = count - reader;
+ decode();
+
+ while (count > 0) {
+ if (count > n - skipped) {
+ reader = (int) (n - skipped);
+ return n;
+ }
+ skipped += count;
+ decode();
+ }
+ return skipped;
+ }
+
+ @Override
+ public int available() throws IOException {
+ if (count == -1) return 0;
+ return (int) (in.available() * 0.813F) + count - reader; // Ratio encoded to decoded with random data
+ }
+
+ @Override
+ public void close() throws IOException {
+ in.close();
+ count = -1;
+ decoder.decReset();
+ buf = null;
+ decbuf = null;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ if (!markSupported()) return;
+ if (count == -1) return;
+ in.mark(readlimit);
+ decoder.decMark();
+ if (count > 0 && reader < count) {
+ markBuf = new byte[count - reader];
+ System.arraycopy(buf, reader, markBuf, 0, markBuf.length);
+ } else {
+ markBuf = null;
+ }
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (!markSupported()) throw new IOException("mark and reset not supported by underlying Stream");
+ in.reset();
+ decoder.decUnmark();
+ reader = 0;
+ count = 0;
+ if (markBuf != null) {
+ System.arraycopy(markBuf, 0, buf, 0, markBuf.length);
+ count = markBuf.length;
+ }
+ }
+
+ @Override
+ public boolean markSupported() {
+ return in.markSupported();
+ }
+}
diff --git a/src/com/dre/brewery/lore/Base91EncoderStream.java b/src/com/dre/brewery/lore/Base91EncoderStream.java
new file mode 100644
index 0000000..0de1354
--- /dev/null
+++ b/src/com/dre/brewery/lore/Base91EncoderStream.java
@@ -0,0 +1,92 @@
+package com.dre.brewery.lore;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Base91EncoderStream extends FilterOutputStream {
+
+ private final basE91 encoder = new basE91();
+ private byte[] buf = new byte[32];
+ private byte[] encBuf = new byte[48];
+ private int writer = 0;
+ private int encoded = 0;
+
+ public Base91EncoderStream(OutputStream out) {
+ super(out);
+ }
+
+ private void encFlush() throws IOException {
+ encoded = encoder.encode(buf, writer, encBuf);
+ out.write(encBuf, 0, encoded);
+ writer = 0;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ buf[writer++] = (byte) b;
+ if (writer >= buf.length) {
+ encFlush();
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (len == 0) return;
+ if (b == null) throw new NullPointerException();
+ if (len < 0 || off < 0 || (off + len) > b.length || off > b.length || (off + len) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ if (buf.length - writer >= len) {
+ // Enough space in the buffer, copy it in
+ System.arraycopy(b, off, buf, writer, len);
+ writer += len;
+ if (writer >= buf.length) {
+ encFlush();
+ }
+ return;
+ }
+
+ if (off == 0 && buf.length >= len) {
+ // Buffer is too full but it would fit, so flush and encode data directly
+ encFlush();
+ encoded = encoder.encode(b, len, encBuf);
+ out.write(encBuf, 0, encoded);
+ return;
+ }
+
+ // More data than space in the Buffer
+ ByteArrayInputStream in = new ByteArrayInputStream(b, off, len);
+ while (true) {
+ writer += in.read(buf, writer, buf.length - writer);
+ if (writer >= buf.length) {
+ encFlush();
+ } else {
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (writer > 0) {
+ encFlush();
+ }
+
+ encoded = encoder.encEnd(encBuf);
+ if (encoded > 0) {
+ out.write(encBuf, 0, encoded);
+ }
+ super.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ encoder.encReset();
+ buf = null;
+ encBuf = null;
+ }
+}
diff --git a/src/com/dre/brewery/lore/BrewLore.java b/src/com/dre/brewery/lore/BrewLore.java
new file mode 100644
index 0000000..c81fa94
--- /dev/null
+++ b/src/com/dre/brewery/lore/BrewLore.java
@@ -0,0 +1,549 @@
+package com.dre.brewery.lore;
+
+import com.dre.brewery.recipe.BEffect;
+import com.dre.brewery.BIngredients;
+import com.dre.brewery.recipe.BRecipe;
+import com.dre.brewery.Brew;
+import com.dre.brewery.P;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.utility.BUtil;
+import org.bukkit.inventory.meta.PotionMeta;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents the Lore on a Brew under Modification.
+ * Can efficiently replace certain lines of lore, to update brew information on an item.
+ */
+public class BrewLore {
+ private Brew brew;
+ private PotionMeta meta;
+ private List lore;
+ private boolean lineAddedOrRem = false;
+
+ public BrewLore(Brew brew, PotionMeta meta) {
+ this.brew = brew;
+ this.meta = meta;
+ if (meta.hasLore()) {
+ lore = meta.getLore();
+ } else {
+ lore = new ArrayList<>();
+ }
+ }
+
+ /**
+ * Write the new lore into the Meta.
+ * Should be called at the end of operation on this Brew Lore
+ */
+ public PotionMeta write() {
+ if (lineAddedOrRem) {
+ updateSpacer();
+ }
+ meta.setLore(lore);
+ return meta;
+ }
+
+ /**
+ * adds or removes an empty line in lore to space out the text a bit
+ */
+ public void updateSpacer() {
+ boolean hasCustom = false;
+ boolean hasSpace = false;
+ for (int i = 0; i < lore.size(); i++) {
+ Type t = Type.get(lore.get(i));
+ if (t == Type.CUSTOM) {
+ hasCustom = true;
+ } else if (t == Type.SPACE) {
+ hasSpace = true;
+ } else if (t != null && t.isAfter(Type.SPACE)) {
+ if (hasSpace) return;
+
+ if (hasCustom || P.useNBT) {
+ // We want to add the spacer if we have Custom Lore, to have a space between custom and brew lore.
+ // Also add a space if there is no Custom Lore but we don't already have a invisible data line
+ lore.add(i, Type.SPACE.id);
+ }
+ return;
+ }
+ }
+ if (hasSpace) {
+ // There was a space but nothing after the space
+ removeLore(Type.SPACE);
+ }
+ }
+
+ /*private void addSpacer() {
+ if (!P.useNBT) return;
+
+ for (int i = 0; i < lore.size(); i++) {
+ if (Type.get(lore.get(i)) != null) {
+ if (i == 0 || !lore.get(i - 1).equals("")) {
+ lore.add(i, "");
+ }
+ break;
+ }
+ }
+ }*/
+
+ /**
+ * Add the list of strings as custom lore for the base potion coming out of the cauldron
+ */
+ public void addCauldronLore(List l) {
+ int index = -1;
+ for (String line : l) {
+ if (index == -1) {
+ index = addLore(Type.CUSTOM, "", line);
+ index++;
+ } else {
+ lore.add(index, Type.CUSTOM.id + line);
+ index++;
+ }
+ }
+ }
+
+ /**
+ * updates the IngredientLore
+ *
+ * @param qualityColor If the lore should have colors according to quality
+ */
+ public void updateIngredientLore(boolean qualityColor) {
+ if (qualityColor && brew.hasRecipe()) {
+ String prefix = getQualityColor(brew.getIngredients().getIngredientQuality(brew.getCurrentRecipe()));
+ addOrReplaceLore(Type.INGR, prefix, P.p.languageReader.get("Brew_Ingredients"));
+ } else {
+ removeLore(Type.INGR, P.p.languageReader.get("Brew_Ingredients"));
+ }
+ }
+
+ /**
+ * updates the CookLore
+ *
+ * @param qualityColor If the lore should have colors according to quality
+ */
+ public void updateCookLore(boolean qualityColor) {
+ if (qualityColor && brew.hasRecipe() && brew.getDistillRuns() > 0 == brew.getCurrentRecipe().needsDistilling()) {
+ BIngredients ingredients = brew.getIngredients();
+ int quality = ingredients.getCookingQuality(brew.getCurrentRecipe(), brew.getDistillRuns() > 0);
+ String prefix = getQualityColor(quality) + ingredients.getCookedTime() + " " + P.p.languageReader.get("Brew_minute");
+ if (ingredients.getCookedTime() > 1) {
+ prefix = prefix + P.p.languageReader.get("Brew_MinutePluralPostfix");
+ }
+ addOrReplaceLore(Type.COOK, prefix, " " + P.p.languageReader.get("Brew_fermented"));
+ } else {
+ removeLore(Type.COOK, P.p.languageReader.get("Brew_fermented"));
+ }
+ }
+
+ /**
+ * updates the DistillLore
+ *
+ * @param qualityColor If the lore should have colors according to quality
+ */
+ public void updateDistillLore(boolean qualityColor) {
+ if (brew.getDistillRuns() <= 0) return;
+ String prefix;
+ byte distillRuns = brew.getDistillRuns();
+ if (qualityColor && !brew.isUnlabeled() && brew.hasRecipe()) {
+ prefix = getQualityColor(brew.getIngredients().getDistillQuality(brew.getCurrentRecipe(), distillRuns));
+ } else {
+ prefix = "§7";
+ }
+ if (!brew.isUnlabeled()) {
+ if (distillRuns > 1) {
+ prefix = prefix + distillRuns + P.p.languageReader.get("Brew_-times") + " ";
+ }
+ }
+ addOrReplaceLore(Type.DISTILL, prefix, P.p.languageReader.get("Brew_Distilled"));
+ }
+
+ /**
+ * updates the AgeLore
+ *
+ * @param qualityColor If the lore should have colors according to quality
+ */
+ public void updateAgeLore(boolean qualityColor) {
+ String prefix;
+ float age = brew.getAgeTime();
+ if (qualityColor && !brew.isUnlabeled() && brew.hasRecipe()) {
+ prefix = getQualityColor(brew.getIngredients().getAgeQuality(brew.getCurrentRecipe(), age));
+ } else {
+ prefix = "§7";
+ }
+ if (!brew.isUnlabeled()) {
+ if (age >= 1 && age < 2) {
+ prefix = prefix + P.p.languageReader.get("Brew_OneYear") + " ";
+ } else if (age < 201) {
+ prefix = prefix + (int) Math.floor(age) + " " + P.p.languageReader.get("Brew_Years") + " ";
+ } else {
+ prefix = prefix + P.p.languageReader.get("Brew_HundredsOfYears") + " ";
+ }
+ }
+ addOrReplaceLore(Type.AGE, prefix, P.p.languageReader.get("Brew_BarrelRiped"));
+ }
+
+ /**
+ * updates the WoodLore
+ *
+ * @param qualityColor If the lore should have colors according to quality
+ */
+ public void updateWoodLore(boolean qualityColor) {
+ if (qualityColor && brew.hasRecipe() && !brew.isUnlabeled()) {
+ int quality = brew.getIngredients().getWoodQuality(brew.getCurrentRecipe(), brew.getWood());
+ addOrReplaceLore(Type.WOOD, getQualityColor(quality), P.p.languageReader.get("Brew_Woodtype"));
+ } else {
+ removeLore(Type.WOOD, P.p.languageReader.get("Brew_Woodtype"));
+ }
+ }
+
+ /**
+ * updates the Custom Lore
+ */
+ public void updateCustomLore() {
+ removeLore(Type.CUSTOM);
+
+ BRecipe recipe = brew.getCurrentRecipe();
+ if (recipe != null && recipe.hasLore()) {
+ int index = -1;
+ for (String line : recipe.getLoreForQuality(brew.getQuality())) {
+ if (index == -1) {
+ index = addLore(Type.CUSTOM, "", line);
+ index++;
+ } else {
+ lore.add(index, Type.CUSTOM.id + line);
+ index++;
+ }
+ }
+ }
+ }
+
+ public void updateQualityStars(boolean qualityColor) {
+ if (brew.hasRecipe() && brew.getCurrentRecipe().needsToAge() && brew.getAgeTime() < 0.5) {
+ return;
+ }
+ if (!brew.isUnlabeled() && brew.getQuality() > 0 && (qualityColor || BConfig.alwaysShowQuality)) {
+ int stars = (brew.getQuality() + 1) / 2;
+ StringBuilder b = new StringBuilder(stars);
+ for (; stars > 0; stars--) {
+ b.append("⭑");
+ }
+ String color;
+ if (qualityColor) {
+ color = getQualityColor(brew.getQuality());
+ } else {
+ color = brew.getQuality() >= 10 ? "§6" : "§8";
+ }
+ addOrReplaceLore(Type.STARS, color, b.toString());
+ } else {
+ removeLore(Type.STARS);
+ }
+ }
+
+ public void updateAlc(boolean inDistiller) {
+ if (!brew.isUnlabeled() && (inDistiller || BConfig.alwaysShowAlc) && (!brew.hasRecipe() || brew.getCurrentRecipe().getAlcohol() > 0)) {
+ int alc = brew.getOrCalcAlc();
+ addOrReplaceLore(Type.ALC, "§8", P.p.languageReader.get("Brew_Alc", alc + ""));
+ } else {
+ removeLore(Type.ALC);
+ }
+ }
+
+ /**
+ * Converts to/from qualitycolored Lore
+ */
+ public void convertLore(boolean toQuality) {
+ if (!brew.hasRecipe()) {
+ return;
+ }
+
+ updateCustomLore();
+ if (toQuality && brew.isUnlabeled()) {
+ return;
+ }
+ updateQualityStars(toQuality);
+
+ // Ingredients
+ updateIngredientLore(toQuality);
+
+ // Cooking
+ updateCookLore(toQuality);
+
+ // Distilling
+ updateDistillLore(toQuality);
+
+ // Ageing
+ if (brew.getAgeTime() >= 1) {
+ updateAgeLore(toQuality);
+ }
+
+ // WoodType
+ if (brew.getAgeTime() > 0.5) {
+ updateWoodLore(toQuality);
+ }
+
+ updateAlc(false);
+ }
+
+ /**
+ * Adds or replaces a line of Lore.
+ * Searches for type and if not found for Substring lore and replaces it
+ *
+ * @param type The Type of BrewLore to replace
+ * @param prefix The Prefix to add to the line of lore
+ * @param line The Line of Lore to add or replace
+ */
+ public int addOrReplaceLore(Type type, String prefix, String line) {
+ int index = type.findInLore(lore);
+ if (index == -1) {
+ index = BUtil.indexOfSubstring(lore, line);
+ }
+ if (index > -1) {
+ lore.set(index, type.id + prefix + line);
+ return index;
+ } else {
+ return addLore(type, prefix, line);
+ }
+ }
+
+ /**
+ * Adds a line of Lore in the correct ordering
+ *
+ * @param type The Type of BrewLore to add
+ * @param prefix The Prefix to add to the line of lore
+ * @param line The Line of Lore to add or add
+ */
+ public int addLore(Type type, String prefix, String line) {
+ lineAddedOrRem = true;
+ for (int i = 0; i < lore.size(); i++) {
+ Type existing = Type.get(lore.get(i));
+ if (existing != null && existing.isAfter(type)) {
+ lore.add(i, type.id + prefix + line);
+ return i;
+ }
+ }
+ lore.add(type.id + prefix + line);
+ return lore.size() - 1;
+ }
+
+ /**
+ * Searches for type and if not found for Substring lore and removes it
+ */
+ public void removeLore(Type type, String line) {
+ int index = type.findInLore(lore);
+ if (index == -1) {
+ index = BUtil.indexOfSubstring(lore, line);
+ }
+ if (index > -1) {
+ lineAddedOrRem = true;
+ lore.remove(index);
+ }
+ }
+
+ /**
+ * Searches for type and removes it
+ */
+ public void removeLore(Type type) {
+ if (type != Type.CUSTOM) {
+ int index = type.findInLore(lore);
+ if (index > -1) {
+ lineAddedOrRem = true;
+ lore.remove(index);
+ }
+ } else {
+ // Lore could have multiple lines of this type
+ for (int i = lore.size() - 1; i >= 0; i--) {
+ if (Type.get(lore.get(i)) == type) {
+ lore.remove(i);
+ lineAddedOrRem = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes all Brew Lore lines
+ */
+ public void removeAll() {
+ for (int i = lore.size() - 1; i >= 0; i--) {
+ if (Type.get(lore.get(i)) != null) {
+ lore.remove(i);
+ lineAddedOrRem = true;
+ }
+ }
+ }
+
+ /**
+ * Adds the Effect names to the Items description
+ */
+ public void addOrReplaceEffects(List effects, int quality) {
+ if (!P.use1_9 && effects != null) {
+ for (BEffect effect : effects) {
+ if (!effect.isHidden()) {
+ effect.writeInto(meta, quality);
+ }
+ }
+ }
+ }
+
+ /**
+ * If the Lore Line at index is a Brew Lore line
+ *
+ * @param index the index in lore to check
+ * @return true if the line at index is of any Brew Lore type
+ */
+ public boolean isBrewLore(int index) {
+ return index < lore.size() && Type.get(lore.get(index)) != null;
+ }
+
+ /**
+ * Removes all effects
+ */
+ public void removeEffects() {
+ if (meta.hasCustomEffects()) {
+ for (PotionEffect effect : new ArrayList<>(meta.getCustomEffects())) {
+ PotionEffectType type = effect.getType();
+ //if (!type.equals(PotionEffectType.REGENERATION)) {
+ meta.removeCustomEffect(type);
+ //}
+ }
+ }
+ }
+
+ /**
+ * Remove the Old Spacer from the legacy potion data system
+ */
+ public void removeLegacySpacing() {
+ if (P.useNBT) {
+ // Using NBT we don't get the invisible line, so we keep our spacing
+ return;
+ }
+ if (lore.size() > 0 && lore.get(0).equals("")) {
+ lore.remove(0);
+ write();
+ }
+ }
+
+ /**
+ * Remove any Brew Data from Lore
+ */
+ public void removeLoreData() {
+ int index = BUtil.indexOfStart(lore, LoreSaveStream.IDENTIFIER);
+ if (index != -1) {
+ lore.set(index, "");
+ write();
+ }
+ }
+
+ /**
+ * True if the PotionMeta has Lore in quality color
+ */
+ public static boolean hasColorLore(PotionMeta meta) {
+ if (!meta.hasLore()) return false;
+ List lore = meta.getLore();
+ if (lore.size() < 2) {
+ return false;
+ }
+ if (Type.INGR.findInLore(lore) != -1) {
+ // Ingredient lore present, must be quality colored
+ return true;
+ }
+ return false;
+ //!meta.getLore().get(1).startsWith("§7");
+ }
+
+ /**
+ * gets the Color that represents a quality in Lore
+ *
+ * @param quality The Quality for which to find the color code
+ * @return Color Code for given Quality
+ */
+ public static String getQualityColor(int quality) {
+ String color;
+ if (quality > 8) {
+ color = "&a";
+ } else if (quality > 6) {
+ color = "&e";
+ } else if (quality > 4) {
+ color = "&6";
+ } else if (quality > 2) {
+ color = "&c";
+ } else {
+ color = "&4";
+ }
+ return P.p.color(color);
+ }
+
+ /**
+ * Type of Lore Line
+ */
+ public enum Type {
+ STARS("§s"),
+ CUSTOM("§t"),
+ SPACE("§u"),
+
+ INGR("§v"),
+ COOK("§w"),
+ DISTILL("§x"),
+ AGE("§y"),
+ WOOD("§z"),
+ ALC("§k");
+
+ public final String id;
+
+ /**
+ * @param id Identifier as Prefix of the Loreline
+ */
+ Type(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Find this type in the Lore
+ *
+ * @param lore The lore to search in
+ * @return index of this type in the lore, -1 if not found
+ */
+ public int findInLore(List lore) {
+ return BUtil.indexOfStart(lore, id);
+ }
+
+ /**
+ * Is this type after the other in lore
+ *
+ * @param other the other type
+ * @return true if this type should be after the other type in lore
+ */
+ public boolean isAfter(Type other) {
+ return other.ordinal() <= ordinal();
+ }
+
+ /**
+ * Get the Type of the given line of Lore
+ */
+ @Nullable
+ public static Type get(String loreLine) {
+ if (loreLine.length() >= 2) {
+ return getById(loreLine.substring(0, 2));
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the Type of the given Identifier, prefix of a line of lore
+ */
+ @Nullable
+ public static Type getById(String id) {
+ for (Type t : values()) {
+ if (t.id.equals(id)) {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ }
+}
diff --git a/src/com/dre/brewery/lore/LoreLoadStream.java b/src/com/dre/brewery/lore/LoreLoadStream.java
new file mode 100644
index 0000000..4ad7ab2
--- /dev/null
+++ b/src/com/dre/brewery/lore/LoreLoadStream.java
@@ -0,0 +1,52 @@
+package com.dre.brewery.lore;
+
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.List;
+
+public class LoreLoadStream extends ByteArrayInputStream {
+
+ public static final String IDENTIFIER = "§%";
+
+ public LoreLoadStream(ItemMeta meta) throws IllegalArgumentException {
+ this(meta, -1);
+ }
+
+ public LoreLoadStream(ItemMeta meta, int line) throws IllegalArgumentException {
+ super(loreToBytes(meta, line));
+ }
+
+ private static byte[] loreToBytes(ItemMeta meta, int lineNum) throws IllegalArgumentException {
+ if (meta.hasLore()) {
+ List lore = meta.getLore();
+ if (lineNum >= 0) {
+ String line = lore.get(lineNum);
+ if (line.startsWith(IDENTIFIER)) {
+ return loreLineToBytes(line);
+ }
+ }
+ for (String line : lore) {
+ if (line.startsWith(IDENTIFIER)) {
+ return loreLineToBytes(line);
+ }
+ }
+ }
+ throw new IllegalArgumentException("Meta has no data in lore");
+ }
+
+ private static byte[] loreLineToBytes(String line) {
+ StringBuilder build = new StringBuilder((int) (line.length() / 2F));
+ byte skip = 2;
+ for (char c : line.toCharArray()) {
+ if (skip > 0) {
+ skip--;
+ continue;
+ }
+ if (c == '§') continue;
+ build.append(c);
+ }
+ return build.toString().getBytes();
+ }
+}
diff --git a/src/com/dre/brewery/lore/LoreSaveStream.java b/src/com/dre/brewery/lore/LoreSaveStream.java
new file mode 100644
index 0000000..de127d3
--- /dev/null
+++ b/src/com/dre/brewery/lore/LoreSaveStream.java
@@ -0,0 +1,80 @@
+package com.dre.brewery.lore;
+
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class LoreSaveStream extends ByteArrayOutputStream {
+
+ public static final String IDENTIFIER = "§%";
+
+ private ItemMeta meta;
+ private int line;
+ private boolean flushed = false;
+
+ public LoreSaveStream(ItemMeta meta) {
+ this(meta, -1);
+ }
+
+ public LoreSaveStream(ItemMeta meta, int line) {
+ super(128);
+ this.meta = meta;
+ this.line = line;
+ }
+
+ // Writes to the Lore
+ // Without calling this, the ItemMeta remains unchanged
+ @Override
+ public void flush() throws IOException {
+ super.flush();
+ if (size() <= 0) return;
+ if (flushed || meta == null) {
+ // Dont write twice
+ return;
+ }
+ flushed = true;
+ String s = toString();
+
+ StringBuilder loreLineBuilder = new StringBuilder((s.length() * 2) + 6);
+ loreLineBuilder.append(IDENTIFIER);
+ for (char c : s.toCharArray()) {
+ loreLineBuilder.append('§').append(c);
+ }
+ List lore;
+ if (meta.hasLore()) {
+ lore = meta.getLore();
+ } else {
+ lore = new ArrayList<>();
+ }
+ int prev = 0;
+ for (Iterator iterator = lore.iterator(); iterator.hasNext(); ) {
+ if (iterator.next().startsWith(IDENTIFIER)) {
+ iterator.remove();
+ break;
+ }
+ prev++;
+ }
+ if (line < 0) {
+ if (prev >= 0) {
+ line = prev;
+ } else {
+ line = lore.size();
+ }
+ }
+ while (lore.size() < line) {
+ lore.add("");
+ }
+ lore.add(line, loreLineBuilder.toString());
+ meta.setLore(lore);
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ meta = null;
+ }
+}
diff --git a/src/com/dre/brewery/lore/NBTLoadStream.java b/src/com/dre/brewery/lore/NBTLoadStream.java
new file mode 100644
index 0000000..46dccd0
--- /dev/null
+++ b/src/com/dre/brewery/lore/NBTLoadStream.java
@@ -0,0 +1,33 @@
+package com.dre.brewery.lore;
+
+import com.dre.brewery.P;
+import com.dre.brewery.utility.LegacyUtil;
+import org.bukkit.NamespacedKey;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.io.ByteArrayInputStream;
+
+public class NBTLoadStream extends ByteArrayInputStream {
+ private static final String TAG = "brewdata";
+ private static final NamespacedKey KEY = new NamespacedKey(P.p, TAG);
+
+ public NBTLoadStream(ItemMeta meta) {
+ super(getNBTBytes(meta));
+ }
+
+ private static byte[] getNBTBytes(ItemMeta meta) {
+ byte[] bytes = LegacyUtil.readBytesItem(meta, KEY);
+ if (bytes == null) {
+ return new byte[0];
+ }
+ return bytes;
+ }
+
+ public boolean hasData() {
+ return count > 0;
+ }
+
+ public static boolean hasDataInMeta(ItemMeta meta) {
+ return LegacyUtil.hasBytesItem(meta, KEY);
+ }
+}
diff --git a/src/com/dre/brewery/lore/NBTSaveStream.java b/src/com/dre/brewery/lore/NBTSaveStream.java
new file mode 100644
index 0000000..457018d
--- /dev/null
+++ b/src/com/dre/brewery/lore/NBTSaveStream.java
@@ -0,0 +1,28 @@
+package com.dre.brewery.lore;
+
+import com.dre.brewery.P;
+import com.dre.brewery.utility.LegacyUtil;
+import org.bukkit.NamespacedKey;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class NBTSaveStream extends ByteArrayOutputStream {
+ private static final String TAG = "brewdata";
+ private static final NamespacedKey KEY = new NamespacedKey(P.p, TAG);
+
+ private final ItemMeta meta;
+
+ public NBTSaveStream(ItemMeta meta) {
+ super(128);
+ this.meta = meta;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ super.flush();
+ if (size() <= 0) return;
+ LegacyUtil.writeBytesItem(toByteArray(), meta, KEY);
+ }
+}
diff --git a/src/com/dre/brewery/lore/SeedInputStream.java b/src/com/dre/brewery/lore/SeedInputStream.java
new file mode 100644
index 0000000..2d892c1
--- /dev/null
+++ b/src/com/dre/brewery/lore/SeedInputStream.java
@@ -0,0 +1,96 @@
+package com.dre.brewery.lore;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.InputStream;
+import java.util.Arrays;
+
+public class SeedInputStream extends InputStream {
+ // From java.util.Random
+ private static final long multiplier = 0x5DEECE66DL;
+ private static final long addend = 0xBL;
+ private static final long mask = (1L << 48) - 1;
+
+ private long seed;
+ private byte[] buf = new byte[4];
+ private byte reader = 4;
+ private long markSeed;
+ private byte[] markbuf;
+
+ public SeedInputStream(long seed) {
+ this.seed = (seed ^ multiplier) & mask;
+ }
+
+ private void calcSeed() {
+ seed = (seed * multiplier + addend) & mask;
+ }
+
+ private void genNext() {
+ calcSeed();
+ int next = (int)(seed >>> 16);
+ buf[0] = (byte) (next >> 24);
+ buf[1] = (byte) (next >> 16);
+ buf[2] = (byte) (next >> 8);
+ buf[3] = (byte) next;
+ reader = 0;
+ }
+
+ @Override
+ public int read(@NotNull byte[] b, int off, int len) {
+ for (int i = off; i < len; i++) {
+ if (reader >= 4) {
+ genNext();
+ }
+ b[i] = buf[reader++];
+ }
+ return len;
+ }
+
+ @Override
+ public int read() {
+ if (reader == 4) {
+ genNext();
+ }
+ return buf[reader++];
+ }
+
+ @Override
+ public long skip(long toSkip) {
+ long n = toSkip;
+ while (n > 0) {
+ if (reader < 4) {
+ reader++;
+ n--;
+ } else if (n >= 4) {
+ calcSeed();
+ n -= 4;
+ } else {
+ genNext();
+ }
+ }
+ return toSkip;
+ }
+
+ @Override
+ public void close() {
+ buf = null;
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ markbuf = new byte[] {buf[0], buf[1], buf[2], buf[3], reader};
+ markSeed = seed;
+ }
+
+ @Override
+ public synchronized void reset() {
+ seed = markSeed;
+ buf = Arrays.copyOfRange(markbuf, 0, 4);
+ reader = markbuf[4];
+ }
+}
diff --git a/src/com/dre/brewery/lore/XORScrambleStream.java b/src/com/dre/brewery/lore/XORScrambleStream.java
new file mode 100644
index 0000000..0072375
--- /dev/null
+++ b/src/com/dre/brewery/lore/XORScrambleStream.java
@@ -0,0 +1,103 @@
+package com.dre.brewery.lore;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+
+/**
+ * A Scramble Stream that uses XOR operations to scramble an outputstream.
+ * a byte generator feeded with the seed is used as xor source
+ *
The resulting data can be unscrambled by the XORUnscrambleStream
+ */
+public class XORScrambleStream extends FilterOutputStream {
+
+ private final long seed;
+ private SeedInputStream xorStream;
+ private boolean running;
+
+ /**
+ * Create a new instance of an XORScrambler, scrambling the given outputstream
+ *
+ * @param out The Outputstream to be scrambled
+ * @param seed The seed used for scrambling
+ */
+ public XORScrambleStream(OutputStream out, long seed) {
+ super(out);
+ this.seed = seed;
+ }
+
+ /**
+ * To start the scrambling process this has to be called before writing any data to this stream.
+ *
Before starting the scrambler, any data will just be passed through unscrambled to the underlying stream.
+ *
The Scrambling can be started and stopped arbitrarily at any point, allowing for parts of unscrambled data in the stream.
+ *
+ * @throws IOException IOException
+ */
+ public void start() throws IOException {
+ running = true;
+ if (xorStream == null) {
+ short id = 0;
+ while (id == 0) {
+ id = (short) new Random().nextInt();
+ }
+ xorStream = new SeedInputStream(seed ^ id);
+ out.write((byte) (id >> 8));
+ out.write((byte) id);
+ write((int) (seed >> 48) & 0xFF); // parity/sanity
+ }
+ }
+
+ /**
+ * Stop the scrambling, any following data will be passed through unscrambled.
+ *
The scrambling can be started again at any point after calling this
+ */
+ public void stop() {
+ running = false;
+ }
+
+ /**
+ * Mark the stream as unscrambled, any effort of unscrambing the data later will automatically read the already unscrambled data.
+ *
Useful if a stream may be scrambled or unscrambled, the unscrambler will automatically identify either way.
+ *
+ * @throws IOException IOException
+ * @throws IllegalStateException If the Scrambler was started in normal scrambling mode before
+ */
+ public void startUnscrambled() throws IOException, IllegalStateException {
+ if (xorStream != null) throw new IllegalStateException("The Scrambler was started in scrambling mode before");
+ short id = 0;
+ out.write((byte) (id >> 8));
+ out.write((byte) id);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ if (!running) {
+ out.write(b);
+ return;
+ }
+ out.write(b ^ xorStream.read());
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (!running) {
+ out.write(b, off, len);
+ return;
+ }
+ byte[] xored = new byte[len];
+ xorStream.read(xored);
+ int j = off;
+ for (int i = 0; i < len; i++) {
+ xored[i] ^= b[j++];
+ }
+ out.write(xored);
+ }
+
+ @Override
+ public void close() throws IOException {
+ running = false;
+ xorStream = null;
+ super.close();
+ }
+}
diff --git a/src/com/dre/brewery/lore/XORUnscrambleStream.java b/src/com/dre/brewery/lore/XORUnscrambleStream.java
new file mode 100644
index 0000000..38a7123
--- /dev/null
+++ b/src/com/dre/brewery/lore/XORUnscrambleStream.java
@@ -0,0 +1,208 @@
+package com.dre.brewery.lore;
+
+import com.dre.brewery.P;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.util.List;
+
+/**
+ * A Scramble Stream that uses XOR operations to unscramble an inputstream.
+ *
a byte generator feeded with the seed is used as xor source
+ *
Used to unscramble data generated by the XORScrambleStream
+ */
+public class XORUnscrambleStream extends FilterInputStream {
+
+ private long seed;
+ private final List prevSeeds;
+ private SeedInputStream xorStream;
+ private boolean running;
+ private boolean markRunning;
+ private boolean markxor;
+
+ private SuccessType successType = SuccessType.NONE;
+
+ /**
+ * Create a new instance of an XORUnscrambler, unscrambling the given inputstream.
+ *
+ * @param in The Inputstream to be unscrambled
+ * @param seed The seed used for unscrambling
+ */
+ public XORUnscrambleStream(InputStream in, long seed) {
+ super(in);
+ this.seed = seed;
+ prevSeeds = null;
+ }
+
+ /**
+ * Create a new instance of an XORUnscrambler, unscrambling the given inputstream.
+ * If given a List of previous Seeds, the unscrambler will try all of them for unscrambling the stream in case the seed fails.
+ *
+ * @param in The Inputstream to be unscrambled
+ * @param seed The seed used for unscrambling
+ * @param prevSeeds List of previously used seeds
+ */
+ public XORUnscrambleStream(InputStream in, long seed, List prevSeeds) {
+ super(in);
+ this.seed = seed;
+ this.prevSeeds = prevSeeds;
+ }
+
+ /**
+ * Before unscrambling, this has to be called to tell the unscrambler that scrambled data will follow.
+ *
Before starting the unscrambler, any data will just be passed through unmodified to the underlying stream.
+ *
The Unscrambling can be started and stopped arbitrarily at any point, allowing for parts of already unscrambled data in the stream.
+ *
+ * @throws IOException IOException
+ * @throws InvalidKeyException If the scrambled data could not be read, very likely caused by a wrong seed. Thrown after checking all previous seeds.
+ */
+ public void start() throws IOException, InvalidKeyException {
+ running = true;
+ if (xorStream == null) {
+ short id = (short) (in.read() << 8 | in.read());
+ if (id == 0) {
+ running = false;
+ successType = SuccessType.UNSCRAMBLED;
+ P.p.debugLog("Unscrambled data");
+ return;
+ }
+ int parity = in.read();
+ xorStream = new SeedInputStream(seed ^ id);
+ boolean success = checkParity(parity);
+ if (success) {
+ successType = SuccessType.MAIN_SEED;
+ P.p.debugLog("Using main Seed to unscramble");
+ }
+
+ if (!success && prevSeeds != null) {
+ for (int i = prevSeeds.size() - 1; i >= 0; i--) {
+ seed = prevSeeds.get(i);
+ xorStream = new SeedInputStream(seed ^ id);
+ if (success = checkParity(parity)) {
+ successType = SuccessType.PREV_SEED;
+ P.p.debugLog("Had to use prevSeed to unscramble");
+ break;
+ }
+ }
+ }
+ if (!success) {
+ throw new InvalidKeyException("Could not read scrambled data, is the seed wrong?");
+ }
+ }
+ }
+
+ private boolean checkParity(int parity) {
+ return ((parity ^ xorStream.read()) & 0xFF) == ((int) (seed >> 48) & 0xFF); // Parity/Sanity
+ }
+
+ /**
+ * Stop the unscrambling, any following data will be passed through unmodified.
+ * The unscrambling can be started again at any point after calling this
+ */
+ public void stop() {
+ running = false;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (!running) {
+ return in.read();
+ }
+ return (in.read() ^ xorStream.read()) & 0xFF;
+ }
+
+ @Override
+ public int read(@NotNull byte[] b, int off, int len) throws IOException {
+ if (!running) {
+ return in.read(b, off, len);
+ }
+ len = in.read(b, off, len);
+ for (int i = off; i < len + off; i++) {
+ b[i] ^= xorStream.read();
+ }
+ return len;
+ }
+
+ /**
+ * What was used to unscramble the stream: it was already unscrambled | Main Seed | Prev Seed
+ *
+ * @return The Type of Seed used to unscramble this, if any
+ */
+ public SuccessType getSuccessType() {
+ return successType;
+ }
+
+ @SuppressWarnings("ResultOfMethodCallIgnored")
+ @Override
+ public long skip(long n) throws IOException {
+ long skipped = in.skip(n);
+ if (running && skipped > 0) {
+ xorStream.skip(skipped);
+ }
+ return skipped;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (xorStream != null) {
+ xorStream.close();
+ xorStream = null;
+ }
+ running = false;
+ super.close();
+ }
+
+ @Override
+ public boolean markSupported() {
+ return in.markSupported();
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ in.reset();
+ if (markxor) {
+ xorStream.reset();
+ } else {
+ xorStream = null;
+ }
+ running = markRunning;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ in.mark(readlimit);
+ if (xorStream != null) {
+ xorStream.mark(readlimit);
+ markxor = true;
+ }
+ markRunning = running;
+ }
+
+ /**
+ * What succeeded in unscrambling the Stream.
+ */
+ public static enum SuccessType {
+ /**
+ * The Stream was already unscrambled.
+ */
+ UNSCRAMBLED,
+
+ /**
+ * The Main Seed was used to unscramble the Stream.
+ */
+ MAIN_SEED,
+
+ /**
+ * One of the Previous Seeds was used to unscramble the Stream.
+ */
+ PREV_SEED,
+
+ /**
+ * It was not successful.
+ */
+ NONE;
+ }
+}
diff --git a/src/com/dre/brewery/lore/basE91.java b/src/com/dre/brewery/lore/basE91.java
new file mode 100644
index 0000000..c564c71
--- /dev/null
+++ b/src/com/dre/brewery/lore/basE91.java
@@ -0,0 +1,155 @@
+package com.dre.brewery.lore;
+
+/*
+ * basE91 encoding/decoding routines
+ *
+ * Copyright (c) 2000-2006 Joachim Henke
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Joachim Henke nor the names of his contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+public class basE91
+{
+ public static final byte[] enctab;
+ private static final byte[] dectab;
+
+ private int ebq, en, dbq, dn, dv;
+ private int[] marker = null;
+
+ public int encode(byte[] ib, int n, byte[] ob)
+ {
+ int i, c = 0;
+
+ for (i = 0; i < n; ++i) {
+ ebq |= (ib[i] & 255) << en;
+ en += 8;
+ if (en > 13) {
+ int ev = ebq & 8191;
+
+ if (ev > 88) {
+ ebq >>= 13;
+ en -= 13;
+ } else {
+ ev = ebq & 16383;
+ ebq >>= 14;
+ en -= 14;
+ }
+ ob[c++] = enctab[ev % 91];
+ ob[c++] = enctab[ev / 91];
+ }
+ }
+ return c;
+ }
+
+ public int encEnd(byte[] ob)
+ {
+ int c = 0;
+
+ if (en > 0) {
+ ob[c++] = enctab[ebq % 91];
+ if (en > 7 || ebq > 90)
+ ob[c++] = enctab[ebq / 91];
+ }
+ encReset();
+ return c;
+ }
+
+ public void encReset()
+ {
+ ebq = 0;
+ en = 0;
+ }
+
+ public int decode(byte[] ib, int n, byte[] ob)
+ {
+ int i, c = 0;
+
+ for (i = 0; i < n; ++i) {
+ if (dectab[ib[i]] == -1)
+ continue;
+ if (dv == -1)
+ dv = dectab[ib[i]];
+ else {
+ dv += dectab[ib[i]] * 91;
+ dbq |= dv << dn;
+ dn += (dv & 8191) > 88 ? 13 : 14;
+ do {
+ ob[c++] = (byte) dbq;
+ dbq >>= 8;
+ dn -= 8;
+ } while (dn > 7);
+ dv = -1;
+ }
+ }
+ return c;
+ }
+
+ public int decEnd(byte[] ob)
+ {
+ int c = 0;
+
+ if (dv != -1)
+ ob[c++] = (byte) (dbq | dv << dn);
+ decReset();
+ return c;
+ }
+
+ public void decReset()
+ {
+ dbq = 0;
+ dn = 0;
+ dv = -1;
+ }
+
+ public void decMark() {
+ marker = new int[] {dbq, dn, dv};
+ }
+
+ public void decUnmark() {
+ if (marker == null) return;
+ dbq = marker[0];
+ dn = marker[1];
+ dv = marker[2];
+ }
+
+ public basE91()
+ {
+ encReset();
+ decReset();
+ }
+
+ static {
+ int i;
+ String ts = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!$%&()*+,-./:;<=>?@[]^_`{|}~\""; // Added '-' removed '#'
+
+ enctab = ts.getBytes();
+ dectab = new byte[256];
+ for (i = 0; i < 256; ++i)
+ dectab[i] = -1;
+ for (i = 0; i < 91; ++i)
+ dectab[enctab[i]] = (byte) i;
+ }
+}
diff --git a/src/com/dre/brewery/recipe/BCauldronRecipe.java b/src/com/dre/brewery/recipe/BCauldronRecipe.java
new file mode 100644
index 0000000..c3143e6
--- /dev/null
+++ b/src/com/dre/brewery/recipe/BCauldronRecipe.java
@@ -0,0 +1,346 @@
+package com.dre.brewery.recipe;
+
+import com.dre.brewery.P;
+import com.dre.brewery.utility.Tuple;
+import org.bukkit.Color;
+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.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * A Recipe for the Base Potion coming out of the Cauldron.
+ */
+public class BCauldronRecipe {
+ public static List recipes = new ArrayList<>();
+ public static int numConfigRecipes;
+ public static List acceptedCustom = new ArrayList<>(); // All accepted custom and other items
+ public static Set acceptedSimple = EnumSet.noneOf(Material.class); // All accepted simple items
+ public static Set acceptedMaterials = EnumSet.noneOf(Material.class); // Fast cache for all accepted Materials
+
+ private String name;
+ private List ingredients;
+ //private List particles
+ private PotionColor color;
+ private List lore;
+ private boolean saveInData; // If this recipe should be saved in data and loaded again when the server restarts. Applicable to non-config recipes
+
+
+ /**
+ * A New Cauldron Recipe with the given name.
+ * Use new BCauldronRecipe.Builder() for easier Cauldron Recipe Creation
+ *
+ * @param name Name of the Cauldron Recipe
+ */
+ public BCauldronRecipe(String name) {
+ this.name = name;
+ color = PotionColor.CYAN;
+ }
+
+ @Nullable
+ public static BCauldronRecipe fromConfig(ConfigurationSection cfg, String id) {
+
+ String name = cfg.getString(id + ".name");
+ if (name != null) {
+ name = P.p.color(name);
+ } else {
+ P.p.errorLog("Missing name for Cauldron-Recipe: " + id);
+ return null;
+ }
+
+ BCauldronRecipe recipe = new BCauldronRecipe(name);
+
+ 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> lore = BRecipe.loadLore(cfg, id + ".lore");
+ if (lore != null && !lore.isEmpty()) {
+ recipe.lore = lore.stream().map(Tuple::second).collect(Collectors.toList());
+ }
+
+ return recipe;
+ }
+
+
+ // Getter
+
+ @NotNull
+ public String getName() {
+ return name;
+ }
+
+ @NotNull
+ public List getIngredients() {
+ return ingredients;
+ }
+
+ @NotNull
+ public PotionColor getColor() {
+ return color;
+ }
+
+ @Nullable
+ public List getLore() {
+ return lore;
+ }
+
+ public boolean isSaveInData() {
+ return saveInData;
+ }
+
+
+ // Setter
+
+ /**
+ * When Changing ingredients, Accepted Lists have to be updated in BCauldronRecipe
+ */
+ public void setIngredients(@NotNull List ingredients) {
+ this.ingredients = ingredients;
+ }
+
+ public void setColor(@NotNull PotionColor color) {
+ this.color = color;
+ }
+
+ public void setLore(List lore) {
+ this.lore = lore;
+ }
+
+ public void setSaveInData(boolean saveInData) {
+ this.saveInData = saveInData;
+ }
+
+ /**
+ * 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 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;
+ }
+
+ public void updateAcceptedLists() {
+ for (RecipeItem ingredient : getIngredients()) {
+ if (ingredient.hasMaterials()) {
+ BCauldronRecipe.acceptedMaterials.addAll(ingredient.getMaterials());
+ }
+ if (ingredient instanceof SimpleItem) {
+ BCauldronRecipe.acceptedSimple.add(((SimpleItem) ingredient).getMaterial());
+ } else {
+ // Add it as acceptedCustom
+ if (!BCauldronRecipe.acceptedCustom.contains(ingredient)) {
+ BCauldronRecipe.acceptedCustom.add(ingredient);
+ }
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "BCauldronRecipe{" + name + '}';
+ }
+
+ @Nullable
+ public static BCauldronRecipe get(String name) {
+ for (BCauldronRecipe recipe : recipes) {
+ if (recipe.name.equalsIgnoreCase(name)) {
+ return recipe;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets a Modifiable Sublist of the CauldronRecipes that are loaded by config.
+ * Changes are directly reflected by the main list of all recipes
+ *
Changes to the main List of all CauldronRecipes will make the reference to this sublist invalid
+ *
+ *
After adding or removing elements, CauldronRecipes.numConfigRecipes MUST be updated!
+ */
+ public static List getConfigRecipes() {
+ return recipes.subList(0, numConfigRecipes);
+ }
+
+ /**
+ * Gets a Modifiable Sublist of the CauldronRecipes that are added by plugins.
+ * Changes are directly reflected by the main list of all recipes
+ *
Changes to the main List of all CauldronRecipes will make the reference to this sublist invalid
+ */
+ public static List getAddedRecipes() {
+ return recipes.subList(numConfigRecipes, recipes.size());
+ }
+
+ /**
+ * Gets the main List of all CauldronRecipes.
+ */
+ public static List getAllRecipes() {
+ return recipes;
+ }
+
+ /*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;
+ }*/
+
+ /**
+ * Builder to easily create BCauldron recipes.
+ */
+ public static class Builder {
+ private BCauldronRecipe recipe;
+
+ public Builder(String name) {
+ recipe = new BCauldronRecipe(name);
+ }
+
+
+ public Builder addIngredient(RecipeItem... item) {
+ if (recipe.ingredients == null) {
+ recipe.ingredients = new ArrayList<>();
+ }
+ Collections.addAll(recipe.ingredients, item);
+ return this;
+ }
+
+ public Builder addIngredient(ItemStack... item) {
+ if (recipe.ingredients == null) {
+ recipe.ingredients = new ArrayList<>();
+ }
+ for (ItemStack i : item) {
+ recipe.ingredients.add(new CustomItem(i));
+ }
+ return this;
+ }
+
+ public Builder color(String colorString) {
+ recipe.color = PotionColor.fromString(colorString);
+ return this;
+ }
+
+ public Builder color(PotionColor color) {
+ recipe.color = color;
+ return this;
+ }
+
+ public Builder color(Color color) {
+ recipe.color = PotionColor.fromColor(color);
+ return this;
+ }
+
+ public Builder addLore(String line) {
+ if (recipe.lore == null) {
+ recipe.lore = new ArrayList<>();
+ }
+ recipe.lore.add(line);
+ return this;
+ }
+
+ public BCauldronRecipe get() {
+ if (recipe.name == null) {
+ throw new IllegalArgumentException("CauldronRecipe name is null");
+ }
+ if (BCauldronRecipe.get(recipe.getName()) != null) {
+ throw new IllegalArgumentException("CauldronRecipe with name " + recipe.getName() + " already exists");
+ }
+ if (recipe.color == null) {
+ throw new IllegalArgumentException("CauldronRecipe has no color");
+ }
+ if (recipe.ingredients == null || recipe.ingredients.isEmpty()) {
+ throw new IllegalArgumentException("CauldronRecipe has no ingredients");
+ }
+ return recipe;
+ }
+ }
+}
diff --git a/src/com/dre/brewery/BEffect.java b/src/com/dre/brewery/recipe/BEffect.java
similarity index 81%
rename from src/com/dre/brewery/BEffect.java
rename to src/com/dre/brewery/recipe/BEffect.java
index 7339f49..edb99cc 100644
--- a/src/com/dre/brewery/BEffect.java
+++ b/src/com/dre/brewery/recipe/BEffect.java
@@ -1,7 +1,10 @@
-package com.dre.brewery;
+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 {
@@ -14,6 +17,15 @@ public class BEffect {
private boolean hidden = false;
+ public BEffect(PotionEffectType type, short minlvl, short maxlvl, short minduration, short maxduration, boolean hidden) {
+ this.type = type;
+ this.minlvl = minlvl;
+ this.maxlvl = maxlvl;
+ this.minduration = minduration;
+ this.maxduration = maxduration;
+ this.hidden = hidden;
+ }
+
public BEffect(String effectString) {
String[] effectSplit = effectString.split("/");
String effect = effectSplit[0];
@@ -81,19 +93,26 @@ public class BEffect {
}
}
- public void apply(int quality, Player player) {
+ public PotionEffect generateEffect(int quality) {
int duration = calcDuration(quality);
int lvl = calcLvl(quality);
if (lvl < 1 || (duration < 1 && !type.isInstant())) {
- return;
+ return null;
}
duration *= 20;
if (!P.use1_14) {
duration /= type.getDurationModifier();
}
- Util.reapplyPotionEffect(player, type.createEffect(duration, lvl - 1), true);
+ 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) {
diff --git a/src/com/dre/brewery/recipe/BRecipe.java b/src/com/dre/brewery/recipe/BRecipe.java
new file mode 100644
index 0000000..753ce66
--- /dev/null
+++ b/src/com/dre/brewery/recipe/BRecipe.java
@@ -0,0 +1,916 @@
+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.BUtil;
+import com.dre.brewery.utility.Tuple;
+import org.apache.commons.lang.NotImplementedException;
+import org.bukkit.Color;
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * A Recipe used to Brew a Brewery Potion.
+ */
+public class BRecipe {
+
+ private static List recipes = new ArrayList<>();
+ public static int numConfigRecipes; // The number of recipes in the list that are from config
+
+ // info
+ private String[] name;
+ private boolean saveInData; // If this recipe should be saved in data and loaded again when the server restarts. Applicable to non-config recipes
+
+ // brewing
+ private List ingredients = new ArrayList<>(); // Items and amounts
+ private int difficulty; // difficulty to brew the potion, how exact the instruction has to be followed
+ 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
+
+ // outcome
+ private PotionColor color; // color of the distilled/finished potion
+ private int alcohol; // Alcohol in perfect potion
+ private List> lore; // Custom Lore on the Potion. The int is for Quality Lore, 0 = any, 1,2,3 = Bad,Middle,Good
+
+ // drinking
+ private List effects = new ArrayList<>(); // Special Effects when drinking
+ private List playercmds; // Commands executed as the player when drinking
+ private List servercmds; // Commands executed as the server when drinking
+ private String drinkMsg; // Message when drinking
+ private String drinkTitle; // Title to show when drinking
+
+ private BRecipe() {
+ }
+
+ /**
+ * New BRecipe with Name.
+ * Use new BRecipe.Builder() for easier Recipe Creation
+ *
+ * @param name The name for all qualities
+ */
+ public BRecipe(String name, @NotNull PotionColor color) {
+ this.name = new String[] {name};
+ this.color = color;
+ difficulty = 5;
+ }
+
+ /**
+ * New BRecipe with Names.
+ *
Use new BRecipe.Builder() for easier Recipe Creation
+ *
+ * @param names {name bad, name normal, name good}
+ */
+ public BRecipe(String[] names, @NotNull PotionColor color) {
+ this.name = names;
+ this.color = color;
+ difficulty = 5;
+ }
+
+ @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");
+
+ recipe.servercmds = BUtil.loadCfgStringList(configSectionRecipes, recipeId + ".servercommands");
+ recipe.playercmds = BUtil.loadCfgStringList(configSectionRecipes, recipeId + ".playercommands");
+
+ if (recipe.servercmds != null && !recipe.servercmds.isEmpty()) {
+ for (ListIterator iter = recipe.servercmds.listIterator(); iter.hasNext(); ) {
+ String cmd = iter.next();
+ if (cmd.startsWith("/")) {
+ iter.set(cmd.substring(1));
+ }
+ }
+ }
+ if (recipe.playercmds != null && !recipe.playercmds.isEmpty()) {
+ for (ListIterator iter = recipe.playercmds.listIterator(); iter.hasNext(); ) {
+ String cmd = iter.next();
+ if (cmd.startsWith("/")) {
+ iter.set(cmd.substring(1));
+ }
+ }
+ }
+
+ recipe.drinkMsg = P.p.color(BUtil.loadCfgString(configSectionRecipes, recipeId + ".drinkmessage"));
+ recipe.drinkTitle = P.p.color(BUtil.loadCfgString(configSectionRecipes, recipeId + ".drinktitle"));
+
+ List 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 loadIngredients(ConfigurationSection cfg, String recipeId) {
+ List 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 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> loadLore(ConfigurationSection cfg, String path) {
+ List load = BUtil.loadCfgStringList(cfg, path);
+ if (load != null) {
+ List> 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 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;
+ }
+
+ public void applyDrinkFeatures(Player player) {
+ if (playercmds != null && !playercmds.isEmpty()) {
+ for (String cmd : playercmds) {
+ player.performCommand(cmd.replaceAll("%player_name%", player.getName()));
+ }
+ }
+ if (servercmds != null && !servercmds.isEmpty()) {
+ for (String cmd : servercmds) {
+ P.p.getServer().dispatchCommand(P.p.getServer().getConsoleSender(), cmd.replaceAll("%player_name%", player.getName()));
+ }
+ }
+ if (drinkMsg != null) {
+ player.sendMessage(drinkMsg.replaceAll("%player_name%", player.getName()));
+ }
+ if (drinkTitle != null) {
+ player.sendTitle("", drinkTitle.replaceAll("%player_name%", player.getName()), 10, 90, 30);
+ }
+ }
+
+ /**
+ * Create a Potion 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 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 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, 0, distillruns, getAge(), wood, getRecipeName(), false, true, 0);
+ }
+
+ public void updateAcceptedLists() {
+ for (RecipeItem ingredient : getIngredients()) {
+ if (ingredient.hasMaterials()) {
+ BCauldronRecipe.acceptedMaterials.addAll(ingredient.getMaterials());
+ }
+ if (ingredient instanceof SimpleItem) {
+ BCauldronRecipe.acceptedSimple.add(((SimpleItem) ingredient).getMaterial());
+ } else {
+ // Add it as acceptedCustom
+ if (!BCauldronRecipe.acceptedCustom.contains(ingredient)) {
+ BCauldronRecipe.acceptedCustom.add(ingredient);
+ }
+ }
+ }
+ }
+
+
+ // 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 List getIngredients() {
+ return ingredients;
+ }
+
+ 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> getLore() {
+ return lore;
+ }
+
+ @Nullable
+ public List 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 list = new ArrayList<>(lore.size());
+ for (Tuple line : lore) {
+ if (line.first() == 0 || line.first() == plus) {
+ list.add(line.second());
+ }
+ }
+ return list;
+ }
+
+ public List getPlayercmds() {
+ return playercmds;
+ }
+
+ public List getServercmds() {
+ return servercmds;
+ }
+
+ public String getDrinkMsg() {
+ return drinkMsg;
+ }
+
+ public String getDrinkTitle() {
+ return drinkTitle;
+ }
+
+ public List getEffects() {
+ return effects;
+ }
+
+ public boolean isSaveInData() {
+ return saveInData;
+ }
+
+ // Setters
+
+ /**
+ * When Changing ingredients, Accepted Lists have to be updated in BCauldronRecipe
+ */
+ public void setIngredients(List ingredients) {
+ this.ingredients = ingredients;
+ }
+
+ public void setCookingTime(int cookingTime) {
+ this.cookingTime = cookingTime;
+ }
+
+ public void setDistillruns(byte distillruns) {
+ this.distillruns = distillruns;
+ }
+
+ public void setDistillTime(int distillTime) {
+ this.distillTime = distillTime;
+ }
+
+ public void setWood(byte wood) {
+ this.wood = wood;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public void setColor(@NotNull PotionColor color) {
+ this.color = color;
+ }
+
+ public void setDifficulty(int difficulty) {
+ this.difficulty = difficulty;
+ }
+
+ public void setAlcohol(int alcohol) {
+ this.alcohol = alcohol;
+ }
+
+ public void setLore(List> lore) {
+ this.lore = lore;
+ }
+
+ public void setEffects(List effects) {
+ this.effects = effects;
+ }
+
+ public void setSaveInData(boolean saveInData) {
+ throw new NotImplementedException();
+ //this.saveInData = saveInData;
+ }
+
+
+ @Override
+ public String toString() {
+ return "BRecipe{" + getRecipeName() + '}';
+ }
+
+ /**
+ * Gets a Modifiable Sublist of the Recipes that are loaded by config.
+ * Changes are directly reflected by the main list of all recipes
+ *
Changes to the main List of all recipes will make the reference to this sublist invalid
+ *
+ *
After adding or removing elements, BRecipe.numConfigRecipes MUST be updated!
+ */
+ public static List getConfigRecipes() {
+ return recipes.subList(0, numConfigRecipes);
+ }
+
+ /**
+ * Gets a Modifiable Sublist of the Recipes that are added by plugins.
+ * Changes are directly reflected by the main list of all recipes
+ *
Changes to the main List of all recipes will make the reference to this sublist invalid
+ */
+ public static List getAddedRecipes() {
+ return recipes.subList(numConfigRecipes, recipes.size());
+ }
+
+ /**
+ * Gets the main List of all recipes.
+ */
+ public static List getAllRecipes() {
+ return recipes;
+ }
+
+ public static BRecipe get(String name) {
+ for (BRecipe recipe : recipes) {
+ if (recipe.getRecipeName().equalsIgnoreCase(name)) {
+ return recipe;
+ }
+ }
+ return null;
+ }
+
+ /*public static void saveAddedRecipes(ConfigurationSection cfg) {
+ int i = 0;
+ for (BRecipe recipe : getAddedRecipes()) {
+ if (recipe.isSaveInData()) {
+ cfg.set(i + ".name", recipe.name);
+ }
+ }
+ }*/
+
+
+ /**
+ * Builder to easily create Recipes
+ */
+ public static class Builder {
+ private BRecipe recipe;
+
+ public Builder(String name) {
+ recipe = new BRecipe(name, PotionColor.WATER);
+ }
+
+ public Builder(String... names) {
+ recipe = new BRecipe(names, PotionColor.WATER);
+ }
+
+
+ public Builder addIngredient(RecipeItem... item) {
+ Collections.addAll(recipe.ingredients, item);
+ return this;
+ }
+
+ public Builder addIngredient(ItemStack... item) {
+ for (ItemStack i : item) {
+ CustomItem customItem = new CustomItem(i);
+ customItem.setAmount(i.getAmount());
+ recipe.ingredients.add(customItem);
+ }
+ return this;
+ }
+
+ public Builder difficulty(int difficulty) {
+ recipe.difficulty = difficulty;
+ return this;
+ }
+
+ public Builder color(String colorString) {
+ recipe.color = PotionColor.fromString(colorString);
+ return this;
+ }
+
+ public Builder color(PotionColor color) {
+ recipe.color = color;
+ return this;
+ }
+
+ public Builder color(Color color) {
+ recipe.color = PotionColor.fromColor(color);
+ return this;
+ }
+
+ public Builder cook(int cookTime) {
+ recipe.cookingTime = cookTime;
+ return this;
+ }
+
+ public Builder distill(byte distillRuns, int distillTime) {
+ recipe.distillruns = distillRuns;
+ recipe.distillTime = distillTime;
+ return this;
+ }
+
+ public Builder age(int age, byte wood) {
+ recipe.age = age;
+ recipe.wood = wood;
+ return this;
+ }
+
+ public Builder alcohol(int alcohol) {
+ recipe.alcohol = alcohol;
+ return this;
+ }
+
+ public Builder addLore(String line) {
+ return addLore(0, line);
+ }
+
+ /**
+ * Add a Line of Lore
+ *
+ * @param quality 0 for any quality, 1: bad, 2: normal, 3: good
+ * @param line The Line for custom lore to add
+ * @return this
+ */
+ public Builder addLore(int quality, String line) {
+ if (quality < 0 || quality > 3) {
+ throw new IllegalArgumentException("Lore Quality must be 0 - 3");
+ }
+ if (recipe.lore == null) {
+ recipe.lore = new ArrayList<>();
+ }
+ recipe.lore.add(new Tuple<>(quality, line));
+ return this;
+ }
+
+ /**
+ * Add Commands that are executed by the player on drinking
+ */
+ public Builder addPlayerCmds(String... cmds) {
+ if (recipe.playercmds == null) {
+ recipe.playercmds = new ArrayList<>(cmds.length);
+ }
+ Collections.addAll(recipe.playercmds, cmds);
+ return this;
+ }
+
+ /**
+ * Add Commands that are executed by the server on drinking
+ */
+ public Builder addServerCmds(String... cmds) {
+ if (recipe.servercmds == null) {
+ recipe.servercmds = new ArrayList<>(cmds.length);
+ }
+ Collections.addAll(recipe.servercmds, cmds);
+ return this;
+ }
+
+ /**
+ * Add Message that is sent to the player in chat when he drinks the brew
+ */
+ public Builder drinkMsg(String msg) {
+ recipe.drinkMsg = msg;
+ return this;
+ }
+
+ /**
+ * Add Message that is sent to the player as a small title when he drinks the brew
+ */
+ public Builder drinkTitle(String title) {
+ recipe.drinkTitle = title;
+ return this;
+ }
+
+ public Builder addEffects(BEffect... effects) {
+ Collections.addAll(recipe.effects, effects);
+ return this;
+ }
+
+ public BRecipe get() {
+ if (recipe.name == null) {
+ throw new IllegalArgumentException("Recipe name is null");
+ }
+ if (recipe.name.length != 1 && recipe.name.length != 3) {
+ throw new IllegalArgumentException("Recipe name neither 1 nor 3");
+ }
+ if (BRecipe.get(recipe.getRecipeName()) != null) {
+ throw new IllegalArgumentException("Recipe with name " + recipe.getRecipeName() + " already exists");
+ }
+ if (recipe.color == null) {
+ throw new IllegalArgumentException("Recipe has no color");
+ }
+ if (recipe.ingredients == null || recipe.ingredients.isEmpty()) {
+ throw new IllegalArgumentException("Recipe has no ingredients");
+ }
+ if (!recipe.isValid()) {
+ throw new IllegalArgumentException("Recipe has not valid");
+ }
+ for (RecipeItem ingredient : recipe.ingredients) {
+ ingredient.makeImmutable();
+ }
+ return recipe;
+ }
+ }
+}
diff --git a/src/com/dre/brewery/recipe/CustomItem.java b/src/com/dre/brewery/recipe/CustomItem.java
new file mode 100644
index 0000000..9ec3d30
--- /dev/null
+++ b/src/com/dre/brewery/recipe/CustomItem.java
@@ -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 lore;
+
+ public CustomItem() {
+ }
+
+ public CustomItem(Material mat) {
+ this.mat = mat;
+ }
+
+ public CustomItem(Material mat, String name, List 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 getMaterials() {
+ List 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 getLore() {
+ return lore;
+ }
+
+ protected void setLore(List 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 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);
+ }
+}
diff --git a/src/com/dre/brewery/recipe/CustomMatchAnyItem.java b/src/com/dre/brewery/recipe/CustomMatchAnyItem.java
new file mode 100644
index 0000000..99dc570
--- /dev/null
+++ b/src/com/dre/brewery/recipe/CustomMatchAnyItem.java
@@ -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 materials;
+ private List names;
+ private List 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 getMaterials() {
+ return materials;
+ }
+
+ protected void setMaterials(List materials) {
+ this.materials = materials;
+ }
+
+ @Nullable
+ public List getNames() {
+ return names;
+ }
+
+ protected void setNames(List names) {
+ this.names = names;
+ }
+
+ @Nullable
+ public List getLore() {
+ return lore;
+ }
+
+ protected void setLore(List 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 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 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 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) +
+ '}';
+ }
+}
diff --git a/src/com/dre/brewery/recipe/Ingredient.java b/src/com/dre/brewery/recipe/Ingredient.java
new file mode 100644
index 0000000..3d27118
--- /dev/null
+++ b/src/com/dre/brewery/recipe/Ingredient.java
@@ -0,0 +1,87 @@
+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> 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 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);
+
+
+}
diff --git a/src/com/dre/brewery/recipe/ItemLoader.java b/src/com/dre/brewery/recipe/ItemLoader.java
new file mode 100644
index 0000000..720a63e
--- /dev/null
+++ b/src/com/dre/brewery/recipe/ItemLoader.java
@@ -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;
+ }
+}
diff --git a/src/com/dre/brewery/recipe/PluginItem.java b/src/com/dre/brewery/recipe/PluginItem.java
new file mode 100644
index 0000000..3a02a1a
--- /dev/null
+++ b/src/com/dre/brewery/recipe/PluginItem.java
@@ -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> 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 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;
+ }
+ }
+
+ /**
+ * Registers the chosen SaveID and the loading Method for loading from Brew or BCauldron.
+ *
Needs to be called at Server start.
+ */
+ public static void registerItemLoader() {
+ Ingredient.registerForItemLoader("PI", PluginItem::loadFrom);
+ }
+
+
+ /**
+ * Called when loading trying to find a config defined Plugin Item. 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 constructor) {
+ constructors.put(pluginId.toLowerCase(), constructor);
+ }
+
+ public static void unRegisterForConfig(String pluginId) {
+ constructors.remove(pluginId.toLowerCase());
+ }
+
+}
diff --git a/src/com/dre/brewery/recipe/PotionColor.java b/src/com/dre/brewery/recipe/PotionColor.java
new file mode 100644
index 0000000..59aac49
--- /dev/null
+++ b/src/com/dre/brewery/recipe/PotionColor.java
@@ -0,0 +1,109 @@
+package com.dre.brewery.recipe;
+
+import com.dre.brewery.P;
+import org.bukkit.Color;
+import org.bukkit.inventory.ItemFlag;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.PotionMeta;
+import org.bukkit.potion.PotionData;
+import org.bukkit.potion.PotionType;
+
+public class PotionColor {
+ public static final PotionColor PINK = new PotionColor(1, PotionType.REGEN, Color.FUCHSIA);
+ public static final PotionColor CYAN = new PotionColor(2, PotionType.SPEED, Color.AQUA);
+ public static final PotionColor ORANGE = new PotionColor(3, PotionType.FIRE_RESISTANCE, Color.ORANGE);
+ public static final PotionColor GREEN = new PotionColor(4, PotionType.POISON, Color.GREEN);
+ public static final PotionColor BRIGHT_RED = new PotionColor(5, PotionType.INSTANT_HEAL, Color.fromRGB(255,0,0));
+ public static final PotionColor BLUE = new PotionColor(6, PotionType.NIGHT_VISION, Color.NAVY);
+ public static final PotionColor BLACK = new PotionColor(8, PotionType.WEAKNESS, Color.BLACK);
+ public static final PotionColor RED = new PotionColor(9, PotionType.STRENGTH, Color.fromRGB(196,0,0));
+ public static final PotionColor GREY = new PotionColor(10, PotionType.SLOWNESS, Color.GRAY);
+ public static final PotionColor WATER = new PotionColor(11, P.use1_9 ? PotionType.WATER_BREATHING : null, Color.BLUE);
+ public static final PotionColor DARK_RED = new PotionColor(12, PotionType.INSTANT_DAMAGE, Color.fromRGB(128,0,0));
+ public static final PotionColor BRIGHT_GREY = new PotionColor(14, PotionType.INVISIBILITY, Color.SILVER);
+
+ private final int colorId;
+ private final PotionType type;
+ private final Color color;
+
+ PotionColor(int colorId, PotionType type, Color color) {
+ this.colorId = colorId;
+ this.type = type;
+ this.color = color;
+ }
+
+ public PotionColor(Color color) {
+ colorId = -1;
+ type = WATER.getType();
+ this.color = color;
+ }
+
+ // gets the Damage Value, that sets a color on the potion
+ // offset +32 is not accepted by brewer, so not further destillable
+ // Only for minecraft pre 1.9
+ public short getColorId(boolean destillable) {
+ if (destillable) {
+ return (short) (colorId + 64);
+ }
+ return (short) (colorId + 32);
+ }
+
+ public PotionType getType() {
+ return type;
+ }
+
+ public Color getColor() {
+ return color;
+ }
+
+ @SuppressWarnings("deprecation")
+ public void colorBrew(PotionMeta meta, ItemStack potion, boolean destillable) {
+ if (P.use1_9) {
+ // We need to Hide Potion Effects even in 1.12, as it would otherwise show "No Effects"
+ meta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS);
+ if (P.use1_11) {
+ // BasePotionData was only used for the Color, so starting with 1.12 we can use setColor instead
+ meta.setColor(getColor());
+ } else {
+ meta.setBasePotionData(new PotionData(getType()));
+ }
+ } else {
+ potion.setDurability(getColorId(destillable));
+ }
+ }
+
+ public static PotionColor fromString(String string) {
+ switch (string) {
+ case "PINK": return PINK;
+ case "CYAN": return CYAN;
+ case "ORANGE": return ORANGE;
+ case "GREEN": return GREEN;
+ case "BRIGHT_RED": return BRIGHT_RED;
+ case "BLUE": return BLUE;
+ case "BLACK": return BLACK;
+ case "RED": return RED;
+ case "GREY": return GREY;
+ case "WATER": return WATER;
+ case "DARK_RED": return DARK_RED;
+ case "BRIGHT_GREY": return BRIGHT_GREY;
+ default:
+ try{
+ if (string.length() >= 7) {
+ string = string.substring(1);
+ }
+ return new PotionColor(Color.fromRGB(
+ Integer.parseInt(string.substring( 0, 2 ), 16 ),
+ Integer.parseInt(string.substring( 2, 4 ), 16 ),
+ Integer.parseInt(string.substring( 4, 6 ), 16 )
+ ));
+ } catch (Exception e) {
+ return WATER;
+ }
+ }
+ }
+
+ public static PotionColor fromColor(Color color) {
+ return new PotionColor(color);
+ }
+
+}
diff --git a/src/com/dre/brewery/recipe/RecipeItem.java b/src/com/dre/brewery/recipe/RecipeItem.java
new file mode 100644
index 0000000..48bf510
--- /dev/null
+++ b/src/com/dre/brewery/recipe/RecipeItem.java
@@ -0,0 +1,294 @@
+package com.dre.brewery.recipe;
+
+import com.dre.brewery.P;
+import com.dre.brewery.filedata.BConfig;
+import com.dre.brewery.utility.BUtil;
+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
+ *