Улучшение предметов

  • Автор темы Автор темы uter81
  • Дата начала Дата начала

uter81

Знающий
Участник
Сообщения
310
Розыгрыши
0
Репутация
1
Реакции
11
Баллы
460
Хроники
  1. Shadow of the Kamael
Исходники
Присутствуют
Сборка
l2jMobius
Всем привет, подскажите как прописать в xml, при улучшение предмета, что бы заточка не учитывалась.
Например улучшаю у нпс пояс Правителя +15 2 лв на 3лв. Если пояс 2 лв не точен то улучшает на 3 лв, а если он вточен пишет нет предмета.

Код:
<item>
        <ingredient id="48418" count="5" /> <!-- Authority Ornament -->
        <ingredient id="45584" count="200" /> <!-- Mark of Battle -->
        <ingredient id="48417" count="1" /> <!-- Ruler's Authority - Genesis Lv. 2-->
        <production id="81751" count="1" chance="0" /> <!-- Ruler's Authority - Chaos Lv. 3 -->
        <production id="81751" count="1" chance="15" /> <!-- Ruler's Authority - Chaos Lv. 3 -->
        <production id="48417" count="1" chance="85" /> <!-- Ruler's Authority - Genesis Lv. 2 -->
    </item>
 
Код:
enchantmentLevel=""
добавь попробуй
 
keep_enchanted наверное нужон.
вот что за привычка тыкать все подряд в качестве атрибутов :pandaredlol: Не поймет такое парсер, и убедится в этом можно открыв MultisellData.java или multisell.xsd

парсер:
Java:
                            if ("ingredient".equalsIgnoreCase(d.getNodeName()))
                            {
                                final int id = parseInteger(d.getAttributes(), "id");
                                final long count = parseLong(d.getAttributes(), "count");
                                final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
                                final Boolean maintainIngredient = parseBoolean(d.getAttributes(), "maintainIngredient", false);
                                final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel, maintainIngredient);
                                if (itemExists(ingredient))
                                {
                                    ingredients.add(ingredient);
                                   
                                    lastIngredientId = id;
                                    lastIngredientCount = count;
                                }
                                else
                                {
                                    LOGGER.warning("Invalid ingredient id or count for itemId: " + ingredient.getId() + ", count: " + ingredient.getCount() + " in list: " + listId);
                                    continue;
                                }
                            }
схема:
XML:
                            <xs:element name="ingredient" minOccurs="0" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:attribute name="id" type="xs:integer" use="required" />
                                    <xs:attribute name="count" type="xs:positiveInteger" use="required" />
                                    <xs:attribute name="enchantmentLevel" type="xs:integer" />
                                    <xs:attribute name="maintainIngredient" type="xs:boolean" />
                                </xs:complexType>
                            </xs:element>

Шел 2024 год, а разрабы л2ж все продолжали насиловать хмл разметку (удобно вносить изменения и т.п.)
Зачем нам (де)сериализация, используя например тот же json. Перебирая ноды через XmlReader :Wahaha:

@uter81, пересмотреть проверки в классе MultiSellChoose, в частности все что связанно с проверками на энчант.

п.с. - Просмотрев часть кода:
Java:
        // Validate the requested item with its full stats.
        //@formatter:off
        if ((itemEnchantment != null) && ((_amount > 1)
            || (itemEnchantment.getEnchantLevel() != _enchantLevel)
            || (itemEnchantment.getAttackElementType() != _attackAttribute)
            || (itemEnchantment.getAttackElementPower() != _attributePower)
            || (itemEnchantment.getAttributeDefence(AttributeType.FIRE) != _fireDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.WATER) != _waterDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.WIND) != _windDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.EARTH) != _earthDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.HOLY) != _holyDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.DARK) != _darkDefence)
            || ((itemEnchantment.getAugmentation() == null) && ((_augmentOption1 != 0) || (_augmentOption2 != 0)))
            || ((itemEnchantment.getAugmentation() != null) && ((itemEnchantment.getAugmentation().getOption1Id() != _augmentOption1) || (itemEnchantment.getAugmentation().getOption2Id() != _augmentOption2)))
            || ((_soulCrystalOptions != null) && !itemEnchantment.soulCrystalOptionsMatch(_soulCrystalOptions))
            || ((_soulCrystalOptions == null) && !itemEnchantment.getSoulCrystalOptions().isEmpty())
            || ((_soulCrystalSpecialOptions != null) && !itemEnchantment.soulCrystalSpecialOptionsMatch(_soulCrystalSpecialOptions))
            || ((_soulCrystalSpecialOptions == null) && !itemEnchantment.getSoulCrystalSpecialOptions().isEmpty())
            ))
        //@formatter:on
        {
            PacketLogger.warning("Character: " + player.getName() + " is trying to upgrade equippable item, but the stats doesn't match. Id: " + _listId + " entry: " + _entryId);
            player.setMultiSell(null);
            return;
        }

Java:
            // Check for enchanted level and ingredient count requirements.
            final List<ItemChanceHolder> summedIngredients = new ArrayList<>();
            for (ItemChanceHolder ingredient : entry.getIngredients())
            {
                boolean added = false;
                for (ItemChanceHolder summedIngredient : summedIngredients)
                {
                    if ((summedIngredient.getId() == ingredient.getId()) && (summedIngredient.getEnchantmentLevel() == ingredient.getEnchantmentLevel()))
                    {
                        summedIngredients.add(new ItemChanceHolder(ingredient.getId(), ingredient.getChance(), ingredient.getCount() + summedIngredient.getCount(), ingredient.getEnchantmentLevel(), ingredient.isMaintainIngredient()));
                        summedIngredients.remove(summedIngredient);
                        added = true;
                    }
                }
                if (!added)
                {
                    summedIngredients.add(ingredient);
                }
            }
            for (ItemChanceHolder ingredient : summedIngredients)
            {
                if (ingredient.getEnchantmentLevel() > 0)
                {
                    int found = 0;
                    for (Item item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
                    {
                        if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
                        {
                            found++;
                        }
                    }
                   
                    if (found < ingredient.getCount())
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
                        sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemData.getInstance().getTemplate(ingredient.getId()).getName());
                        player.sendPacket(sm);
                        return;
                    }
                }
                else if (!checkIngredients(player, list, inventory, clan, ingredient.getId(), Math.multiplyExact(ingredient.getCount(), _amount)))
                {
                    return;
                }
            }
           
            final InventoryUpdate iu = new InventoryUpdate();
            boolean itemEnchantmentProcessed = (itemEnchantment == null);
           
            // Take all ingredients
            for (ItemChanceHolder ingredient : entry.getIngredients())
