Данные инвентаря не сохраняются после выхода из GUI

Версия Minecraft
1.7.10
1,159
38
544
Здравствуйте. У меня есть GUI-форма, контейнер и кастомный инвентарь. Я хочу сделать так, чтобы инвентарь заполнялся определенным набором блоков в зависимости от того, какую кнопку я нажму пока GUI открыто. Например, мне нужно чтобы в первом блоке инвертаря появлялся меч когда я нажму на цифру "1", когда нажму цифру "2" - зелье и т.д. Т.е. мне по нажатию кнопки нужно программно добавить предмет в инвентарь и сохранить его в NBT.

И вот с сохранением у меня и вылезают проблемы. Для начала, вот так я переопределяю keyTyped(char, int) в своем GUI:

Java:
    @Override
    protected void keyTyped(char p_73869_1_, int p_73869_2_) {
        // Заталкиваю в мой кастомный инвентарь свой кастомный итем
        player.skillsInventory.setInventorySlotContents(1, new ItemStack(GameRegistry.findItem(RSStats.MODID, "StrenghtStatItem"), 1, 4));
        // Пытаюсь сохранить изменения в NBT
        player.saveNBTData(player.entityPlayer.getEntityData());

        super.keyTyped(p_73869_1_, p_73869_2_);
    }

Как только я захожу в GUI снова - изменения не сохраняются. Я думаю проблема в том, что я неправильно сохраняю данные (скорее всего передаю неправильный аргумент).

Вот что принимает ExtendedPlayer.saveNBTData(NBTTagCompound), когда этот метод вызывает сама игра:
2017-12-15_11-53-43.png
а вот что он принимает, когда его пытаюсь вызвать я из keyTyped(char, int):
2017-12-15_11-54-48.png
Где properties - как раз тот NBTTagCompound, что передается в saveNBTData.

Мне кажется, что я передаю не тот NBTTagCompound, но где взять нужный - я не знаю. Пожалуйста, помогите разобраться с этим.
ExtendedPlayer
Java:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package rsstats.data;

import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;
import rsstats.inventory.SkillsInventory;
import rsstats.inventory.StatsInventory;

/**
 *
 * @author rares
 */
public class ExtendedPlayer implements IExtendedEntityProperties {
    /** Каждый наследник {@link IExtendedEntityProperties} должен иметь индивидуальное имя */
    private static final String INV_NAME = "StatsInventory";
    
    public final EntityPlayer entityPlayer;
    
    /** Инвентарь для статов */
    public final StatsInventory statsInventory = new StatsInventory();
    /** Инвентарь для скиллов */
    public final SkillsInventory skillsInventory = new SkillsInventory();
    //public Map<String, SkillsInventory> categorizedSkills;

    /*
    Тут в виде полей можно хранить дополнительную информацию о Entity: мана,
    золото, хп, переносимый вес, уровень радиации, репутацию и т.д. Т.е. все то,
    что нельзя хранить в виде блоков
    */

    public ExtendedPlayer(EntityPlayer player) {
        this.entityPlayer = player;
    }
    
    /**
     * Used to register these extended properties for the entityPlayer during EntityConstructing event
     * This method is for convenience only; it will make your code look nicer
     * @param player
     */
    public static final void register(EntityPlayer player) {
        player.registerExtendedProperties(ExtendedPlayer.INV_NAME, new ExtendedPlayer(player));
    }
    
    /**
     * Returns ExtendedPlayer properties for entityPlayer
     * This method is for convenience only; it will make your code look nicer
     */
    public static final ExtendedPlayer get(EntityPlayer player) {
       return (ExtendedPlayer) player.getExtendedProperties(INV_NAME);
    }

    public boolean isServerSide() {
        return this.entityPlayer instanceof EntityPlayerMP;
    }

    // LOAD, SAVE =============================================================

    @Override
    public void saveNBTData(NBTTagCompound properties) {
        this.statsInventory.writeToNBT(properties);
        this.skillsInventory.writeToNBT(properties);
    }

    @Override
    public void loadNBTData(NBTTagCompound properties) {
        this.statsInventory.readFromNBT(properties);
        this.skillsInventory.readFromNBT(properties);
    }

    @Override
    public void init(Entity entity, World world) {
    }
}

