Программно добавить в IInventory предмет - не отоббражаются текстуры

Версия Minecraft
1.7.10
1,159
38
544
Здравствуйте, стоит задача заполнять инвентарь блоками, если он не был найден в NBT . Т.е. если d NBT блоков нет - программно добавить нужные блоки.

Вот так я читаю NBT
Java:
public void readFromNBT(NBTTagCompound compound) {
        NBTTagList items = compound.getTagList(tagName, Constants.NBT.TAG_COMPOUND);

        // Если предметов нет - заполняем инвентарь нужными предметами
        if (items.tagCount() == 0) {
            // Определяем данные для нового итема
            ArrayList<DiceRoll> dices = new ArrayList<DiceRoll>();
            dices.add(new DiceRoll(null, null, 4));
            dices.add(new DiceRoll(null, null, 6));
            dices.add(new DiceRoll(null, null, 8));
            dices.add(new DiceRoll(null, null, 10));
            dices.add(new DiceRoll(null, null, 12));
           
            // Создаем итемы и заполняем ими первые 5 слотов инвентаря
            inventory[0] = new ItemStack(new StatItem(dices, "StrenghtStatItem", "rsstats:strenght", "item.StrenghtStatItem"));
            inventory[1] = new ItemStack(new StatItem(dices, "AgilityStatItem", "rsstats:agility", "item.AgilityStatItem"));
            inventory[2] = new ItemStack(new StatItem(dices, "IntelligenceStatItem", "rsstats:intelligence", "item.IntelligenceStatItem"));
            inventory[3] = new ItemStack(new StatItem(dices, "EnduranceStatItem", "rsstats:endurance", "item.EnduranceStatItem"));
            inventory[4] = new ItemStack(new StatItem(dices, "CharacterStatItem", "rsstats:character", "item.CharacterStatItem"));
            return;
        }

        // Восстанавливаем предметы из NBT
        for (int i = 0; i < items.tagCount(); ++i) {
            NBTTagCompound item = (NBTTagCompound) items.getCompoundTagAt(i);
            byte slot = item.getByte("Slot");

            if (slot >= 0 && slot < getSizeInventory()) {
                inventory[slot] = ItemStack.loadItemStackFromNBT(item);
            }
        }
    }

На выходе я получаю вот такое:

2017-12-10_16-14-07.png

См. блоки сверху (нижние блоки вообще из другого инвентаря и нас не интересуют) - у них не отрисовалась текстура, хотя в креативе все отрисовывается успешно:
2017-12-10_16-12-57.png

Вот код предмета, который не может отрисоваться:

Java:
package rsstats.items;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import rsstats.common.network.RollPacketToServer;
import rsstats.utils.DescriptionCutter;
import rsstats.utils.DiceRoll;

import java.util.ArrayList;
import java.util.List;
import rsstats.common.RSStats;


// Эти классы передаются в методы

/**
* Предмет, реализующий функции статы
* @author RareScrap
*/
public class StatItem extends Item {
    /** Общее количество уровней статы */
    private static int NUMBER_OF_LEVELS = 5;
   
    /** Хранилище иконов для каждого уровня статы */
    private IIcon[] icons = new IIcon[NUMBER_OF_LEVELS]; // хранилище иконок для всего семейства предмета
    /** Набор разных дайсов. Порядковый номер в списке обозачает уровень статы,
     * для которой будет использован дайс. */
    protected ArrayList<DiceRoll> basicRolls;
    /** Префикс, используемый игрой для нахождеия текстур мода */
    protected final String registerIconPrefix; // "rarescrap:StrenghtIcon_" например
    /** Префикс, используемый игрой для нахождеия файлов локализации мода */
    protected final String localePrefix; // "item.StrenghtStatItem" например
    /** Префикс, одинаковый для всех статов */
    protected final String generalPrefix = "item.StatItem";
   