у меня чуть глаза не вытекли :Bloodnose: какие-то безконечные переборы, цикл в цикле с циклами. Зато версия явы апнута до 21
 
подскажите пожалуйста, где поправить, что бы улучшались предметы с заточкой, не нашел где поправить .

Код:
package org.l2jmobius.gameserver.data.xml;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

import org.l2jmobius.Config;
import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.commons.util.file.filter.NumericNameFilter;
import org.l2jmobius.gameserver.enums.SpecialItemType;
import org.l2jmobius.gameserver.model.StatSet;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import org.l2jmobius.gameserver.model.holders.MultisellListHolder;
import org.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import org.l2jmobius.gameserver.model.item.ItemTemplate;
import org.l2jmobius.gameserver.model.item.enchant.EnchantItemGroup;
import org.l2jmobius.gameserver.network.serverpackets.MultiSellList;

public class MultisellData implements IXmlReader
{
    private static final Logger LOGGER = Logger.getLogger(MultisellData.class.getName());
   
    public static final int PAGE_SIZE = 40;
    private static final FileFilter NUMERIC_FILTER = new NumericNameFilter();
   
    private final Map<Integer, MultisellListHolder> _multisells = new ConcurrentHashMap<>();
   
    protected MultisellData()
    {
        load();
    }
   
    @Override
    public void load()
    {
        _multisells.clear();
        parseDatapackDirectory("data/multisell", false);
        parseDatapackDirectory("data/multisell/items", false);
        if (Config.CUSTOM_MULTISELL_LOAD)
        {
            parseDatapackDirectory("data/multisell/custom", false);
        }
       
        LOGGER.info(getClass().getSimpleName() + ": Loaded " + _multisells.size() + " multisell lists.");
    }
   
