Repository navigation
Resolve Brewery ingredients from Cooking food identities #82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
61daf73
fix: identify whole Cooking potatoes in Brewery cauldrons
XxFran10xX c9a2197
fix: resolve Brewery ingredients from the Cooking catalog
XxFran10xX 688ff3a
fix: keep the Brewery gate out of cauldron recipes
XxFran10xX dad49cf
fix: restore the Brewery gate before cauldron clicks
XxFran10xX 2b74243
fix: keep warm raw foods as Brewery ingredients
XxFran10xX File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
src/main/java/net/tfminecraft/cooking/brewery/BreweryBridge.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package net.tfminecraft.cooking.brewery; | ||
|
|
||
| import org.bukkit.event.EventHandler; | ||
| import org.bukkit.event.Listener; | ||
| import org.bukkit.event.server.PluginDisableEvent; | ||
| import org.bukkit.event.server.PluginEnableEvent; | ||
| import org.bukkit.plugin.Plugin; | ||
| import org.bukkit.plugin.java.JavaPlugin; | ||
|
|
||
| /** Loads the Brewery-linked classes only while the optional plugin is available. */ | ||
| public final class BreweryBridge implements Listener, AutoCloseable { | ||
| private final JavaPlugin plugin; | ||
| private Runnable cleanup; | ||
|
|
||
| public BreweryBridge(JavaPlugin plugin) { this.plugin = plugin; } | ||
|
|
||
| @EventHandler | ||
| public void onPluginEnable(PluginEnableEvent event) { | ||
| if ("BreweryX".equals(event.getPlugin().getName())) registerIfPresent(); | ||
| } | ||
|
|
||
| @EventHandler | ||
| public void onPluginDisable(PluginDisableEvent event) { | ||
| if ("BreweryX".equals(event.getPlugin().getName())) close(); | ||
| } | ||
|
|
||
| public void registerIfPresent() { | ||
| Plugin brewery = plugin.getServer().getPluginManager().getPlugin("BreweryX"); | ||
| if (cleanup != null || brewery == null || !brewery.isEnabled()) return; | ||
| try { | ||
| Class<?> listener = Class.forName("net.tfminecraft.cooking.brewery.BreweryIngredientListener", | ||
| true, BreweryBridge.class.getClassLoader()); | ||
| cleanup = (Runnable) listener.getMethod("register", JavaPlugin.class).invoke(null, plugin); | ||
| plugin.getLogger().info("BreweryX Cooking ingredient resolver enabled."); | ||
| } catch (ReflectiveOperationException | LinkageError exception) { | ||
| plugin.getLogger().warning("BreweryX Cooking ingredient resolver could not register: " + exception); | ||
| } | ||
| } | ||
|
|
||
| @Override public void close() { | ||
| if (cleanup == null) return; | ||
| cleanup.run(); | ||
| cleanup = null; | ||
| } | ||
| } |
84 changes: 84 additions & 0 deletions
84
src/main/java/net/tfminecraft/cooking/brewery/BreweryIngredientListener.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| package net.tfminecraft.cooking.brewery; | ||
|
|
||
| import org.bukkit.event.EventHandler; | ||
| import org.bukkit.event.EventPriority; | ||
| import org.bukkit.event.HandlerList; | ||
| import org.bukkit.event.Listener; | ||
| import org.bukkit.event.block.Action; | ||
| import org.bukkit.event.player.PlayerInteractEvent; | ||
| import org.bukkit.inventory.ItemStack; | ||
| import org.bukkit.plugin.java.JavaPlugin; | ||
|
|
||
| import com.dre.brewery.api.events.IngedientAddEvent; | ||
| import com.dre.brewery.recipe.BCauldronRecipe; | ||
| import com.dre.brewery.recipe.RecipeItem; | ||
| import com.dre.brewery.recipe.SimpleItem; | ||
|
|
||
| import net.tfminecraft.cooking.item.FoodItem; | ||
| import net.tfminecraft.cooking.utils.ItemRef; | ||
| import net.tfminecraft.tlibs.TLibs; | ||
|
|
||
| /** Replaces only Brewery's internal ingredient copy; Brewery consumes the original item normally. */ | ||
| public final class BreweryIngredientListener implements Listener { | ||
| private final CookingIngredientGate gate = new CookingIngredientGate(); | ||
|
|
||
| public static Runnable register(JavaPlugin plugin) { | ||
| BreweryIngredientListener listener = new BreweryIngredientListener(); | ||
| listener.ensureGate(); | ||
| Runnable cleanup = () -> { | ||
| HandlerList.unregisterAll(listener); | ||
| BCauldronRecipe.acceptedCustom.removeIf(item -> item == listener.gate); | ||
| }; | ||
| try { | ||
| plugin.getServer().getPluginManager().registerEvents(listener, plugin); | ||
| } catch (RuntimeException | LinkageError exception) { | ||
| cleanup.run(); | ||
| throw exception; | ||
| } | ||
| return cleanup; | ||
| } | ||
|
|
||
| // Brewery only appends to this list when it reloads. A cauldron recipe would also keep the gate there, | ||
| // but would break /brew simulate, which cannot describe custom items. | ||
| private void ensureGate() { | ||
| if (!BCauldronRecipe.acceptedCustom.contains(gate)) BCauldronRecipe.acceptedCustom.add(gate); | ||
| } | ||
|
|
||
| /** Restores the gate before Brewery's click handler if anything rebuilt the accepted list. */ | ||
| @EventHandler(priority = EventPriority.LOWEST) | ||
| public void onCauldronClick(PlayerInteractEvent event) { | ||
| if (event.getAction() == Action.RIGHT_CLICK_BLOCK && BrewingIngredientResolver.isCookingItem(event.getItem())) ensureGate(); | ||
| } | ||
|
|
||
| @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) | ||
| public void onIngredient(IngedientAddEvent event) { | ||
| ItemStack input = event.getIngredient(); | ||
| try { | ||
| if (!BrewingIngredientResolver.isCookingItem(input)) { | ||
| // Preserve explicit custom ingredient recipes, but never treat another custom item as its base material. | ||
| if (event.getRecipeItem() instanceof SimpleItem) { | ||
| String path = TLibs.getItemAPI().getChecker().getAsStringPath(input); | ||
| if (path.startsWith("ia.") || path.startsWith("m.")) event.setCancelled(true); | ||
| } | ||
| return; | ||
| } | ||
| String source = BrewingIngredientResolver.sourceFor(FoodItem.fromItem(input)); | ||
| ItemStack canonical = source == null ? null : ItemRef.resolve(source); | ||
| if (canonical == null || canonical.getType().isAir() || BrewingIngredientResolver.isCookingItem(canonical)) { | ||
| event.setCancelled(true); | ||
| return; | ||
| } | ||
| RecipeItem match = RecipeItem.getMatchingRecipeItem(canonical, false); | ||
| if (match == null || (!source.startsWith("v.") && match instanceof SimpleItem)) { | ||
| event.setCancelled(true); | ||
| return; | ||
| } | ||
| canonical = canonical.clone(); | ||
| canonical.setAmount(1); | ||
| event.setIngredient(canonical); | ||
| } catch (RuntimeException | LinkageError exception) { | ||
| event.setCancelled(true); | ||
| throw exception; | ||
| } | ||
| } | ||
| } |
51 changes: 51 additions & 0 deletions
51
src/main/java/net/tfminecraft/cooking/brewery/BrewingIngredientResolver.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package net.tfminecraft.cooking.brewery; | ||
|
|
||
| import java.util.HashSet; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
|
|
||
| import org.bukkit.inventory.ItemStack; | ||
| import org.bukkit.persistence.PersistentDataType; | ||
|
|
||
| import net.tfminecraft.cooking.item.FoodItem; | ||
| import net.tfminecraft.cooking.item.tag.TagTrack; | ||
| import net.tfminecraft.cooking.loader.ConversionLoader; | ||
| import net.tfminecraft.cooking.utils.FoodParser; | ||
| import net.tfminecraft.cooking.utils.Keys; | ||
|
|
||
| /** Resolves whole ingredients back to their configured input, independently of their visual model. */ | ||
| public final class BrewingIngredientResolver { | ||
| private static final Set<String> IDENTITY_NEUTRAL = Set.of("freshness", "warmth"); | ||
|
|
||
| private BrewingIngredientResolver() {} | ||
|
|
||
| public static boolean isCookingItem(ItemStack item) { | ||
| return item != null && item.hasItemMeta() && item.getItemMeta().getPersistentDataContainer() | ||
| .has(Keys.FOOD_ID, PersistentDataType.STRING); | ||
| } | ||
|
|
||
| public static String sourceFor(FoodItem food) { | ||
| if (food == null || food.getOrigin() == null || food.hasSauce() || !food.getIngredients().isEmpty()) return null; | ||
| // Freshness and warmth never change identity. Other preparation states must remain raw. | ||
| for (TagTrack track : food.getTagTracks()) { | ||
| if (track.getCurrentStep() == null || IDENTITY_NEUTRAL.contains(track.getId())) continue; | ||
| if (!"cooked".equals(track.getId()) || !"raw".equals(track.getCurrentStep().getId())) return null; | ||
| } | ||
|
|
||
| Set<String> sources = new HashSet<>(); | ||
| for (Map.Entry<String, String> entry : ConversionLoader.get().entrySet()) { | ||
| String source = entry.getKey(); | ||
| String specification = entry.getValue(); | ||
| int open = specification.indexOf('('); | ||
| if (open < 0 || !specification.endsWith(")")) continue; | ||
| Map<String, String> fields = FoodParser.extractFields(specification.substring(open + 1, specification.length() - 1)); | ||
| if (food.getId().equalsIgnoreCase(fields.get("type")) | ||
| && food.getOrigin().equalsIgnoreCase(fields.get("origin"))) sources.add(source); | ||
| } | ||
| // Prefer the canonical vanilla name when several input variants describe the same food (e.g. eggs). | ||
| String vanilla = "v." + food.getOrigin().toLowerCase(Locale.ROOT).replace(' ', '_'); | ||
| if (sources.contains(vanilla)) return vanilla; | ||
| return sources.size() == 1 ? sources.iterator().next() : null; | ||
| } | ||
| } | ||
23 changes: 23 additions & 0 deletions
23
src/main/java/net/tfminecraft/cooking/brewery/CookingIngredientGate.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package net.tfminecraft.cooking.brewery; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import org.bukkit.Material; | ||
| import org.bukkit.inventory.ItemStack; | ||
|
|
||
| import com.dre.brewery.recipe.Ingredient; | ||
| import com.dre.brewery.recipe.RecipeItem; | ||
|
|
||
| /** Lets metadata-bearing Cooking items reach the resolver before Brewery rejects their visual base. */ | ||
| final class CookingIngredientGate extends RecipeItem { | ||
| CookingIngredientGate() { setAmount(1); makeImmutable(); } | ||
| @Override public boolean matches(ItemStack item) { return BrewingIngredientResolver.isCookingItem(item); } | ||
| @Override public boolean matches(Ingredient ingredient) { return false; } | ||
| @Override public boolean hasMaterials() { return false; } | ||
| @Override public List<Material> getMaterials() { return List.of(); } | ||
| @Override public String getDebugID() { return "cooking:identity_gate"; } | ||
| @Override public Ingredient toIngredient(ItemStack item) { throw new IllegalStateException("Cooking ingredient must be resolved first"); } | ||
| @Override public Ingredient toIngredientGeneric() { throw new IllegalStateException("Cooking gate is not a brewing ingredient"); } | ||
| @Override public boolean equals(Object other) { return this == other; } | ||
| @Override public int hashCode() { return System.identityHashCode(this); } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.