[1.7.10] Хранение вещей в предмете (слив кода)

timaxa007

Команда форума
Сообщения
5,052
Лучшие ответы
291
Симпатии
377
#1
Я уже почти начал создавать, по своему инвентарь Item Storage, но остановился на разные количество слотов. Так как если-бы я продолжал делать, то ещё больше функций и тогда я уже вряд-ли бы выложил хоть какой-то код (или не скоро выложил) связанный с хранением предмете какие-либо вещи.

(github.com) mod backpack 1.7.10

Надеюсь вы знаете как создать свой GuiHandler (у меня во общем другой). У каждого может быть по своему написан GuiHandler, так что постарайтесь понять. В вашем GuiHandler'е:
В метод "getServerGuiElement":
Код:
return new ItemStorageContainer(player, new InventoryItemStorage(current));
В метод "getClientGuiElement":
Код:
return new ItemStorageGui(player, new InventoryItemStorage(current));
Код:
ItemStack current = player.getCurrentEquippedItem();
if (current != null) {
}

Контейнер:
Код:
public class ContainerItemStorage extends net.minecraft.inventory.Container {

    private InventoryItemStorage inv;
    private int numRows;

    public ContainerItemStorage(EntityPlayer player, InventoryItemStorage inventoryItemStorage) {
        inv = inventoryItemStorage;
        inv.openInventory();//Типа инициализируем открытия инвентаря
        numRows = inv.getSizeInventory() / 9;
        int i = (numRows - 4) * 18;
        int j;
        int k;

        //Слоты инвентаря Item Storage
        for (int id = 0; id < inv.getSizeInventory(); ++id) {
            addSlotToContainer(new StorageSlot(inv, id, 8 + (id % 9) * 18, 18 + (id / 9) * 18));
        }

        //Слоты инвентаря игрока
        for (j = 0; j < 3; ++j) {
            for (k = 0; k < 9; ++k) {
                addSlotToContainer(new SlotNoTakeStorage(player.inventory, k + j * 9 + 9, 8 + k * 18, 103 + j * 18 + i));
            }
        }

        //Слоты хот-бара игрока
        for (j = 0; j < 9; ++j) {
            addSlotToContainer(new SlotNoTakeStorage(player.inventory, j, 8 + j * 18, 161 + i));
        }

    }

    @Override
    public boolean canInteractWith(EntityPlayer player) {
        return inv.isUseableByPlayer(player);
    }

    @Override
    public ItemStack transferStackInSlot(EntityPlayer player, int slot_i) {
        ItemStack is = null;
        Slot slot = (Slot)inventorySlots.get(slot_i);

        if (slot != null && slot.getHasStack()) {
            ItemStack is1 = slot.getStack();
            is = is1.copy();

            //Или иначе по шифт-клику можно было засунуть в наш рюкзак ещё один рюкзак.
            if (is1.getItem() instanceof ItemBackpack) return null;

            if (slot_i < inv.getSizeInventory()) {
                if (!mergeItemStack(is1, inv.getSizeInventory(), inventorySlots.size(), true)) return null;
            } else if (!mergeItemStack(is1, 0, inv.getSizeInventory(), false))
                return null;

            if (is1.stackSize == 0) slot.putStack((ItemStack)null);
            else slot.onSlotChanged();
        }

        return is;
    }

    @Override
    public ItemStack slotClick(int slot, int button, int modifier, EntityPlayer player) {
        if (modifier == 2) return null;//Блокируем возможность использование игроком цифровых кнопок, чтобы не было попытки подмены
        return super.slotClick(slot, button, modifier, player);
    }

    @Override
    public void onContainerClosed(EntityPlayer player) {
        super.onContainerClosed(player);
        inv.closeInventory();//Типа инициализируем закрытия инвентаря
    }

    public void update(EntityPlayer player) {
        if (inv != null) inv.update(player);
    }

}
Пример взял из ContainerChest.

Код:
public class StorageSlot extends Slot {

    public StorageSlot(IInventory inv, int id, int x, int y) {
        super(inv, id, x, y);
    }