    @Override
    public void parseDocument(Document doc, File f)
    {
        final EnchantItemGroup magicWeaponGroup = EnchantItemGroupsData.getInstance().getItemGroup("MAGE_WEAPON_GROUP");
        final int magicWeaponGroupMax = magicWeaponGroup != null ? magicWeaponGroup.getMaximumEnchant() : -2;
        final EnchantItemGroup weapongroup = EnchantItemGroupsData.getInstance().getItemGroup("FIGHTER_WEAPON_GROUP");
        final int weaponGroupMax = weapongroup != null ? weapongroup.getMaximumEnchant() : -2;
        final EnchantItemGroup fullArmorGroup = EnchantItemGroupsData.getInstance().getItemGroup("FULL_ARMOR_GROUP");
        final int fullArmorGroupMax = fullArmorGroup != null ? fullArmorGroup.getMaximumEnchant() : -2;
        final EnchantItemGroup armorGroup = EnchantItemGroupsData.getInstance().getItemGroup("ARMOR_GROUP");
        final int armorGroupMax = armorGroup != null ? armorGroup.getMaximumEnchant() : -2;
       
        try
        {
            forEach(doc, "list", listNode ->
            {
                final StatSet set = new StatSet(parseAttributes(listNode));
                final int listId = Integer.parseInt(f.getName().substring(0, f.getName().length() - 4));
                final List<MultisellEntryHolder> entries = new ArrayList<>(listNode.getChildNodes().getLength());
                final AtomicInteger entryCounter = new AtomicInteger();
               
                forEach(listNode, itemNode ->
                {
                    if ("item".equalsIgnoreCase(itemNode.getNodeName()))
                    {
                        long totalPrice = 0;
                        int lastIngredientId = 0;
                        long lastIngredientCount = 0;
                        entryCounter.incrementAndGet();
                       
                        final List<ItemChanceHolder> ingredients = new ArrayList<>(1);
                        final List<ItemChanceHolder> products = new ArrayList<>(1);
                        final MultisellEntryHolder entry = new MultisellEntryHolder(ingredients, products);
                        for (Node d = itemNode.getFirstChild(); d != null; d = d.getNextSibling())
                        {
                            if ("ingredient".equalsIgnoreCase(d.getNodeName()))
                            {
                                final int id = parseInteger(d.getAttributes(), "id");
                                final long count = parseLong(d.getAttributes(), "count");
                                final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
                                final Boolean maintainIngredient = parseBoolean(d.getAttributes(), "maintainIngredient", false);
                                final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel, maintainIngredient);
                                if (itemExists(ingredient))
                                {
                                    ingredients.add(ingredient);
                                   
                                    lastIngredientId = id;
                                    lastIngredientCount = count;
                                }
                                else
                                {
                                    LOGGER.warning("Invalid ingredient id or count for itemId: " + ingredient.getId() + ", count: " + ingredient.getCount() + " in list: " + listId);
                                    continue;
                                }
                            }
                            else if ("production".equalsIgnoreCase(d.getNodeName()))
                            {
                                final int id = parseInteger(d.getAttributes(), "id");
                                final long count = parseLong(d.getAttributes(), "count");
                                final double chance = parseDouble(d.getAttributes(), "chance", Double.NaN);
                                byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
                                if (enchantmentLevel > 0)
                                {
                                    final ItemTemplate item = ItemData.getInstance().getTemplate(id);
                                    if (item != null)
                                    {
                                        if (item.isWeapon())
                                        {
                                            enchantmentLevel = (byte) Math.min(enchantmentLevel, item.isMagicWeapon() ? magicWeaponGroupMax > -2 ? magicWeaponGroupMax : enchantmentLevel : weaponGroupMax > -2 ? weaponGroupMax : enchantmentLevel);
                                        }
                                        else if (item.isArmor())
                                        {
                                            enchantmentLevel = (byte) Math.min(enchantmentLevel, item.getBodyPart() == ItemTemplate.SLOT_FULL_ARMOR ? fullArmorGroupMax > -2 ? fullArmorGroupMax : enchantmentLevel : armorGroupMax > -2 ? armorGroupMax : enchantmentLevel);
                                        }
                                    }
                                }
                               
                                final ItemChanceHolder product = new ItemChanceHolder(id, chance, count, enchantmentLevel);
                                if (itemExists(product))
                                {
                                    // Check chance only of items that have set chance. Items without chance (NaN) are used for displaying purposes.
                                    if ((!Double.isNaN(chance) && (chance < 0)) || (chance > 100))
                                    {
                                        LOGGER.warning("Invalid chance for itemId: " + product.getId() + ", count: " + product.getCount() + ", chance: " + chance + " in list: " + listId);
                                        continue;
                                    }
                                   
                                    products.add(product);
                                   
                                    final ItemTemplate item = ItemData.getInstance().getTemplate(id);
                                    if (item != null)
                                    {
                                        if (chance > 0)
                                        {
                                            totalPrice += ((item.getReferencePrice() / 2) * count) * (chance / 100);
                                        }
                                        else
                                        {
                                            totalPrice += ((item.getReferencePrice() / 2) * count);
                                        }
                                    }
                                }
                                else
                                {
                                    LOGGER.warning("Invalid product id or count for itemId: " + product.getId() + ", count: " + product.getCount() + " in list: " + listId);
                                    continue;
                                }
                            }
                        }
                       
                        final double totalChance = products.stream().filter(i -> !Double.isNaN(i.getChance())).mapToDouble(ItemChanceHolder::getChance).sum();
                        if (totalChance > 100)
                        {
                            LOGGER.warning("Products' total chance of " + totalChance + "% exceeds 100% for list: " + listId + " at entry " + entries.size() + 1 + ".");
                        }
                       
                        // Check if buy price is lower than sell price.
                        // Only applies when there is only one ingredient and it is adena.
                        if (Config.CORRECT_PRICES && (ingredients.size() == 1) && (lastIngredientId == 57) && (lastIngredientCount < totalPrice))
                        {
                            LOGGER.warning("Buy price " + lastIngredientCount + " is less than sell price " + totalPrice + " at entry " + entryCounter.intValue() + " of multisell " + listId + ".");
                            // Adjust price.
                            final ItemChanceHolder ingredient = new ItemChanceHolder(57, 0, totalPrice, (byte) 0, ingredients.get(0).isMaintainIngredient());
                            ingredients.clear();
                            ingredients.add(ingredient);
                        }
                       
                        entries.add(entry);
                    }
                    else if ("npcs".equalsIgnoreCase(itemNode.getNodeName()))
                    {
                        // Initialize NPCs with the size of child nodes.
                        final Set<Integer> allowNpc = new HashSet<>(itemNode.getChildNodes().getLength());
                        forEach(itemNode, n -> "npc".equalsIgnoreCase(n.getNodeName()), n -> allowNpc.add(Integer.parseInt(n.getTextContent())));
                       
                        // Add npcs to stats set.
                        set.set("allowNpc", allowNpc);
                    }
                });
               
                set.set("listId", listId);
                set.set("entries", entries);
                _multisells.put(listId, new MultisellListHolder(set));
            });
        }
        catch (Exception e)
        {
            LOGGER.log(Level.SEVERE, getClass().getSimpleName() + ": Error in file " + f, e);
        }
    }
   
    @Override
    public FileFilter getCurrentFileFilter()
    {
        return NUMERIC_FILTER;
    }
   
    /**
     * This will generate the multisell list for the items.<br>
     * There exist various parameters in multisells that affect the way they will appear:
     * <ol>
     * <li>Inventory only:
     * <ul>
     * <li>If true, only show items of the multisell for which the "primary" ingredients are already in the player's inventory. By "primary" ingredients we mean weapon and armor.</li>
     * <li>If false, show the entire list.</li>
     * </ul>
     * </li>
     * <li>Maintain enchantment: presumably, only lists with "inventory only" set to true should sometimes have this as true. This makes no sense otherwise...
     * <ul>
     * <li>If true, then the product will match the enchantment level of the ingredient.<br>
     * If the player has multiple items that match the ingredient list but the enchantment levels differ, then the entries need to be duplicated to show the products and ingredients for each enchantment level.<br>
     * For example: If the player has a crystal staff +1 and a crystal staff +3 and goes to exchange it at the mammon, the list should have all exchange possibilities for the +1 staff, followed by all possibilities for the +3 staff.</li>
     * <li>If false, then any level ingredient will be considered equal and product will always be at +0</li>
     * </ul>
     * </li>
     * <li>Apply taxes: Uses the "taxIngredient" entry in order to add a certain amount of adena to the ingredients.
     * <li>
     * <li>Additional product and ingredient multipliers.</li>
     * </ol>
     * @param listId
     * @param player
     * @param npc
     * @param inventoryOnly
     * @param ingredientMultiplierValue
     * @param productMultiplierValue
     * @param type
     */
    public void separateAndSend(int listId, Player player, Npc npc, boolean inventoryOnly, double ingredientMultiplierValue, double productMultiplierValue, int type)
    {
        final MultisellListHolder template = _multisells.get(listId);
        if (template == null)
        {
            LOGGER.warning("Can't find list id: " + listId + " requested by player: " + player.getName() + ", npcId: " + (npc != null ? npc.getId() : 0));
            return;
        }
       
        if (!template.isNpcAllowed(-1) && ((npc == null) || !template.isNpcAllowed(npc.getId())))
        {
            if (player.isGM())
            {
                player.sendMessage("Multisell " + listId + " is restricted. Under current conditions cannot be used. Only GMs are allowed to use it.");
            }
            else
            {
                LOGGER.warning(getClass().getSimpleName() + ": " + player + " attempted to open multisell " + listId + " from npc " + npc + " which is not allowed!");
                return;
            }
        }
       
        // Check if ingredient/product multipliers are set, if not, set them to the template value.
        final double ingredientMultiplier = (Double.isNaN(ingredientMultiplierValue) ? template.getIngredientMultiplier() : ingredientMultiplierValue);
        final double productMultiplier = (Double.isNaN(productMultiplierValue) ? template.getProductMultiplier() : productMultiplierValue);
        final PreparedMultisellListHolder list = new PreparedMultisellListHolder(template, inventoryOnly, player.getInventory(), npc, ingredientMultiplier, productMultiplier);
        int index = 0;
        do
        {
            // send list at least once even if size = 0
            player.sendPacket(new MultiSellList(player, list, index, type));
            index += PAGE_SIZE;
        }
        while (index < list.getEntries().size());
       
        player.setMultiSell(list);
    }
   
    public void separateAndSend(int listId, Player player, Npc npc, boolean inventoryOnly)
    {
        separateAndSend(listId, player, npc, inventoryOnly, Double.NaN, Double.NaN, 0);
    }
   
    private final boolean itemExists(ItemHolder holder)
    {
        final SpecialItemType specialItem = SpecialItemType.getByClientId(holder.getId());
        if (specialItem != null)
        {
            return true;
        }
       
        final ItemTemplate template = ItemData.getInstance().getTemplate(holder.getId());
        return (template != null) && (template.isStackable() ? (holder.getCount() >= 1) : (holder.getCount() == 1));
    }
   
    public MultisellListHolder getMultisell(int id)
    {
        return _multisells.getOrDefault(id, null);
    }
   
    public static MultisellData getInstance()
    {
        return SingletonHolder.INSTANCE;
    }
   
    private static class SingletonHolder
    {
        protected static final MultisellData INSTANCE = new MultisellData();
    }
}


