Jump to content

[1.10.2][GUI][Containers]I don't know how to do GUI


Starless

Recommended Posts

I can't move items in the hotbar. I'm not even close to finish the GUI and the container, and I already ran into this problem...

 

This is a super class implementing some basics. As it is, the players hotbar is part of the rectangle drawn. I will move it out so some GUIs can choose not to display the hotbar. This class apparently works fine (the entire drawing process works as intended. What is not working is the interaction: to pick a hot bar item and put it somewhere else. Also, the inventory seems to be duplicating stacks)

public class GuiBasicContainer extends GuiContainer
{
/**
 * The {@code ResourceLocation} for the basic GUI elements
 */
    private static final ResourceLocation texture = new ResourceLocation(TheMod.MODID, "textures/gui/gui_01.png");
    
        private int windowX;
private int windowY;

public GuiBasicContainer(Container inventorySlotsIn)
{
	super(inventorySlotsIn);
}

@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
	GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
                this.mc.getTextureManager().bindTexture(texture);
	windowX = (this.width - this.xSize) / 2;
	windowY = (this.height - this.ySize) / 2;
	this.drawTexturedModalRect(windowX, windowY, 0, 0, this.xSize, this.ySize);
}

protected void drawPlayerInventory(int relativeX, int relativeY)
{
	drawTexturedModalRect(windowX + relativeX, windowY + relativeY, 0, 166, 161, 53);
}
}

 

This is the GUI. As said before, it seems to work.

public class GuiExtractor extends GuiBasicContainer
{
    public GuiExtractor(ContainerExtractor inventorySlotsIn)
    {
        super(inventorySlotsIn);
    }

    @Override
    protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
    {
        super.drawGuiContainerBackgroundLayer(partialTicks, mouseX, mouseY);
        drawPlayerInventory(7, 83);
    }
}

 

Bellow is a class that is supposed to implement basic behaviours to be used by its derived classes.

 

public abstract class ContainerBasic extends Container
{	
    protected final EntityPlayer player;
    protected int inventorySize;
    
    public ContainerBasic(EntityPlayer player, int inventorySize)
    {
        this.inventorySize = inventorySize;
        this.player = player;
    }

    public EntityPlayer getPlayer()
    {
        return player;
    }
    
    protected void addHotBar(int x, int y)
    {
        for(int i = 0; i < 9; ++i)
        {
            this.addSlotToContainer(new Slot(player.inventory, i, x + i * 18, y));
        }
    }
    
    protected void addPlayerInventory(int x, int y)
    {
        for(int line = 0; line < 3; ++line)
        {
            for(int row = 0; row < 9; ++row)
            {
                int slotID = 9 + line * 9 + row;
                this.addSlotToContainer(new Slot(player.inventory, slotID, x + row * 18, y + line * 18));
            }
        }
    }
    
    //I believe this is the problem. I don't understand the new set of arguments of this method.
    @Override
    public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player)
    {
    	Slot slot;
    	if(slotId > 0)
    	{
    	    slot = (Slot) this.inventorySlots.get(slotId);
    	}
    	else
    	{
    	    slot = null;
    	}
if (slot instanceof SlotFake) 
{
    return slotClickFake(slot, dragType, clickTypeIn, player);
}
        return super.slotClick(slotId, dragType, clickTypeIn, player);
    }

    private ItemStack slotClickFake(Slot slot, int mouseButton, ClickType clickTypeIn, EntityPlayer player)
    {
        System.out.println("Clicked Fake Slot");
    	return null;
    }
}

 

I don't think this class is the problem:

public class ContainerExtractor extends ContainerBasic
{
private final TileExtractor extractor;
private final InventoryFake filter;

public ContainerExtractor(EntityPlayer player, TileExtractor extractor)
{
	super(player, 5);
	this.extractor = extractor;
	filter = extractor.getFilter();

	addHotBar(8, 142);
	addPlayerInventory(8, 84);

	this.addSlotToContainer(new SlotItemHandler(filter, 0, 44, 53));
	this.addSlotToContainer(new SlotItemHandler(filter, 1, 44 + 16, 53));
	this.addSlotToContainer(new SlotItemHandler(filter, 2, 44 + 32, 53));
	this.addSlotToContainer(new SlotItemHandler(filter, 3, 44 + 48, 53));
	this.addSlotToContainer(new SlotItemHandler(filter, 4, 44 + 64, 53));
}

@Override
public boolean canInteractWith(EntityPlayer playerIn)
{
	return extractor.isUsableByPlayer(playerIn);
}
}

 

The whole GUI is a mess, things disapear, things get dupped, the game crashes, things can't be moved. It's all broken.

Link to comment
Share on other sites

You have literally overwritten the slotClick method. Do super.slotClick() before you do anything else i, so it's like this:'s like this:

//I believe this is the problem. I don't understand the new set of arguments of this method.
    @Override
    public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player)
    {
        super.slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player);
    	Slot slot;
    	if(slotId > 0)
    	{
    	    slot = (Slot) this.inventorySlots.get(slotId);
    	}
    	else
    	{
    	    slot = null;
    	}
if (slot instanceof SlotFake) 
{
    return slotClickFake(slot, dragType, clickTypeIn, player);
}
        return super.slotClick(slotId, dragType, clickTypeIn, player);
    }

Link to comment
Share on other sites

You have literally overwritten the slotClick method. Do super.slotClick() before you do anything else i, so it's like this:'s like this:

//I believe this is the problem. I don't understand the new set of arguments of this method.
    @Override
    public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player)
    {
        super.slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player);
    	Slot slot;
    	if(slotId > 0)
    	{
    	    slot = (Slot) this.inventorySlots.get(slotId);
    	}
    	else
    	{
    	    slot = null;
    	}
if (slot instanceof SlotFake) 
{
    return slotClickFake(slot, dragType, clickTypeIn, player);
}
        return super.slotClick(slotId, dragType, clickTypeIn, player);
    }

 

That didn't help.

Link to comment
Share on other sites

I learned a lot since I asked this question a couple of days ago. My GUI is almost working 100%. But I still feel I need to know exactly what each

dragMode

and

clickType

means and when

[s]Slot.slotClick[/s]

Container.slotClick

is invoked with what parameters.

 

For example, I notice the middle mouse buttom gives a

dragMode

of 2 and a

clickType

of

CLONE

, if you middle click a slot, but it gives a

dragMode