    //Нельзя поставить в этот слот предмет с экземпляром ItemBackpack.
    //В дальнейшем я тут буду добавлять, чтобы нельзя из других модов вставлять предметы с хранением вещей.
    @Override
    public boolean isItemValid(ItemStack is) {
        return (is != null && is.getItem() instanceof ItemBackpack) ? false : super.isItemValid(is);
    }

}

Код:
public class SlotNoTakeStorage extends Slot {

    public SlotNoTakeStorage(IInventory inv, int id, int x, int y) {
        super(inv, id, x, y);
    }

    //Нельзя взять из этого слота, если это находиться в руке игрока.
    //Хотя по стандарту, можно только для хот-бара, но я не уверен на счёт других модов.
    @Override
    public boolean canTakeStack(EntityPlayer player) {
        ItemStack is = inventory.getStackInSlot(getSlotIndex());
        if (is != null && is == player.getCurrentEquippedItem()) return false;
        return super.canTakeStack(player);
    }

}

Код:
public class GuiItemStorage extends GuiContainer {

    private static final ResourceLocation field_147017_u = new ResourceLocation("textures/gui/container/generic_54.png");
    private int inventoryRows;
    private InventoryPlayer inv_p;
    private InventoryItemStorage inv;

    public GuiItemStorage(EntityPlayer player, InventoryItemStorage inventoryItemStorage) {
        super(new timaxa007.backpack.inventory.ContainerItemStorage(player, inventoryItemStorage));
        inv_p = player.inventory;
        inv = inventoryItemStorage;
        inventoryRows = inventoryItemStorage.getSizeInventory() / 9;
        short short1 = 222;
        int i = short1 - 108;
        ySize = i + inventoryRows * 18;
    }

    @Override
    public void drawGuiContainerForegroundLayer(int i1, int i2) {
        //Именование инвентаря Item Storage
        if (inv != null) fontRendererObj.drawString(
                (inv.hasCustomInventoryName() ? inv.getInventoryName() : StatCollector.translateToLocal("inventory.backpack.name")), 8, 6, 4210752);
        //Именование инвентаря игрока
        if (inv_p != null) fontRendererObj.drawString(
                StatCollector.translateToLocal("container.inventory"), 8, inventoryRows * 18 + 19, 4210752);
    }

    @Override
    public void drawGuiContainerBackgroundLayer(float i1, int i2, int i3) {
        GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
        mc.getTextureManager().bindTexture(field_147017_u);
        int k = (width - xSize) / 2;
        int l = (height - ySize) / 2;
        drawTexturedModalRect(k, l, 0, 0, xSize, inventoryRows * 18 + 17);
        drawTexturedModalRect(k, l + inventoryRows * 18 + 17, 0, 126, xSize, 96);
    }

}
Пример взял из GuiChest.
В файл "en_US.lang" вписать "inventory.backpack.name=Backpack Inventory.".
В файл "ru_RU.lang" вписать "inventory.backpack.name=Инвентарь Рюкзака".

Функции инвентаря:
Код:
public class InventoryItemStorage implements IInventory {

    final ItemStack current;//Предмет в котором будет хранить вещи
    ItemStack[] inventory;//Массив слотов инвентаря в виде ItemStack
    boolean isSave = false;

    public InventoryItemStorage(ItemStack is) {
        current = is;
        if (!current.hasTagCompound()) current.setTagCompound(new NBTTagCompound());
        load(current);
        //openInventory();
    }

    @Override
    public int getSizeInventory() {
        return inventory.length;//Количество слотов инвентаря
    }

    @Override
    public ItemStack getStackInSlot(int slot_id) {
        return slot_id >= 0 && slot_id < inventory.length ? inventory[slot_id] : null;
    }

    @Override
    public ItemStack decrStackSize(int slot, int amount) {
        if (inventory[slot] != null) {
            ItemStack is;

            if (inventory[slot].stackSize <= amount) {
                is = inventory[slot];
                inventory[slot] = null;
                markDirty();
                return is;
            } else {
                is = inventory[slot].splitStack(amount);
                if (inventory[slot].stackSize == 0) inventory[slot] = null;

                markDirty();
                return is;
            }
        } else return null;
    }

    @Override
    public ItemStack getStackInSlotOnClosing(int slot_id) {
        if (inventory[slot_id] != null) {
            ItemStack itemstack = inventory[slot_id];
            inventory[slot_id] = null;
            return itemstack;
        } else return null;
    }