MainGUI:
Java:
package rsstats.client.gui;

import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.InventoryEffectRenderer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import rsstats.common.RSStats;
import rsstats.data.ExtendedPlayer;
import rsstats.inventory.SkillsInventory;
import rsstats.inventory.StatsInventory;
import rsstats.inventory.container.MainContainer;
import rsstats.inventory.slots.StatSlot;

import java.util.List;

/**
 * GUI для основного окна мода, содержащее информацию о персонаже (имя, уровень, здоровье, защита, харизма,
 * стойкость), панель предметов и панели статов, навыков и перков.
 * @author RareScrap
 */
public class MainMenuGUI extends InventoryEffectRenderer {
    /** Расположение фона GUI */
    public static final ResourceLocation background =
            new ResourceLocation("rsstats","textures/gui/StatsAndInvTab.png");

    /** Длина GUI в пикселях. Defined as  float, passed as int. */
    private float xSizeFloat;
    /** Ширина GUI в пикселях. Defined as  float, passed as int. */
    private float ySizeFloat;

    private StatsInventory statsInventory;
    public SkillsInventory skillsInventory;

    public MainContainer mainContainer;
    public ExtendedPlayer player;

    /** Инвентарь для статов */
    // Could use IInventory type to be more generic, but this way will save an import...
    // Нужно для запроса кастомного имени инвентаря для отрисоки названия инвентаря
    //private final StatsInventory statsInventory;


    public MainMenuGUI(ExtendedPlayer player, MainContainer mainContainer) {
        super(mainContainer);
        this.mainContainer = mainContainer;
        this.allowUserInput = true;
        this.player = player;
    }

    /**
     * Draws the screen and all the components in it
     * @param mouseX
     * @param mouseY
     * @param partialTicks
     */
    @Override
    public void drawScreen(int mouseX, int mouseY, float partialTicks) {
        super.drawScreen(mouseX, mouseY, partialTicks);
        this.xSizeFloat = (float) mouseX;
        this.ySizeFloat = (float) mouseY;
    }

