All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.nukkit.inventory.transaction.CraftingTransaction Maven / Gradle / Ivy

There is a newer version: 1.20.40-r1
Show newest version
package cn.nukkit.inventory.transaction;

import cn.nukkit.Player;
import cn.nukkit.api.DeprecationDetails;
import cn.nukkit.api.PowerNukkitDifference;
import cn.nukkit.api.PowerNukkitOnly;
import cn.nukkit.api.Since;
import cn.nukkit.event.inventory.CraftItemEvent;
import cn.nukkit.inventory.*;
import cn.nukkit.inventory.transaction.action.DamageAnvilAction;
import cn.nukkit.inventory.transaction.action.InventoryAction;
import cn.nukkit.inventory.transaction.action.SlotChangeAction;
import cn.nukkit.inventory.transaction.action.TakeLevelAction;
import cn.nukkit.item.Item;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author CreeperFace
 */
public class CraftingTransaction extends InventoryTransaction {

    protected int gridSize;

    protected List inputs;

    protected List secondaryOutputs;

    protected Item primaryOutput;

    @Deprecated
    @DeprecationDetails(since = "FUTURE", reason = "When the recipe is not a CraftingRecipe, this is set to null instead of the recipe",
            by = "PowerNukkit", replaceWith = "getTransactionRecipe()")
    @Nullable
    @Since("FUTURE")
    protected CraftingRecipe recipe;

    private Recipe transactionRecipe;

    @PowerNukkitOnly
    protected int craftingType;
    
    private boolean readyToExecute;

    public CraftingTransaction(Player source, List actions) {
        super(source, actions, false);

        this.craftingType = source.craftingType;
        if (source.craftingType == Player.CRAFTING_STONECUTTER) {
            this.gridSize = 1;
            
            this.inputs = new ArrayList<>(1);
            
            this.secondaryOutputs = new ArrayList<>(1);
        } else {
            this.gridSize = (source.getCraftingGrid() instanceof BigCraftingGrid) ? 3 : 2;

            this.inputs = new ArrayList<>();

            this.secondaryOutputs = new ArrayList<>();
        }

        init(source, actions);
    }
    
    public void setInput(Item item) {
        if (inputs.size() < gridSize * gridSize) {
            for (Item existingInput : this.inputs) {
                if (existingInput.equals(item, item.hasMeta(), item.hasCompoundTag())) {
                    existingInput.setCount(existingInput.getCount() + item.getCount());
                    return;
                }
            }
            inputs.add(item.clone());
        } else {
            throw new RuntimeException("Input list is full can't add " + item);
        }
    }

    public List getInputList() {
        return inputs;
    }

    public void setExtraOutput(Item item) {
        if (secondaryOutputs.size() < gridSize * gridSize) {
            secondaryOutputs.add(item.clone());
        } else {
            throw new RuntimeException("Output list is full can't add " + item);
        }
    }

    public Item getPrimaryOutput() {
        return primaryOutput;
    }

    public void setPrimaryOutput(Item item) {
        if (primaryOutput == null) {
            primaryOutput = item.clone();
        } else if (!primaryOutput.equals(item)) {
            throw new RuntimeException("Primary result item has already been set and does not match the current item (expected " + primaryOutput + ", got " + item + ")");
        }
    }

    @Deprecated
    @DeprecationDetails(since = "FUTURE", reason = "When the recipe is not a CraftingRecipe, returns null instead of the recipe",
        by = "PowerNukkit", replaceWith = "getTransactionRecipe()")
    @Since("FUTURE")
    @Nullable
    public CraftingRecipe getRecipe() {
        return recipe;
    }

    @PowerNukkitOnly
    @Since("FUTURE")
    public Recipe getTransactionRecipe() {
        return transactionRecipe;
    }

    @PowerNukkitOnly
    @Since("FUTURE")
    protected void setTransactionRecipe(Recipe recipe) {
        this.transactionRecipe = recipe;
        this.recipe = (recipe instanceof CraftingRecipe)? (CraftingRecipe) recipe: null;
    }