Код:
/*
package org.l2jmobius.gameserver.network.clientpackets;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.l2jmobius.Config;
import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.data.xml.EnsoulData;
import org.l2jmobius.gameserver.data.xml.ItemData;
import org.l2jmobius.gameserver.data.xml.MultisellData;
import org.l2jmobius.gameserver.enums.AttributeType;
import org.l2jmobius.gameserver.enums.SpecialItemType;
import org.l2jmobius.gameserver.model.ItemInfo;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.clan.Clan;
import org.l2jmobius.gameserver.model.ensoul.EnsoulOption;
import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import org.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import org.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import org.l2jmobius.gameserver.model.item.ItemTemplate;
import org.l2jmobius.gameserver.model.item.enchant.attribute.AttributeHolder;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.model.itemcontainer.Inventory;
import org.l2jmobius.gameserver.model.itemcontainer.PlayerInventory;
import org.l2jmobius.gameserver.network.PacketLogger;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.ExMultiSellResult;
import org.l2jmobius.gameserver.network.serverpackets.ExPCCafePointInfo;
import org.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;

/**
 * The Class MultiSellChoose.
 */
public class MultiSellChoose extends ClientPacket
{
    private int _listId;
    private int _entryId;
    private long _amount;
    private int _enchantLevel;
    private int _augmentOption1;
    private int _augmentOption2;
    private short _attackAttribute;
    private short _attributePower;
    private short _fireDefence;
    private short _waterDefence;
    private short _windDefence;
    private short _earthDefence;
    private short _holyDefence;
    private short _darkDefence;
    private EnsoulOption[] _soulCrystalOptions;
    private EnsoulOption[] _soulCrystalSpecialOptions;
   
    @Override
    protected void readImpl()
    {
        _listId = readInt();
        _entryId = readInt();
        _amount = readLong();
        _enchantLevel = readShort();
        _augmentOption1 = readInt();
        _augmentOption2 = readInt();
        _attackAttribute = readShort();
        _attributePower = readShort();
        _fireDefence = readShort();
        _waterDefence = readShort();
        _windDefence = readShort();
        _earthDefence = readShort();
        _holyDefence = readShort();
        _darkDefence = readShort();
        _soulCrystalOptions = new EnsoulOption[readByte()]; // Ensoul size
        for (int i = 0; i < _soulCrystalOptions.length; i++)
        {
            final int ensoulId = readInt(); // Ensoul option id
            _soulCrystalOptions[i] = EnsoulData.getInstance().getOption(ensoulId);
        }
        _soulCrystalSpecialOptions = new EnsoulOption[readByte()]; // Special ensoul size
        for (int i = 0; i < _soulCrystalSpecialOptions.length; i++)
        {
            final int ensoulId = readInt(); // Special ensoul option id.
            _soulCrystalSpecialOptions[i] = EnsoulData.getInstance().getOption(ensoulId);
        }
    }
   
    @Override
    protected void runImpl()
    {
        final Player player = getPlayer();
        if (player == null)
        {
            return;
        }
       
        if (!getClient().getFloodProtectors().canUseMultiSell())
        {
            player.setMultiSell(null);
            return;
        }
       
        if ((_amount < 1) || (_amount > Config.MULTISELL_AMOUNT_LIMIT)) // 999 999 is client max.
        {
            player.sendPacket(SystemMessageId.YOU_HAVE_EXCEEDED_THE_QUANTITY_THAT_CAN_BE_INPUTTED);
            return;
        }
       
        final PreparedMultisellListHolder list = player.getMultiSell();
        if ((list == null) || (list.getId() != _listId))
        {
            player.setMultiSell(null);
            return;
        }
       
        final Npc npc = player.getLastFolkNPC();
        if (!list.isNpcAllowed(-1))
        {
            if ((npc == null) //
                || !list.isNpcAllowed(npc.getId()) //
                || !list.checkNpcObjectId(npc.getObjectId()) //
                || (player.getInstanceId() != npc.getInstanceId()) //
                || !player.isInsideRadius3D(npc, Npc.INTERACTION_DISTANCE))
            {
                if (player.isGM())
                {
                    player.sendMessage("Multisell " + _listId + " is restricted. Under current conditions cannot be used. Only GMs are allowed to use it.");
                }
                else
                {
                    player.setMultiSell(null);
                    return;
                }
            }
        }
       
        if (((_soulCrystalOptions != null) && CommonUtil.contains(_soulCrystalOptions, null)) || ((_soulCrystalSpecialOptions != null) && CommonUtil.contains(_soulCrystalSpecialOptions, null)))
        {
            PacketLogger.warning("Character: " + player.getName() + " requested multisell entry with invalid soul crystal options. Multisell: " + _listId + " entry: " + _entryId);
            player.setMultiSell(null);
            return;
        }
       
        final List<MultisellEntryHolder> entries = list.getEntries();
        if (entries == null)
        {
            PacketLogger.warning("Character: " + player.getName() + " requested null multisell entry. Multisell: " + _listId + " entry: " + _entryId);
            return;
        }
        if (entries.isEmpty())
        {
            PacketLogger.warning("Character: " + player.getName() + " requested empty multisell entry. Multisell: " + _listId + " entry: " + _entryId);
            return;
        }
        if ((_entryId - 1) >= entries.size())
        {
            PacketLogger.warning("Character: " + player.getName() + " requested out of bounds multisell entry. Multisell: " + _listId + " entry: " + _entryId);
            return;
        }
       
        final MultisellEntryHolder entry = entries.get(_entryId - 1); // Entry Id begins from 1. We currently use entry IDs as index pointer.
        if (entry == null)
        {
            PacketLogger.warning("Character: " + player.getName() + " requested inexistant prepared multisell entry. Multisell: " + _listId + " entry: " + _entryId);
            player.setMultiSell(null);
            return;
        }
       
        if (!entry.isStackable() && (_amount > 1))
        {
            PacketLogger.warning("Character: " + player.getName() + " is trying to set amount > 1 on non-stackable multisell. Id: " + _listId + " entry: " + _entryId);
            player.setMultiSell(null);
            return;
        }
       
        ItemInfo itemEnchantment = list.getItemEnchantment(_entryId - 1); // Entry Id begins from 1. We currently use entry IDs as index pointer.
       
        // Validate the requested item with its full stats.
        //@formatter:off
        if ((itemEnchantment != null) && ((_amount > 1)
            || (itemEnchantment.getEnchantLevel() != _enchantLevel)
            || (itemEnchantment.getAttackElementType() != _attackAttribute)
            || (itemEnchantment.getAttackElementPower() != _attributePower)
            || (itemEnchantment.getAttributeDefence(AttributeType.FIRE) != _fireDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.WATER) != _waterDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.WIND) != _windDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.EARTH) != _earthDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.HOLY) != _holyDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.DARK) != _darkDefence)
            || ((itemEnchantment.getAugmentation() == null) && ((_augmentOption1 != 0) || (_augmentOption2 != 0)))
            || ((itemEnchantment.getAugmentation() != null) && ((itemEnchantment.getAugmentation().getOption1Id() != _augmentOption1) || (itemEnchantment.getAugmentation().getOption2Id() != _augmentOption2)))
            || ((_soulCrystalOptions != null) && !itemEnchantment.soulCrystalOptionsMatch(_soulCrystalOptions))
            || ((_soulCrystalOptions == null) && !itemEnchantment.getSoulCrystalOptions().isEmpty())
            || ((_soulCrystalSpecialOptions != null) && !itemEnchantment.soulCrystalSpecialOptionsMatch(_soulCrystalSpecialOptions))
            || ((_soulCrystalSpecialOptions == null) && !itemEnchantment.getSoulCrystalSpecialOptions().isEmpty())
            ))
        //@formatter:on
        {
            PacketLogger.warning("Character: " + player.getName() + " is trying to upgrade equippable item, but the stats doesn't match. Id: " + _listId + " entry: " + _entryId);
            player.setMultiSell(null);
            return;
        }
       
        final Clan clan = player.getClan();
        final PlayerInventory inventory = player.getInventory();
       
        try
        {
            int slots = 0;
            int weight = 0;
            for (ItemChanceHolder product : entry.getProducts())
            {
                if (product.getId() < 0)
                {
                    // Check if clan exists for clan reputation products.
                    if ((clan == null) && (SpecialItemType.CLAN_REPUTATION.getClientId() == product.getId()))
                    {
                        player.sendPacket(SystemMessageId.YOU_ARE_NOT_A_CLAN_MEMBER_2);
                        return;
                    }
                    continue;
                }
               
                final ItemTemplate template = ItemData.getInstance().getTemplate(product.getId());
                if (template == null)
                {
                    player.setMultiSell(null);
                    return;
                }
               
                final long totalCount = Math.multiplyExact(list.getProductCount(product), _amount);
                if ((totalCount < 1) || (totalCount > Integer.MAX_VALUE))
                {
                    player.sendPacket(SystemMessageId.YOU_HAVE_EXCEEDED_THE_QUANTITY_THAT_CAN_BE_INPUTTED);
                    return;
                }
               
                if (!template.isStackable() || (player.getInventory().getItemByItemId(product.getId()) == null))
                {
                    slots++;
                }
               
                weight += totalCount * template.getWeight();
                if (!inventory.validateWeight(weight))
                {
                    player.sendPacket(SystemMessageId.YOU_HAVE_EXCEEDED_THE_WEIGHT_LIMIT);
                    return;
                }
               
                if ((slots > 0) && !inventory.validateCapacity(slots))
                {
                    player.sendPacket(SystemMessageId.YOUR_INVENTORY_IS_FULL);
                    return;
                }
               
                // If this is a chance multisell, reset slots and weight because only one item should be seleted. We just need to check if conditions for every item is met.
                if (list.isChanceMultisell())
                {
                    slots = 0;
                    weight = 0;
                }
            }
           
            // Check for enchanted item if it is present in the inventory.
            if ((itemEnchantment != null) && (inventory.getItemByObjectId(itemEnchantment.getObjectId()) == null))
            {
                final SystemMessage sm = new SystemMessage(SystemMessageId.REQUIRED_S1);
                sm.addItemName(itemEnchantment.getItem().getId());
                player.sendPacket(sm);
                return;
            }
           
            // Check for enchanted level and ingredient count requirements.
            final List<ItemChanceHolder> summedIngredients = new ArrayList<>();
            for (ItemChanceHolder ingredient : entry.getIngredients())
            {
                boolean added = false;
                for (ItemChanceHolder summedIngredient : summedIngredients)
                {
                    if ((summedIngredient.getId() == ingredient.getId()) && (summedIngredient.getEnchantmentLevel() == ingredient.getEnchantmentLevel()))
                    {
                        summedIngredients.add(new ItemChanceHolder(ingredient.getId(), ingredient.getChance(), ingredient.getCount() + summedIngredient.getCount(), ingredient.getEnchantmentLevel(), ingredient.isMaintainIngredient()));
                        summedIngredients.remove(summedIngredient);
                        added = true;
                    }
                }
                if (!added)
                {
                    summedIngredients.add(ingredient);
                }
            }
            for (ItemChanceHolder ingredient : summedIngredients)
            {
                if (ingredient.getEnchantmentLevel() > 0)
                {
                    int found = 0;
                    for (Item item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
                    {
                        if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
                        {
                            found++;
                        }
                    }
                   
                    if (found < ingredient.getCount())
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.REQUIRED_S1);
                        sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemData.getInstance().getTemplate(ingredient.getId()).getName());
                        player.sendPacket(sm);
                        return;
                    }
                }
                else if (!checkIngredients(player, list, inventory, clan, ingredient.getId(), Math.multiplyExact(ingredient.getCount(), _amount)))
                {
                    return;
                }
            }
           
            final InventoryUpdate iu = new InventoryUpdate();
            boolean itemEnchantmentProcessed = (itemEnchantment == null);
           
            // Take all ingredients
            for (ItemChanceHolder ingredient : entry.getIngredients())
            {
                if (ingredient.isMaintainIngredient())
                {
                    continue;
                }
               
                final long totalCount = Math.multiplyExact(list.getIngredientCount(ingredient), _amount);
                final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredient.getId());
                if (specialItem != null)
                {
                    // Take special item.
                    switch (specialItem)
                    {
                        case CLAN_REPUTATION:
                        {
                            if (clan != null)
                            {
                                clan.takeReputationScore((int) totalCount);
                                final SystemMessage smsg = new SystemMessage(SystemMessageId.CLAN_REPUTATION_POINTS_S1_2);
                                smsg.addLong(totalCount);
                                player.sendPacket(smsg);
                            }
                            break;
                        }
                        case FAME:
                        {
                            player.setFame(player.getFame() - (int) totalCount);
                            player.updateUserInfo();
                            // player.sendPacket(new ExBrExtraUserInfo(player));
                            break;
                        }
                        case RAIDBOSS_POINTS:
                        {
                            player.setRaidbossPoints(player.getRaidbossPoints() - (int) totalCount);
                            player.updateUserInfo();
                            player.sendPacket(new SystemMessage(SystemMessageId.YOU_CONSUMED_S1_RAID_POINTS).addLong(totalCount));
                            break;
                        }
                        case PC_CAFE_POINTS:
                        {
                            player.setPcCafePoints((int) (player.getPcCafePoints() - totalCount));
                            player.sendPacket(new ExPCCafePointInfo(player.getPcCafePoints(), (int) -totalCount, 1));
                            break;
                        }
                        case HONOR_COINS:
                        {
                            player.setHonorCoins(player.getHonorCoins() - totalCount);
                            break;
                        }
                        default:
                        {
                            PacketLogger.warning("Character: " + player.getName() + " has suffered possible item loss by using multisell " + _listId + " which has non-implemented special ingredient with id: " + ingredient.getId() + ".");
                            return;
                        }
                    }
                }
                else if (ingredient.getEnchantmentLevel() > 0)
                {
                    // Take the enchanted item.
                    final Item destroyedItem = inventory.destroyItem("Multisell", inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()).iterator().next(), totalCount, player, npc);
                    if (destroyedItem != null)
                    {
                        itemEnchantmentProcessed = true;
                        iu.addItem(destroyedItem);
                        if (itemEnchantmentProcessed && destroyedItem.isEquipable()) // Will only consider first equipable ingredient.
                        {
                            itemEnchantment = new ItemInfo(destroyedItem);
                        }
                    }
                    else
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.REQUIRED_S1);
                        sm.addItemName(ingredient.getId());
                        player.sendPacket(sm);
                        return;
                    }
                }
                else if (!itemEnchantmentProcessed && (itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId()))
                {
                    // Take the enchanted item.
                    final Item destroyedItem = inventory.destroyItem("Multisell", itemEnchantment.getObjectId(), totalCount, player, npc);
                    if (destroyedItem != null)
                    {
                        itemEnchantmentProcessed = true;
                        iu.addItem(destroyedItem);
                        if (itemEnchantmentProcessed && destroyedItem.isEquipable()) // Will only consider first equipable ingredient.
                        {
                            itemEnchantment = new ItemInfo(destroyedItem);
                        }
                    }
                    else
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.REQUIRED_S1);
                        sm.addItemName(ingredient.getId());
                        player.sendPacket(sm);
                        return;
                    }
                }
                else
                {
                    // Take a regular item.
                    final Item destroyedItem = inventory.destroyItemByItemId("Multisell", ingredient.getId(), totalCount, player, npc);
                    if (destroyedItem != null)
                    {
                        iu.addItem(destroyedItem);
                        if (itemEnchantmentProcessed && destroyedItem.isEquipable()) // Will only consider first equipable ingredient.
                        {
                            itemEnchantment = new ItemInfo(destroyedItem);
                        }
                    }
                    else
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.YOU_NEED_S1_X_S2);
                        sm.addItemName(ingredient.getId());
                        sm.addLong(totalCount);
                        player.sendPacket(sm);
                        return;
                    }
                }
            }
           
            // Generate the appropriate items
            List<ItemChanceHolder> products = entry.getProducts();
            if (list.isChanceMultisell())
            {
                final ItemChanceHolder randomProduct = ItemChanceHolder.getRandomHolder(entry.getProducts());
                products = randomProduct != null ? Collections.singletonList(randomProduct) : Collections.emptyList();
            }
           
            for (ItemChanceHolder product : products)
            {
                final long totalCount = Math.multiplyExact(list.getProductCount(product), _amount);
                final SpecialItemType specialItem = SpecialItemType.getByClientId(product.getId());
                if (specialItem != null)
                {
                    // Give special item.
                    switch (specialItem)
                    {
                        case CLAN_REPUTATION:
                        {
                            if (clan != null)
                            {
                                clan.addReputationScore((int) totalCount);
                            }
                            break;
                        }
                        case FAME:
                        {
                            player.setFame((int) (player.getFame() + totalCount));
                            player.updateUserInfo();
                            // player.sendPacket(new ExBrExtraUserInfo(player));
                            break;
                        }
                        case RAIDBOSS_POINTS:
                        {
                            player.increaseRaidbossPoints((int) totalCount);
                            player.updateUserInfo();
                            break;
                        }
                        case HONOR_COINS:
                        {
                            player.setHonorCoins(player.getHonorCoins() + totalCount);
                            break;
                        }
                        default:
                        {
                            PacketLogger.warning("Character: " + player.getName() + " has suffered possible item loss by using multisell " + _listId + " which has non-implemented special product with id: " + product.getId() + ".");
                            return;
                        }
                    }
                }
                else
                {
                    // Give item.
                    final Item addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc, false);
                   
                    // Check if the newly given item should be enchanted.
                    if (itemEnchantmentProcessed && list.isMaintainEnchantment() && (itemEnchantment != null) && addedItem.isEquipable() && addedItem.getTemplate().getClass().equals(itemEnchantment.getItem().getClass()))
                    {
                        addedItem.setEnchantLevel(itemEnchantment.getEnchantLevel());
                        addedItem.setAugmentation(itemEnchantment.getAugmentation(), false);
                        if (addedItem.isWeapon())
                        {
                            if (itemEnchantment.getAttackElementPower() > 0)
                            {
                                addedItem.setAttribute(new AttributeHolder(AttributeType.findByClientId(itemEnchantment.getAttackElementType()), itemEnchantment.getAttackElementPower()), false);
                            }
                        }
                        else
                        {
                            if (itemEnchantment.getAttributeDefence(AttributeType.FIRE) > 0)
                            {
                                addedItem.setAttribute(new AttributeHolder(AttributeType.FIRE, itemEnchantment.getAttributeDefence(AttributeType.FIRE)), false);
                            }
                            if (itemEnchantment.getAttributeDefence(AttributeType.WATER) > 0)
                            {
                                addedItem.setAttribute(new AttributeHolder(AttributeType.WATER, itemEnchantment.getAttributeDefence(AttributeType.WATER)), false);
                            }
                            if (itemEnchantment.getAttributeDefence(AttributeType.WIND) > 0)
                            {
                                addedItem.setAttribute(new AttributeHolder(AttributeType.WIND, itemEnchantment.getAttributeDefence(AttributeType.WIND)), false);
                            }
                            if (itemEnchantment.getAttributeDefence(AttributeType.EARTH) > 0)
                            {
                                addedItem.setAttribute(new AttributeHolder(AttributeType.EARTH, itemEnchantment.getAttributeDefence(AttributeType.EARTH)), false);
                            }
                            if (itemEnchantment.getAttributeDefence(AttributeType.HOLY) > 0)
                            {
                                addedItem.setAttribute(new AttributeHolder(AttributeType.HOLY, itemEnchantment.getAttributeDefence(AttributeType.HOLY)), false);
                            }
                            if (itemEnchantment.getAttributeDefence(AttributeType.DARK) > 0)
                            {
                                addedItem.setAttribute(new AttributeHolder(AttributeType.DARK, itemEnchantment.getAttributeDefence(AttributeType.DARK)), false);
                            }
                        }
                        if (_soulCrystalOptions != null)
                        {
                            int pos = -1;
                            for (EnsoulOption ensoul : _soulCrystalOptions)
                            {
                                pos++;
                                addedItem.addSpecialAbility(ensoul, pos, 1, false);
                            }
                        }
                        if (_soulCrystalSpecialOptions != null)
                        {
                            for (EnsoulOption ensoul : _soulCrystalSpecialOptions)
                            {
                                addedItem.addSpecialAbility(ensoul, 0, 2, false);
                            }
                        }
                       
                        addedItem.updateDatabase(true);
                       
                        // Mark that we have already upgraded the item.
                        itemEnchantmentProcessed = false;
                    }
                   
                    if (product.getEnchantmentLevel() > 0)
                    {
                        addedItem.setEnchantLevel(product.getEnchantmentLevel());
                        addedItem.updateDatabase(true);
                    }
                   
                    if (addedItem.getCount() > 1)
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.YOU_HAVE_OBTAINED_S1_X_S2);
                        sm.addItemName(addedItem.getId());
                        sm.addLong(totalCount);
                        player.sendPacket(sm);
                    }
                    else if (addedItem.getEnchantLevel() > 0)
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.YOU_HAVE_OBTAINED_S1_S2_2);
                        sm.addLong(addedItem.getEnchantLevel());
                        sm.addItemName(addedItem.getId());
                        player.sendPacket(sm);
                    }
                    else
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.YOU_HAVE_OBTAINED_S1_2);
                        sm.addItemName(addedItem);
                        player.sendPacket(sm);
                    }
                   
                    // Inventory update.
                    iu.addItem(addedItem);
                    player.sendPacket(new ExMultiSellResult(1, 0, (int) (addedItem.getCount())));
                }
            }
           
            // Update inventory and weight.
            player.sendInventoryUpdate(iu);
           
            // Finally, give the tax to the castle.
            if ((npc != null) && list.isApplyTaxes())
            {
                long taxPaid = 0;
                for (ItemChanceHolder ingredient : entry.getIngredients())
                {
                    if (ingredient.getId() == Inventory.ADENA_ID)
                    {
                        taxPaid += Math.round(ingredient.getCount() * list.getIngredientMultiplier() * list.getTaxRate()) * _amount;
                    }
                }
                if (taxPaid > 0)
                {
                    npc.handleTaxPayment(taxPaid);
                }
            }
        }
        catch (ArithmeticException ae)
        {
            player.sendPacket(SystemMessageId.YOU_HAVE_EXCEEDED_THE_QUANTITY_THAT_CAN_BE_INPUTTED);
            return;
        }
       
        // Re-send multisell after successful exchange of inventory-only shown items.
        if (list.isInventoryOnly() || list.isMaintainEnchantment())
        {
            MultisellData.getInstance().separateAndSend(list.getId(), player, npc, list.isInventoryOnly(), list.getProductMultiplier(), list.getIngredientMultiplier(), 0);
        }
    }
   
    /**
     * @param player
     * @param list
     * @param inventory
     * @param clan
     * @param ingredientId
     * @param totalCount
     * @return {@code false} if ingredient amount is not enough, {@code true} otherwise.
     */
    private boolean checkIngredients(Player player, PreparedMultisellListHolder list, PlayerInventory inventory, Clan clan, int ingredientId, long totalCount)
    {
        final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredientId);
        if (specialItem != null)
        {
            // Check special item.
            switch (specialItem)
            {
                case CLAN_REPUTATION:
                {
                    if (clan == null)
                    {
                        player.sendPacket(SystemMessageId.YOU_ARE_NOT_A_CLAN_MEMBER_2);
                        return false;
                    }
                    else if (!player.isClanLeader())
                    {
                        player.sendPacket(SystemMessageId.AVAILABLE_ONLY_TO_THE_CLAN_LEADER);
                        return false;
                    }
                    else if (clan.getReputationScore() < totalCount)
                    {
                        player.sendPacket(SystemMessageId.THE_CLAN_REPUTATION_IS_TOO_LOW);
                        return false;
                    }
                    return true;
                }
                case FAME:
                {
                    if (player.getFame() < totalCount)
                    {
                        player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_REPUTATION_POINTS);
                        return false;
                    }
                    return true;
                }
                case RAIDBOSS_POINTS:
                {
                    if (player.getRaidbossPoints() < totalCount)
                    {
                        player.sendPacket(SystemMessageId.NOT_ENOUGH_RAID_POINTS);
                        return false;
                    }
                    return true;
                }
                case PC_CAFE_POINTS:
                {
                    if (player.getPcCafePoints() < totalCount)
                    {
                        player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_PA_POINTS);
                        return false;
                    }
                    return true;
                }
                case HONOR_COINS:
                {
                    if (player.getHonorCoins() < totalCount)
                    {
                        player.sendMessage("You are short of Honor Points.");
                        return false;
                    }
                    return true;
                }
                default:
                {
                    PacketLogger.warning("Multisell: " + _listId + " is using a non-implemented special ingredient with id: " + ingredientId + ".");
                    return false;
                }
            }
        }
        // Check if the necessary items are there. If list maintains enchantment, allow all enchanted items, otherwise only unenchanted. TODO: Check how retail does it.
        else if (inventory.getInventoryItemCount(ingredientId, list.isMaintainEnchantment() ? -1 : 0, false) < totalCount)
        {
            final SystemMessage sm = new SystemMessage(SystemMessageId.YOU_NEED_S1_X_S2);
            sm.addItemName(ingredientId);
            sm.addLong(totalCount);
            player.sendPacket(sm);
            return false;
        }
        return true;
    }
}
 
Всем привет, подскажите как прописать в xml, при улучшение предмета, что бы заточка не учитывалась.
Например улучшаю у нпс пояс Правителя +15 2 лв на 3лв. Если пояс 2 лв не точен то улучшает на 3 лв, а если он вточен пишет нет предмета.

Код:
<item>
        <ingredient id="48418" count="5" /> <!-- Authority Ornament -->
        <ingredient id="45584" count="200" /> <!-- Mark of Battle -->
        <ingredient id="48417" count="1" /> <!-- Ruler's Authority - Genesis Lv. 2-->
        <production id="81751" count="1" chance="0" /> <!-- Ruler's Authority - Chaos Lv. 3 -->
        <production id="81751" count="1" chance="15" /> <!-- Ruler's Authority - Chaos Lv. 3 -->
        <production id="48417" count="1" chance="85" /> <!-- Ruler's Authority - Genesis Lv. 2 -->
    </item>
Код:
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/multisell.xsd" maintainEnchantment="true">
Попробуй так
 
вот что за привычка тыкать все подряд в качестве атрибутов :pandaredlol: Не поймет такое парсер, и убедится в этом можно открыв MultisellData.java или multisell.xsd

парсер:
Java:
                            if ("ingredient".equalsIgnoreCase(d.getNodeName()))
                            {
                                final int id = parseInteger(d.getAttributes(), "id");
                                final long count = parseLong(d.getAttributes(), "count");
                                final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
                                final Boolean maintainIngredient = parseBoolean(d.getAttributes(), "maintainIngredient", false);
                                final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel, maintainIngredient);
                                if (itemExists(ingredient))
                                {
                                    ingredients.add(ingredient);
                                  
                                    lastIngredientId = id;
                                    lastIngredientCount = count;
                                }
                                else
                                {
                                    LOGGER.warning("Invalid ingredient id or count for itemId: " + ingredient.getId() + ", count: " + ingredient.getCount() + " in list: " + listId);
                                    continue;
                                }
                            }
схема:
XML:
                            <xs:element name="ingredient" minOccurs="0" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:attribute name="id" type="xs:integer" use="required" />
                                    <xs:attribute name="count" type="xs:positiveInteger" use="required" />
                                    <xs:attribute name="enchantmentLevel" type="xs:integer" />
                                    <xs:attribute name="maintainIngredient" type="xs:boolean" />
                                </xs:complexType>
                            </xs:element>

Шел 2024 год, а разрабы л2ж все продолжали насиловать хмл разметку (удобно вносить изменения и т.п.)
Зачем нам (де)сериализация, используя например тот же json. Перебирая ноды через XmlReader :Wahaha:

@uter81, пересмотреть проверки в классе MultiSellChoose, в частности все что связанно с проверками на энчант.

п.с. - Просмотрев часть кода:
Java:
        // Validate the requested item with its full stats.
        //@formatter:off
        if ((itemEnchantment != null) && ((_amount > 1)
            || (itemEnchantment.getEnchantLevel() != _enchantLevel)
            || (itemEnchantment.getAttackElementType() != _attackAttribute)
            || (itemEnchantment.getAttackElementPower() != _attributePower)
            || (itemEnchantment.getAttributeDefence(AttributeType.FIRE) != _fireDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.WATER) != _waterDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.WIND) != _windDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.EARTH) != _earthDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.HOLY) != _holyDefence)
            || (itemEnchantment.getAttributeDefence(AttributeType.DARK) != _darkDefence)
            || ((itemEnchantment.getAugmentation() == null) && ((_augmentOption1 != 0) || (_augmentOption2 != 0)))
            || ((itemEnchantment.getAugmentation() != null) && ((itemEnchantment.getAugmentation().getOption1Id() != _augmentOption1) || (itemEnchantment.getAugmentation().getOption2Id() != _augmentOption2)))
            || ((_soulCrystalOptions != null) && !itemEnchantment.soulCrystalOptionsMatch(_soulCrystalOptions))
            || ((_soulCrystalOptions == null) && !itemEnchantment.getSoulCrystalOptions().isEmpty())
            || ((_soulCrystalSpecialOptions != null) && !itemEnchantment.soulCrystalSpecialOptionsMatch(_soulCrystalSpecialOptions))
            || ((_soulCrystalSpecialOptions == null) && !itemEnchantment.getSoulCrystalSpecialOptions().isEmpty())
            ))
        //@formatter:on
        {
            PacketLogger.warning("Character: " + player.getName() + " is trying to upgrade equippable item, but the stats doesn't match. Id: " + _listId + " entry: " + _entryId);
            player.setMultiSell(null);
            return;
        }

Java:
            // Check for enchanted level and ingredient count requirements.
            final List<ItemChanceHolder> summedIngredients = new ArrayList<>();
            for (ItemChanceHolder ingredient : entry.getIngredients())
            {
                boolean added = false;
                for (ItemChanceHolder summedIngredient : summedIngredients)
                {
                    if ((summedIngredient.getId() == ingredient.getId()) && (summedIngredient.getEnchantmentLevel() == ingredient.getEnchantmentLevel()))
                    {
                        summedIngredients.add(new ItemChanceHolder(ingredient.getId(), ingredient.getChance(), ingredient.getCount() + summedIngredient.getCount(), ingredient.getEnchantmentLevel(), ingredient.isMaintainIngredient()));
                        summedIngredients.remove(summedIngredient);
                        added = true;
                    }
                }
                if (!added)
                {
                    summedIngredients.add(ingredient);
                }
            }
            for (ItemChanceHolder ingredient : summedIngredients)
            {
                if (ingredient.getEnchantmentLevel() > 0)
                {
                    int found = 0;
                    for (Item item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
                    {
                        if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
                        {
                            found++;
                        }
                    }
                  
                    if (found < ingredient.getCount())
                    {
                        final SystemMessage sm = new SystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
                        sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemData.getInstance().getTemplate(ingredient.getId()).getName());
                        player.sendPacket(sm);
                        return;
                    }
                }
                else if (!checkIngredients(player, list, inventory, clan, ingredient.getId(), Math.multiplyExact(ingredient.getCount(), _amount)))
                {
                    return;
                }
            }
          
            final InventoryUpdate iu = new InventoryUpdate();
            boolean itemEnchantmentProcessed = (itemEnchantment == null);
          
            // Take all ingredients
            for (ItemChanceHolder ingredient : entry.getIngredients())
у меня чуть глаза не вытекли :Bloodnose: какие-то безконечные переборы, цикл в цикле с циклами. Зато версия явы апнута до 21
(де)сериализация это общие термины, они не привязаны к определенному языку разметки. По сути, то что сейчас есть в XmlReader'aх это и есть десериализация. Вопрос больше в том, что на таких низких уровнях десериализация не к месту.
Есть например либа fasterxml, которая позволяет легко десериализовать xml/json/yaml в java классы.
Java:
public class RelicsData extends JsonReader<Relics>{
private static final Logger LOGGER = Logger.getLogger(RelicsData.class.getName());

protected RelicsData()
{
super(Relics.class);
load();
}

@Override
public synchronized void load()
{
parseDatapackFile("data/Relics.json");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + get().getRelics().size() + " relics");
}

public static RelicsData getInstance()
{
return SingletonHolder.INSTANCE;
}

private static class SingletonHolder
{
protected static final RelicsData INSTANCE = new RelicsData();
}
}
 
  • Мне нравится
Реакции: òbi
Назад
Сверху