    /**
     * Свой аналог {@link #drawTexturedModalRect(int, int, int, int, int, int)}, способный работать с текстурами
     * разрешением более чем 256x256.
     * @param x Координата начала отрисовки относительно левого-верхнего угла экрана игрока
     * @param y Координата начала отрисовки относительно левого-верхнего угла экрана игрока
     * @param u Координата начала текстуры по оси X относительно левого-верхнего угла текстуры
     * @param v Координата начала текстуры по оси Y относительно левого-верхнего угла текстуры
     * @param width Ширина текстуры, которую нужно отрисовать
     * @param height Высота текстуры, которую нужно отрисовать
     * @param textureWidth Общая ширина текстуры (кол-во пикселей в файле)
     * @param textureHeight Общая высота текстуры (кол-во пикселей в файле)
     */
    // Взято отсюда: http://www.minecraftforge.net/forum/topic/20177-172-gui-cant-more-than-256256/
    private void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight) {
        float f = 1F / (float)textureWidth;
        float f1 = 1F / (float)textureHeight;
        Tessellator tessellator = Tessellator.instance;
        tessellator.startDrawingQuads();
        tessellator.addVertexWithUV((double)(x), (double)(y + height), 0, (double)((float)(u) * f), (double)((float)(v + height) * f1));
        tessellator.addVertexWithUV((double)(x + width), (double)(y + height), 0, (double)((float)(u + width) * f), (double)((float)(v + height) * f1));
        tessellator.addVertexWithUV((double)(x + width), (double)(y), 0, (double)((float)(u + width) * f), (double)((float)(v) * f1));
        tessellator.addVertexWithUV((double)(x), (double)(y), 0, (double)((float)(u) * f), (double)((float)(v) * f1));
        tessellator.draw();
    }

    /**
     * Draw the background layer for the GuiContainer (everything behind the items)
     * @param partialTicks
     * @param mouseX
     * @param mouseY
     */
    @Override
    protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
        GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
        //GL11.glScalef(2.0F, 2.0F, 1.0F);
        this.mc.getTextureManager().bindTexture(background);

        this.xSize = 339;///2;
        this.ySize = 211;///2;
        //339 211
        int k = this.guiLeft/1 - xSize/4;
        int l = this.guiTop/1 - ySize/4;

        drawTexturedRect(k, l, 0, 0, xSize, ySize, 512, 512);

        // Орисовываем превью игрока
        drawPlayerModel(k+30, l+90, /*17*/ 40, (float)(k + 51) - this.xSizeFloat, (float)(l + 75 - 50) - this.ySizeFloat, this.mc.thePlayer);

        // Это было в туторах, но я хз на что это влияет. Слоты и рендер предметов работают и без этого
        /*for (int i1 = 0; i1 < this.inventorySlots.inventorySlots.size(); ++i1)
        {
            Slot slot = (Slot)this.inventorySlots.inventorySlots.get(i1);
            //if (slot.getHasStack() && slot.getSlotStackLimit()==1)
            //{
                this.drawTexturedModalRect(k+slot.xDisplayPosition, l+slot.yDisplayPosition, 200, 0, 16, 16);
            //}
        }*/
    }

    /**
     * Отрисовывает превью игрока
     * @param x TODO
     * @param y TODO
     * @param scale Маштаб модели
     * @param yaw TODO
     * @param pitch TODO
     * @param playerdrawn TODO
     */
    public static void drawPlayerModel(int x, int y, int scale, float yaw, float pitch, EntityLivingBase playerdrawn) {
        GL11.glEnable(GL11.GL_COLOR_MATERIAL);
        GL11.glPushMatrix();
        GL11.glTranslatef((float)x, (float)y, 50.0F);
        GL11.glScalef((float)(-scale), (float)scale, (float)scale);
        GL11.glRotatef(180.0F, 0.0F, 0.0F, 1.0F);
        float f2 = playerdrawn.renderYawOffset;
        float f3 = playerdrawn.rotationYaw;
        float f4 = playerdrawn.rotationPitch;
        float f5 = playerdrawn.prevRotationYawHead;
        float f6 = playerdrawn.rotationYawHead;
        GL11.glRotatef(135.0F, 0.0F, 1.0F, 0.0F);
        RenderHelper.enableStandardItemLighting();
        GL11.glRotatef(-135.0F, 0.0F, 1.0F, 0.0F);
        GL11.glRotatef(-((float)Math.atan((double)(pitch / 40.0F))) * 20.0F, 1.0F, 0.0F, 0.0F);
        playerdrawn.renderYawOffset = (float)Math.atan((double)(yaw / 40.0F)) * 20.0F;
        playerdrawn.rotationYaw = (float)Math.atan((double)(yaw / 40.0F)) * 40.0F;
        playerdrawn.rotationPitch = -((float)Math.atan((double)(pitch / 40.0F))) * 20.0F;
        playerdrawn.rotationYawHead = playerdrawn.rotationYaw;
        playerdrawn.prevRotationYawHead = playerdrawn.rotationYaw;
        GL11.glTranslatef(0.0F, playerdrawn.yOffset, 0.0F);
        RenderManager.instance.playerViewY = 180.0F;
        RenderManager.instance.renderEntityWithPosYaw(playerdrawn, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F);
        playerdrawn.renderYawOffset = f2;
        playerdrawn.rotationYaw = f3;
        playerdrawn.rotationPitch = f4;
        playerdrawn.prevRotationYawHead = f5;
        playerdrawn.rotationYawHead = f6;
        GL11.glPopMatrix();
        RenderHelper.disableStandardItemLighting();
        GL11.glDisable(GL12.GL_RESCALE_NORMAL);
        OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
        GL11.glDisable(GL11.GL_TEXTURE_2D);
        OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit);
    }

    @Override
    protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
        //System.out.println("mouseClicked: " + mouseX + " " + mouseY + " " + mouseButton);
        super.mouseClicked(mouseX, mouseY, mouseButton);
    }

    @Override
    protected void mouseMovedOrUp(int p_146286_1_, int p_146286_2_, int p_146286_3_) {
        //System.out.println("mouseMovedOrUp: " + p_146286_1_ + " " + p_146286_2_ + " " + p_146286_3_);
        super.mouseMovedOrUp(p_146286_1_, p_146286_2_, p_146286_3_);
    }

    @Override
    protected void handleMouseClick(Slot p_146984_1_, int p_146984_2_, int p_146984_3_, int p_146984_4_) {
        //System.out.println("handleMouseClick: " + p_146984_1_ + " " + p_146984_2_ + " " + p_146984_3_ + " " + p_146984_4_);
        super.handleMouseClick(p_146984_1_, p_146984_2_, p_146984_3_, p_146984_4_);
    }


    @Override
    protected void renderToolTip(ItemStack p_146285_1_, int p_146285_2_, int p_146285_3_) {
        //System.out.println("hoover");
        super.renderToolTip(p_146285_1_, p_146285_2_, p_146285_3_);
    }

    @Override
    protected void drawHoveringText(List p_146283_1_, int p_146283_2_, int p_146283_3_, FontRenderer font) {
        //System.out.println("hoover");
        super.drawHoveringText(p_146283_1_, p_146283_2_, p_146283_3_, font);
    }

    /**
     * Fired when a key is typed. This is the equivalent of KeyListener.keyTyped(KeyEvent e).
     *
     * @param p_73869_1_
     * @param p_73869_2_
     */
    @Override
    protected void keyTyped(char p_73869_1_, int p_73869_2_) {
        //mainContainer.getSlot(18).inventory.setInventorySlotContents(1, new ItemStack(GameRegistry.findItem(RSStats.MODID, "StrenghtStatItem"), 1, 4));
        //mainContainer.skillsInventory.inventory[0] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "StrenghtStatItem"), 1, 4);
        //mainContainer.detectAndSendChanges();
        //updateScreen();
        //entityPlayer.saveNBTData(entityPlayer.entityPlayer.getEntityData());
        //this.skillsInventory.inventory[1].writeToNBT(mainContainer.getSlot(18).getStack().getItem().);

        player.skillsInventory.setInventorySlotContents(1, new ItemStack(GameRegistry.findItem(RSStats.MODID, "StrenghtStatItem"), 1, 4));
        player.saveNBTData(player.entityPlayer.getEntityData());
        //entityPlayer.saveNBTData();

        super.keyTyped(p_73869_1_, p_73869_2_);
    }

    /**
     * Called when the screen is unloaded. Used to disable keyboard repeat events
     */
    @Override
    public void onGuiClosed() {


        super.onGuiClosed();
    }
}

