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

cn.nukkit.inventory.AnvilInventory Maven / Gradle / Ivy

Go to download

A Minecraft Bedrock Edition server software implementation made in Java from scratch which supports all new features.

There is a newer version: 1.6.0.1-PN
Show newest version
package cn.nukkit.inventory;

import cn.nukkit.Player;
import cn.nukkit.api.DeprecationDetails;
import cn.nukkit.block.BlockID;
import cn.nukkit.item.Item;
import cn.nukkit.item.ItemID;
import cn.nukkit.item.enchantment.Enchantment;
import cn.nukkit.level.Position;
import cn.nukkit.nbt.tag.CompoundTag;
import io.netty.util.internal.StringUtil;
import lombok.NonNull;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Stream;

/**
 * @author MagicDroidX (Nukkit Project)
 */
public class AnvilInventory extends FakeBlockUIComponent {
    
    public static final int OFFSET = 1;
    public static final int TARGET = 0;
    public static final int SACRIFICE = 1;
    public static final int RESULT = 50;
    
    private int levelCost;
    private String newItemName;
    
    @NonNull
    private Item currentResult = Item.get(0);

    public AnvilInventory(PlayerUIInventory playerUI, Position position) {
        super(playerUI, InventoryType.ANVIL, OFFSET, position);
    }
    
    @Override
    public void onSlotChange(int index, Item before, boolean send) {
        try {
            if (index <= 1) {
                updateResult();
            }
        } finally {
            super.onSlotChange(index, before, send);
        }
    }
    