of 9 if you click and drag (with the same

clickType

of

CLONE

.

 

Right clicking:

dragMode

of 1 and

clickType

of

PICKUP

, but sometimes

dragMode

of 5 and

clickType

of

QUICK_CRAFT

.

 

I feel that if I knew what's going on with these parameters I would be able to implement my GUIs free of bugs. I can't be sure if my GUIs will always work as intended if I don't know this method's contract.

Link to comment
Share on other sites

I learned a lot since I asked this question a couple of days ago. My GUI is almost working 100%. But I still feel I need to know exactly what each

dragMode

and

clickType

means and when

Slot.slotClick

is invoked with what parameters.

 

For example, I notice the middle mouse buttom gives a

dragMode

of 2 and a

clickType

of

CLONE

, if you middle click a slot, but it gives a

dragMode

of 9 if you click and drag (with the same

clickType

of

CLONE

.

 

Right clicking:

dragMode

of 1 and

clickType

of

PICKUP

, but sometimes

dragMode

of 5 and

clickType

of

QUICK_CRAFT

.

 

I feel that if I knew what's going on with these parameters I would be able to implement my GUIs free of bugs. I can't be sure if my GUIs will always work as intended if I don't know this method contract.

Look at Container#slotaclick(...) if you understand that code it will lead you to what they mean exactly. If you have some check you need to do like for a backpack. You shouldnt be able to pickup the backpack in the backpacks inventory, to do that you would just check which slotIndex you are clicking and if it is return null otherwise return super.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

Look at Container#slotaclick(...) if you understand that code it will lead you to what they mean exactly. If you have some check you need to do like for a backpack. You shouldnt be able to pickup the backpack in the backpacks inventory, to do that you would just check which slotIndex you are clicking and if it is return null otherwise return super.

 

Container.slotClick

was what I meant to say. The method is too long and it has too many conditionals. I want to know the method's contract, meaning, what arguments the method expects and what are the results the caller can expect from the method: if the arguments set is A, invoking the method will have R as return and will cause S as a set of side effects.

 

If anyone could tell me what is

Container.slotClick

contract I would really appreciate it.

Link to comment
Share on other sites

Look at Container#slotaclick(...) if you understand that code it will lead you to what they mean exactly. If you have some check you need to do like for a backpack. You shouldnt be able to pickup the backpack in the backpacks inventory, to do that you would just check which slotIndex you are clicking and if it is return null otherwise return super.

 

Container.slotClick

was what I meant to say. The method is too long and it has too many conditionals. I want to know the method's contract, meaning, what arguments the method expects and what are the results the caller can expect from the method: if the arguments set is A, invoking the method will have R as return and will cause S as a set of side effects.

 

If anyone could tell me what is

Container.slotClick

contract I would really appreciate it.

It is obviously called when a slot in the container is clicked. It expects the return to be an ItemStack. Correct me if I am wrong but I believe the returned stack is the Stack that is bound to the mouse? ClickType.CLONE is used for creative mode when you middle click a slot it returns a new ItemStack of the Item but with the stacksize of 64(or the max stacksize). Drag mode is if the player is binding it to the mouse or not(again subject to correction). ClickType.QUICK_CRAFT is clicking and dragging the item through slots. Any more questions do ask.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

I was hoping for something way more exact than that...

 

Anyway, I have a somewhat satisfactory Container, but it still has an issue (look at the comment on top of

slotClickFake

method):

    @Override
    public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player)
    {
    	Slot slot= null;
    	ItemStack stack = null;
    	if(slotId > 0)
    	{
            slot = (Slot) this.inventorySlots.get(slotId);
            stack = slot.getStack();
    	}
    	else
    	{
            slot = null;
    	}
if (slot instanceof SlotFake) 
{
            return slotClickFake((SlotFake)slot, dragType, clickTypeIn, player);
}
        return super.slotClick(slotId, dragType, clickTypeIn, player);
    }

    //A SlotFake is basically a slot to mark things like filters (e.g only consider ItemStacks that are equal to the ItemStack in the fake slot).
    //when you are holding an ItemStack with your mouse, you set the fake slot to have a stack of 0 size equal to that item,
    //without affecting the ItemStack being held (You don't actually put anything in a SlotFake).
    //when you are not holding an ItemStack with your mouse, you pick up the zero sized ItemStack in the SlotFake (if the slot has one).
    //this 0 sized ItemStack is supposed to be valid for other SlotFakes, but, as it is, there is a minor nuissance:
    //you can put these 0 sized ItemStacks in your normal inventory. They disappear when clicked, but I wish this behaviour wouldn't exist.
    private ItemStack slotClickFake(SlotFake slot, int dragType, ClickType clickTypeIn, EntityPlayer player)
    {
        InventoryPlayer playerInv = player.inventory;
ItemStack itemInHand = playerInv.getItemStack();
ItemStack itemInSlot = slot.getStack();

ItemStack result = itemInSlot != null ? itemInSlot.copy() : null;

switch(clickTypeIn)
        {
            case CLONE:
	if(itemInSlot != null)
	{
	    if(player.capabilities.isCreativeMode)
                    {
                        if(itemInHand != null
		    && itemInHand.stackSize < itemInHand.getMaxStackSize()
		    && ItemHandlerHelper.canItemStacksStack(itemInHand, itemInHand))
		{
		    itemInHand.stackSize = itemInHand.getMaxStackSize();
		}
		else
		{
		    slot.putStack(null);
		}			
	    }
	    else
	    {
		slot.putStack(null);
                    }
                }
                break;
            case PICKUP:
            case PICKUP_ALL:
            case QUICK_CRAFT:
            case QUICK_MOVE:
                if(itemInHand != null && slot.isItemValid(itemInHand))
	{
                    ItemStack copy = itemInHand.copy();
                    slot.putStack(copy);
                    result = copy;
	}
	else if(itemInSlot != null)
	{
                    playerInv.setItemStack(itemInSlot);
                    slot.putStack(null);
                }
                break;
            case SWAP://I don't know what to do in these cases
	break;
            case THROW:
	break;
            default:
	break;
        }
        return result;
    }

Link to comment
Share on other sites

I was hoping for something way more exact than that...

 

Anyway, I have a somewhat satisfactory Container, but it still has an issue (look at the comment on top of

slotClickFake

method):

    @Override
    public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player)
    {
    	Slot slot= null;
    	ItemStack stack = null;
    	if(slotId > 0)
    	{
            slot = (Slot) this.inventorySlots.get(slotId);
            stack = slot.getStack();
    	}
    	else
    	{
            slot = null;
    	}
if (slot instanceof SlotFake) 
{
            return slotClickFake((SlotFake)slot, dragType, clickTypeIn, player);
}
        return super.slotClick(slotId, dragType, clickTypeIn, player);
    }

    //A SlotFake is basically a slot to mark things like filters (e.g only consider ItemStacks that are equal to the ItemStack in the fake slot).
    //when you are holding an ItemStack with your mouse, you set the fake slot to have a stack of 0 size equal to that item,
    //without affecting the ItemStack being held (You don't actually put anything in a SlotFake).
    //when you are not holding an ItemStack with your mouse, you pick up the zero sized ItemStack in the SlotFake (if the slot has one).
    //this 0 sized ItemStack is supposed to be valid for other SlotFakes, but, as it is, there is a minor nuissance:
    //you can put these 0 sized ItemStacks in your normal inventory. They disappear when clicked, but I wish this behaviour wouldn't exist.
    private ItemStack slotClickFake(SlotFake slot, int dragType, ClickType clickTypeIn, EntityPlayer player)
    {
        InventoryPlayer playerInv = player.inventory;
ItemStack itemInHand = playerInv.getItemStack();
ItemStack itemInSlot = slot.getStack();

ItemStack result = itemInSlot != null ? itemInSlot.copy() : null;

switch(clickTypeIn)
        {
            case CLONE:
	if(itemInSlot != null)
	{
	    if(player.capabilities.isCreativeMode)
                    {
                        if(itemInHand != null
		    && itemInHand.stackSize < itemInHand.getMaxStackSize()
		    && ItemHandlerHelper.canItemStacksStack(itemInHand, itemInHand))
		{
		    itemInHand.stackSize = itemInHand.getMaxStackSize();
		}
		else
		{
		    slot.putStack(null);
		}			
	    }
	    else
	    {
		slot.putStack(null);
                    }
                }
                break;
            case PICKUP:
            case PICKUP_ALL:
            case QUICK_CRAFT:
            case QUICK_MOVE:
                if(itemInHand != null && slot.isItemValid(itemInHand))
	{
                    ItemStack copy = itemInHand.copy();
                    slot.putStack(copy);
                    result = copy;
	}
	else if(itemInSlot != null)
	{
                    playerInv.setItemStack(itemInSlot);
                    slot.putStack(null);
                }
                break;
            case SWAP://I don't know what to do in these cases
	break;
            case THROW:
	break;
            default:
	break;
        }
        return result;
    }