SkillInventory - именно в него я пытаюсь программно добавить предмет:
Java:
package rsstats.inventory;

import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.common.util.Constants;
import rsstats.common.RSStats;
import rsstats.items.SkillItem;
import rsstats.utils.DiceRoll;

import java.util.ArrayList;

public class SkillsInventory extends StatsInventory {
    /** The name your custom inventory will display in the GUI, possibly just "Inventory" */
    // TODO: Локализировать эту строку
    private final String name = "Skills";

    /** The key used to store and retrieve the inventory from NBT */
    private static final String NBT_TAG = "skills";

    /** Define the inventory size here for easy reference */
    /* This is also the place to define which slot is which if you have different types,
     * for example SLOT_SHIELD = 0, SLOT_AMULET = 1; */
    private static final int INV_SIZE = 27;
    /** Масимальный размер стака для предметов в инвенторе {@link #inventory} */
    private static final int STACK_LIMIT = 1;

    /** Структура, хранящая предметы инвентаря в стаках.
     * Inventory's size must be same as number of slots you add to the Container class. */
    public ItemStack[] inventory = new ItemStack[INV_SIZE];

    /**
     * Необходимый пустой публичный контсруктор
     */
    public SkillsInventory() {}

    /**
     * Геттер для {@link #inventory}
     * @return Размер массива {@link #inventory}
     */
    @Override
    public int getSizeInventory() {
        return inventory.length;
    }

    /**
     * Геттер для получения элементов из инвентаря {@link #inventory}
     * @param slotIndex Индекс слота в инвенторе, из которого нужно получить предмет
     * @return Стак предметов под индексом slotIndex в инвенторе
     */
    @Override
    public ItemStack getStackInSlot(int slotIndex) {
        return inventory[slotIndex];
    }

