90 lines
3.6 KiB
Java
90 lines
3.6 KiB
Java
package games.dmg.spigotheights;
|
|
|
|
import org.bukkit.Material;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.event.EventHandler;
|
|
import org.bukkit.event.EventPriority;
|
|
import org.bukkit.event.Listener;
|
|
import org.bukkit.event.inventory.BrewEvent;
|
|
|
|
/** Completes authenticated stature conversions at the native brewing transaction boundary. */
|
|
public final class StatureBrewing implements Listener {
|
|
private final PotionRecipes potions;
|
|
|
|
public StatureBrewing(PotionRecipes potions) {
|
|
this.potions = potions;
|
|
}
|
|
|
|
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
|
public void detachResults(BrewEvent event) {
|
|
if (event.isCancelled()) {
|
|
return;
|
|
}
|
|
try {
|
|
// Native no-op results can mirror the input itself. Detach before normal result modifiers
|
|
// run, otherwise an in-place result edit also changes the inventory despite cancellation.
|
|
for (int slot = 0; slot < Math.min(3, event.getResults().size()); slot++) {
|
|
ItemStack input = event.getContents().getItem(slot);
|
|
if (potions.identify(input) != null && input.equals(event.getResults().get(slot))) {
|
|
event.getResults().set(slot, input.clone());
|
|
}
|
|
}
|
|
} catch (RuntimeException exception) {
|
|
event.setCancelled(true);
|
|
throw exception;
|
|
}
|
|
}
|
|
|
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
|
public void brew(BrewEvent event) {
|
|
try {
|
|
convert(event);
|
|
} catch (RuntimeException exception) {
|
|
// Paper logs listener exceptions and continues dispatch: cancel first to prevent item loss.
|
|
event.setCancelled(true);
|
|
throw exception;
|
|
}
|
|
}
|
|
|
|
private void convert(BrewEvent event) {
|
|
ItemStack ingredient = event.getContents().getIngredient();
|
|
if (event.isCancelled() || ingredient == null) {
|
|
return;
|
|
}
|
|
Material source;
|
|
Material target;
|
|
if (ingredient.getType() == Material.GUNPOWDER) {
|
|
source = Material.POTION;
|
|
target = Material.SPLASH_POTION;
|
|
} else if (ingredient.getType() == Material.DRAGON_BREATH) {
|
|
source = Material.SPLASH_POTION;
|
|
target = Material.LINGERING_POTION;
|
|
} else {
|
|
return;
|
|
}
|
|
for (int slot = 0; slot < 3; slot++) {
|
|
ItemStack input = event.getContents().getItem(slot);
|
|
StaturePotion kind = potions.identify(input);
|
|
if (kind != null && input.getType() == source) {
|
|
if (slot >= event.getResults().size() || input.getAmount() != 1) {
|
|
event.setCancelled(true);
|
|
return;
|
|
}
|
|
ItemStack result = event.getResults().get(slot);
|
|
if (result != null && result.getType() == target
|
|
&& result.getAmount() == 1 && potions.identify(result) == kind) {
|
|
continue;
|
|
}
|
|
if (!input.equals(result)) {
|
|
// Do not overwrite another plugin's output or spend ingredients on a failed conversion.
|
|
event.setCancelled(true);
|
|
return;
|
|
}
|
|
// 2618 recognizes custom recipes but mix() returns base-less potions unchanged.
|
|
// Correct only that no-op; leave inventory and ingredient accounting to the server.
|
|
event.getResults().set(slot, potions.create(kind, target));
|
|
}
|
|
}
|
|
}
|
|
}
|