    @Override
    public void setInventorySlotContents(int slot_id, ItemStack is) {
        inventory[slot_id] = is;

        if (is != null && is.stackSize > getInventoryStackLimit())
            is.stackSize = getInventoryStackLimit();

        markDirty();
    }

    @Override
    public String getInventoryName() {
        return current.getDisplayName();//Своё имя
    }

    @Override
    public boolean hasCustomInventoryName() {
        return current.hasDisplayName();//Есть-ли своё имя
    }

    @Override
    public int getInventoryStackLimit() {
        return 64;//Лимит размер стака в слоте
    }

    @Override
    public void markDirty() {
        if (!isSave) isSave = true;
    }

    @Override
    public boolean isUseableByPlayer(EntityPlayer player) {
        //Может-ли игрок использовать этот инвентарь
        return true;
    }

    //Открытие инвентаря
    @Override
    public void openInventory() {
        //load();
    }

    //Закрытие инвентаря
    @Override
    public void closeInventory() {
        //save();
    }

    @Override
    public boolean isItemValidForSlot(int slot, ItemStack is) {
        //Можно-ли взаимодействовать со слотом(-ами).
        return true;
    }

    //Методы "load" должны из предмета брать нужные теги для простой работы с инвентарём.
    public void load() {
        load(current);
    }

    public void load(ItemStack is) {
        load(is.getTagCompound());
    }

    public void load(NBTTagCompound nbt) {
        if (nbt != null) {
            NBTTagList nbttaglist = nbt.getTagList("Items", NBT.TAG_COMPOUND);

            //Мне так показалось проще сделать, чем брать значение из "nbttagcompound1.getByte("Slot")"
            //Наш NBT тег из которого будем брать максимальное количества слотов для нашего инвентаря Item Storage
            //Желательно, чтобы размеры инвентаря были [9 * n]
            if (nbt.hasKey("CustomSize", NBT.TAG_BYTE))
                inventory = new ItemStack[nbt.getByte("CustomSize") & 255];
            //Если нету нужно тега, то замер инвентаря Item Storage будет в 27 слотов.
            else inventory = new ItemStack[(9 * 3)];

            for (int i = 0; i < nbttaglist.tagCount(); ++i) {
                NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i);
                int j = nbttagcompound1.getByte("Slot") & 255;

                if (j >= 0 && j < inventory.length)
                    inventory[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
            }

        }
    }

    //Методы "save" должны в предмет сохранять инвентарь Item Storage в теги.
    public void save() {
        /*current = */save(current);
    }

    public void save(ItemStack is) {
        /*if (is != null && current != null) {
            NBTTagCompound nbt = save(current.getTagCompound());
            if (nbt != null) is.setTagCompound(nbt);
            return current;
        }*/
        /*
        NBTTagCompound nbt = current.getTagCompound();
        save(nbt);
        is.setTagCompound(nbt);
         */
        save(is.getTagCompound());
        //return is;
    }

    public void save(NBTTagCompound nbt) {
        NBTTagList nbttaglist = new NBTTagList();

        nbt.setByte("CustomSize", (byte)getSizeInventory());

        for (int i = 0; i < inventory.length; ++i) {
            if (inventory[i] != null) {
                NBTTagCompound nbttagcompound1 = new NBTTagCompound();
                nbttagcompound1.setByte("Slot", (byte)i);
                inventory[i].writeToNBT(nbttagcompound1);
                nbttaglist.appendTag(nbttagcompound1);
            }
        }

        nbt.setTag("Items", nbttaglist);
    }

    public void update(EntityPlayer player) {
        if (isSave) {
            save();
            player.inventory.setInventorySlotContents(player.inventory.currentItem, current);
            isSave = false;
        }
    }

}
Пример взял из InventoryBasic.

Этот код можно записать для Эвента или в апдейт предмета (у меня в Эвенте):
Код:
ItemStack current = player.getCurrentEquippedItem();
Container con = player.openContainer;
if (con != null) {
//-----------------------------------------------------------------------------------
if (con instanceof ItemStorageContainer) {
ItemStorageContainer bc = (ItemStorageContainer)con;
ItemStack new_is = bc.update(player);
if (new_is != null) current = new_is;
//Закрытия окна, в случаи если предмета нет нужного нам предмета.
if (new_is == null || !(new_is != null && new_is.getItem() instanceof ItemBackpack))
player.closeScreen();
}
//------------------------------------------------------------------------------------
}
Эвант
Код:
@SubscribeEvent
public void actiCon(TickEvent.PlayerTickEvent e) {
EntityPlayer player = e.player;
if (player != null) {
//Сюда код
}
}

Код:
@Override
public void onUpdate(ItemStack is, World world, Entity entity, int tick, boolean flag) {
if (!world.isRemote && entity instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer)entity;
//Суда код
}
}

Клиентский Эвент - в случаи если не сработало на эвенте или апдейте предмета выше (или перестраховка в случаи высокого TPS):
---(Не обязателен к использованию)---
Код:
public class EventItemStorageClient {
//--------------------------------------------------------------------------------------
@SubscribeEvent
public void closeGUI(TickEvent.PlayerTickEvent e) {
if (e.side == Side.CLIENT) {//Данный метод для клиентской стороны
EntityPlayer player = e.player;
if (player != null) {
ItemStack current = player.getCurrentEquippedItem();
GuiScreen gui = FMLClientHandler.instance().getClient().currentScreen;
if (gui != null) {
//---------------------------------------------------------------------------------------
if (gui instanceof ItemStorageGui) {
//Закрытия окна, в случаи если предмета нет нужного нам предмета.
if (current == null || !(current != null && current.getItem() instanceof IItemStorage))
player.closeScreen();
}
//---------------------------------------------------------------------------------------
}
}
}
}
//---------------------------------------------------------------------------------------
}

Надеюсь вы знаете как зарегистрировать предмет. Предмет:
Код:
public static Item backpack = new ItemBackpack().setUnlocalizedName("backpack").setCreativeTab(CreativeTabs.tabMisc).setMaxStackSize(1).setTextureName(MODID + ":backpack");
Код:
public class ItemBackpack extends Item {

    public ItemStack onItemRightClick(ItemStack is, World world, EntityPlayer player) {
        if (player.isSneaking()) {

        } else {
            GuiHandler.openGui(GuiHandler.GuiID.BACKPACK, player);
        }
        return super.onItemRightClick(is, world, player);
    }

    @SideOnly(Side.CLIENT)
    public void getSubItems(Item id, CreativeTabs table, List list) {
        //list.add(new ItemStack(id, 1, 0));
        list.add(addNBT(new ItemStack(id, 1, 0), 1));
        list.add(addNBT(new ItemStack(id, 1, 0), 3));
        list.add(addNBT(id, SizeStorage.SIZE1));
        list.add(addNBT(id, SizeStorage.SIZE2));
        list.add(addNBT(id, SizeStorage.SIZE3));
        list.add(addNBT(id, SizeStorage.SIZE4));
        list.add(addNBT(id, SizeStorage.SIZE5));
        list.add(addNBT(id, SizeStorage.SIZE6));
        list.add(addNBT(id, SizeStorage.SIZE7));
        list.add(addNBT(id, SizeStorage.SIZE8));
        list.add(addNBT(id, SizeStorage.SIZE9));
    }

    public void addInformation(ItemStack is, EntityPlayer player, List list, boolean flag) {
        NBTTagCompound nbt = is.getTagCompound();
        if (nbt != null && nbt.hasKey("CustomSize")) list.add("Slots: " + (int)(nbt.getByte("CustomSize") & 255) + ".");
    }

    public static ItemStack addNBT(Item item, SizeStorage size) {
        return addNBT(new ItemStack(item, 1, 0), size);
    }

    public static ItemStack addNBT(ItemStack is, SizeStorage size) {
        return addNBT(is, size.getSize());
    }

    public static ItemStack addNBT(ItemStack is, int size) {
        NBTTagCompound nbt = new NBTTagCompound();
        nbt.setByte("CustomSize", (byte)size);
        is.setTagCompound(nbt);
        return is;
    }

    public static enum SizeStorage {

        SIZE1(9),//(9 * 1)
        SIZE2(18),//(9 * 2)
        SIZE3(27),//(9 * 3)//размеры как у одинарного сундука
        SIZE4(36),//(9 * 4)
        SIZE5(45),//(9 * 5)
        SIZE6(54),//(9 * 6)//размеры как у двойного сундука
        SIZE7(63),//(9 * 7)
        SIZE8(72),//(9 * 8)
        SIZE9(81);//(9 * 9)