    /**
     * Конструктор, инициализирующий свои поля
     * @param basicRolls Дайсы бросков для каждого уровня статы
     * @param unlocalizedName Нелокализированое имя мода (TODO: ХЗ для чего нужно)
     * @param registerIconPrefix Префикс, который будет использоваться игрой для нахождения текстур данного предмета
     * @param localePrefix Префикс, который будет использоваться игрой для нахождения файлов локализации данного предмета
     */
    public StatItem(ArrayList<DiceRoll> basicRolls, String unlocalizedName, String registerIconPrefix, String localePrefix) {
        // TODO: Дайсы должны задаваться через серверный конфиг
        this.basicRolls = basicRolls;
       
        // Сохранение префиксов
        this.registerIconPrefix = registerIconPrefix;
        this.localePrefix = localePrefix;
       
        // Базовая настройка
        this.setUnlocalizedName(unlocalizedName);
        this.setMaxStackSize(1);
        this.setCreativeTab(CreativeTabs.tabMaterials);
        this.setHasSubtypes(true);
    }

    // Создание вкладок для режима креатива
    // TODO: Локализировать строки
    /*public static final CreativeTabs statsTab = new CreativeTabs(RSStats.MODNAME + " Stats") {
        @Override
        public Item getTabIconItem() {
            return Items.
        }
    };*/
   
    /**
     * Добавляет к предмету пояснение.
     * @param itemstack TODO: Добавить Javadoc
     * @param player TODO: Добавить Javadoc
     * @param list TODO: Добавить Javadoc
     * @param par4 TODO: Добавить Javadoc
     */
    @Override
    public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean par4) {
        // Уровень статы
        int statLevel = itemstack.getItemDamage(); // Нумерация с нуля
       
        // Строка "Уровень X"
        list.add(StatCollector.translateToLocalFormatted( generalPrefix + ".level", statLevel+1) );
       
        // Строка броска (пример: "Бросок: d6+1")
        list.add(StatCollector.translateToLocal(generalPrefix + ".roll") + ": d" + basicRolls.get(statLevel).getDice());
       
        // Пустая строка-разделитель
        list.add("");
       
        // Дополнительная информация по кнопке Shift
        if (GuiScreen.isShiftKeyDown()) {
            String[] str = DescriptionCutter.cut(4, StatCollector.translateToLocal(localePrefix + ".descriprion"));
            for (int i = 0; i < str.length; i++)
                list.add( str[i] );
        } else {
            list.add( StatCollector.translateToLocal(generalPrefix + ".moreInfo") );
        }
    }

    /**
     * Регистрирует иконку для каждого подтипа статы
     * @param reg TODO: Добавить Javadoc
     */
    @Override
    public void registerIcons(IIconRegister reg) {
        for (int i = 0; i < this.icons.length; ++i) {
            this.icons[i] = reg.registerIcon(registerIconPrefix + (i + 1));
        }
    }

    /**
     * Возвращает иконку, соответствующую субтипу.
     * @param meta Порядковый номер субтипа
     * @return Икнока, соответвующая субтипу
     */
    @Override
    public IIcon getIconFromDamage(int meta) {
        if (meta > this.icons.length) {
            meta = 0;
        }
        return this.icons[meta];
    }
   
    /**
     * Создает анимацию зачарования к последнему субтипу.
     * Нужно для того, чтобы красиво выделить максимальный уровень статы.
     * @param par1ItemStack TODO: Добавить Javadoc
     * @return True, если предмету нужно включить анимацию зачарования. Иначе - false.
     */
    @SideOnly(Side.CLIENT)
    @Override
    public boolean hasEffect(ItemStack par1ItemStack) {
         //par1ItemStack.setTagInfo("ench", new NBTTagList());
         if (par1ItemStack.getItemDamage() == NUMBER_OF_LEVELS-1)
            return true;
         else
             return false;
    }

    /**
     * Создание субтипов (уровней) статы
     * @param item TODO: Добавить Javadoc
     * @param tab TODO: Добавить Javadoc
     * @param list TODO: Добавить Javadoc
     */
    @Override
    public void getSubItems(Item item, CreativeTabs tab, List list) {
        for (int i = 0; i < this.icons.length; ++i) {
            list.add(new ItemStack(item, 1, i));
        }
    }

    /**
     * Возвращает нелокализированное имя предмета
     * @param stack Предмет, для которого требуется вернуть нелокализированное имя
     * @return Нелокализированное имя предмета
     */
    @Override
    public String getUnlocalizedName(ItemStack stack) {
        return this.getUnlocalizedName();
        //return this.getUnlocalizedName() + "_" + (Integer.valueOf( stack.getItemDamage() ) + 1); - пригодится когда каждому подтипу нужно дать индивидуальное имя
    }
   
    // Работает когда юзаешь предмет на панели
    @Override
    public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) {
        // If нужен, чтобы броить бросок только один раз
        //if (world.isRemote) { // TODO: На какой стороне вычисляется бросок?
            //String num = String.valueOf( basicRolls[ Integer.parseInt(itemstack.getIconIndex().toString()) ].dice );
            String statName = StatCollector.translateToLocalFormatted( localePrefix + ".name");
            int lvl = itemstack.getItemDamage();
           
            // TODO ХЗ зачем
            //String str = itemstack.getIconIndex().getIconName();
            //str = str.replaceAll("[^\\d.]", "");

            DiceRoll roll = new DiceRoll(
                    basicRolls.get(lvl),
                    entityplayer.getDisplayName(),
                    statName,
                    basicRolls.get(lvl).getModificators() // TODO: Получить дополнительные модификаторы извне. Пока сюда передаются только те модификаторы, что были включены при инициализации базовых бросков
            );
           
            //entityplayer.addChatComponentMessage(new ChatComponentText(basicRolls.get(lvl).dice + " " + statName));
           
            RollPacketToServer packet = new RollPacketToServer(roll);
            RSStats.INSTANCE.sendToServer(packet); // "123" // itemstack.getIconIndex(
         
        //}
        //entityplayer.addChatComponentMessage(new ChatComponentText(this.roll()));
       
        return itemstack;
        //return super.onItemRightClick(itemstack, world, entityplayer); //To change body of generated methods, choose Tools | Templates.
    }
   
   
    /*public float getStrVsBlock(ItemStack stack, Block block, int meta)
    {
        entityplayer.addChatMessage("Open inventory");
       
        return (float) 1.0;
    }*/
}

Я попытался сохранить в NBT такие неотрисованные итемы. Вот такие данные попыталась записать игра:

2017-12-10_16-19-04.png
Очень странно, что id этих предметов равен -1. Я подумал, что проблема может быть в том, что я не зарегистрировал предмет, но я точно знаю что это нет так:
Java:
public void preInit(FMLPreInitializationEvent event, ArrayList<DiceRoll> dices) {
        ...
       
        // Инициализация предметов статов
        StatItem strenghtStatItem = new StatItem(dices, "StrenghtStatItem", "rsstats:strenght", "item.StrenghtStatItem"); // 3 - rarescrap:StrenghtIcon_
        StatItem agilityStatItem = new StatItem(dices, "AgilityStatItem", "rsstats:agility", "item.AgilityStatItem");
        StatItem intelligenceStatItem = new StatItem(dices, "IntelligenceStatItem", "rsstats:intelligence", "item.IntelligenceStatItem");
        StatItem enduranceStatItem = new StatItem(dices, "EnduranceStatItem", "rsstats:endurance", "item.EnduranceStatItem");
        StatItem characterStatItem = new StatItem(dices, "CharacterStatItem", "rsstats:character", "item.CharacterStatItem");
        // Регистрация предметов статов
        GameRegistry.registerItem(strenghtStatItem, "StrenghtStatItem");
        GameRegistry.registerItem(agilityStatItem, "AgilityStatItem");
        GameRegistry.registerItem(intelligenceStatItem, "IntelligenceStatItem");
        GameRegistry.registerItem(enduranceStatItem, "EnduranceStatItem");
        GameRegistry.registerItem(characterStatItem, "CharacterStatItem");
       
        ...
}

Мне кажется, что я неправильно создаю итем, но что конкретно я делаю неправильно - пока не пойму. Пожалуйста, помогите.
 
Решение
Разобрался. Оказывается, если нужно использовать зарегистрированный предмет, то не нужно создавать новый итем. Нужно просто использоваться GameRegistry.findItem():

Java:
inventory[0] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "StrenghtStatItem"));
inventory[1] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "AgilityStatItem"));
inventory[2] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "IntelligenceStatItem"));
inventory[3] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "EnduranceStatItem"));
inventory[4] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "CharacterStatItem"));
1,159
38
544
Разобрался. Оказывается, если нужно использовать зарегистрированный предмет, то не нужно создавать новый итем. Нужно просто использоваться GameRegistry.findItem():

Java:
inventory[0] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "StrenghtStatItem"));
inventory[1] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "AgilityStatItem"));
inventory[2] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "IntelligenceStatItem"));
inventory[3] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "EnduranceStatItem"));
inventory[4] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "CharacterStatItem"));
 
3,005
192
592
Сверху