    @Override
    public boolean canExecute() {
        CraftingManager craftingManager = source.getServer().getCraftingManager();
        Inventory inventory;
        switch (craftingType) {
            case Player.CRAFTING_STONECUTTER:
                setTransactionRecipe(craftingManager.matchStonecutterRecipe(this.primaryOutput));
                break;
            case Player.CRAFTING_CARTOGRAPHY:
                setTransactionRecipe(craftingManager.matchCartographyRecipe(inputs, this.primaryOutput, this.secondaryOutputs));
                break;
            case Player.CRAFTING_SMITHING:
                inventory = source.getWindowById(Player.SMITHING_WINDOW_ID);
                if (inventory instanceof SmithingInventory) {
                    addInventory(inventory);
                    SmithingInventory smithingInventory = (SmithingInventory) inventory;
                    SmithingRecipe smithingRecipe = smithingInventory.matchRecipe();
                    if (smithingRecipe != null && this.primaryOutput.equals(smithingRecipe.getFinalResult(smithingInventory.getEquipment()), true, true)) {
                        setTransactionRecipe(smithingRecipe);
                    }
                }
                
                break;
            case Player.CRAFTING_ANVIL:
                inventory = source.getWindowById(Player.ANVIL_WINDOW_ID);
                if (inventory instanceof AnvilInventory) {
                    AnvilInventory anvil = (AnvilInventory) inventory;
                    addInventory(anvil);
                    if (this.primaryOutput.equalsIgnoringEnchantmentOrder(anvil.getResult(), true)) {
                        actions.removeIf(action -> action instanceof TakeLevelAction);
                        TakeLevelAction takeLevel = new TakeLevelAction(anvil.getLevelCost());
                        addAction(takeLevel);
                        if (takeLevel.isValid(source)) {
                            setTransactionRecipe(new RepairRecipe(InventoryType.ANVIL, this.primaryOutput, this.inputs));
                            PlayerUIInventory uiInventory = source.getUIInventory();
                            actions.add(new DamageAnvilAction(anvil, !source.isCreative() && ThreadLocalRandom.current().nextFloat() < 0.12F, this));
                            actions.stream()
                                    .filter(a -> a instanceof SlotChangeAction)
                                    .map(a -> (SlotChangeAction) a)
                                    .filter(a -> a.getInventory() == uiInventory)
                                    .filter(a -> a.getSlot() == 50)
                                    .findFirst()
                                    .ifPresent(a -> {
                                        // Move the set result action to the end, otherwise the result would be cleared too early
                                        actions.remove(a);
                                        actions.add(a);
                                    });
                        }
                    }
                }
                if (getTransactionRecipe() == null) {
                    source.sendExperienceLevel();
                }
                source.getUIInventory().setItem(AnvilInventory.RESULT, Item.get(0), false);
                break;
            case Player.CRAFTING_GRINDSTONE:
                inventory = source.getWindowById(Player.GRINDSTONE_WINDOW_ID);
                if (inventory instanceof GrindstoneInventory) {
                    GrindstoneInventory grindstone = (GrindstoneInventory) inventory;
                    addInventory(grindstone);
                    if (grindstone.updateResult(false) && this.primaryOutput.equals(grindstone.getResult(), true, true)) {
                        setTransactionRecipe(new RepairRecipe(InventoryType.GRINDSTONE, this.primaryOutput, this.inputs));
                        grindstone.setResult(Item.get(0), false);
                    }
                }
                break;
            default:
                setTransactionRecipe(craftingManager.matchRecipe(inputs, this.primaryOutput, this.secondaryOutputs));
                break;
        }

        return this.getTransactionRecipe() != null && super.canExecute();
    }

    @Override
    protected boolean callExecuteEvent() {
        CraftItemEvent ev;

        this.source.getServer().getPluginManager().callEvent(ev = new CraftItemEvent(this));
        return !ev.isCancelled();
    }

    @Override
    @PowerNukkitDifference(since = "1.4.0.0-PN", info = "No longer closes the inventory")
    protected void sendInventories() {
        super.sendInventories();
    }

    @Override
    public boolean execute() {
        if (super.execute()) {
            switch (this.primaryOutput.getId()) {
                case Item.CRAFTING_TABLE:
                    source.awardAchievement("buildWorkBench");
                    break;
                case Item.WOODEN_PICKAXE:
                    source.awardAchievement("buildPickaxe");
                    break;
                case Item.FURNACE:
                    source.awardAchievement("buildFurnace");
                    break;
                case Item.WOODEN_HOE:
                    source.awardAchievement("buildHoe");
                    break;
                case Item.BREAD:
                    source.awardAchievement("makeBread");
                    break;
                case Item.CAKE:
                    source.awardAchievement("bakeCake");
                    break;
                case Item.STONE_PICKAXE:
                case Item.GOLDEN_PICKAXE:
                case Item.IRON_PICKAXE:
                case Item.DIAMOND_PICKAXE:
                    source.awardAchievement("buildBetterPickaxe");
                    break;
                case Item.WOODEN_SWORD:
                    source.awardAchievement("buildSword");
                    break;
                case Item.DIAMOND:
                    source.awardAchievement("diamond");
                    break;
            }

            return true;
        }

        return false;
    }

    @Since("1.3.0.0-PN")
    public boolean checkForCraftingPart(List actions) {
        for (InventoryAction action : actions) {
            if (action instanceof SlotChangeAction) {
                SlotChangeAction slotChangeAction = (SlotChangeAction) action;
                if (slotChangeAction.getInventory().getType() == InventoryType.UI && slotChangeAction.getSlot() == 50 &&
                        !slotChangeAction.getSourceItem().equals(slotChangeAction.getTargetItem())) {
                    return true;
                }
            }
        }
        return false;
    }

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public void setReadyToExecute(boolean readyToExecute) {
        this.readyToExecute = readyToExecute;
    }

    @PowerNukkitOnly
    @Since("1.4.0.0-PN")
    public boolean isReadyToExecute() {
        return readyToExecute;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy