mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2025-03-30 16:26:24 +02:00
337 lines
12 KiB
Java
337 lines
12 KiB
Java
package com.gmail.nossr50.skills.alchemy;
|
|
|
|
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
|
|
import com.gmail.nossr50.datatypes.skills.SubSkillType;
|
|
import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion;
|
|
import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage;
|
|
import com.gmail.nossr50.events.fake.FakeBrewEvent;
|
|
import com.gmail.nossr50.mcMMO;
|
|
import com.gmail.nossr50.runnables.player.PlayerUpdateInventoryTask;
|
|
import com.gmail.nossr50.runnables.skills.AlchemyBrewCheckTask;
|
|
import com.gmail.nossr50.util.Permissions;
|
|
import com.gmail.nossr50.util.player.UserManager;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.block.BlockState;
|
|
import org.bukkit.block.BrewingStand;
|
|
import org.bukkit.entity.HumanEntity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.event.inventory.ClickType;
|
|
import org.bukkit.inventory.BrewerInventory;
|
|
import org.bukkit.inventory.Inventory;
|
|
import org.bukkit.inventory.InventoryView;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
// TODO: Update to use McMMOPlayer
|
|
public final class AlchemyPotionBrewer {
|
|
@Deprecated(forRemoval = true, since = "2.2.010")
|
|
public static boolean isValidBrew(Player player, ItemStack[] contents) {
|
|
if (!isValidIngredientByPlayer(player, contents[Alchemy.INGREDIENT_SLOT])) {
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (contents[i] == null || contents[i].getType() != Material.POTION
|
|
&& contents[i].getType() != Material.SPLASH_POTION
|
|
&& contents[i].getType() != Material.LINGERING_POTION) {
|
|
continue;
|
|
}
|
|
|
|
final AlchemyPotion potion = mcMMO.p.getPotionConfig().getPotion(contents[i]);
|
|
if (getChildPotion(potion, contents[Alchemy.INGREDIENT_SLOT]) != null) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static boolean isValidBrew(int ingredientLevel, ItemStack[] contents) {
|
|
if (!isValidIngredientByLevel(ingredientLevel, contents[Alchemy.INGREDIENT_SLOT])) {
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (contents[i] == null || contents[i].getType() != Material.POTION
|
|
&& contents[i].getType() != Material.SPLASH_POTION
|
|
&& contents[i].getType() != Material.LINGERING_POTION) {
|
|
continue;
|
|
}
|
|
|
|
final AlchemyPotion potion = mcMMO.p.getPotionConfig().getPotion(contents[i]);
|
|
if (getChildPotion(potion, contents[Alchemy.INGREDIENT_SLOT]) != null) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static AlchemyPotion getChildPotion(AlchemyPotion potion, ItemStack ingredient) {
|
|
if (potion != null) {
|
|
return potion.getChild(ingredient);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static boolean isEmpty(ItemStack item) {
|
|
return item == null || item.getType() == Material.AIR || item.getAmount() == 0;
|
|
}
|
|
|
|
private static void removeIngredient(BrewerInventory inventory, Player player) {
|
|
if(inventory.getIngredient() == null)
|
|
return;
|
|
|
|
ItemStack ingredient = inventory.getIngredient().clone();
|
|
|
|
if (!isEmpty(ingredient) && isValidIngredientByPlayer(player, ingredient)) {
|
|
if (ingredient.getAmount() <= 1) {
|
|
inventory.setIngredient(null);
|
|
}
|
|
else {
|
|
ingredient.setAmount(ingredient.getAmount() - 1);
|
|
inventory.setIngredient(ingredient);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static boolean hasIngredient(BrewerInventory inventory, Player player) {
|
|
ItemStack ingredient = inventory.getIngredient() == null ? null : inventory.getIngredient().clone();
|
|
|
|
return !isEmpty(ingredient) && isValidIngredientByPlayer(player, ingredient);
|
|
}
|
|
|
|
public static boolean isValidIngredientByPlayer(Player player, ItemStack item) {
|
|
if (isEmpty(item)) {
|
|
return false;
|
|
}
|
|
|
|
for (ItemStack ingredient : getValidIngredients(UserManager.getPlayer(player))) {
|
|
if (item.isSimilar(ingredient)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static boolean isValidIngredientByLevel(int ingredientLevel, ItemStack item) {
|
|
if (isEmpty(item)) {
|
|
return false;
|
|
}
|
|
|
|
// TODO: Update this when we fix loading from hoppers
|
|
for (ItemStack ingredient : mcMMO.p.getPotionConfig().getIngredients(ingredientLevel)) {
|
|
if (item.isSimilar(ingredient)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static List<ItemStack> getValidIngredients(@Nullable McMMOPlayer mmoPlayer) {
|
|
if(mmoPlayer == null) {
|
|
return mcMMO.p.getPotionConfig().getIngredients(1);
|
|
}
|
|
|
|
return mcMMO.p.getPotionConfig().getIngredients(!Permissions.isSubSkillEnabled(mmoPlayer, SubSkillType.ALCHEMY_CONCOCTIONS)
|
|
? 1 : mmoPlayer.getAlchemyManager().getTier());
|
|
}
|
|
|
|
public static void finishBrewing(BlockState brewingStand, Player player, boolean forced) {
|
|
// Check if the brewing stand block state is an actual brewing stand
|
|
if (!(brewingStand instanceof BrewingStand)) {
|
|
return;
|
|
}
|
|
|
|
// Retrieve the inventory of the brewing stand and clone the current ingredient for safe manipulation
|
|
final BrewerInventory inventory = ((BrewingStand) brewingStand).getInventory();
|
|
final ItemStack ingredient = inventory.getIngredient() == null ? null : inventory.getIngredient().clone();
|
|
|
|
// Check if the brewing stand has a valid ingredient; if not, exit the method
|
|
if (!hasIngredient(inventory, player)) {
|
|
// debug
|
|
return;
|
|
}
|
|
|
|
// Initialize lists to hold the potions before and after brewing, initially setting them to null
|
|
List<AlchemyPotion> inputList = new ArrayList<>(Collections.nCopies(3, null));
|
|
List<ItemStack> outputList = new ArrayList<>(Collections.nCopies(3, null));
|
|
|
|
// Process each of the three slots in the brewing stand
|
|
for (int i = 0; i < 3; i++) {
|
|
ItemStack item = inventory.getItem(i);
|
|
|
|
// Skip the slot if it's empty, contains a glass bottle, or holds an invalid potion
|
|
if (isEmpty(item)
|
|
|| item.getType() == Material.GLASS_BOTTLE
|
|
|| !mcMMO.p.getPotionConfig().isValidPotion(item)) {
|
|
// debug
|
|
continue;
|
|
}
|
|
|
|
// Retrieve the potion configurations for the input and resulting output potion
|
|
AlchemyPotion input = mcMMO.p.getPotionConfig().getPotion(item);
|
|
AlchemyPotion output = input.getChild(ingredient);
|
|
|
|
// Update the input list with the current potion
|
|
inputList.set(i, input);
|
|
|
|
// If there is a valid output potion, add it to the output list
|
|
if (output != null) {
|
|
outputList.set(i, output.toItemStack(item.getAmount()).clone());
|
|
}
|
|
}
|
|
|
|
// Create a fake brewing event and pass it to the plugin's event system
|
|
FakeBrewEvent event = new FakeBrewEvent(brewingStand.getBlock(), inventory, outputList, ((BrewingStand) brewingStand).getFuelLevel());
|
|
mcMMO.p.getServer().getPluginManager().callEvent(event);
|
|
|
|
// If the event is cancelled or there are no potions processed, exit the method
|
|
if (event.isCancelled() || inputList.isEmpty()) {
|
|
// debug
|
|
return;
|
|
}
|
|
|
|
// Update the brewing inventory with the new potions
|
|
for (int i = 0; i < 3; i++) {
|
|
if(outputList.get(i) != null) {
|
|
inventory.setItem(i, outputList.get(i));
|
|
}
|
|
}
|
|
|
|
// Remove the used ingredient from the brewing inventory
|
|
removeIngredient(inventory, player);
|
|
|
|
// Handle potion brewing success and related effects for each potion processed
|
|
for (AlchemyPotion input : inputList) {
|
|
if (input == null) continue;
|
|
|
|
AlchemyPotion output = input.getChild(ingredient);
|
|
|
|
if (output != null && player != null) {
|
|
PotionStage potionStage = PotionStage.getPotionStage(input, output);
|
|
|
|
// Update player alchemy skills or effects based on brewing success
|
|
if (UserManager.getPlayer(player) != null) {
|
|
UserManager.getPlayer(player).getAlchemyManager().handlePotionBrewSuccesses(potionStage, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the brewing was not forced by external conditions, schedule a new update
|
|
if (!forced) {
|
|
scheduleUpdate(inventory);
|
|
}
|
|
}
|
|
|
|
public static boolean transferItems(InventoryView view, int fromSlot, ClickType click) {
|
|
boolean success = false;
|
|
|
|
if (click.isLeftClick()) {
|
|
success = transferItems(view, fromSlot);
|
|
}
|
|
else if (click.isRightClick()) {
|
|
success = transferOneItem(view, fromSlot);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
private static boolean transferOneItem(InventoryView view, int fromSlot) {
|
|
ItemStack from = view.getItem(fromSlot).clone();
|
|
ItemStack to = view.getItem(Alchemy.INGREDIENT_SLOT).clone();
|
|
|
|
if (isEmpty(from)) {
|
|
return false;
|
|
}
|
|
|
|
boolean emptyTo = isEmpty(to);
|
|
int fromAmount = from.getAmount();
|
|
|
|
if (!emptyTo && fromAmount >= from.getType().getMaxStackSize()) {
|
|
return false;
|
|
}
|
|
else if (emptyTo || from.isSimilar(to)) {
|
|
if (emptyTo) {
|
|
to = from.clone();
|
|
to.setAmount(1);
|
|
}
|
|
else {
|
|
to.setAmount(to.getAmount() + 1);
|
|
}
|
|
|
|
from.setAmount(fromAmount - 1);
|
|
view.setItem(Alchemy.INGREDIENT_SLOT, to);
|
|
view.setItem(fromSlot, from);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Transfer items between two ItemStacks, returning the leftover status
|
|
*/
|
|
private static boolean transferItems(InventoryView view, int fromSlot) {
|
|
ItemStack from = view.getItem(fromSlot).clone();
|
|
ItemStack to = view.getItem(Alchemy.INGREDIENT_SLOT).clone();
|
|
|
|
if (isEmpty(from)) {
|
|
return false;
|
|
}
|
|
else if (isEmpty(to)) {
|
|
view.setItem(Alchemy.INGREDIENT_SLOT, from);
|
|
view.setItem(fromSlot, null);
|
|
|
|
return true;
|
|
}
|
|
else if (from.isSimilar(to)) {
|
|
int fromAmount = from.getAmount();
|
|
int toAmount = to.getAmount();
|
|
int maxSize = to.getType().getMaxStackSize();
|
|
|
|
if (fromAmount + toAmount > maxSize) {
|
|
int left = fromAmount + toAmount - maxSize;
|
|
|
|
to.setAmount(maxSize);
|
|
view.setItem(Alchemy.INGREDIENT_SLOT, to);
|
|
|
|
from.setAmount(left);
|
|
view.setItem(fromSlot, from);
|
|
|
|
return true;
|
|
}
|
|
|
|
to.setAmount(fromAmount + toAmount);
|
|
view.setItem(fromSlot, null);
|
|
view.setItem(Alchemy.INGREDIENT_SLOT, to);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static void scheduleCheck(@NotNull BrewingStand brewingStand) {
|
|
mcMMO.p.getFoliaLib().getImpl().runAtLocation(
|
|
brewingStand.getLocation(), new AlchemyBrewCheckTask(brewingStand));
|
|
}
|
|
|
|
public static void scheduleUpdate(Inventory inventory) {
|
|
for (HumanEntity humanEntity : inventory.getViewers()) {
|
|
if (humanEntity instanceof Player) {
|
|
mcMMO.p.getFoliaLib().getImpl().runAtEntity(humanEntity, new PlayerUpdateInventoryTask((Player) humanEntity));
|
|
}
|
|
}
|
|
}
|
|
}
|