        private final int size;

        SizeStorage(int size) {
            this.size = size;
        }

        public int getSize() {
            return size;
        }

    }

}

Как приблизительно должны выглядят рецепты:
Код:
GameRegistry.addRecipe(ItemStorage.addNBT(PackFurniture.item.storage, ItemStorage.size_storage.SIZE1), new Object[]{
"SLS", "LSL", 'L', Items.leather, 'S', Items.string});

GameRegistry.addRecipe(ItemStorage.addNBT(PackFurniture.item.storage, ItemStorage.size_storage.SIZE2), new Object[]{
"SSS", "L L", "LCL", 'L', Items.leather, 'S', Items.string, 'C', Blocks.carpet});

GameRegistry.addRecipe(ItemStorage.addNBT(PackFurniture.item.storage, ItemStorage.size_storage.SIZE3), new Object[]{
"LSL", "SWS", "LLL", 'L', Items.leather, 'W', Blocks.wool, 'S', Items.string});

GameRegistry.addRecipe(ItemStorage.addNBT(PackFurniture.item.storage, ItemStorage.size_storage.SIZE4), new Object[]{
"LLL", "WCW", "LLL", 'L', Items.leather, 'W', Blocks.carpet, 'C', Blocks.chest});

На сервере не проверялось!!!

 
Последнее редактирование:

krok

Каменная лига
Сообщения
503
Лучшие ответы
0
Симпатии
0
#2
У меня есть похожая вещь,только к своему инвентарю её ещё прикрепить надо.Я прикрепил.Все предметы хранятся внутри этого,но ,самая главная особенность,кол-во слотов - любое.Тобишь ,если слотов >24,появляется стрелочка,пролистывающая дальше.В будущем надо её на Скролл заменить.Видео могу снять,если надо
 

timaxa007

Команда форума
Сообщения
5,052
Лучшие ответы
291
Симпатии
377
#3
krok, у меня тоже такие-же планы. Я выложил этот код в случаи, если кому-то нужен (простой) пример кода для создания своего предмета с инвентарём (подобия рюкзака и т.п.).
У меня будут разные "Item Storage" с разными функционалом, с различными назначениями и использованием. Т.е. если у него назначения хранить только семена, то будет возможность по (стандарту) shift+пкм сажать 3х3, 5х5, 7х7 и т.д будет зависит от функционала.
Я мог-бы и дальше перечислять дальнейшее его использование, но не все идеи могут быть реализованы так, как сейчас они в задумке.
 

krok

Каменная лига
Сообщения
503
Лучшие ответы
0
Симпатии
0
#4
У меня ещё запросто можно иконку добавлять,слоты разных типов и тд.Вообщем там абстрактно большинство.Код не выложу(азаза),а вот видео как-нибудь сниму
[merge_posts_bbcode]Добавлено: 11.08.2015 13:31:05[/merge_posts_bbcode]

[youtube]gVipkSz3vGw[/youtube]
Вот и он
 

Lobotino

Каменная лига
Сообщения
149
Лучшие ответы
1
Симпатии
0
#5
Что такое IItemStorage? Нигде не нашел...
 

timaxa007

Команда форума
Сообщения
5,052
Лучшие ответы
291
Симпатии
377
#6
Пустой интерфейс.
[Ссылка удалена.]
Код:
public interface IItemStorage {

}
 

timaxa007

Команда форума
Сообщения
5,052
Лучшие ответы
291
Симпатии
377
#7
Код обновил. Пост подправил.
Теперь вещи не сохраняются каждый тик, при открытом инвентаре. Теперь вещи сохраняются один раз в тик при вызове метода markDirty() и при открытом инверторе.
 

Liahim

Золотая лига
Сообщения
2,863
Лучшие ответы
31
Симпатии
145
#8
О! Спс... Скоро мне эта вещь понадобится )))
 

Maxik001

Золотая лига
Сообщения
3,926
Лучшие ответы
37
Симпатии
384
#9
Полезно. Буду рюкзачок грибника делать :)
 
Сверху