From d0263c611c721bb3c1b7dd11dbfbb9264b4aa5ef Mon Sep 17 00:00:00 2001 From: Sn0wStorm Date: Tue, 29 Oct 2019 16:20:32 +0100 Subject: [PATCH] Added Custom Items and Cauldron-Recipes --- resources/config/v13/de/config.yml | 451 +++++++++++------- resources/config/v13/en/config.yml | 415 +++++++++------- src/com/dre/brewery/BCauldron.java | 52 +- src/com/dre/brewery/BCauldronRecipe.java | 141 ++++++ src/com/dre/brewery/BIngredients.java | 98 ++-- src/com/dre/brewery/BRecipe.java | 298 ++++++------ src/com/dre/brewery/Brew.java | 60 ++- src/com/dre/brewery/P.java | 14 +- src/com/dre/brewery/filedata/BConfig.java | 56 ++- .../brewery/listeners/CommandListener.java | 7 +- src/com/dre/brewery/lore/BrewLore.java | 57 ++- src/com/dre/brewery/utility/CustomItem.java | 329 +++++++++++++ src/com/dre/brewery/utility/Tuple.java | 42 +- test/com/dre/brewery/RecipeTests.java | 50 ++ 14 files changed, 1420 insertions(+), 650 deletions(-) create mode 100644 src/com/dre/brewery/BCauldronRecipe.java create mode 100644 src/com/dre/brewery/utility/CustomItem.java create mode 100644 test/com/dre/brewery/RecipeTests.java diff --git a/resources/config/v13/de/config.yml b/resources/config/v13/de/config.yml index d7079c9..fb0f925 100644 --- a/resources/config/v13/de/config.yml +++ b/resources/config/v13/de/config.yml @@ -40,8 +40,8 @@ pukeDespawntime: 60 # Konsumierbares Item/Stärke. Senkt den Alkoholpegel um wenn konsumiert. drainItems: -- Bread/4 -- Milk_Bucket/2 + - Bread/4 + - Milk_Bucket/2 # Zeit (in Tagen) die Trunkenheitsdaten nach offlinegehen eines Spielers im Speicher verbleiben, um z.B. Kater-Effekte anzuwenden. [7] hangoverDays: 7 @@ -80,6 +80,111 @@ autosave: 3 version: '1.8' +# -- Eigene Items Definieren -- +# Die festgelegte id kann dann in einem Rezept verwendet werden + +# matchAny: true wenn es schon reicht wenn eine der Angaben zutrifft +# material: Welche Art das Item haben muss +# name: Welchen Namen das Item haben muss (Farbcodes möglich: z.b. &6) +# lore: Was in der Lore des Items stehen muss + +customItems: + bsp-item: +# Ein Barriere Item das Mauer heißt und in der Lore die angegebene Zeile hat + material: Barrier + name: 'Mauer' + lore: + - '&7Besonders gut geschützt' + + bsp-item2: +# Mit matchAny muss nur eine der Angaben zutreffen. +# Hier also eine der Türarten, oder ein Item namens Buchenholztür, oder ein Item mit 'Eine Tür' in der Lore + matchAny: true + material: + - Acacia_Door + - Oak_Door + - Spruce_Door + name: + - 'Buchenholztür' + lore: + - 'Eine Tür' + + himbeere: + name: '&cHimbeere' + + +# -- Zutaten im Kessel -- +# Hier kann angegeben werden welche Zutaten in den Kessel getan werden können und was mit ihnen geschieht. + +# name: Name des Basistrankes der aus dem Kessel kommt (Farbcodes möglich: z.b. &6) +# ingredients: Auflistung von 'Material/Anzahl' +# Halte ein Item in der Hand und benutze /brew ItemName um dessen Material herauszufinden und für ein Rezept zu benutzen +# (Item-ids anstatt Material können in Bukkit nicht mehr benutzt werden) +# Eine Liste von allen Materialien kann hier gefunden werden: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html +# color: Farbe des Trankes der aus dem Kessel kommt +# Benutzbare Farben: DARK_RED, RED, BRIGHT_RED, ORANGE, PINK, BLUE, CYAN, WATER, GREEN, BLACK, GREY, BRIGHT_GREY +# Oder RGB Farben (Hex: also zB '99FF33') (Ohne #) (mit '') (Einfach nach "HTML color" im Internet suchen) +# lore: Auflistung von zusätzlichem Text auf dem Trank. (Farbcodes möglich: z.b. &6) + + +cauldron: + bsp: + name: Beispiel + ingredients: + - Bedrock/2 + - Diamond + color: BLACK + lore: + - Ein Beispiel für einen Basistrank + - So kommt er aus dem Kessel + +# -- Eine Zutat: -- + wheat: + name: Getreideferment + ingredients: Wheat + + sugarcane: + name: Zuckersud + ingredients: Sugar_Cane + color: 'f1ffad' # gelbliches grün + + apple: + name: Apfelmost + ingredients: Apple + + potato: + name: Kartoffelmaische + ingredients: Potato + + grass: + name: Kräuterbrühe + ingredients: Grass + color: '99ff66' # helles grün + + rmushroom: + name: Pilzsud + ingredients: Red_Mushroom + color: 'ff5c33' # bernsteinrot + + cocoa: + name: Kakaobrühe + ingredients: Cocoa_Beans + color: '804600' # mokka + + milk: + name: Milchiges Wasser + ingredients: Milk_Bucket + color: BRIGHT_GREY + + # -- Mehrere Zutaten: -- + apfelmet_basis: + name: Apfel-Zuckersud + ingredients: + - Sugar_Cane/3 + - Apple + color: 'e1ff4d' # grünliches gelb + + # -- Rezepte für Getränke -- # name: Verschiedene Namen für schlecht/mittel/gut (Farbcodes möglich: z.b. &6) @@ -108,185 +213,181 @@ version: '1.8' recipes: # Ein vollständiges Beispiel zuerst: - 0: - name: Schlechtes Beispiel/Beispiel/Gutes Beispiel - ingredients: - - Sugar_Cane/5 - - Diamond/1 - - Cocoa_Beans/20 - - Spruce_Planks/8 - - Bedrock/1 - cookingtime: 3 - distillruns: 2 - distilltime: 60 - wood: 4 - age: 11 - color: DARK_RED - difficulty: 3 - alcohol: 23 - lore: - - Dies ist ein Beispiel Trank - - ++Ganz normales Beispiel - - Dies würde auf dem Trank stehen - - + Riecht eklig - - ++ Riecht ganz ok - - +++ Riecht richtig gut - effects: - - FIRE_RESISTANCE/20 - - HEAL/1 - - WEAKNESS/2-3/50-60 - - POISON/1-0/20-0 - 1: - name: Ranziges Weißbier/Weißbier/Feines Weißbier - ingredients: - - Wheat/3 - cookingtime: 8 - distillruns: 0 - wood: 1 - age: 2 - color: BRIGHT_GREY - difficulty: 1 - alcohol: 5 - 2: - name: Ranziges Bier/Bier/Feines Bier - ingredients: - - Wheat/6 - cookingtime: 8 - distillruns: 0 - wood: 0 - age: 3 - color: ORANGE - difficulty: 1 - lore: - - +++ &8Das perlt - alcohol: 6 - 3: - name: Ranziges Dunkelbier/Dunkelbier/Feines Dunkelbier - ingredients: - - Wheat/6 - cookingtime: 8 - distillruns: 0 - wood: 4 - age: 8 - color: BLACK - difficulty: 2 - alcohol: 7 - 4: - name: Scheußlicher Met/Met/&6Goldener Met - ingredients: - - Sugar_Cane/6 - cookingtime: 3 - distillruns: 0 - wood: 2 - age: 4 - color: ORANGE - difficulty: 2 - alcohol: 9 - lore: - - +++ Hat einen goldenen Schein - 5: - name: Apfelmet/Süßer Apfelmet/&6Goldensüßer Apfelmet - ingredients: - - Sugar_Cane/6 - - Apple/2 - cookingtime: 4 - distillruns: 0 - wood: 2 - age: 4 - color: ORANGE - difficulty: 4 - alcohol: 12 - lore: - - + Ist da wirklich Apfel drin? - - ++ Schmeckt nach süßem Apfel - - +++ Hat eine wunderbare Apfelnote - effects: - - WATER_BREATHING/1-2/150 - 6: - name: Bitterer Rum/Würziger Rum/&6Goldener Rum - ingredients: - - Sugar_Cane/14 - cookingtime: 5 - distillruns: 2 - distilltime: 30 - wood: 2 - age: 14 - color: DARK_RED - difficulty: 6 - alcohol: 30 - effects: - - FIRE_RESISTANCE/1/20-100 - - POISON/1-0/30-0 - 7: - name: Abgeranzter Vodka/Vodka/Russischer Vodka - ingredients: - - Potato/10 - cookingtime: 15 - distillruns: 3 - age: 0 - color: BRIGHT_GREY - difficulty: 4 - alcohol: 20 - lore: - - + &8Fast nicht trinkbar - effects: - - WEAKNESS/15 - - POISON/10 - 8: - name: minderwertiger Absinth/Absinth/Starker Absinth - ingredients: - - Grass/15 - cookingtime: 3 - distillruns: 6 - distilltime: 80 - color: GREEN - difficulty: 8 - alcohol: 45 - effects: - - POISON/20-30 - 9: - name: Kartoffelsuppe - ingredients: - - Potato/5 - - Grass/3 - cookingtime: 3 - color: PINK - difficulty: 1 - effects: - - HEAL/0-1 - 10: - name: Fader Kaffee/Kaffee/Starker Kaffee - ingredients: - - Cocoa_Beans/12 - - Milk_Bucket/2 - cookingtime: 2 - color: BLACK - difficulty: 3 - lore: + &8Bestimmt schon eine Woche alt - effects: - - REGENERATION/1/2-5 - - SPEED/1/30-140 + bsp: + name: Schlechtes Beispiel/Beispiel/Gutes Beispiel + ingredients: + - Diamond/1 + - Spruce_Planks/8 + - Bedrock/1 +# - Brewery:Weißbier/2 +# - ExoticGarden:Grape/3 + - bsp-item/1 + cookingtime: 3 + distillruns: 2 + distilltime: 60 + wood: 4 + age: 11 + color: DARK_RED + difficulty: 3 + alcohol: 23 + lore: + - Dies ist ein Beispiel Trank + - ++Ganz normales Beispiel + - Dies würde auf dem Trank stehen + - + Riecht eklig + - ++ Riecht ganz ok + - +++ Riecht richtig gut + effects: + - FIRE_RESISTANCE/20 + - HEAL/1 + - WEAKNESS/2-3/50-60 + - POISON/1-0/20-0 + + weißbier: + name: Ranziges Weißbier/Weißbier/Feines Weißbier + ingredients: + - Wheat/3 + cookingtime: 8 + distillruns: 0 + wood: 1 + age: 2 + color: BRIGHT_GREY + difficulty: 1 + alcohol: 5 + + bier: + name: Ranziges Bier/Bier/Feines Bier + ingredients: + - Wheat/6 + cookingtime: 8 + distillruns: 0 + wood: 0 + age: 3 + color: ORANGE + difficulty: 1 + lore: + - +++ &8Das perlt + alcohol: 6 + + dunkelbier: + name: Ranziges Dunkelbier/Dunkelbier/Feines Dunkelbier + ingredients: + - Wheat/6 + cookingtime: 8 + distillruns: 0 + wood: 4 + age: 8 + color: BLACK + difficulty: 2 + alcohol: 7 + + met: + name: Scheußlicher Met/Met/&6Goldener Met + ingredients: + - Sugar_Cane/6 + cookingtime: 3 + distillruns: 0 + wood: 2 + age: 4 + color: ORANGE + difficulty: 2 + alcohol: 9 + lore: + - +++ Hat einen goldenen Schein + + apfelmet: + name: Apfelmet/Süßer Apfelmet/&6Goldensüßer Apfelmet + ingredients: + - Sugar_Cane/6 + - Apple/2 + cookingtime: 4 + distillruns: 0 + wood: 2 + age: 4 + color: ORANGE + difficulty: 4 + alcohol: 12 + lore: + - + Ist da wirklich Apfel drin? + - ++ Schmeckt nach süßem Apfel + - +++ Hat eine wunderbare Apfelnote + effects: + - WATER_BREATHING/1-2/150 + + rum: + name: Bitterer Rum/Würziger Rum/&6Goldener Rum + ingredients: + - Sugar_Cane/14 + cookingtime: 5 + distillruns: 2 + distilltime: 30 + wood: 2 + age: 14 + color: DARK_RED + difficulty: 6 + alcohol: 30 + effects: + - FIRE_RESISTANCE/1/20-100 + - POISON/1-0/30-0 + + vodka: + name: Abgeranzter Vodka/Vodka/Russischer Vodka + ingredients: + - Potato/10 + cookingtime: 15 + distillruns: 3 + age: 0 + color: BRIGHT_GREY + difficulty: 4 + alcohol: 20 + lore: + - + &8Fast nicht trinkbar + effects: + - WEAKNESS/15 + - POISON/10 + + absinth: + name: minderwertiger Absinth/Absinth/Starker Absinth + ingredients: + - Grass/15 + cookingtime: 3 + distillruns: 6 + distilltime: 80 + color: GREEN + difficulty: 8 + alcohol: 45 + effects: + - POISON/20-30 + + kartoffelsuppe: + name: Kartoffelsuppe + ingredients: + - Potato/5 + - Grass/3 + cookingtime: 3 + color: PINK + difficulty: 1 + effects: + - HEAL/0-1 + + kaffee: + name: Fader Kaffee/Kaffee/Starker Kaffee + ingredients: + - Cocoa_Beans/12 + - Milk_Bucket/2 + cookingtime: 2 + color: BLACK + difficulty: 3 + lore: + &8Bestimmt schon eine Woche alt + effects: + - REGENERATION/1/2-5 + - SPEED/1/30-140 # Mehr Ideen für Rezepte: Cachaca, Gin, Whiskey, Tequila, Cidre, etc, sowie Rezeptvarianten wie Goldener Vodka etc. # Ich werde keine weiteren Rezepte zu dieser Standardconfig hinzufügen, da diese öffentlich und für Spieler zum Abschauen einsehbar wären # Der Serveradmin kann neue Rezepte hinzufügen und bestehende ändern, um das Abschauen aus der Standardconfig zu verhindern. -# cooked: ALLE möglichen Zutaten und die nach dem Gähren daraus entstehenden Tranknamen: -# [Beispiel] MATERIAL: Name nach Gähren - -cooked: - Wheat: Getreideferment - Sugar_Cane: Zuckersud - Apple: Apfelmost - Potato: Kartoffelmaische - Grass: Kräuterbrühe - Red_Mushroom: Pilzsud - Cocoa_Beans: Farbige Brühe - Milk_Bucket: Milchiges Wasser - - - # -- Plugin Kompatiblität -- # Andere Plugins (wenn installiert) nach Rechten zum öffnen von Fässern checken [true] diff --git a/resources/config/v13/en/config.yml b/resources/config/v13/en/config.yml index 7227b2d..3e5050f 100644 --- a/resources/config/v13/en/config.yml +++ b/resources/config/v13/en/config.yml @@ -40,8 +40,8 @@ pukeDespawntime: 60 # Consumable Item/strength. Decreases the alcohol level by when consumed. (list) drainItems: -- Bread/4 -- Milk_Bucket/2 + - Bread/4 + - Milk_Bucket/2 # Time (in days) that drunkeness-data stays in memory after a player goes offline, to apply hangover etc. [7] hangoverDays: 7 @@ -81,6 +81,111 @@ autosave: 3 version: '1.8' +# -- Define custom items -- +# The defined id can then be used in recipes + +# matchAny: true if it is already enough if one of the info matches +# material: Which type the item has to be +# name: Which name the item has to be (Formatting codes possible: such as &6) +# lore: What has to be in the lore of the item + +customItems: + ex-item: + # A Barrier item called Wall and has the given line in its lore + material: Barrier + name: 'Wall' + lore: + - '&7Very well protected' + + ex-item2: + # Using matchAny only one of the following has to match. + # In this case on of the door types, or an item called Beechwood Door, or an item with 'A door' in its lore + matchAny: true + material: + - Acacia_Door + - Oak_Door + - Spruce_Door + name: + - 'Beechwood Door' + lore: + - 'A door' + + rasp: + name: '&cRaspberry' + + +# -- Ingredients in the Cauldron -- +# Which Ingredients are accepted by the Cauldron and the base potion resulting from them + +# name: Name of the base potion coming out of the Cauldron (Formatting codes possible: such as &6) +# ingredients: List of 'material/amount' +# With an item in your hand, use /brew ItemName to get its material for use in a recipe +# (Item-ids instead of material are not supported by bukkit anymore and will not work) +# A list of materials can be found here: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html +# color: Color of the potion from a cauldron. +# Usable Colors: DARK_RED, RED, BRIGHT_RED, ORANGE, PINK, BLUE, CYAN, WATER, GREEN, BLACK, GREY, BRIGHT_GREY +# Or RGB colors (hex: for example '99FF33') (with '') (search for "HTML color" on the internet) +# lore: List of additional text on the base potion. (Formatting codes possible: such as &6) + +cauldron: + ex: + name: Example + ingredients: + - Bedrock/2 + - Diamond + color: BLACK + lore: + - An example for a Base Potion + - This is how it comes out of a Cauldron + + # -- One Ingredient: -- + wheat: + name: Fermented wheat + ingredients: Wheat + + sugarcane: + name: Sugar brew + ingredients: Sugar_Cane + color: 'f1ffad' # yellowish green + + apple: + name: Apple cider + ingredients: Apple + + potato: + name: Potatomash + ingredients: Potato + + grass: + name: Boiled herbs + ingredients: Grass + color: '99ff66' # bright green + + rmushroom: + name: Mushroom brew + ingredients: Red_Mushroom + color: 'ff5c33' # amber red + + cocoa: + name: Chocolately brew + ingredients: Cocoa_Beans + color: '804600' # mocca + + milk: + name: Milky water + ingredients: Milk_Bucket + color: BRIGHT_GREY + + # -- Multiple Ingredients: -- + apfelmet_base: + name: Apple-Sugar brew + ingredients: + - Sugar_Cane/3 + - Apple + color: 'e1ff4d' # greenish yellow + + + # -- Recipes for Potions -- # name: Different names for bad/normal/good (Formatting codes possible: such as &6) @@ -101,8 +206,6 @@ version: '1.8' # alcohol: Absolute amount of alcohol 0-100 in a perfect potion (will be added directly to the player, where 100 means fainting) # 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. -# 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. # effects: List of effect/level/duration Special potion-effect when drinking, duration in sek. # Possible Effects: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionEffectType.html # Level or Duration ranges may be specified with a "-", ex. 'SPEED/1-2/30-40' = lvl 1 and 30 sec at worst and lvl 2 and 40 sec at best @@ -110,188 +213,180 @@ version: '1.8' # Highest possible Duration: 1638 sec. Instant Effects dont need any duration specified. recipes: -# Example Recipe with every possible entry first: - 0: - name: Bad Example/Example/Good Example - ingredients: - - Sugar_Cane/5 + # Example Recipe with every possible entry first: + ex: + name: Bad Example/Example/Good Example + ingredients: - Diamond/1 - - Cocoa_Beans/20 - Spruce_Planks/8 - Bedrock/1 - cookingtime: 3 - distillruns: 2 - distilltime: 60 - wood: 4 - age: 11 - color: DARK_RED - difficulty: 3 - alcohol: 23 - lore: - - This is an examble brew - - ++Just a normal Example - - This text would be on the brew - - + Smells disgusting - - ++ Smells alright - - +++ Smells really good - effects: + cookingtime: 3 + distillruns: 2 + distilltime: 60 + wood: 4 + age: 11 + color: DARK_RED + difficulty: 3 + alcohol: 23 + lore: + - This is an examble brew + - ++Just a normal Example + - This text would be on the brew + - + Smells disgusting + - ++ Smells alright + - +++ Smells really good + effects: - FIRE_RESISTANCE/20 - HEAL/1 - WEAKNESS/2-3/50-60 - POISON/1-0/20-0 - 1: - name: Skunky Wheatbeer/Wheatbeer/Fine Wheatbeer - ingredients: + + wheatbeer: + name: Skunky Wheatbeer/Wheatbeer/Fine Wheatbeer + ingredients: - Wheat/3 - cookingtime: 8 - distillruns: 0 - wood: 1 - age: 2 - color: BRIGHT_GREY - difficulty: 1 - alcohol: 5 - 2: - name: Skunky Beer/Beer/Fine Beer - ingredients: + cookingtime: 8 + distillruns: 0 + wood: 1 + age: 2 + color: BRIGHT_GREY + difficulty: 1 + alcohol: 5 + + beer: + name: Skunky Beer/Beer/Fine Beer + ingredients: - Wheat/6 - cookingtime: 8 - distillruns: 0 - wood: 0 - age: 3 - color: ORANGE - difficulty: 1 - lore: - - +++ &8Crisp taste - alcohol: 6 - 3: - name: Skunky Darkbeer/Darkbeer/Fine Darkbeer - ingredients: + cookingtime: 8 + distillruns: 0 + wood: 0 + age: 3 + color: ORANGE + difficulty: 1 + lore: + - +++ &8Crisp taste + alcohol: 6 + + darkbeer: + name: Skunky Darkbeer/Darkbeer/Fine Darkbeer + ingredients: - Wheat/6 - cookingtime: 8 - distillruns: 0 - wood: 4 - age: 8 - color: BLACK - difficulty: 2 - lore: - - +++ &8Roasted taste - alcohol: 7 - 4: - name: Awkward Mead/Mead/&6Golden Mead - ingredients: + cookingtime: 8 + distillruns: 0 + wood: 4 + age: 8 + color: BLACK + difficulty: 2 + lore: + - +++ &8Roasted taste + alcohol: 7 + + mead: + name: Awkward Mead/Mead/&6Golden Mead + ingredients: - Sugar_Cane/6 - cookingtime: 3 - distillruns: 0 - wood: 2 - age: 4 - color: ORANGE - difficulty: 2 - lore: - - +++ Has a golden shine - alcohol: 9 - 5: - name: Apple Mead/Sweet Apple Mead/&6Sweet Golden Apple Mead - ingredients: + cookingtime: 3 + distillruns: 0 + wood: 2 + age: 4 + color: ORANGE + difficulty: 2 + lore: + - +++ Has a golden shine + alcohol: 9 + + ap_mead: + name: Apple Mead/Sweet Apple Mead/&6Sweet Golden Apple Mead + ingredients: - Sugar_Cane/6 - Apple/2 - cookingtime: 4 - distillruns: 0 - wood: 2 - age: 4 - color: ORANGE - difficulty: 4 - alcohol: 12 - lore: - - +Is there any Apple in this? - - ++Refreshing taste of Apple - - +++Sweetest hint of Apple - effects: + cookingtime: 4 + distillruns: 0 + wood: 2 + age: 4 + color: ORANGE + difficulty: 4 + alcohol: 12 + lore: + - +Is there any Apple in this? + - ++Refreshing taste of Apple + - +++Sweetest hint of Apple + effects: - WATER_BREATHING/1-2/150 - 6: - name: Bitter Rum/Spicy Rum/&6Golden Rum - ingredients: + + rum: + name: Bitter Rum/Spicy Rum/&6Golden Rum + ingredients: - Sugar_Cane/14 - cookingtime: 5 - distillruns: 2 - distilltime: 30 - wood: 2 - age: 14 - color: DARK_RED - difficulty: 6 - alcohol: 30 - effects: + cookingtime: 5 + distillruns: 2 + distilltime: 30 + wood: 2 + age: 14 + color: DARK_RED + difficulty: 6 + alcohol: 30 + effects: - FIRE_RESISTANCE/1/20-100 - POISON/1-0/30-0 - 7: - name: Lousy Vodka/Vodka/Russian Vodka - ingredients: + + vodka: + name: Lousy Vodka/Vodka/Russian Vodka + ingredients: - Potato/10 - cookingtime: 15 - distillruns: 3 - age: 0 - color: BRIGHT_GREY - difficulty: 4 - alcohol: 20 - lore: +&8Almost undrinkable - effects: + cookingtime: 15 + distillruns: 3 + age: 0 + color: BRIGHT_GREY + difficulty: 4 + alcohol: 20 + lore: +&8Almost undrinkable + effects: - WEAKNESS/15 - POISON/10 - 8: - name: Poor Absinthe/Absinthe/Strong Absinthe - ingredients: - - Grass/15 - cookingtime: 3 - distillruns: 6 - distilltime: 80 - color: GREEN - difficulty: 8 - alcohol: 45 - effects: - - POISON/20-30 - 9: - name: Potato soup - ingredients: - - Potato/5 - - Grass/3 - cookingtime: 3 - color: PINK - difficulty: 1 - effects: - - HEAL/0-1 - 10: - name: Stale Coffee/Coffee/Strong Coffee - ingredients: - - Cocoa_Beans/12 - - Milk_Bucket/2 - cookingtime: 2 - color: BLACK - difficulty: 3 - lore: + &8Probably a week old - effects: - - REGENERATION/1/2-5 - - SPEED/1/30-140 + + absinthe: + name: Poor Absinthe/Absinthe/Strong Absinthe + ingredients: + - Grass/15 + cookingtime: 3 + distillruns: 6 + distilltime: 80 + color: GREEN + difficulty: 8 + alcohol: 45 + effects: + - POISON/20-30 + + potato_soup: + name: Potato soup + ingredients: + - Potato/5 + - Grass/3 + cookingtime: 3 + color: PINK + difficulty: 1 + effects: + - HEAL/0-1 + + coffee: + name: Stale Coffee/Coffee/Strong Coffee + ingredients: + - Cocoa_Beans/12 + - Milk_Bucket/2 + cookingtime: 2 + color: BLACK + difficulty: 3 + lore: + &8Probably a week old + effects: + - REGENERATION/1/2-5 + - SPEED/1/30-140 # More Recipes ideas: Cachaca, Gin, Whiskey, Tequila, Cider, etc. as well as high quality abbreviations like golden vodka etc. # I will not add more Recipes to the default config, as they would be public and viewable by users to cheat. # It is up to the Serveradmin to change and add Recipes, so players cannot cheat from the default config. - -# cooked: EVERY possible ingredient and the names for the originating potions after fermenting: -# [Example] MATERIAL: Name after cooking - -cooked: - Wheat: Fermented wheat - Sugar_Cane: Sugar brew - Apple: Apple cider - Potato: Potatomash - Grass: Boiled herbs - Red_Mushroom: Mushroom brew - Cocoa_Beans: Colored brew - Milk_Bucket: Milky water - - - # -- Plugin Compatibility -- # Enable checking of other Plugins (if installed) for Barrel Permissions [true] diff --git a/src/com/dre/brewery/BCauldron.java b/src/com/dre/brewery/BCauldron.java index b8cd460..3552f66 100644 --- a/src/com/dre/brewery/BCauldron.java +++ b/src/com/dre/brewery/BCauldron.java @@ -177,6 +177,7 @@ public class BCauldron { ItemStack item = event.getItem(); Player player = event.getPlayer(); Block clickedBlock = event.getClickedBlock(); + assert clickedBlock != null; if (materialInHand == null || materialInHand == Material.AIR || materialInHand == Material.BUCKET) { return; @@ -187,6 +188,7 @@ public class BCauldron { // fill a glass bottle with potion } else if (materialInHand == Material.GLASS_BOTTLE) { + assert item != null; if (player.getInventory().firstEmpty() != -1 || item.getAmount() == 1) { BCauldron bcauldron = get(clickedBlock); if (bcauldron != null) { @@ -233,12 +235,7 @@ public class BCauldron { if (event.getHand() == EquipmentSlot.HAND) { final UUID id = player.getUniqueId(); plInteracted.add(id); - P.p.getServer().getScheduler().runTask(P.p, new Runnable() { - @Override - public void run() { - plInteracted.remove(id); - } - }); + P.p.getServer().getScheduler().runTask(P.p, () -> plInteracted.remove(id)); } else if (event.getHand() == EquipmentSlot.OFF_HAND) { if (!plInteracted.remove(player.getUniqueId())) { item = player.getInventory().getItemInMainHand(); @@ -254,29 +251,30 @@ public class BCauldron { if (item == null) return; // add ingredient to cauldron that meet the previous conditions - if (BIngredients.possibleIngredients.contains(materialInHand)) { + if (BCauldronRecipe.acceptedMaterials.contains(materialInHand)) { - if (player.hasPermission("brewery.cauldron.insert")) { - if (ingredientAdd(clickedBlock, item, player)) { - 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 (!player.hasPermission("brewery.cauldron.insert")) { + P.p.msg(player, P.p.languageReader.get("Perms_NoCauldronInsert")); + return; + } - if (isBucket) { - giveItem(player, new ItemStack(Material.BUCKET)); - } + if (ingredientAdd(clickedBlock, item, player)) { + 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) { + giveItem(player, new ItemStack(Material.BUCKET)); + } + } else { + if (isBucket) { + setItemInHand(event, Material.BUCKET, handSwap); } else { - if (isBucket) { - setItemInHand(event, Material.BUCKET, handSwap); - } else { - setItemInHand(event, Material.AIR, handSwap); - } + setItemInHand(event, Material.AIR, handSwap); } } - } else { - P.p.msg(player, P.p.languageReader.get("Perms_NoCauldronInsert")); } } } @@ -353,11 +351,7 @@ public class BCauldron { // bukkit bug not updating the inventory while executing event, have to // schedule the give public static void giveItem(final Player player, final ItemStack item) { - P.p.getServer().getScheduler().runTaskLater(P.p, new Runnable() { - public void run() { - player.getInventory().addItem(item); - } - }, 1L); + P.p.getServer().getScheduler().runTaskLater(P.p, () -> player.getInventory().addItem(item), 1L); } } diff --git a/src/com/dre/brewery/BCauldronRecipe.java b/src/com/dre/brewery/BCauldronRecipe.java new file mode 100644 index 0000000..6968829 --- /dev/null +++ b/src/com/dre/brewery/BCauldronRecipe.java @@ -0,0 +1,141 @@ +package com.dre.brewery; + +import com.dre.brewery.utility.CustomItem; +import com.dre.brewery.utility.PotionColor; +import com.dre.brewery.utility.Tuple; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class BCauldronRecipe { + public static List recipes = new ArrayList<>(); + public static Set acceptedMaterials = EnumSet.noneOf(Material.class); + + private String name; + private List> ingredients; // Item and amount + //private List particles + private PotionColor color; + private List lore; + + + @Nullable + public static BCauldronRecipe fromConfig(ConfigurationSection cfg, String id) { + BCauldronRecipe recipe = new BCauldronRecipe(); + + recipe.name = cfg.getString(id + ".name"); + if (recipe.name != null) { + recipe.name = P.p.color(recipe.name); + } else { + P.p.errorLog("Missing name for Cauldron-Recipe: " + id); + return null; + } + + recipe.ingredients = BRecipe.loadIngredients(cfg, id); + if (recipe.ingredients == null || recipe.ingredients.isEmpty()) { + P.p.errorLog("No ingredients for Cauldron-Recipe: " + recipe.name); + return null; + } + + String col = cfg.getString(id + ".color"); + if (col != null) { + recipe.color = PotionColor.fromString(col); + } else { + recipe.color = PotionColor.CYAN; + } + if (recipe.color == PotionColor.WATER && !col.equals("WATER")) { + recipe.color = PotionColor.CYAN; + // Don't throw error here as old mc versions will not know even the default colors + //P.p.errorLog("Invalid Color '" + col + "' in Cauldron-Recipe: " + recipe.name); + //return null; + } + + + List> lore = BRecipe.loadLore(cfg, id + ".lore"); + if (lore != null && !lore.isEmpty()) { + recipe.lore = lore.stream().map(Tuple::second).collect(Collectors.toList()); + } + + return recipe; + } + + @NotNull + public String getName() { + return name; + } + + @NotNull + public List> getIngredients() { + return ingredients; + } + + @NotNull + public PotionColor getColor() { + return color; + } + + @Nullable + public List getLore() { + return lore; + } + + /** + * Find how much these ingredients match the given ones from 0-10. + * If any ingredient is missing, returns 0 + * If all Ingredients and their amounts are equal, returns 10 + * Returns something between 0 and 10 if all ingredients present, but differing amounts, depending on how much the amount differs. + */ + public float getIngredientMatch(List items) { + if (items.size() < ingredients.size()) { + return 0; + } + float match = 10; + search: for (Tuple ing : ingredients) { + for (ItemStack item : items) { + if (ing.a().matches(item)) { + double difference = Math.abs(ing.b() - item.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 = item.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 " + ing.a() + "/" + ing.b() + ": " + mod); + assert mod >= 0.1; + assert mod <= 1; // TODO Test + + + + + match *= mod; + continue search; + } + } + return 0; + } + if (items.size() > ingredients.size()) { + // If there are too many items in the List, multiply the match by 0.1 per Item thats too much + float tooMuch = items.size() - ingredients.size(); + float mod = 0.1f / tooMuch; + match *= mod; + } + P.p.debugLog("Match for Cauldron Recipe " + name + ": " + match); + return match; + } + + @Override + public String toString() { + return "BCauldronRecipe{" + name + '}'; + } +} diff --git a/src/com/dre/brewery/BIngredients.java b/src/com/dre/brewery/BIngredients.java index 873dcc5..9d3b0fd 100644 --- a/src/com/dre/brewery/BIngredients.java +++ b/src/com/dre/brewery/BIngredients.java @@ -7,21 +7,21 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.PotionMeta; +import org.jetbrains.annotations.Nullable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class BIngredients { - public static Set possibleIngredients = new HashSet<>(); - public static ArrayList recipes = new ArrayList<>(); - public static Map cookedNames = new HashMap<>(); private static int lastId = 0; private int id; // Legacy private List ingredients = new ArrayList<>(); - private Map materials = new HashMap<>(); // Merged List Of ingredients that doesnt consider Durability private int cookedTime; // Represents ingredients in Cauldron, Brew @@ -37,10 +37,6 @@ public class BIngredients { this.cookedTime = cookedTime; //this.id = lastId; //lastId++; - - for (ItemStack item : ingredients) { - addMaterial(item); - } } // Load from legacy Brew section @@ -54,7 +50,6 @@ public class BIngredients { // Add an ingredient to this public void add(ItemStack ingredient) { - addMaterial(ingredient); for (ItemStack item : ingredients) { if (item.isSimilar(ingredient)) { item.setAmount(item.getAmount() + ingredient.getAmount()); @@ -64,20 +59,12 @@ public class BIngredients { ingredients.add(ingredient); } - 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()); - } - } - // 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; @@ -96,11 +83,11 @@ public class BIngredients { lore.updateQualityStars(false); lore.updateCustomLore(); lore.updateAlc(false); - lore.addOrReplaceEffects(brew.getEffects(), brew.getQuality()); + lore.write(); cookedName = cookRecipe.getName(quality); - PotionColor.fromString(cookRecipe.getColor()).colorBrew(potionMeta, potion, false); + cookRecipe.getColor().colorBrew(potionMeta, potion, false); } else { // new base potion @@ -110,14 +97,16 @@ public class BIngredients { cookedName = P.p.languageReader.get("Brew_ThickBrew"); 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); - 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); } } } @@ -174,7 +163,7 @@ public class BIngredients { int woodQuality; int ageQuality; BRecipe bestRecipe = null; - for (BRecipe recipe : recipes) { + for (BRecipe recipe : BRecipe.recipes) { ingredientQuality = getIngredientQuality(recipe); cookingQuality = getCookingQuality(recipe, distilled); @@ -221,9 +210,29 @@ 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.recipes) { + 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 @@ -235,8 +244,7 @@ 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); @@ -248,8 +256,7 @@ 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; @@ -258,20 +265,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; - } 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)) { @@ -346,8 +342,7 @@ public class BIngredients { if (!(obj instanceof BIngredients)) return false; BIngredients other = ((BIngredients) obj); return cookedTime == other.cookedTime && - ingredients.equals(other.ingredients) && - materials.equals(other.materials); + ingredients.equals(other.ingredients); } // Creates a copy ingredients @@ -355,11 +350,10 @@ public class BIngredients { public BIngredients clone() { try { super.clone(); - } catch (CloneNotSupportedException ingored) { + } catch (CloneNotSupportedException ignored) { } BIngredients copy = new BIngredients(); copy.ingredients.addAll(ingredients); - copy.materials.putAll(materials); copy.cookedTime = cookedTime; return copy; } diff --git a/src/com/dre/brewery/BRecipe.java b/src/com/dre/brewery/BRecipe.java index 6ce49e9..2e107ce 100644 --- a/src/com/dre/brewery/BRecipe.java +++ b/src/com/dre/brewery/BRecipe.java @@ -1,121 +1,195 @@ package com.dre.brewery; import com.dre.brewery.filedata.BConfig; +import com.dre.brewery.utility.CustomItem; import com.dre.brewery.utility.PotionColor; import com.dre.brewery.utility.Tuple; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.craftbukkit.libs.jline.internal.Nullable; 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.stream.Collectors; public class BRecipe { + public static List recipes = new ArrayList<>(); + private String[] name; - private ArrayList ingredients = new ArrayList<>(); // material and amount + private List> ingredients = new ArrayList<>(); // Items and amounts private int cookingTime; // time to cook in cauldron private byte distillruns; // runs through the brewer private int distillTime; // time for one distill run in seconds private byte wood; // type of wood the barrel has to consist of private int age; // time in minecraft days for the potions to age in barrels - private String color; // color of the destilled/finished potion + private PotionColor color; // color of the destilled/finished potion private int difficulty; // difficulty to brew the potion, how exact the instruction has to be followed private int alcohol; // Alcohol in perfect potion private List> lore; // Custom Lore on the Potion. The int is for Quality Lore, 0 = any, 1,2,3 = Bad,Middle,Good private ArrayList effects = new ArrayList<>(); // Special Effects when drinking - public BRecipe(ConfigurationSection configSectionRecipes, String recipeId) { + public BRecipe() { + } + + @Nullable + public static BRecipe fromConfig(ConfigurationSection configSectionRecipes, String recipeId) { + BRecipe recipe = new BRecipe(); String nameList = configSectionRecipes.getString(recipeId + ".name"); if (nameList != null) { String[] name = nameList.split("/"); if (name.length > 2) { - this.name = name; + recipe.name = name; } else { - this.name = new String[1]; - this.name[0] = name[0]; + recipe.name = new String[1]; + recipe.name[0] = name[0]; } } else { - return; + P.p.errorLog(recipeId + ": Recipe Name missing or invalid!"); + return null; } - 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 && 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) { - 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; - } + if (recipe.getRecipeName() == null || recipe.getRecipeName().length() < 1) { + P.p.errorLog(recipeId + ": Recipe Name invalid"); + return null; + } + + recipe.ingredients = loadIngredients(configSectionRecipes, recipeId); + if (recipe.ingredients == null || recipe.ingredients.isEmpty()) { + P.p.errorLog("No ingredients for: " + recipe.getRecipeName()); + return null; + } + recipe.cookingTime = configSectionRecipes.getInt(recipeId + ".cookingtime", 1); + int dis = configSectionRecipes.getInt(recipeId + ".distillruns", 0); + if (dis > Byte.MAX_VALUE) { + recipe.distillruns = Byte.MAX_VALUE; + } else { + recipe.distillruns = (byte) dis; + } + recipe.distillTime = configSectionRecipes.getInt(recipeId + ".distilltime", 0) * 20; + recipe.wood = (byte) configSectionRecipes.getInt(recipeId + ".wood", 0); + recipe.age = configSectionRecipes.getInt(recipeId + ".age", 0); + recipe.difficulty = configSectionRecipes.getInt(recipeId + ".difficulty", 0); + recipe.alcohol = configSectionRecipes.getInt(recipeId + ".alcohol", 0); + + String col = configSectionRecipes.getString(recipeId + ".color", "BLUE"); + recipe.color = PotionColor.fromString(col); + if (recipe.color == PotionColor.WATER && !col.equals("WATER")) { + P.p.errorLog("Invalid Color '" + col + "' in Recipe: " + recipe.getRecipeName()); + return null; + } + + recipe.lore = loadLore(configSectionRecipes, recipeId + ".lore"); + + List 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 { - return; + P.p.errorLog("Error adding Effect to Recipe: " + recipe.getRecipeName()); } } } - this.cookingTime = configSectionRecipes.getInt(recipeId + ".cookingtime", 1); - int dis = configSectionRecipes.getInt(recipeId + ".distillruns", 0); - if (dis > Byte.MAX_VALUE) { - this.distillruns = Byte.MAX_VALUE; - } else { - this.distillruns = (byte) dis; - } - 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); + 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 if (ingredParts[0].contains(";")) { + matParts = ingredParts[0].split(";"); + } else { + matParts = ingredParts[0].split("\\."); + } + + // Try to find this Ingredient as Custom Item + for (CustomItem custom : BConfig.customItems) { + if (custom.getId().equalsIgnoreCase(matParts[0])) { + ingredients.add(new Tuple<>(custom, amount)); + BCauldronRecipe.acceptedMaterials.addAll(custom.getMaterials()); + 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) { + CustomItem custom; + if (durability > -1) { + custom = CustomItem.asSimpleItem(mat, durability); + } else { + custom = CustomItem.asSimpleItem(mat); + } + ingredients.add(new Tuple<>(custom, amount)); + BCauldronRecipe.acceptedMaterials.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 = null; - if (configSectionRecipes.isString(recipeId + ".lore")) { + if (cfg.isString(path)) { load = new ArrayList<>(1); - load.add(configSectionRecipes.getString(recipeId + ".lore")); - } else if (configSectionRecipes.isList(recipeId + ".lore")) { - load = configSectionRecipes.getStringList(recipeId + ".lore"); + load.add(cfg.getString(path)); + } else if (cfg.isList(path)) { + load = cfg.getStringList(path); } if (load != null) { + List> lore = new ArrayList<>(load.size()); for (String line : load) { line = P.p.color(line); int plus = 0; @@ -135,34 +209,15 @@ public class BRecipe { if (!line.startsWith("§")) { line = "§9" + line; } - if (lore == null) lore = new ArrayList<>(); lore.add(new Tuple<>(plus, line)); } + return lore; } - - 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: " + getRecipeName()); - } - } - } + return null; } // 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 (getRecipeName() == null || getRecipeName().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: " + getRecipeName()); return false; @@ -187,11 +242,6 @@ public class BRecipe { P.p.errorLog("Invalid age time '" + age + "' in Recipe: " + getRecipeName()); return false; } - String c = getColor(); - if (!c.equals("WATER") && PotionColor.fromString(c) == PotionColor.WATER) { - P.p.errorLog("Invalid Color '" + color + "' in Recipe: " + getRecipeName()); - return false; - } if (difficulty < 0 || difficulty > 10) { P.p.errorLog("Invalid difficulty '" + difficulty + "' in Recipe: " + getRecipeName()); return false; @@ -251,10 +301,10 @@ public class BRecipe { if (list.size() < ingredients.size()) { return true; } - for (ItemStack ingredient : ingredients) { + for (Tuple ingredient : ingredients) { boolean matches = false; for (ItemStack used : list) { - if (ingredientsMatch(used, ingredient)) { + if (ingredient.a().matches(used)) { matches = true; break; } @@ -266,24 +316,6 @@ public class BRecipe { 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 * @@ -301,14 +333,7 @@ public class BRecipe { * @return The created Brew */ public Brew createBrew(int quality) { - 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()); - } - } + List list = ingredients.stream().map(ing -> ing.a().createDummy(ing.b())).collect(Collectors.toList()); BIngredients bIngredients = new BIngredients(list, cookingTime); @@ -320,9 +345,9 @@ public class BRecipe { // 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(); + for (Tuple ingredient : ingredients) { + if (ingredient.a().matches(item)) { + return ingredient.b(); } } return 0; @@ -371,11 +396,8 @@ public class BRecipe { } @NotNull - public String getColor() { - if (color != null) { - return color.toUpperCase(); - } - return "BLUE"; + public PotionColor getColor() { + return color; } // get the woodtype @@ -434,7 +456,7 @@ public class BRecipe { } public static BRecipe get(String name) { - for (BRecipe recipe : BIngredients.recipes) { + for (BRecipe recipe : recipes) { if (recipe.getRecipeName().equalsIgnoreCase(name)) { return recipe; } diff --git a/src/com/dre/brewery/Brew.java b/src/com/dre/brewery/Brew.java index 69b4e6d..d23ef3e 100644 --- a/src/com/dre/brewery/Brew.java +++ b/src/com/dre/brewery/Brew.java @@ -194,7 +194,7 @@ public class Brew { public boolean setRecipeFromString(String name) { currentRecipe = null; if (name != null && !name.equals("")) { - for (BRecipe recipe : BIngredients.recipes) { + for (BRecipe recipe : BRecipe.recipes) { if (recipe.getRecipeName().equalsIgnoreCase(name)) { currentRecipe = recipe; return true; @@ -458,9 +458,9 @@ public class Brew { this.immutable = immutable; if (currentRecipe != null && canDistill()) { if (immutable) { - PotionColor.fromString(currentRecipe.getColor()).colorBrew(((PotionMeta) potion.getItemMeta()), potion, false); + 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); } } } @@ -488,7 +488,7 @@ public class Brew { distillRuns += 1; BrewLore lore = new BrewLore(this, potionMeta); - BRecipe recipe = ingredients.getdistillRecipe(wood, ageTime); + BRecipe recipe = ingredients.getDistillRecipe(wood, ageTime); if (recipe != null) { // distillRuns will have an effect on the amount of alcohol, not the quality currentRecipe = recipe; @@ -496,7 +496,7 @@ public class Brew { 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; @@ -506,14 +506,13 @@ public class Brew { } // Distill Lore - if (currentRecipe != null) { - if (BConfig.colorInBrewer != BrewLore.hasColorLore(potionMeta)) { - lore.convertLore(BConfig.colorInBrewer); - } + if (currentRecipe != null && BConfig.colorInBrewer != BrewLore.hasColorLore(potionMeta)) { + lore.convertLore(BConfig.colorInBrewer); + } else { lore.updateQualityStars(BConfig.colorInBrewer); lore.updateCustomLore(); + lore.updateDistillLore(BConfig.colorInBrewer); } - lore.updateDistillLore(BConfig.colorInBrewer); lore.updateAlc(true); lore.write(); touch(); @@ -538,7 +537,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(); } @@ -568,7 +567,7 @@ public class Brew { 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; lore.removeEffects(); @@ -578,21 +577,20 @@ public class Brew { } // Lore - if (currentRecipe != null) { - if (BConfig.colorInBarrels != BrewLore.hasColorLore(potionMeta)) { - lore.convertLore(BConfig.colorInBarrels); + if (currentRecipe != null && BConfig.colorInBarrels != BrewLore.hasColorLore(potionMeta)) { + lore.convertLore(BConfig.colorInBarrels); + } else { + if (ageTime >= 1) { + lore.updateAgeLore(BConfig.colorInBarrels); } - } - if (ageTime >= 1) { - lore.updateAgeLore(BConfig.colorInBarrels); - } - if (ageTime > 0.5) { - if (BConfig.colorInBarrels && !unlabeled && currentRecipe != null) { - lore.updateWoodLore(true); + if (ageTime > 0.5) { + if (BConfig.colorInBarrels && !unlabeled && currentRecipe != null) { + lore.updateWoodLore(true); + } + lore.updateQualityStars(BConfig.colorInBarrels); + lore.updateCustomLore(); + lore.updateAlc(false); } - lore.updateQualityStars(BConfig.colorInBarrels); - lore.updateCustomLore(); - lore.updateAlc(false); } lore.write(); touch(); @@ -652,12 +650,12 @@ public class Brew { recipe = getCurrentRecipe(); } if (recipe == null) { - throw new IllegalArgumentException("Recipe can't be null if the brew doesn't have a currentRecipe"); + 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(); - PotionColor.fromString(recipe.getColor()).colorBrew(potionMeta, potion, false); + 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 @@ -762,15 +760,15 @@ public class Brew { if ((bools & 4) != 0) { wood = in.readFloat(); } + String recipe = null; if ((bools & 8) != 0) { - setRecipeFromString(in.readUTF()); - } else { - setRecipeFromString(null); + recipe = in.readUTF(); } unlabeled = (bools & 16) != 0; //persistent = (bools & 32) != 0; immutable = (bools & 32) != 0; ingredients = BIngredients.load(in); + setRecipeFromString(recipe); } // Save brew data into meta: lore/nbt @@ -895,7 +893,7 @@ public class Brew { if (hasRecipe()) { BrewLore lore = new BrewLore(this, potionMeta); lore.removeEffects(); - PotionColor.fromString(currentRecipe.getColor()).colorBrew(potionMeta, item, canDistill()); + currentRecipe.getColor().colorBrew(potionMeta, item, canDistill()); lore.removeLegacySpacing(); } else { PotionColor.GREY.colorBrew(potionMeta, item, canDistill()); diff --git a/src/com/dre/brewery/P.java b/src/com/dre/brewery/P.java index 57e5782..1a9cf2b 100644 --- a/src/com/dre/brewery/P.java +++ b/src/com/dre/brewery/P.java @@ -440,9 +440,10 @@ public class P extends JavaPlugin { // delete Data from Ram Barrel.barrels.clear(); BCauldron.bcauldrons.clear(); - BIngredients.possibleIngredients.clear(); - BIngredients.recipes.clear(); - BIngredients.cookedNames.clear(); + BRecipe.recipes.clear(); + BCauldronRecipe.acceptedMaterials.clear(); + BCauldronRecipe.recipes.clear(); + BConfig.customItems.clear(); BPlayer.clear(); Brew.legacyPotions.clear(); Wakeup.wakeups.clear(); @@ -458,9 +459,10 @@ public class P extends JavaPlugin { BConfig.reloader = sender; } // clear all existent config Data - BIngredients.possibleIngredients.clear(); - BIngredients.recipes.clear(); - BIngredients.cookedNames.clear(); + BRecipe.recipes.clear(); + BCauldronRecipe.acceptedMaterials.clear(); + BCauldronRecipe.recipes.clear(); + BConfig.customItems.clear(); DistortChat.words.clear(); DistortChat.ignoreText.clear(); DistortChat.commands = null; diff --git a/src/com/dre/brewery/filedata/BConfig.java b/src/com/dre/brewery/filedata/BConfig.java index f7ea235..03fe142 100644 --- a/src/com/dre/brewery/filedata/BConfig.java +++ b/src/com/dre/brewery/filedata/BConfig.java @@ -2,10 +2,11 @@ package com.dre.brewery.filedata; import com.dre.brewery.*; import com.dre.brewery.integration.WGBarrel; -import com.dre.brewery.integration.WGBarrel7; -import com.dre.brewery.integration.WGBarrel6; import com.dre.brewery.integration.WGBarrel5; +import com.dre.brewery.integration.WGBarrel6; +import com.dre.brewery.integration.WGBarrel7; import com.dre.brewery.utility.BUtil; +import com.dre.brewery.utility.CustomItem; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.command.CommandSender; @@ -18,6 +19,7 @@ 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; @@ -58,6 +60,9 @@ public class BConfig { 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() { @@ -184,40 +189,41 @@ public class BConfig { Brew.loadSeed(config, file); + // Loading custom items + ConfigurationSection configSection = config.getConfigurationSection("customItems"); + if (configSection != null) { + for (String custId : configSection.getKeys(false)) { + CustomItem custom = CustomItem.fromConfig(configSection, custId); + if (custom != null) { + customItems.add(custom); + } else { + p.errorLog("Loading the Custom Item with id: '" + custId + "' failed!"); + } + } + } + // loading recipes - ConfigurationSection configSection = config.getConfigurationSection("recipes"); + 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); + BRecipe recipe = BRecipe.fromConfig(configSection, recipeId); + if (recipe != null && recipe.isValid()) { + BRecipe.recipes.add(recipe); } else { p.errorLog("Loading the Recipe with id: '" + recipeId + "' failed!"); } } } - // loading cooked names and possible ingredients - configSection = config.getConfigurationSection("cooked"); + // Loading Cauldron Recipes + configSection = config.getConfigurationSection("cauldron"); 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); + for (String id : configSection.getKeys(false)) { + BCauldronRecipe recipe = BCauldronRecipe.fromConfig(configSection, id); + if (recipe != null) { + BCauldronRecipe.recipes.add(recipe); } else { - p.errorLog("Unknown Material: " + ingredient); + p.errorLog("Loading the Cauldron-Recipe with id: '" + id + "' failed!"); } } } diff --git a/src/com/dre/brewery/listeners/CommandListener.java b/src/com/dre/brewery/listeners/CommandListener.java index 12dbf7d..be9f50c 100644 --- a/src/com/dre/brewery/listeners/CommandListener.java +++ b/src/com/dre/brewery/listeners/CommandListener.java @@ -378,7 +378,6 @@ public class CommandListener implements CommandExecutor { } @Deprecated - @SuppressWarnings("deprecation") public void cmdCopy(CommandSender sender, int count) { if (!(sender instanceof Player)) { @@ -415,7 +414,6 @@ public class CommandListener implements CommandExecutor { } @Deprecated - @SuppressWarnings("deprecation") public void cmdDelete(CommandSender sender) { if (!(sender instanceof Player)) { @@ -441,7 +439,6 @@ public class CommandListener implements CommandExecutor { } @Deprecated - @SuppressWarnings("deprecation") public void cmdPersist(CommandSender sender) { if (!(sender instanceof Player)) { @@ -496,6 +493,7 @@ public class CommandListener implements CommandExecutor { } 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()) { @@ -526,6 +524,7 @@ public class CommandListener implements CommandExecutor { 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()) { @@ -607,7 +606,7 @@ public class CommandListener implements CommandExecutor { } BRecipe recipe = null; - for (BRecipe r : BIngredients.recipes) { + for (BRecipe r : BRecipe.recipes) { if (r.hasName(name)) { recipe = r; break; diff --git a/src/com/dre/brewery/lore/BrewLore.java b/src/com/dre/brewery/lore/BrewLore.java index 293cab6..8251fa8 100644 --- a/src/com/dre/brewery/lore/BrewLore.java +++ b/src/com/dre/brewery/lore/BrewLore.java @@ -1,6 +1,10 @@ package com.dre.brewery.lore; -import com.dre.brewery.*; +import com.dre.brewery.BEffect; +import com.dre.brewery.BIngredients; +import com.dre.brewery.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; @@ -81,6 +85,22 @@ public class BrewLore { } }*/ + /** + * 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 * @@ -179,16 +199,11 @@ public class BrewLore { * updates the Custom Lore */ public void updateCustomLore() { - int index = Type.CUSTOM.findInLore(lore); - - while (index > -1) { - lore.remove(index); - index = Type.CUSTOM.findInLore(lore); - } + removeLore(Type.CUSTOM); BRecipe recipe = brew.getCurrentRecipe(); if (recipe != null && recipe.hasLore()) { - index = -1; + int index = -1; for (String line : recipe.getLoreForQuality(brew.getQuality())) { if (index == -1) { index = addLore(Type.CUSTOM, "", line); @@ -198,11 +213,6 @@ public class BrewLore { index++; } } - - /*if (index < lore.size()) { - // If there are more lines after this, add a spacer - lore.add(index, Type.SPACE.id); - }*/ } } @@ -229,7 +239,7 @@ public class BrewLore { } public void updateAlc(boolean inDistiller) { - if (!brew.isUnlabeled() && (inDistiller || BConfig.alwaysShowAlc)) { + if (!brew.isUnlabeled() && (inDistiller || BConfig.alwaysShowAlc) && (!brew.hasRecipe() || brew.getCurrentRecipe().getAlcohol() > 0)) { int alc = brew.calcAlcohol(); addOrReplaceLore(Type.ALC, "§8", P.p.languageReader.get("Brew_Alc", alc + "")); } else { @@ -333,10 +343,20 @@ public class BrewLore { * Searches for type and removes it */ public void removeLore(Type type) { - int index = type.findInLore(lore); - if (index > -1) { - lineAddedOrRem = true; - lore.remove(index); + 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; + } + } } } @@ -347,6 +367,7 @@ public class BrewLore { for (int i = lore.size() - 1; i >= 0; i--) { if (Type.get(lore.get(i)) != null) { lore.remove(i); + lineAddedOrRem = true; } } } diff --git a/src/com/dre/brewery/utility/CustomItem.java b/src/com/dre/brewery/utility/CustomItem.java new file mode 100644 index 0000000..8ec6849 --- /dev/null +++ b/src/com/dre/brewery/utility/CustomItem.java @@ -0,0 +1,329 @@ +package com.dre.brewery.utility; + +import com.dre.brewery.P; +import com.dre.brewery.filedata.BConfig; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +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.stream.Collectors; + +public class CustomItem { + private String id; + private boolean simple; // Simple Custom Item is just materials.get(0) and durability for old mc + private boolean matchAny; // If only one of the values needs to match + private short dur; // Old Mc + private List materials; + private List names; + private List lore; + + public static CustomItem asSimpleItem(Material mat) { + return asSimpleItem(mat, (short) 0); + } + + public static CustomItem asSimpleItem(Material mat, short dur) { + CustomItem it = new CustomItem(); + it.simple = true; + it.dur = dur; + it.materials = new ArrayList<>(1); + it.materials.add(mat); + return it; + } + + @Nullable + public static CustomItem fromConfig(ConfigurationSection cfg, String id) { + CustomItem custom = new CustomItem(); + + custom.id = id; + custom.matchAny = cfg.getBoolean(id + ".matchAny", false); + + List load = null; + String path = id + ".material"; + if (cfg.isString(path)) { + load = new ArrayList<>(1); + load.add(cfg.getString(path)); + } else if (cfg.isList(path)) { + load = cfg.getStringList(path); + } + if (load != null && !load.isEmpty()) { + custom.materials = new ArrayList<>(load.size()); + if (!custom.loadMaterials(load)) { + return null; + } + } else { + custom.materials = new ArrayList<>(0); + } + + load = null; + path = id + ".name"; + if (cfg.isString(path)) { + load = new ArrayList<>(1); + load.add(cfg.getString(path)); + } else if (cfg.isList(path)) { + load = cfg.getStringList(path); + } + if (load != null && !load.isEmpty()) { + custom.names = load.stream().map(l -> P.p.color(l)).collect(Collectors.toList()); + if (P.use1_13) { + // In 1.13 trailing Color white is removed from display names + custom.names = custom.names.stream().map(l -> l.startsWith("§f") ? l.substring(2) : l).collect(Collectors.toList()); + } + } else { + custom.names = new ArrayList<>(0); + } + + load = null; + path = id + ".lore"; + if (cfg.isString(path)) { + load = new ArrayList<>(1); + load.add(cfg.getString(path)); + } else if (cfg.isList(path)) { + load = cfg.getStringList(path); + } + if (load != null && !load.isEmpty()) { + custom.lore = load.stream().map(l -> P.p.color(l)).collect(Collectors.toList()); + } else { + custom.lore = new ArrayList<>(0); + } + + if (custom.materials.isEmpty() && custom.names.isEmpty() && custom.lore.isEmpty()) { + P.p.errorLog("No Config Entries found for Custom Item"); + return null; + } + + return custom; + } + + private boolean loadMaterials(List ingredientsList) { + for (String item : ingredientsList) { + String[] ingredParts = item.split("/"); + if (ingredParts.length == 2) { + P.p.errorLog("Item Amount can not be specified for Custom Items: " + item); + return false; + } + Material mat = Material.matchMaterial(ingredParts[0]); + + if (mat == null && BConfig.hasVault) { + try { + net.milkbowl.vault.item.ItemInfo vaultItem = net.milkbowl.vault.item.Items.itemByString(ingredParts[0]); + if (vaultItem != null) { + mat = vaultItem.getType(); + } + } catch (Exception e) { + P.p.errorLog("Could not check vault for Item Name"); + e.printStackTrace(); + } + } + if (mat != null) { + materials.add(mat); + } else { + P.p.errorLog("Unknown Material: " + ingredParts[0]); + return false; + } + } + return true; + } + + public String getId() { + return id; + } + + public boolean isSimple() { + return simple; + } + + public boolean isMatchAny() { + return matchAny; + } + + public List getMaterials() { + return materials; + } + + public Material getSimpleMaterial() { + return materials.get(0); + } + + public List getNames() { + return names; + } + + public List getLore() { + return lore; + } + + public boolean matches(ItemStack usedItem) { + if (simple) { + return matchSimple(usedItem); + } else if (matchAny){ + return matchAny(usedItem); + } else { + return matchOne(usedItem); + } + } + + private boolean matchSimple(ItemStack usedItem) { + if (!materials.get(0).equals(usedItem.getType())) { + return false; + } + //noinspection deprecation + return P.use1_13 || dur == usedItem.getDurability(); + } + + private boolean matchAny(ItemStack usedItem) { + Material usedMat = usedItem.getType(); + for (Material mat : materials) { + if (usedMat == mat) { + return true; + } + } + if (!usedItem.hasItemMeta()) { + return false; + } + ItemMeta meta = usedItem.getItemMeta(); + assert meta != null; + if (meta.hasDisplayName()) { + String usedName = meta.getDisplayName(); + for (String name : names) { + if (name.equalsIgnoreCase(usedName)) { + return true; + } + } + } + + if (meta.hasLore()) { + List usedLore = meta.getLore(); + assert usedLore != null; + for (String line : this.lore) { + for (String usedLine : usedLore) { + if (line.equalsIgnoreCase(usedLine) || line.equalsIgnoreCase(ChatColor.stripColor(usedLine))) { + return true; + } + } + } + } + return false; + } + + private boolean matchOne(ItemStack item) { + if (!materials.isEmpty()) { + if (item.getType() != materials.get(0)) { + return false; + } + } + if (names.isEmpty() && lore.isEmpty()) { + return true; + } + if (!item.hasItemMeta()) { + return false; + } + ItemMeta meta = item.getItemMeta(); + assert meta != null; + if (!names.isEmpty()) { + if (!meta.hasDisplayName() || !names.get(0).equalsIgnoreCase(meta.getDisplayName())) { + return false; + } + } + + + if (!lore.isEmpty()) { + if (!meta.hasLore()) { + return false; + } + + int lastIndex = 0; + List usedLore = meta.getLore(); + assert usedLore != null; + 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; + } + + @NotNull + public ItemStack createDummy(int amount) { + if (simple) { + if (P.use1_13) { + return new ItemStack(getSimpleMaterial(), amount); + } else { + //noinspection deprecation + return new ItemStack(getSimpleMaterial(), amount, dur); + } + } else if (matchAny) { + if (!materials.isEmpty()) { + return new ItemStack(materials.get(0), amount); + } else if (!names.isEmpty()) { + ItemStack item = new ItemStack(Material.DIAMOND_HOE, amount); + ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : P.p.getServer().getItemFactory().getItemMeta(Material.DIAMOND_HOE); + assert meta != null; + meta.setDisplayName(names.get(0)); + item.setItemMeta(meta); + return item; + } else if (!lore.isEmpty()) { + ItemStack item = new ItemStack(Material.DIAMOND_HOE, amount); + ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : P.p.getServer().getItemFactory().getItemMeta(Material.DIAMOND_HOE); + assert meta != null; + List l = new ArrayList<>(); + l.add(lore.get(0)); + meta.setLore(l); + item.setItemMeta(meta); + return item; + } + return new ItemStack(Material.DIAMOND_HOE, amount); + } else { + ItemStack item; + ItemMeta meta; + if (!materials.isEmpty()) { + item = new ItemStack(materials.get(0), amount); + meta = item.hasItemMeta() ? item.getItemMeta() : P.p.getServer().getItemFactory().getItemMeta(materials.get(0)); + } else { + item = new ItemStack(Material.DIAMOND_HOE, amount); + meta = item.hasItemMeta() ? item.getItemMeta() : P.p.getServer().getItemFactory().getItemMeta(Material.DIAMOND_HOE); + } + assert meta != null; + if (!names.isEmpty()) { + meta.setDisplayName(names.get(0)); + item.setItemMeta(meta); + } + if (!lore.isEmpty()) { + meta.setLore(lore); + item.setItemMeta(meta); + } + return item; + } + } + + @Override + public String toString() { + if (simple) { + return "CustomItem{Simple: " + getSimpleMaterial().name().toLowerCase() + "}"; + } + if (materials == null || names == null || lore == null) { + return "CustomItem{" + id + "}"; + } + return "CustomItem{" + id + ": " + (matchAny ? "MatchAny, " : "MatchOne, ") + materials.size() + " Materials, " + names.size() + " Names, " + lore.size() + " Lore}"; + } +} diff --git a/src/com/dre/brewery/utility/Tuple.java b/src/com/dre/brewery/utility/Tuple.java index 2d50c92..e388de5 100644 --- a/src/com/dre/brewery/utility/Tuple.java +++ b/src/com/dre/brewery/utility/Tuple.java @@ -27,21 +27,21 @@ */ package com.dre.brewery.utility; -public class Tuple { +public class Tuple { /** * The first value in the tuple */ - private final X x; + private final A a; /** * The second value in the tuple */ - private final Y y; + private final B b; - public Tuple(X x, Y y) { - this.x = x; - this.y = y; + public Tuple(A a, B b) { + this.a = a; + this.b = b; } /** @@ -49,8 +49,8 @@ public class Tuple { * * @return */ - public X first() { - return x; + public A first() { + return a; } /** @@ -58,8 +58,26 @@ public class Tuple { * * @return */ - public Y second() { - return y; + public B second() { + return b; + } + + /** + * Gets the first value in the tuple, Synonym for first() + * + * @return + */ + public A a() { + return a; + } + + /** + * Gets the second value in the tuple, Synonym for second() + * + * @return + */ + public B b() { + return b; } @Override @@ -69,12 +87,12 @@ public class Tuple { } Tuple tuple = (Tuple) object; - return tuple.x == x && tuple.y == y; + return tuple.a == a && tuple.b == b; } @Override public int hashCode() { - return x.hashCode() ^ y.hashCode(); + return a.hashCode() ^ b.hashCode(); } } diff --git a/test/com/dre/brewery/RecipeTests.java b/test/com/dre/brewery/RecipeTests.java new file mode 100644 index 0000000..284d325 --- /dev/null +++ b/test/com/dre/brewery/RecipeTests.java @@ -0,0 +1,50 @@ +package com.dre.brewery; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.List; + +public class RecipeTests { + + public static void testCauldronRecipe() { + ItemStack item = new ItemStack(Material.BARRIER); + ItemMeta itemMeta = item.getItemMeta(); + List l = new ArrayList<>(); + l.add("Eine Tür"); + l.add("§6Besonders gut geschützt"); + itemMeta.setLore(l); + itemMeta.setDisplayName("Mauer"); + item.setItemMeta(itemMeta); + + BRecipe recipe = BRecipe.get("Beispiel"); + int x = recipe.amountOf(item); + int y = recipe.amountOf(new ItemStack(Material.NETHER_BRICK)); + + + List list = new ArrayList<>(); + list.add(new ItemStack(Material.DIAMOND_HOE, 3)); + list.add(new ItemStack(Material.RED_MUSHROOM, 1)); + for (int i = 1; i < 20; i++) { + list.get(0).setAmount(i + 3); + list.get(1).setAmount(i); + BCauldronRecipe best = null; + float bestMatch = 0; + float match; + for (BCauldronRecipe r : BCauldronRecipe.recipes) { + match = r.getIngredientMatch(list); + if (match >= 10) { + P.p.debugLog("Found match 10 Recipe: " + r); + return; + } + if (match > bestMatch) { + best = r; + bestMatch = match; + } + } + P.p.debugLog("Found best for i:" + i + " " + best); + } + } +}