Instead return null.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

I want to be able to grab the 0 sized stacks, I just don't want to be able to put them anywhere other than in a SlotFake.

Have every other slot that is not a SlotFake be a custom slot that overrides onSlotChanged and check if par2's stackSize is <= 0 if so set this slots ItemStack = null. (This may work I am not sure when this method is called. Be sure to check what happens when you click on a slot with another ItemStack in it).

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Post logs as per https://forums.minecraftforge.net/topic/125488-rules-and-frequently-asked-questions-faq/ They may have information that will answer these questions.
    • I was left reeling when a glitch on a cryptocurrency exchange caused me to lose $166,000 worth of my hard-earned savings. It felt like my entire world had crumbled in the blink of an eye, leaving me with a sense of hopelessness. Determined not to give up, I delved into research on recovery options, unsure of what to expect. That's when I stumbled upon I was left reeling when a glitch on a cryptocurrency exchange caused me to lose $166,000 worth of my hard-earned savings. It felt like my entire world had crumbled in the blink of an eye, leaving me with a sense of hopelessness. Determined not to give up, I delved into research on recovery options, unsure of what to expect. That's when I stumbled upon DIGITAL HACK RECOVERY, a beacon of hope in my darkest hour. Despite my initial doubts, I decided to take a leap of faith and give them a shot as a final lifeline. The experts at DIGITAL HACK RECOVERY proved to be masters of their craft, guiding me through their exclusive process with precision and expertise. Utilizing cutting-edge blockchain analysis methods, they were able to track down the elusive trail of my missing funds and identify the exact point of failure. Their forensic talents were unparalleled as they tirelessly combed through the intricate web of blockchain data to locate my cryptocurrency. With each step they took, they kept me informed of their progress, never wavering in their belief that my funds could be rescued. After several painstaking weeks, DIGITAL HACK RECOVERY finally located and restored my $166,000 worth of cryptocurrency. I was awestruck that they were able to salvage what I had thought was lost forever. The whole experience restored my faith in the crypto space and proved that even in the worst situations, recovery is possible with the right experts on your side. I will be forever grateful to DIGITAL HACK RECOVERY for giving me back my life savings when I needed it most. Their tireless efforts and technical mastery turned what could have been a devastating loss into an uplifting success story. Book a time with DIGITAL HACK RECOVERY through: digital hack recovery @ techie . com &  +12018871705
    • public class ParticleReboundRecipe implements Recipe<CraftingContainer> { private List<ParticleReboundIngredient> inputs; private ParticleReboundFuel fuel; private ItemStack output; public ParticleReboundRecipe(List<ParticleReboundIngredient> inputs, ParticleReboundFuel fuel, ItemStack output) { this.inputs = inputs; this.fuel = fuel; this.output = output; } // TODO: Implement interface ... // TODO: Move to separate file if desired public record ParticleReboundIngredient(Ingredient ingredient, int count) { public static final Codec<ParticleReboundIngredient> CODEC = RecordCodecBuilder.create( builder -> builder.group( Ingredient.CODEC.fieldOf("ingredient").forGetter((i) -> i.ingredient), Codec.INT.fieldOf("count").forGetter(i -> i.count) ).apply(builder, ParticleReboundIngredient::new) ); } // TODO: Move to separate file if desired public record ParticleReboundFuel(String tag) { public static final Codec<ParticleReboundFuel> CODEC = RecordCodecBuilder.create( builder -> builder.group(Codec.STRING.fieldOf("tag").forGetter(f -> f.tag)).apply(builder, ParticleReboundFuel::new) ); public boolean isFuel(ItemStack stack) { // TODO: Check if fuel item matches the tag } } public class Serializer implements RecipeSerializer<ParticleReboundRecipe> { public static final Codec<ParticleReboundRecipe> CODEC = RecordCodecBuilder.create( builder -> builder.group( ParticleReboundIngredient.CODEC.listOf().fieldOf("inputs").forGetter(r -> r.inputs), ParticleReboundFuel.CODEC.fieldOf("fuel").forGetter(r -> r.fuel), ItemStack.CODEC.fieldOf("output").forGetter(r -> r.output) ).apply(builder, ParticleReboundRecipe::new) ); @Override public @NotNull Codec<ParticleReboundRecipe> codec() { return CODEC; } // TODO: The rest ... } }   ?
    • I'm sure load and SaveAdditional are what you are looking for, probably. Mind sharing your BE class code? You also need to override onLoad method if you haven't
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.