    /**
     * Уменьшает размер стака предмета
     *
     * @param slotIndex Слот в инвенторе, где лежит предмет, стак которого нужно уменьшить
     * @param amount    На сколько нужно уменьший стак
     * @return Предмет с уменьшенным стаком
     */
    @Override
    public ItemStack decrStackSize(int slotIndex, int amount) {
        // Можно ли вызывать супер? Пока я просто скопирую супер сюда
        // getStackInSlot в супере вызовется для инвенторя в супере или для инвенторя тут?
        // return super.decrStackSize(slotIndex, amount);

        ItemStack stack = getStackInSlot(slotIndex);
        if (stack != null) {
            if (stack.stackSize > amount) {
                stack = stack.splitStack(amount);
                // ВАЖНО this.onInventoryChanged();
            }
            else {
                setInventorySlotContents(slotIndex, null);
            }
        }
        return stack;
    }

    @Override
    public void setInventorySlotContents(int slotIndex, ItemStack itemStack) {
        //super.setInventorySlotContents(slotIndex, itemStack);

        this.inventory[slotIndex] = itemStack;
        if (itemStack != null && itemStack.stackSize > this.getInventoryStackLimit()) {
            itemStack.stackSize = this.getInventoryStackLimit();
        }
        // TODO: ВАЖНО this.onInventoryChanged();
        //this.onInventoryChanged();
        //super.setInventorySlotContents(slotIndex, itemStack);
    }

    /**
     * Проверяет, можно ли поместить предмет в данный слот инвентаря {@link #inventory}
     * <p>
     * This method doesn't seem to do what it claims to do, as
     * items can still be left-clicked and placed in the inventory
     * even when this returns false
     *
     * @param slotIndex TODO
     * @param itemStack Предмет, который хочет поместиться в инвентарь
     * @return Итог проверки: возвращает true, если предмет можно поместить в инвентарь.
     * Иначе - false.
     */
    @Override
    public boolean isItemValidForSlot(int slotIndex, ItemStack itemStack) {
        boolean a = itemStack.getItem() instanceof SkillItem;
        return itemStack.getItem() instanceof SkillItem;
    }

    /**
     * Возвращает масимальный размер стака для предметов в этом инвенторе
     *
     * @return {@link #STACK_LIMIT}
     */
    @Override
    public int getInventoryStackLimit() {
        return STACK_LIMIT;
    }

    /**
     * Записывает состояние инвентаря в NBT
     *
     * @param compound TODO
     */
    @Override
    public void writeToNBT(NBTTagCompound compound) {
        NBTTagList items = new NBTTagList();

        for (int i = 0; i < getSizeInventory(); ++i) {
            if (getStackInSlot(i) != null) {
                NBTTagCompound item = new NBTTagCompound();
                item.setByte("Slot", (byte) i);
                getStackInSlot(i).writeToNBT(item);
                items.appendTag(item);
            }
        }

        // We're storing our items in a custom tag list using our 'NBT_TAG' from above
        // to prevent potential conflicts
        compound.setTag(NBT_TAG, items);
    }

    /**
     * Читает данные из NBT, восстанавливая состояние инвентаря
     *
     * @param compound TODO
     */
    @Override
    public void readFromNBT(NBTTagCompound compound) {
        //super.readFromNBT(compound);

        NBTTagList items = compound.getTagList(NBT_TAG, Constants.NBT.TAG_COMPOUND);

        if (items.tagCount() == 0) {
            // TODO: Инициализировать базовый навыки
        }

        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);
            }
        }
    }
}

И MainContainer:
Java:
package rsstats.inventory.container;

import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import rsstats.common.RSStats;
import rsstats.inventory.SkillsInventory;
import rsstats.inventory.StatsInventory;
import rsstats.inventory.slots.StatSlot;
import rsstats.items.SkillItem;
import rsstats.items.StatItem;

/**
 *
 * @author rares
 */
public class MainContainer extends Container {
    private final EntityPlayer player;
    private final InventoryPlayer inventoryPlayer;
    private final StatsInventory statsInventory;
    public final SkillsInventory skillsInventory;
  
    public MainContainer(EntityPlayer player, InventoryPlayer inventoryPlayer, StatsInventory statsInventory, SkillsInventory skillsInventory) {
        this.player = player;
        this.inventoryPlayer = inventoryPlayer;
        this.statsInventory = statsInventory;
        this.skillsInventory = skillsInventory;
        addSlots();
    }


