Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/dependencies.sha256
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ a37f7789fcdcd11c9e5890a2fac742aa4501749588af23182991953e06ee1d17 libs/MMOItems-
81d511d0830951f988615b6533cc93e82d00a83fb31e8ccbb36441ae3e8157ef libs/MMOCore-1.13.1-SNAPSHOT.jar
93317bf08c9dae4a645644caa313b5436b19e65cc13abf9f3e0afb951bd6c1d2 libs/CustomCrops-3.6.56.jar
7d3083bd05998d8cafd7114ced74a6fa2ec1c4d36f75dbbaee9f20d499a7c3ad libs/CustomFishing-2.3.27.jar
d7156d1cd2425d56592976351a3cfcb8646b1429a687d33c32098066c6c1c1c6 libs/BreweryX-3.7.0.jar
4 changes: 4 additions & 0 deletions .github/scripts/install-local-dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ set -euo pipefail
# Hash-qualified versions prevent different private JARs sharing a Maven cache key.
sha256sum --check .github/dependencies.sha256

mvn -B --no-transfer-progress org.apache.maven.plugins:maven-install-plugin:3.1.4:install-file \
-Dfile="libs/BreweryX-3.7.0.jar" -DgroupId="local" -DartifactId="BreweryX" \
-Dversion="3.7.0-tfmc-d7156d1cd242" -Dpackaging=jar -DgeneratePom=true "$@"

mvn -B --no-transfer-progress org.apache.maven.plugins:maven-install-plugin:3.1.4:install-file \
-Dfile="libs/gson-2.14.0.jar" -DgroupId="local" -DartifactId="gson" \
-Dversion="2.14.0-tfmc-2cbd119bf196" -Dpackaging=jar -DgeneratePom=true "$@"
Expand Down
1 change: 1 addition & 0 deletions .github/scripts/prepare-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set -euo pipefail
: "${GH_TOKEN:?Set DEPS_TOKEN with Contents read access to TF-Minecraft/ServerAssets}"
ref=4b80431398e4ff35d703cad915b7ee4e5924a763
mkdir -p libs
curl --fail --location --silent --show-error --retry 3 "https://cdn.modrinth.com/data/gvXaGv1n/versions/Q1Iefaeb/BreweryX-3.7.0.jar" > "libs/BreweryX-3.7.0.jar"
curl --fail --location --silent --show-error --retry 3 -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github.raw+json" "https://api.github.com/repos/TF-Minecraft/ServerAssets/contents/jars/2cbd119bf196/gson-2.14.0.jar?ref=$ref" > "libs/gson-2.14.0.jar"
curl --fail --location --silent --show-error --retry 3 -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github.raw+json" "https://api.github.com/repos/TF-Minecraft/ServerAssets/contents/jars/feca4db85337/joml-1.10.9.jar?ref=$ref" > "libs/joml-1.10.9.jar"
curl --fail --location --silent --show-error --retry 3 -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github.raw+json" "https://api.github.com/repos/TF-Minecraft/ServerAssets/contents/jars/225aa7f75d4e/MythicLib-1.7.1-SNAPSHOT.jar?ref=$ref" > "libs/MythicLib-1.7.1-SNAPSHOT.jar"
Expand Down
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
</dependencyManagement>

<dependencies>
<dependency>
<groupId>local</groupId>
<artifactId>BreweryX</artifactId>
<version>3.7.0-tfmc-d7156d1cd242</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/net/tfminecraft/cooking/Cooking.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import net.tfminecraft.tlibs.TLibs;
import net.tfminecraft.cooking.item.CookingPathHandler;
import net.tfminecraft.cooking.brewery.BreweryBridge;
import net.tfminecraft.cooking.loader.FoodLoader;
import net.tfminecraft.cooking.loader.ModelLoader;
import net.tfminecraft.cooking.loader.TrackLoader;
Expand Down Expand Up @@ -97,6 +98,7 @@ public class Cooking extends JavaPlugin {
private boolean incompatibleCharacterApi;

private final CommandManager commands = new CommandManager();
private final BreweryBridge breweryBridge = new BreweryBridge(this);

private final ModelLoader modelLoader = new ModelLoader();
private final FoodLoader foodLoader = new FoodLoader();
Expand Down Expand Up @@ -223,6 +225,7 @@ static void warnIfCharacterIdentityMissing(Logger logger) {
@Override
public void onDisable() {
if (incompatibleCharacterApi) return;
breweryBridge.close();
SaturationGuard.stop();
NutritionDrainTask.stop();
HusbandryTickTask.stop();
Expand Down Expand Up @@ -298,6 +301,8 @@ private void releaseAnimalsCommand() {
// Listeners
// ----------------------------------------------------------------------
public void registerListeners() {
getServer().getPluginManager().registerEvents(breweryBridge, this);
breweryBridge.registerIfPresent();
getServer().getPluginManager().registerEvents(plateManager, this);
getServer().getPluginManager().registerEvents(craftingManager, this);
getServer().getPluginManager().registerEvents(cookingManager, this);
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/net/tfminecraft/cooking/brewery/BreweryBridge.java
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;
}
}
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;
}
}
}
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;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

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;
}
}
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); }
}
2 changes: 1 addition & 1 deletion src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version: ${project.version}
author: Drefvelin

depend: [TLibs, InteractibleFurniture]
softdepend: [RPCharacters, MMOCore, MMOItems, CustomCrops, SimpleFactions, CustomFishing]
softdepend: [RPCharacters, MMOCore, MMOItems, CustomCrops, SimpleFactions, CustomFishing, BreweryX]

commands:
cooking:
Expand Down
Loading
Loading