    public void updateResult() {
        Item target = getFirstItem();
        Item sacrifice = getSecondItem();
        
        if (target.isNull() && sacrifice.isNull()) {
            setResult(Item.get(0));
            setLevelCost(0);
            return;
        }
        
        setLevelCost(1);
        int extraCost = 0;
        int costHelper = 0;
        int repairMaterial = getRepairMaterial(target);
        Item result = target.clone();
        int levelCost = getRepairCost(result) + (sacrifice.isNull() ? 0 : getRepairCost(sacrifice));
        Map enchantmentMap = new LinkedHashMap<>();
        for (Enchantment enchantment : target.getEnchantments()) {
            enchantmentMap.put(enchantment.getId(), enchantment);
        }
        if (!sacrifice.isNull()) {
            boolean enchantedBook = sacrifice.getId() == Item.ENCHANTED_BOOK && sacrifice.getEnchantments().length > 0;
            int repair;
            int repair2;
            int repair3;
            if (result.getMaxDurability() != -1 && sacrifice.getId() == repairMaterial) {
                repair = Math.min(result.getDamage(), result.getMaxDurability() / 4);
                if (repair <= 0) {
                    setResult(Item.get(0));
                    setLevelCost(0);
                    return;
                }
        
                for(repair2 = 0; repair > 0 && repair2 < sacrifice.getCount(); ++repair2) {
                    repair3 = result.getDamage() - repair;
                    result.setDamage(repair3);
                    ++extraCost;
                    repair = Math.min(result.getDamage(), result.getMaxDurability() / 4);
                }
    
            } else {
                if (!enchantedBook && (result.getId() != sacrifice.getId() || result.getMaxDurability() == -1)) {
                    setResult(Item.get(0));
                    setLevelCost(0);
                    return;
                }
        
                if ((result.getMaxDurability() != -1) && !enchantedBook) {
                    repair = target.getMaxDurability() - target.getDamage();
                    repair2 = sacrifice.getMaxDurability() - sacrifice.getDamage();
                    repair3 = repair2 + result.getMaxDurability() * 12 / 100;
                    int totalRepair = repair + repair3;
                    int finalDamage = result.getMaxDurability() - totalRepair + 1;
                    if (finalDamage < 0) {
                        finalDamage = 0;
                    }
            
                    if (finalDamage < result.getDamage()) {
                        result.setDamage(finalDamage);
                        extraCost += 2;
                    }
                }
        
                Enchantment[] sacrificeEnchantments = sacrifice.getEnchantments();
                boolean compatibleFlag = false;
                boolean incompatibleFlag = false;
                Iterator sacrificeEnchIter = Arrays.stream(sacrificeEnchantments).iterator();
        
                iter:
                while(true) {
                    Enchantment sacrificeEnchantment;
                    do {
                        if (!sacrificeEnchIter.hasNext()) {
                            if (incompatibleFlag && !compatibleFlag) {
                                setResult(Item.get(0));
                                setLevelCost(0);
                                return;
                            }
                            break iter;
                        }
                
                        sacrificeEnchantment = sacrificeEnchIter.next();
                    } while(sacrificeEnchantment == null);

                    Enchantment resultEnchantment = result.getEnchantment(sacrificeEnchantment.id);
                    int targetLevel = resultEnchantment != null? resultEnchantment.getLevel() : 0;
                    int resultLevel = sacrificeEnchantment.getLevel();
                    resultLevel = targetLevel == resultLevel ? resultLevel + 1 : Math.max(resultLevel, targetLevel);
                    boolean compatible = sacrificeEnchantment.isItemAcceptable(target);
                    if (playerUI.getHolder().isCreative() || target.getId() == Item.ENCHANTED_BOOK) {
                        compatible = true;
                    }
            
                    Iterator targetEnchIter = Stream.of(target.getEnchantments()).iterator();
            
                    while(targetEnchIter.hasNext()) {
                        Enchantment targetEnchantment = targetEnchIter.next();
                        if (targetEnchantment.id != sacrificeEnchantment.id && (!sacrificeEnchantment.isCompatibleWith(targetEnchantment) || !targetEnchantment.isCompatibleWith(sacrificeEnchantment))) {
                            compatible = false;
                            ++extraCost;
                        }
                    }
            
                    if (!compatible) {
                        incompatibleFlag = true;
                    } else {
                        compatibleFlag = true;
                        if (resultLevel > sacrificeEnchantment.getMaxLevel()) {
                            resultLevel = sacrificeEnchantment.getMaxLevel();
                        }
                        
                        enchantmentMap.put(sacrificeEnchantment.getId(), Enchantment.get(sacrificeEnchantment.getId()).setLevel(resultLevel));
                        int rarity = 0;
                        int weight = sacrificeEnchantment.getWeight();
                        if (weight >= 10) {
                            rarity = 1;
                        } else if (weight >= 5) {
                            rarity = 2;
                        } else if (weight >= 2) {
                            rarity = 4;
                        } else {
                            rarity = 8;
                        }
                
                        if (enchantedBook) {
                            rarity = Math.max(1, rarity / 2);
                        }
                
                        extraCost += rarity * Math.max(0, resultLevel - targetLevel);
                        if (target.getCount() > 1) {
                            extraCost = 40;
                        }
                    }
                }
            }
        }
        
        if (StringUtil.isNullOrEmpty(this.newItemName)) {
            if (target.hasCustomName()) {
                costHelper = 1;
                extraCost += costHelper;
                result.clearCustomName();
            }
        } else {
            costHelper = 1;
            extraCost += costHelper;
            result.setCustomName(this.newItemName);
        }
        
        setLevelCost(levelCost + extraCost);
        if (extraCost <= 0) {
            result = Item.get(0);
        }
        
        if (costHelper == extraCost && costHelper > 0 && getLevelCost() >= 40) {
            setLevelCost(39);
        }
        
        if (getLevelCost() >= 40 && !this.playerUI.getHolder().isCreative()) {
            result = Item.get(0);
        }
        
        if (!result.isNull()) {
            int repairCost = getRepairCost(result);
            if (!sacrifice.isNull() && repairCost < getRepairCost(sacrifice)) {
                repairCost = getRepairCost(sacrifice);
            }
    
            if (costHelper != extraCost || costHelper == 0) {
                repairCost = repairCost * 2 + 1;
            }

            CompoundTag namedTag = result.getNamedTag();
            if (namedTag == null) {
                namedTag = new CompoundTag();
            }
            namedTag.putInt("RepairCost", repairCost);
            namedTag.remove("ench");
            result.setNamedTag(namedTag);
            if (!enchantmentMap.isEmpty()) {
                result.addEnchantment(enchantmentMap.values().toArray(Enchantment.EMPTY_ARRAY));
            }
        }
        setResult(result);
    }
    
    @Override
    public void onClose(Player who) {
        super.onClose(who);
        who.craftingType = Player.CRAFTING_SMALL;

        Item[] drops = new Item[]{ getFirstItem(), getSecondItem() };
        drops = who.getInventory().addItem(drops);
        for (Item drop : drops) {
            if (!who.dropItem(drop)) {
                this.getHolder().getLevel().dropItem(this.getHolder().add(0.5, 0.5, 0.5), drop);
            }
        }
        
        clear(TARGET);
        clear(SACRIFICE);
        
        who.resetCraftingGridType();
    }

    @Override
    public void onOpen(Player who) {
        super.onOpen(who);
        who.craftingType = Player.CRAFTING_ANVIL;
    }
    
    @Override
    public Item getItem(int index) {
        if (index < 0 || index > 3) {
            return Item.get(0);
        }
        if (index == 2) {
            return getResult();
        }
        
        return super.getItem(index);
    }
    
    @Override
    public boolean setItem(int index, Item item, boolean send) {
        if (index < 0 || index > 3) {
            return false;
        }
        
        if (index == 2) {
            return setResult(item);
        }
        
        return super.setItem(index, item, send);
    }
    
    public Item getFirstItem() {
        return getItem(TARGET);
    }
    
    public Item getSecondItem() {
        return getItem(SACRIFICE);
    }
    
    public Item getResult() {
        return currentResult.clone();
    }

