[Решено] Работа с инвентарём.

  • Автор темы Автор темы CoolBoy
  • Дата начала Дата начала
Статус
Закрыто для дальнейших ответов.

CoolBoy

Активный участник
Пользователь
Баллы
96
Имя в Minecraft
Xezard
Доброго времени суток, уважаемые форумчане.

Сразу к делу.
Не найдя нормального магазина на версию 1.9.4 решил написать свой.
За небольшой срок написал таковой, но возникла проблема.
Если в инвентаре имеется, к примеру, 4 блока земли и я продаю их - команда срабатывает.
Если в инвентаре лежит 4 блока земли по одному блоку в каждом слоте - команда не работает и пишет что предметов не хватает.
И это вполне очевидно, ведь я проверяю условия на каждый отдельный слот, а не на весь инвентарь в целом.

Вопрос:
Каким образом можно решить мою проблему?
Я конечно, понимаю, что можно сделать HashMap, или просто Map и заносить туда инвентарь целиком, а после - работать с мапой.
Но не представляю каким образом это может выглядеть.

То, что имею на данный момент:
- Commands:

Java:
if (args.length == 4 && args[0].equalsIgnoreCase("sell"))  
{
    Player player = (Player) sender;
    Inventory inventory = player.getInventory();
    String[] split = args[1].split(":");
               
    if (!inventory.containsAtLeast(new ItemStack(Material.valueOf(split[0]), 1, Byte.valueOf(split[1])), 1)) 
    {
        player.sendMessage(no_item);
        return true;
    }
               
    for (int i = 0; i < inventory.getSize(); i++) 
    {
        ItemStack itemStack = inventory.getItem(i);
                   
        if (itemStack != null && itemStack.getType().equals(Material.valueOf(split[0]))) 
        {
            if (itemStack.getAmount() < Integer.valueOf(args[2])) 
            {
                 player.sendMessage(no_item_to_sell);
                 break;
            }
                       
            int amount = itemStack.getAmount() - Integer.valueOf(args[2]);
            ItemStack item = new ItemStack(Material.valueOf(split[0]), amount, Byte.valueOf(split[1]));
            itemStack.setAmount(amount);
            inventory.setItem(i, amount > 0 ? item : null);
            this.plugin.giveMoney(player, Double.parseDouble(args[3]));
            player.updateInventory();
            break;
        }
    }
}

Прошу помощи знающих людей)
Любые комментарии по коду приветствуются :)
 
Java:
static int getItemCountInInventory(Inventory inv, Material type)
{
    int count = 0;
  
    ItemStack[] contents = inv.getContents();
  
    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
      
        if(s.getType() == type)
            count += s.getAmount();
    }
  
    return count;
}
Возможно, я старомоден.
 
Java:
static int getItemCountInInventory(Inventory inv, Material type)
{
    int count = 0;

    ItemStack[] contents = inv.getContents();

    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
    
        if(s.getType() == type)
            count += s.getAmount();
    }

    return count;
}
Возможно, я старомоден.
Спасибо за помощь, но ведь это просто счётчик?
Как я смогу удалить ItemStack'и из всех слотов, в которых они расположены, зная только их количество?
:)
 
Спасибо за помощь, но ведь это просто счётчик?
Как я смогу удалить ItemStack'и из всех слотов, в которых они расположены, зная только их количество?
:)
Java:
static boolean remove(Inventory inv, Material type, int count)
{
    int realCount = 0;
    int nCnt = count;
 
    ItemStack[] contents = inv.getContents();
 
    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
     
        if(s.getType() == type)
            count += s.getAmount();
    }
 
    if(realCount < count)
        return false;//не достаточно предметов
 
    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
     
        if(s.getAmount() >= nCnt)
        {
            if(s.getAmount() > nCnt)
                s.setAmount(s.getAmount() - nCnt);
            else
                inv.remove(s);

            break;
        }
        else
        { 
            nCnt -= s.getAmount();
         
            inv.remove(s);
        }
    }
 
    return true;
}
 
Java:
static boolean remove(Inventory inv, Material type, int count)
{
    int realCount = 0;
    int nCnt = count;

    ItemStack[] contents = inv.getContents();

    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
   
        if(s.getType() == type)
            count += s.getAmount();
    }

    if(realCount < count)
        return false;//не достаточно предметов

    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
   
        if(s.getAmount() >= nCnt)
        {
            if(s.getAmount() > nCnt)
                s.setAmount(s.getAmount() - nCnt);
            else
                inv.remove(s);

            break;
        }
        else
        {
            nCnt -= s.getAmount();
       
            inv.remove(s);
        }
    }

    return true;
}
Вопрос.
Зачем нужен realCount если он всегда = 0? И всегда отменяет метод?
2 вопрос. :)
  1. if(s.getType() == type)
  2. count += s.getAmount(); // Тут разве нужно не realCount += s.getAmount(); ?
  3. }
Подредактировав немного ваш метод у меня почти получилось сделать то, что я хочу.
Но пока не всё идеально.
То, что получилось:
Java:
    public static boolean remove(Player player, Inventory inv, Material type, int count)
    {
       int realCount = 0;
       int nCnt = count;
       player.sendMessage("Поехали!");
    
       ItemStack[] contents = inv.getContents();
    
       for (int i = 0; i < contents.length; i++)
       {
           ItemStack stack = contents[i];
      
           if (stack != null && stack.getType() == type)
           {
              player.sendMessage("Тип стака = типу нашего материала! Добавили к счётчику!");
               realCount += stack.getAmount();
           }
       }
    
       if (realCount < count)
       {
          player.sendMessage("Ресов нету(");
           return false;
       }
    
       for (int i = 0; i < contents.length; i++)
       {
           ItemStack stack = contents[i];
      
           if (stack != null && stack.getAmount() >= nCnt)
           {
              player.sendMessage("Количество больше либо равно вычитаемому!");
            
               if (stack != null && stack.getAmount() > nCnt)
               {
                   stack.setAmount(stack.getAmount() - nCnt);
                   player.sendMessage("Отняли количество от товара!");
               } else {
                   inv.remove(stack);
                   player.sendMessage("Убрали стак!");
                   break;
               }
           } else { 
               nCnt -= stack.getAmount();
               inv.remove(stack);
               player.sendMessage("Отняли количество от товара!");
           }
       }
       return true;
    }
Если вычитать из целого стака - всё нормально. Если разложить по слотам, то иногда считает правильно - иногда нет.
Можете проверить ? :)

Спасибо за помощь, ещё раз)
UP!
 
У меня на данный момент так. Но, честно говоря, не особо нравится такое решение. Возможно позже переделаю. Ну а пока... Что есть...
Java:
    public static boolean takeItem(GamePlayer gamePlayer, GameItem gameItem, short amount) {
        String name = gameItem.getStack().getItemMeta().getDisplayName();
        //gamePlayer - сам игрок (у меня просто наследует CraftPlayer)
        //name - название требуемых предметов (у меня сравнение производится не по материалу, но, думаю, переделать не составит труда)
        //amount - количество требуемых предметов
        ItemStack[] contents = gamePlayer.getInventory().getContents();
        HashMap<Integer, ItemStack> replacing = new HashMap<>(); // Таблица заменяемых предметов: слот, новый стак
        for (int slot = 0; slot < contents.length; slot++) {
            ItemStack current = contents[slot];
            if (current == null) continue;
            if (!current.getItemMeta().getDisplayName().equals(name)) continue;
            int currentAmount = current.getAmount();
            int newAmount = currentAmount - amount;
            if (newAmount < 1) //Удаляем стак из инвентаря, если количество предметов в нём меньше единицы
                replacing.put(slot, null);
            else { //Иначе просто устанавливаем новый размер стака
                current.setAmount(newAmount);
                replacing.put(slot, current);
            }
            amount -= currentAmount; //Уменьшаем количество требуемых предметов на размер стака
            if (amount <= 0) {
                Inventory inventory = gamePlayer.getInventory();
                for (Map.Entry<Integer, ItemStack> entry : replacing.entrySet()) //Обновление изменённых стаков
                    inventory.setItem(entry.getKey(), entry.getValue());
                //Предметов хватает
                return true;
            }
        }
        //Недостаточно предметов
        return false;
    }
 
У меня на данный момент так. Но, честно говоря, не особо нравится такое решение. Возможно позже переделаю. Ну а пока... Что есть...
Java:
    public static boolean takeItem(GamePlayer gamePlayer, GameItem gameItem, short amount) {
        String name = gameItem.getStack().getItemMeta().getDisplayName();
        //gamePlayer - сам игрок (у меня просто наследует CraftPlayer)
        //name - название требуемых предметов (у меня сравнение производится не по материалу, но, думаю, переделать не составит труда)
        //amount - количество требуемых предметов
        ItemStack[] contents = gamePlayer.getInventory().getContents();
        HashMap<Integer, ItemStack> replacing = new HashMap<>(); // Таблица заменяемых предметов: слот, новый стак
        for (int slot = 0; slot < contents.length; slot++) {
            ItemStack current = contents[slot];
            if (current == null) continue;
            if (!current.getItemMeta().getDisplayName().equals(name)) continue;
            int currentAmount = current.getAmount();
            int newAmount = currentAmount - amount;
            if (newAmount < 1) //Удаляем стак из инвентаря, если количество предметов в нём меньше единицы
                replacing.put(slot, null);
            else { //Иначе просто устанавливаем новый размер стака
                current.setAmount(newAmount);
                replacing.put(slot, current);
            }
            amount -= currentAmount; //
            if (amount <= 0) {
                Inventory inventory = gamePlayer.getInventory();
                for (Map.Entry<Integer, ItemStack> entry : replacing.entrySet())
                    inventory.setItem(entry.getKey(), entry.getValue());
                //Предметов хватает
                return true;
            }
        }
        //Недостаточно предметов
        return false;
    }
Спасибо. Протестирую ближе к утру.
 
Вопрос.
Зачем нужен realCount если он всегда = 0? И всегда отменяет метод?
2 вопрос. :)
  1. if(s.getType() == type)
  2. count += s.getAmount(); // Тут разве нужно не realCount += s.getAmount(); ?
  3. }
Подредактировав немного ваш метод у меня почти получилось сделать то, что я хочу.
Но пока не всё идеально.
То, что получилось:
Java:
...
Если вычитать из целого стака - всё нормально. Если разложить по слотам, то иногда считает правильно - иногда нет.
Можете проверить ? :)

Спасибо за помощь, ещё раз)
UP!
Java:
static boolean remove(Inventory inv, Material type, int count)
{
    int realCount = 0;
    int nCnt = count;

    ItemStack[] contents = inv.getContents();

    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
  
        if(s != null)
           if(s.getType() == type)
               realCount += s.getAmount();
    }

    if(realCount < count)
        return false;//не достаточно предметов

    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
  
        if(s == null)
            continue;
    
        if(s.getAmount() >= nCnt)
        {
            if(s.getAmount() > nCnt)
                s.setAmount(s.getAmount() - nCnt);
            else
                contents[i] = null;

            break;
        }
        else
        {
            nCnt -= s.getAmount();
      
            contents[i] = null;
        }
    }

    inv.setContents(contents);

    return true;
}
Java:
if(remove(player.getInventory(), mat, count))
    player.sendMessage("Удалено " + count + " " + mat);
else
    player.sendMessage("Не достаточно  " + mat);
Проверил; вроде бы работает.
 
Java:
static boolean remove(Inventory inv, Material type, int count)
{
    int realCount = 0;
    int nCnt = count;

    ItemStack[] contents = inv.getContents();

    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
 
        if(s != null)
           if(s.getType() == type)
               realCount += s.getAmount();
    }

    if(realCount < count)
        return false;//не достаточно предметов

    for(int i = 0; i < contents.length; i++)
    {
        ItemStack s = contents[i];
 
        if(s == null)
            continue;
   
        if(s.getAmount() >= nCnt)
        {
            if(s.getAmount() > nCnt)
                s.setAmount(s.getAmount() - nCnt);
            else
                contents[i] = null;

            break;
        }
        else
        {
            nCnt -= s.getAmount();
     
            contents[i] = null;
        }
    }

    inv.setContents(contents);

    return true;
}
Java:
if(remove(player.getInventory(), mat, count))
    player.sendMessage("Удалено " + count + " " + mat);
else
    player.sendMessage("Не достаточно  " + mat);
Проверил; вроде бы работает.
Просто огроменное тебе спасибо!
Очень выручил, причём не в первый раз!

P.S. До этого глядел исходник Essentials, как там предметы продаются, так там используется Мапа :)

Решено. Закрыто.
 
Статус
Закрыто для дальнейших ответов.
Назад
Верх