    public MainContainer() {
        this.player = null;
        this.inventoryPlayer = null;
        this.statsInventory = null;
        this.skillsInventory = null;
    }
    
    private void addSlots() {
        /*if (inventoryPlayer != null)
            for (int y = 0; y < 3; ++y) {
                for (int x = 0; x < 9; ++x) {
                    this.addSlotToContainer(new Slot(inventoryPlayer, x + y * 9 + 9, 8 + x * 18, 84 + y * 18));
                }
            }*/

        // Расставляем слоты на панели руки
        for (int i = 0; i < 9; i++) {
            this.addSlotToContainer(new Slot(inventoryPlayer, i, (i*18 -87) +8, 136));
        }

        // Расставляем слоты на панели статов
        for (int i = 0, slotIndex = 0; i < statsInventory.getSizeInventory(); ++i, slotIndex++) {
            this.addSlotToContainer(new StatSlot(statsInventory, i, (i*18 +83) +8, -44));
            //this.addSlotToContainer(new StatSlot(statsInventory, slotIndex, i*9, 0));
        }

        // Расставляем слоты на панели скиллов
        for (int y = 0; y < 3; ++y) {
            for (int x = 0; x < 9; ++x) {
                this.addSlotToContainer(new Slot(skillsInventory, x + y * 9 /*+ 9*/, (x*18 +83) +8, (y * 18) - 26));
                //skillsInventory.inventory[x + y * 9] = new ItemStack(GameRegistry.findItem(RSStats.MODID, "StrenghtStatItem"), 1, 3);
            }
        }
    }
    
    
    /**
     * This should always return true, since custom inventory can be accessed from anywhere
     * @param player TODO
     * @return TODO
     */
    @Override
    public boolean canInteractWith(EntityPlayer player) {
        return true;
    }
    
    /**
    * Called when a entityPlayer shift-clicks on a slot. You must override this or you will crash when someone does that.
    * Basically the same as every other container I make, since I define the same constant indices for all of them
     * @param player TODO
     * @param par2 TODO
     * @return TODO
    */
    @Override
    public ItemStack transferStackInSlot(EntityPlayer player, int par2) {
        ItemStack itemstack = null;
        Slot slot = (Slot) this.inventorySlots.get(par2);
        return itemstack;
    }

    @Override
    public ItemStack slotClick(int slotId, int clickedButton, int mode, EntityPlayer playerIn) {
        System.out.println(slotId);
        Slot slot;
        try {
            slot = getSlot(slotId);
        } catch(Exception e) {
            return super.slotClick(slotId, clickedButton, mode, playerIn);
            //return null; // костыль
        }
        Item itemInSlot;
        if (slot.getStack() != null && slot.getStack().getItem() != null) {
            itemInSlot = slot.getStack().getItem();
        } else {
            return super.slotClick(slotId, clickedButton, mode, playerIn);
            //return null;
        }

        if ((slot.inventory == statsInventory || slot.inventory == skillsInventory) && (itemInSlot instanceof SkillItem || itemInSlot instanceof StatItem)) {
            ItemStack itemStack = getSlot(slotId).getStack();
            if (!playerIn.worldObj.isRemote)
                ( (StatItem) itemStack.getItem() ).roll(itemStack, playerIn);
            return null;
        }
        return super.slotClick(slotId, clickedButton, mode, playerIn);
    }
}
Возможно код покажется вам довольно сумбурным - не стесняйтесь спросить что есть что. Заранее спасибо.
 
3,005
192
592
keyTyped - работает только на клиенте. Тебе же нужно в этом методе посылать пакет на сервер, и на нем уже делать изменения.
 
1,159
38
544
Сейчас запилю, отрефакторю и залью. Всем спасибо за советы и ответы
 
1,159
38
544
1,159
38
544
Да, нужно слать пакеты, но и обезопасить их (проверок понатыкать), чтобы нельзя было отправить левый пакет и получить этот предмет ещё где-то (ведь програмно ставишь его).
Можно подробнее насчет проверок? Я сделал пакет, который посылается на сервер по клику по какому-нибудь слоту в контейнере. Не представляю, как его можно иначе послать этот пакет. Т.е. зачем и где делать проверку? И что представляет собой эта проверка?
 
Сверху