    @Override
    public void sendContents(Player... players) {
        super.sendContents(players);
        // Fixes desync when transactions are cancelled.
        for (Player player : players) {
            player.sendExperienceLevel();
        }
    }

    public boolean setFirstItem(Item item, boolean send) {
        return setItem(SACRIFICE, item, send);
    }
    
    public boolean setFirstItem(Item item) {
        return setFirstItem(item, true);
    }
    
    public boolean setSecondItem(Item item, boolean send) {
        return setItem(SACRIFICE, item, send);
    }
    
    public boolean setSecondItem(Item item) {
        return setSecondItem(item, true);
    }

    /**
     * @deprecated send parameter is deprecated. This method will be removed in 1.3.0.0-PN.
     */
    @Deprecated
    public boolean setResult(Item item, boolean send) {
        return setItem(2, item, send);
    }

    @DeprecationDetails(since = "TBD", reason = "the client won't see this change, and the transaction might fail",
        toBeRemovedAt = "1.4.0.0-PN")
    @Deprecated
    public boolean setResult(Item item) {
        if (item == null || item.isNull()) {
            this.currentResult = Item.get(0);
        } else {
            this.currentResult = item.clone();
        }
        return true;
    }
    
    private static int getRepairCost(Item item) {
        return item.hasCompoundTag() && item.getNamedTag().contains("RepairCost") ? item.getNamedTag().getInt("RepairCost") : 0;
    }
    
    public int getLevelCost() {
        return levelCost;
    }
    
    protected void setLevelCost(int levelCost) {
        this.levelCost = levelCost;
    }
    
    public String getNewItemName() {
        return newItemName;
    }
    
    public void setNewItemName(String newItemName) {
        this.newItemName = newItemName;
    }
    
    private static int getRepairMaterial(Item target) {
        switch (target.getId()) {
            case ItemID.WOODEN_SWORD:
            case ItemID.WOODEN_PICKAXE:
            case ItemID.WOODEN_SHOVEL:
            case ItemID.WOODEN_AXE:
            case ItemID.WOODEN_HOE:
                return BlockID.PLANKS;
        
            case ItemID.IRON_SWORD:
            case ItemID.IRON_PICKAXE:
            case ItemID.IRON_SHOVEL:
            case ItemID.IRON_AXE:
            case ItemID.IRON_HOE:
            case ItemID.IRON_HELMET:
            case ItemID.IRON_CHESTPLATE:
            case ItemID.IRON_LEGGINGS:
            case ItemID.IRON_BOOTS:
            case ItemID.CHAIN_HELMET:
            case ItemID.CHAIN_CHESTPLATE:
            case ItemID.CHAIN_LEGGINGS:
            case ItemID.CHAIN_BOOTS:
                return ItemID.IRON_INGOT;
        
            case ItemID.GOLD_SWORD:
            case ItemID.GOLD_PICKAXE:
            case ItemID.GOLD_SHOVEL:
            case ItemID.GOLD_AXE:
            case ItemID.GOLD_HOE:
            case ItemID.GOLD_HELMET:
            case ItemID.GOLD_CHESTPLATE:
            case ItemID.GOLD_LEGGINGS:
            case ItemID.GOLD_BOOTS:
                return ItemID.GOLD_INGOT;
        
            case ItemID.DIAMOND_SWORD:
            case ItemID.DIAMOND_PICKAXE:
            case ItemID.DIAMOND_SHOVEL:
            case ItemID.DIAMOND_AXE:
            case ItemID.DIAMOND_HOE:
            case ItemID.DIAMOND_HELMET:
            case ItemID.DIAMOND_CHESTPLATE:
            case ItemID.DIAMOND_LEGGINGS:
            case ItemID.DIAMOND_BOOTS:
                return ItemID.DIAMOND;
        
            case ItemID.LEATHER_CAP:
            case ItemID.LEATHER_TUNIC:
            case ItemID.LEATHER_PANTS:
            case ItemID.LEATHER_BOOTS:
                return ItemID.LEATHER;
                
            case ItemID.STONE_SWORD:
            case ItemID.STONE_PICKAXE:
            case ItemID.STONE_SHOVEL:
            case ItemID.STONE_AXE:
            case ItemID.STONE_HOE:
                return BlockID.COBBLESTONE;

            case ItemID.NETHERITE_SWORD:
            case ItemID.NETHERITE_PICKAXE:
            case ItemID.NETHERITE_SHOVEL:
            case ItemID.NETHERITE_AXE:
            case ItemID.NETHERITE_HOE:
            case ItemID.NETHERITE_HELMET:
            case ItemID.NETHERITE_CHESTPLATE:
            case ItemID.NETHERITE_LEGGINGS:
            case ItemID.NETHERITE_BOOTS:
                return ItemID.NETHERITE_INGOT;
                
            case ItemID.ELYTRA:
                return ItemID.PHANTOM_MEMBRANE;

            default:
                return 0;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy