Jump to content

[SOLVED] GUI Items in player inventory behaving awkwardly


intermediateuser

Recommended Posts

I have a very simple block.  When you right-click that block, there appears a very simple GUI that, currently, only has one placeholder button and the player's inventory.  The items in the player's inventory appear to be placed correctly, but when clicked, they hop to the cursor then immediately drop back into the inventory.  Sometimes I can pick up an item but it doesn't appear to *actually* be happening when I click again; or the item disappears entirely; or the item is dropped into the world.

 

Edit: added the tile entity and my proxies, for reference.

 

MerchantBlock.java

package x.thealphaelement.block;

import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import x.thealphaelement.TheAlphaElement;
import x.thealphaelement.tileentity.TileEntityMerchantBlock;

public class MerchantBlock extends BlockContainer {

private InventoryPlayer playerInventory;

        public MerchantBlock (int id, int texture, Material material) {
                super(id, material);
                
                setHardness(0.3F);
        		setStepSound(soundWoodFootstep);
        		setUnlocalizedName("merchantBlock");
        		setCreativeTab(CreativeTabs.tabDecorations);
        }
        
        public void registerIcons(IconRegister iconRegister) {
        	blockIcon = iconRegister.registerIcon("TheAlphaElement:blocktest");
        }
        
        public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
        {
        	TileEntityMerchantBlock merchantBlock = (TileEntityMerchantBlock)par1World.getBlockTileEntity(par2, par3, par4);
            par5EntityPlayer.openGui(TheAlphaElement.instance, 0, par1World, par2, par3, par4);
            return true;
        }

	@Override
	public TileEntity createNewTileEntity(World world) {
		return new TileEntityMerchantBlock();
	}

 

GuiMerchantBlock.java

package x.thealphaelement.client.gui;

import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.EntityPlayer;

import org.lwjgl.opengl.GL11;

import x.thealphaelement.tileentity.TileEntityMerchantBlock;

public class GuiMerchantBlock extends GuiContainer {

public final int xSizeOfTexture = 176;
public final int ySizeOfTexture = 207;
private int inventoryRows = 0;

private EntityPlayer player; 

public GuiMerchantBlock(EntityPlayer player, TileEntityMerchantBlock te) {
	super(new ContainerMerchantBlock(player.inventory, te));
	this.player = player;
	short short1 = 223;
        int i = short1 - 108;
        this.inventoryRows = player.inventory.getSizeInventory() / 9;
        this.ySize = i + this.inventoryRows * 18;
       

}

public void initGui()
{
	super.initGui();
	int posX = (this.width - xSizeOfTexture) / 2;
	int posY = (this.height - ySizeOfTexture) / 2;
	this.buttonList.clear();
	this.buttonList.add(new GuiButton(0, posX+ 40, posY + 40, 100, 20, "no use"));
}

@Override
public boolean doesGuiPauseGame()
{
return false;
}

@Override
protected void keyTyped(char par1, int par2) {
	if (par2 == 1 || par2 == this.mc.gameSettings.keyBindInventory.keyCode) {
		this.mc.thePlayer.closeScreen();
	}
}

public void actionPerformed(GuiButton button) {
	switch(button.id) {
		case 0: player.addChatMessage("Good job!");

		break;
		default:	
	}
}

@Override
protected void drawGuiContainerBackgroundLayer(float f, int i, int j) {
	GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
	this.mc.renderEngine.bindTexture("/mods/TheAlphaElement/textures/gui/generalMerchant.png");

	int posX = (this.width - xSizeOfTexture) / 2;
	int posY = (this.height - ySizeOfTexture) / 2;


	drawTexturedModalRect(posX, posY, 0, 0, this.xSize, ySizeOfTexture);

}


}

 

ContainerMerchantBlock.java

package x.thealphaelement.client.gui;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import x.thealphaelement.tileentity.TileEntityMerchantBlock;

public class ContainerMerchantBlock extends Container {

private TileEntityMerchantBlock tileEntity;
    private int numRows;
    protected IInventory playerInventory;

public ContainerMerchantBlock(InventoryPlayer playerInv, TileEntityMerchantBlock te) {
	tileEntity = te;
	playerInventory = playerInv;
	playerInv.openChest();
        this.numRows = playerInv.getSizeInventory() / 9;
        int i = (this.numRows - 4) * 18;
        int j;
        int k;

        for (j = 0; j < 3; ++j)
        {
            for (k = 0; k < 9; ++k)
            {
                this.addSlotToContainer(new Slot(playerInv, k + j * 9 + 9, 8 + k * 18, 115 + j * 18 + i));
            }  
        }
        
        for (j = 0; j < 9; ++j)
        {
            this.addSlotToContainer(new Slot(playerInv, j, 8 + j * 18, 173 + i));
        }
        
}

@Override
public boolean canInteractWith(EntityPlayer entityplayer) {
	return playerInventory.isUseableByPlayer(entityplayer);
}

public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2) {
        return null;
    }

}

 

TileEntityMerchantBlock.java

package x.thealphaelement.tileentity;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;

public class TileEntityMerchantBlock extends TileEntity implements IInventory {

public TileEntityMerchantBlock() {

}

public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
{
         if (worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) != this)
         {
                 return false;
         }

         return par1EntityPlayer.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64D;
}

@Override
public int getSizeInventory() {
	// TODO Auto-generated method stub
	return 0;
}

@Override
public ItemStack getStackInSlot(int i) {
	// TODO Auto-generated method stub
	return null;
}

@Override
public ItemStack decrStackSize(int i, int j) {
	// TODO Auto-generated method stub
	return null;
}

@Override
public ItemStack getStackInSlotOnClosing(int i) {
	// TODO Auto-generated method stub
	return null;
}

@Override
public void setInventorySlotContents(int i, ItemStack itemstack) {
	// TODO Auto-generated method stub

}

@Override
public String getInvName() {
	// TODO Auto-generated method stub
	return null;
}

@Override
public boolean isInvNameLocalized() {
	// TODO Auto-generated method stub
	return false;
}

@Override
public int getInventoryStackLimit() {
	// TODO Auto-generated method stub
	return 0;
}

@Override
public void openChest() {
	// TODO Auto-generated method stub

}

@Override
public void closeChest() {
	// TODO Auto-generated method stub

}

@Override
public boolean isStackValidForSlot(int i, ItemStack itemstack) {
	// TODO Auto-generated method stub
	return false;
}

}

 

ClientProxy.java

package x.thealphaelement.client;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import x.thealphaelement.CommonProxy;
import x.thealphaelement.client.gui.GuiMerchantBlock;
import x.thealphaelement.client.renderer.RenderBlazeModded;
import x.thealphaelement.client.renderer.RenderCreeperModded;
import x.thealphaelement.client.renderer.RenderEndermanModded;
import x.thealphaelement.client.renderer.RenderGhastModded;
import x.thealphaelement.client.renderer.RenderSkeletonModded;
import x.thealphaelement.client.renderer.RenderSpiderModded;
import x.thealphaelement.client.renderer.RenderWitchModded;
import x.thealphaelement.client.renderer.RenderZombieModded;
import x.thealphaelement.entity.monster.EntityBlazeModded;
import x.thealphaelement.entity.monster.EntityBlueSkeleton;
import x.thealphaelement.entity.monster.EntityBlueSpider;
import x.thealphaelement.entity.monster.EntityBlueZombie;
import x.thealphaelement.entity.monster.EntityCaveSpiderModded;
import x.thealphaelement.entity.monster.EntityCreeperModded;
import x.thealphaelement.entity.monster.EntityEndermanModded;
import x.thealphaelement.entity.monster.EntityGhastModded;
import x.thealphaelement.entity.monster.EntityPigZombieModded;
import x.thealphaelement.entity.monster.EntityRedSkeleton;
import x.thealphaelement.entity.monster.EntityRedSpider;
import x.thealphaelement.entity.monster.EntityRedZombie;
import x.thealphaelement.entity.monster.EntitySkeletonModded;
import x.thealphaelement.entity.monster.EntitySpiderModded;
import x.thealphaelement.entity.monster.EntitySpiderling;
import x.thealphaelement.entity.monster.EntityWitchModded;
import x.thealphaelement.entity.monster.EntityZombieModded;
import x.thealphaelement.tileentity.TileEntityMerchantBlock;
import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.registry.EntityRegistry;

public class ClientProxy extends CommonProxy {
        
        @Override
        public void registerRenderers() {
        	RenderingRegistry.registerEntityRenderingHandler(EntitySkeletonModded.class, new RenderSkeletonModded());
            EntityRegistry.registerGlobalEntityID(EntitySkeletonModded.class, "NormalSkeleton", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityZombieModded.class, new RenderZombieModded());
            EntityRegistry.registerGlobalEntityID(EntityZombieModded.class, "NormalZombie", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntitySpiderModded.class, new RenderSpiderModded());
            EntityRegistry.registerGlobalEntityID(EntitySpiderModded.class, "NormalSpider", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityCreeperModded.class, new RenderCreeperModded());
            EntityRegistry.registerGlobalEntityID(EntityCreeperModded.class, "NormalCreeper", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityEndermanModded.class, new RenderEndermanModded());
            EntityRegistry.registerGlobalEntityID(EntityEndermanModded.class, "NormalEnderman", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityCaveSpiderModded.class, new RenderSpiderModded());
            EntityRegistry.registerGlobalEntityID(EntityCaveSpiderModded.class, "NormalCaveSpider", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityWitchModded.class, new RenderWitchModded());
            EntityRegistry.registerGlobalEntityID(EntityWitchModded.class, "NormalWitch", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityBlazeModded.class, new RenderBlazeModded());
            EntityRegistry.registerGlobalEntityID(EntityBlazeModded.class, "NormalBlaze", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityGhastModded.class, new RenderGhastModded());
            EntityRegistry.registerGlobalEntityID(EntityGhastModded.class, "NormalGhast", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityPigZombieModded.class, new RenderZombieModded());
            EntityRegistry.registerGlobalEntityID(EntityPigZombieModded.class, "NormalPigZombie", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityRedZombie.class, new RenderZombieModded());
            EntityRegistry.registerGlobalEntityID(EntityRedZombie.class, "RedZombie", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityBlueZombie.class, new RenderZombieModded());
            EntityRegistry.registerGlobalEntityID(EntityBlueZombie.class, "BlueZombie", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityRedSkeleton.class, new RenderSkeletonModded());
            EntityRegistry.registerGlobalEntityID(EntityRedSkeleton.class, "RedSkeleton", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityBlueSkeleton.class, new RenderSkeletonModded());
            EntityRegistry.registerGlobalEntityID(EntityBlueSkeleton.class, "BlueSkeleton", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityRedSpider.class, new RenderSpiderModded());
            EntityRegistry.registerGlobalEntityID(EntityRedSpider.class, "RedSpider", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntityBlueSpider.class, new RenderSpiderModded());
            EntityRegistry.registerGlobalEntityID(EntityBlueSpider.class, "BlueSpider", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            RenderingRegistry.registerEntityRenderingHandler(EntitySpiderling.class, new RenderSpiderModded());
            EntityRegistry.registerGlobalEntityID(EntitySpiderling.class, "Spiderling", EntityRegistry.findGlobalUniqueEntityId(), 3515848, 12102);
            
            
       }
        
        public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
        	TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
        	if (tileEntity != null) {
        		switch(ID) {
        			case 0: return new GuiMerchantBlock(player, (TileEntityMerchantBlock)tileEntity); // your GUIs go here
        		}
        	}
        	return null;
        }
        
}

 

 

CommonProxy.java

package x.thealphaelement;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import cpw.mods.fml.common.network.IGuiHandler;

public class CommonProxy implements IGuiHandler {
        
	// Client stuff
        public void registerRenderers() {
                // Nothing here as the server doesn't render graphics!
        }

	@Override
	public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
		return null;
	}

	@Override
	public Object getServerGuiElement(int ID, EntityPlayer player,
			World world, int x, int y, int z) {
		// TODO Auto-generated method stub
		return null;
	}

        
}

 

I feel like I'm really close here.  Any ideas?

Link to comment
Share on other sites

public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
        {
        	TileEntityMerchantBlock merchantBlock = (TileEntityMerchantBlock)par1World.getBlockTileEntity(par2, par3, par4);
            par5EntityPlayer.openGui(TheAlphaElement.instance, 0, par1World, par2, par3, par4);
            return true;
        }

Here is your problem.Just change it to:

public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
        {
           if(!par1World.isRemote){
        	TileEntityMerchantBlock merchantBlock =    (TileEntityMerchantBlock)par1World.getBlockTileEntity(par2, par3, par4);
            par5EntityPlayer.openGui(TheAlphaElement.instance, 0, par1World, par2, par3, par4);
            }
            return true;
        }

Link to comment
Share on other sites

public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
        {
        	TileEntityMerchantBlock merchantBlock = (TileEntityMerchantBlock)par1World.getBlockTileEntity(par2, par3, par4);
            par5EntityPlayer.openGui(TheAlphaElement.instance, 0, par1World, par2, par3, par4);
            return true;
        }

Here is your problem.Just change it to:

public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
        {
           if(!par1World.isRemote){
        	TileEntityMerchantBlock merchantBlock =    (TileEntityMerchantBlock)par1World.getBlockTileEntity(par2, par3, par4);
            par5EntityPlayer.openGui(TheAlphaElement.instance, 0, par1World, par2, par3, par4);
            }
            return true;
        }

 

Thank you so much for the response.  I've honestly been working on this sole issue for about 3 days.  When I make your change, though, the block simply doesn't activate anymore, lol.  This is really confusing.

Link to comment
Share on other sites

I forgot. Make the canInteractWith() method in your container aleays return true.

 

I've done that; it has no effect.  I tried making canInteractWith() always return true again with your code from above too, and the block still does not activate with the proposed change, so I simply changed it back.

Link to comment
Share on other sites

I posted my code here as per your PM. I'm not sure what your problem is, but I think it might be with your TileEntity.

 

Thanks for the help.  The problem persists quite stubbornly... as for my tile entity, I've updated the original post with it.  But it's mostly empty; I didn't think the tile entity had anything to do with the player's inventory.  The gui and block aren't calling for the block's inventory at all; for now, it's just trying to properly bind the player's inventory to the gui/container.

 

But, if you can see something in the mostly barebones tile entity, please let me know.

Link to comment
Share on other sites

I posted my code here as per your PM. I'm not sure what your problem is, but I think it might be with your TileEntity.

 

Thanks for the help.  The problem persists quite stubbornly... as for my tile entity, I've updated the original post with it.  But it's mostly empty; I didn't think the tile entity had anything to do with the player's inventory.  The gui and block aren't calling for the block's inventory at all; for now, it's just trying to properly bind the player's inventory to the gui/container.

 

But, if you can see something in the mostly barebones tile entity, please let me know.

The TileEntity is just as important as the Container. Perhaps more so. You need to add an ItemStack[] field and fix all those auto-generated IInventory functions. Look at my code for an example.

BEWARE OF GOD

---

Co-author of Pentachoron Labs' SBFP Tech.

Link to comment
Share on other sites

The TileEntity is just as important as the Container. Perhaps more so. You need to add an ItemStack[] field and fix all those auto-generated IInventory functions. Look at my code for an example.

 

I thought that might be the case, so before updating my original post I did change my tile entity to this, but it had no effect:

 

package x.thealphaelement.tileentity;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.StringTranslate;

public class TileEntityMerchantBlock extends TileEntity implements IInventory {

private ItemStack[] inventory = new ItemStack[8];
private boolean hasItem = false;

public TileEntityMerchantBlock() {

}

public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
{
         if (worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) != this)
         {
                 return false;
         }

         return par1EntityPlayer.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64D;
}

@Override
public int getSizeInventory(){
	return this.inventory.length;
}

@Override
public ItemStack getStackInSlot(int index){
	return this.inventory[index];
}

@Override
public ItemStack decrStackSize(int slot, int num){
	if(this.inventory[slot]!=null){
		ItemStack stack;
		if(this.inventory[slot].stackSize<=num){
			stack = this.inventory[slot];
			this.inventory[slot] = null;
			return stack;
		}else{
			stack = this.inventory[slot].splitStack(num);
			if(this.inventory[slot].stackSize==0){
				this.inventory[slot] = null;
			}
			return stack;
		}
	}else return null;
}

@Override
public ItemStack getStackInSlotOnClosing(int index){
	if(this.inventory[index]!=null){
		ItemStack var2 = this.inventory[index];
		this.inventory[index] = null;
		return var2;
	}else return null;
}

@Override
public void setInventorySlotContents(int index, ItemStack stack){
	this.inventory[index] = stack;
	if(stack!=null&&stack.stackSize>this.getInventoryStackLimit()){
		stack.stackSize = this.getInventoryStackLimit();
	}
}

@Override
public String getInvName(){
	return StringTranslate.getInstance().translateKey("merchantBlock.name");
}

@Override
public boolean isInvNameLocalized(){
	return true;
}

@Override
public int getInventoryStackLimit(){
	return 64;
}

@Override
public void openChest() {
	// TODO Auto-generated method stub

}

@Override
public void closeChest() {
	// TODO Auto-generated method stub

}

@Override
public boolean isStackValidForSlot(int i, ItemStack itemstack) {
	// TODO Auto-generated method stub
	return true;
}



}

 

Then I reverted back to my original, barebones tile entity, seeing that the change didn't seem significant.  Am I editing the wrong methods in the tile entity?  Also, I suppose I'm confused as to how the tile entity can affect this because although the tile entity is called in the block's constructor, the tile entity is never actually used in the code.

Link to comment
Share on other sites

Considering that I am having the same problem, and that my tile entity does have the read and write functions (as well as simple packet code), and that their container doesn't actually create any slots for the tile, I would be quite surprised if that were the root of the problem.

 

here is my tile code to be clear:

package com.quargos.am.blocks.tiles;

import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.Packet132TileEntityData;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.liquids.ILiquidTank;
import net.minecraftforge.liquids.LiquidContainerRegistry;
import net.minecraftforge.liquids.LiquidStack;

public class TileCrystaliser extends TileEntity implements IInventory,
        ILiquidTank
{
    public LiquidStack liquid = new LiquidStack(Block.waterStill, 0);
    
    public ItemStack[] contents = new ItemStack[3];
    
    @Override
    public void updateEntity()
    {
        super.updateEntity();
    }
    
    public Packet getDescriptionPacket()
    {
        NBTTagCompound nbtTag = new NBTTagCompound();
        this.writeToNBT(nbtTag);
        return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, nbtTag);
    }

    public void onDataPacket(INetworkManager net, Packet132TileEntityData packet) {
        readFromNBT(packet.customParam1);
    }
    
    @Override
    public void readFromNBT(NBTTagCompound nbt)
    {
        for(int i = 0; i < contents.length; i++)
        {
            contents[i] = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("content_" + i));
        }
        liquid.amount = nbt.getInteger("waterLevel");
        
        super.readFromNBT(nbt);
    }
    
    @Override
    public void writeToNBT(NBTTagCompound nbt)
    {
        for(int i = 0; i < contents.length; i++)
        {
            if(contents[i] != null)
                contents[i].writeToNBT(nbt.getCompoundTag("content_" + i)); //Ensure works!
        }
        nbt.setInteger("waterLevel", liquid.amount);
        
        super.writeToNBT(nbt);
    }
    
    
    //ILiquidTank
    @Override
    public LiquidStack getLiquid()
    {
        return liquid;
    }
    
    @Override
    public int getCapacity()
    {
        return 8*LiquidContainerRegistry.BUCKET_VOLUME;
    }
    
    @Override
    public int fill(LiquidStack resource, boolean doFill)
    {
        if(doFill)
        {
            if(resource.itemID == Block.waterStill.blockID)
            {
                int amount = liquid.amount + resource.amount;
                if(amount > getCapacity())
                {
                    amount -= getCapacity();
                    liquid.amount = getCapacity();
                    return resource.amount - amount;
                }
                liquid.amount += resource.amount;
                return resource.amount;
            }
        }
        return 0;
    }
    
    @Override
    public LiquidStack drain(int maxDrain, boolean doDrain)
    {
        if(doDrain)
        {
            liquid.amount -= maxDrain;
            if(liquid.amount < 0)
            {
                LiquidStack out = new LiquidStack(liquid.itemID, -liquid.amount);
                liquid.amount = 0;
                return out;
            }
            return new LiquidStack(liquid.itemID, maxDrain);
        }
        return null;
    }
    
    @Override
    public int getTankPressure()
    {
        return 0;
    }
    
    
    //IInventory
    
    
    @Override
    public int getSizeInventory()
    {
        return contents.length;
    }
    
    @Override
    public ItemStack getStackInSlot(int i)
    {
        if(i >= 0 && i < contents.length)
            return contents[i];
        return null;
    }
    
    @Override
    public ItemStack decrStackSize(int i, int j)
    {
        if(i >= 0 && i < contents.length)
        {
            if(contents[i].stackSize > j)
            {
                contents[i].stackSize -= j;
                return new ItemStack(contents[i].itemID,j,contents[i].getItemDamage());
            }
            ItemStack out = contents[i];
            contents[i] = null;
            return out;
        }
        return null;
    }
    
    @Override
    public ItemStack getStackInSlotOnClosing(int i)
    {
        return null;
    }
    
    @Override
    public void setInventorySlotContents(int i, ItemStack itemstack)
    {
        contents[i] = itemstack;
    }
    
    @Override
    public String getInvName()
    {
        return "Soul Crystaliser";
    }
    
    @Override
    public boolean isInvNameLocalized()
    {
        return true; //should change when implementing localisation stuff.
    }
    
    @Override
    public int getInventoryStackLimit()
    {
        return 64;
    }
    
    @Override
    public boolean isUseableByPlayer(EntityPlayer entityplayer)
    {
        return true;
    }
    
    @Override
    public void openChest()
    {
        
    }
    
    @Override
    public void closeChest()
    {
        
    }
    
    @Override
    public boolean isStackValidForSlot(int i, ItemStack itemstack)
    {
        return true;
    }
    
}

Link to comment
Share on other sites

You also need the NBT read/write functions. Actually, I think that is at the root of the problem.

 

I just added them, but am I mistaken to think the NBT stuff is for storing and loading the tile entity's inventory?  We're only dealing with player inventory here; the tile entity doesn't have an inventory (well, now it might, with the NBT stuff added).  New code here, though the problem is unaffected:

 

package x.thealphaelement.tileentity;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.StringTranslate;

public class TileEntityMerchantBlock extends TileEntity implements IInventory {

private ItemStack[] inventory = new ItemStack[8];
private boolean hasItem = false;

public TileEntityMerchantBlock() {

}

public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
{
         if (worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) != this)
         {
                 return false;
         }

         return par1EntityPlayer.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64D;
}

@Override
public int getSizeInventory(){
	return this.inventory.length;
}

@Override
public ItemStack getStackInSlot(int index){
	return this.inventory[index];
}

@Override
public ItemStack decrStackSize(int slot, int num){
	if(this.inventory[slot]!=null){
		ItemStack stack;
		if(this.inventory[slot].stackSize<=num){
			stack = this.inventory[slot];
			this.inventory[slot] = null;
			return stack;
		}else{
			stack = this.inventory[slot].splitStack(num);
			if(this.inventory[slot].stackSize==0){
				this.inventory[slot] = null;
			}
			return stack;
		}
	}else return null;
}

@Override
public ItemStack getStackInSlotOnClosing(int index){
	if(this.inventory[index]!=null){
		ItemStack var2 = this.inventory[index];
		this.inventory[index] = null;
		return var2;
	}else return null;
}

@Override
public void setInventorySlotContents(int index, ItemStack stack){
	this.inventory[index] = stack;
	if(stack!=null&&stack.stackSize>this.getInventoryStackLimit()){
		stack.stackSize = this.getInventoryStackLimit();
	}
}

@Override
public String getInvName(){
	return StringTranslate.getInstance().translateKey("merchantBlock.name");
}

@Override
public boolean isInvNameLocalized(){
	return true;
}

@Override
public int getInventoryStackLimit(){
	return 64;
}

@Override
public void openChest() {
	// TODO Auto-generated method stub

}

@Override
public void closeChest() {
	// TODO Auto-generated method stub

}

@Override
public boolean isStackValidForSlot(int i, ItemStack itemstack) {
	// TODO Auto-generated method stub
	return true;
}

@Override
public void writeToNBT(NBTTagCompound tagCompound){
	super.writeToNBT(tagCompound);
	NBTTagList tagList = new NBTTagList();
	for(int i = 0; i<this.inventory.length; ++i){
		if(this.inventory[i]!=null){
			NBTTagCompound ntc3 = new NBTTagCompound();
			ntc3.setByte("slot",(byte) i);
			this.inventory[i].writeToNBT(ntc3);
			tagList.appendTag(ntc3);
		}
	}
	tagCompound.setTag("items",tagList);
}

@Override
public void readFromNBT(NBTTagCompound tagCompound){
	super.readFromNBT(tagCompound);
	NBTTagList var2 = tagCompound.getTagList("items");
	for(int i = 0; i<var2.tagCount(); ++i){
		NBTTagCompound ntc3 = (NBTTagCompound) var2.tagAt(i);
		byte slot = ntc3.getByte("slot");
		if(slot>=0&&slot<this.inventory.length){
			this.inventory[slot] = ItemStack.loadItemStackFromNBT(ntc3);
		}
	}
}



}

Link to comment
Share on other sites

You also need the NBT read/write functions. Actually, I think that is at the root of the problem.

 

I just added them, but am I mistaken to think the NBT stuff is for storing and loading the tile entity's inventory?  We're only dealing with player inventory here; the tile entity doesn't have an inventory (well, now it might, with the NBT stuff added).  New code here, though the problem is unaffected:

-snip-

*impersonates Dirk Gently*

"I believe in the fundamental interconnectedness of all things."

 

...Actually, I'm just trying various things and hoping something works. I can't find anything wrong.

BEWARE OF GOD

---

Co-author of Pentachoron Labs' SBFP Tech.

Link to comment
Share on other sites

You also need the NBT read/write functions. Actually, I think that is at the root of the problem.

 

I just added them, but am I mistaken to think the NBT stuff is for storing and loading the tile entity's inventory?  We're only dealing with player inventory here; the tile entity doesn't have an inventory (well, now it might, with the NBT stuff added).  New code here, though the problem is unaffected:

-snip-

*impersonates Dirk Gently*

"I believe in the fundamental interconnectedness of all things."

 

...Actually, I'm just trying various things and hoping something works. I can't find anything wrong.

 

Hahaha alright then.  Well, at least I know it is most likely that my logic isn't flawed, and the issue probably has something more to do with Minecraft or Forge.

 

I really do appreciate you at least taking a look.

 

A bit more info that has come to light: it seems that when I click an item in the inventory, the item that gets picked up is the one from the slot above it.  I've run the process in a verbose manner, echoing the id's of the slots, and they seem to be placed in the correct order, but maybe this symptom of the problem tells of something you might know more about than a new modder does?

Link to comment
Share on other sites

I had realised much the same thing, except adding additional slots *before* the inventory results in offsetting the slot taken from, (see my post here which goes into a bit more detail about it and some other odd behaviour.)

 

Yeah I'm following your post and reading your updates.  Thanks for posting here to let me know in case I wasn't, though.  :)  Here's something I just tried, and it's produced some interesting information.  In your Container class, try adding this method:

 

public ItemStack slotClick(int par1, int par2, int par3, EntityPlayer par4EntityPlayer) {
	par4EntityPlayer.addChatMessage("clicky " + par1 + " " + par2 + " " + par3);
	super.slotClick(par1, par2, par3, par4EntityPlayer);
	return new ItemStack(Item.wheat);
}

 

The wheat is just a placeholder ItemStack to satisfy the return requirement.  What this does is override (but still activate, because of the super method call) the slotClick method, and it outputs the parameters the slotClick method is using to the player's chat screen (though you could use System.out.println() instead of player.addChatMessage() to have the echo go only to the console if you wanted).

 

I'm finding the only thing that changes is the first int, par1 (everything else is 0's; I'm not sure if that should concern me yet).  But the result is what interests me; the par1 is always a number that's equal to the slot it should be clicking on, plus 9 (meaning the method always tries to use the slot directly above the slot actually clicked).

 

I'm trying to find out why the method is identifying each slot the way it is.

Link to comment
Share on other sites

I just updated my latest post in the other thread, it appears that (with my mod at least) the server thinks that the player has their regular inventory open while the client thinks that the tile inventory is open. (which explains all of these oddities, since the player inventory has nine additional slots, 4 armour, 4 crafting, and the crafting output, and adding more slots in the custom container class will move the slots that the client closer to those the server uses)

 

As such; I guess there must be something we are both missing for the opening of the GUI.

 

EDIT: here is the code used for opening the GUI for me:

@Override
    public boolean onBlockActivated(World world, int i, int j, int k, EntityPlayer player, int a, float b, float c, float d)
    {
        TileEntity tileEntity = world.getBlockTileEntity(i, j, k);
        if (tileEntity == null || player.isSneaking()) 
        {
            return false;
        }
        player.openGui(Alchemagic.instance, 0, world, i, j, k);
        return true;
    }

Link to comment
Share on other sites

I decided to use a few break points to see what actually happens when I open the gui, and I found that it wasn't opening the gui handler server-side because my @Mod file didn't have an @NetworkMod annotation, simply adding @NetworkMod after the @Mod annotation and it's parameters seems to have fixed it for me.

Link to comment
Share on other sites

You also need the NBT read/write functions. Actually, I think that is at the root of the problem.

 

I just added them, but am I mistaken to think the NBT stuff is for storing and loading the tile entity's inventory?  We're only dealing with player inventory here; the tile entity doesn't have an inventory (well, now it might, with the NBT stuff added).  New code here, though the problem is unaffected:

-snip-

*impersonates Dirk Gently*

"I believe in the fundamental interconnectedness of all things."

 

...Actually, I'm just trying various things and hoping something works. I can't find anything wrong.

 

Hahaha alright then.  Well, at least I know it is most likely that my logic isn't flawed, and the issue probably has something more to do with Minecraft or Forge.

 

I really do appreciate you at least taking a look.

 

A bit more info that has come to light: it seems that when I click an item in the inventory, the item that gets picked up is the one from the slot above it.  I've run the process in a verbose manner, echoing the id's of the slots, and they seem to be placed in the correct order, but maybe this symptom of the problem tells of something you might know more about than a new modder does?

To be quite frank, I think it's more likely that you have a small typo somewhere; after all, I have a TE that works just fine. Maybe I can try doing an exhaustive compare... if I find the time.

BEWARE OF GOD

---

Co-author of Pentachoron Labs' SBFP Tech.

Link to comment
Share on other sites

Alright, finally got it.  My CommonProxy class didn't have container information in it.  I added this to my CommonProxy class:

 

@Override
	public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
		TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
		if (tileEntity != null) {
			switch(ID) {
				case 0: return new ContainerMerchantBlock(player.inventory, (TileEntityMerchantBlock)tileEntity); // your Containers go here
			}
		}
		return null;
	}

 

I was mistakenly under the impression that a "server GUI element" (as in the method's name) wouldn't be needed for what I was trying to do, as the block was only supposed to display the player's inventory, and thus wouldn't need any inventory information from the server.  I therefore omitted this code.

 

It was only after hours of tracking through Minecraft's code and adding verbosity through System.out.println() at key points was I able to discover that, when opening a normal chest or furnace, or anything of the sort, Minecraft was referring to the container by its container class name (so, something like ContainerChest or ContainerFurnace), but when activating my MerchantBlock the container object that Minecraft referenced was "ContainerPlayer", which is the same container used when a player opens their inventory normally.

 

So my block was actually trying to manipulate the player's inventory via what Minecraft thought was the player's normal inventory window (which has additional slots), and the slots my ContainerMerchantBlock class were using, were, of course, mismatched to that of the player's inventory window.

 

Once I discovered this, it still took me quite some time searching through the code and adding verbosity to realize I had to tell the server what container to use by adding the above code to the CommonProxy class.

 

Thanks a ton Quarg, Newt, and Dark for your replies!  This has been quite a learning experience.

Link to comment
Share on other sites

Alright, finally got it.  My CommonProxy class didn't have container information in it.  I added this to my CommonProxy class:

 

@Override
	public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
		TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
		if (tileEntity != null) {
			switch(ID) {
				case 0: return new ContainerMerchantBlock(player.inventory, (TileEntityMerchantBlock)tileEntity); // your Containers go here
			}
		}
		return null;
	}

 

I was mistakenly under the impression that a "server GUI element" (as in the method's name) wouldn't be needed for what I was trying to do, as the block was only supposed to display the player's inventory, and thus wouldn't need any inventory information from the server.  I therefore omitted this code.

 

It was only after hours of tracking through Minecraft's code and adding verbosity through System.out.println() at key points was I able to discover that, when opening a normal chest or furnace, or anything of the sort, Minecraft was referring to the container by its container class name (so, something like ContainerChest or ContainerFurnace), but when activating my MerchantBlock the container object that Minecraft referenced was "ContainerPlayer", which is the same container used when a player opens their inventory normally.

 

So my block was actually trying to manipulate the player's inventory via what Minecraft thought was the player's normal inventory window (which has additional slots), and the slots my ContainerMerchantBlock class were using, were, of course, mismatched to that of the player's inventory window.

 

Once I discovered this, it still took me quite some time searching through the code and adding verbosity to realize I had to tell the server what container to use by adding the above code to the CommonProxy class.

 

Thanks a ton Quarg, Newt, and Dark for your replies!  This has been quite a learning experience.

This is what programming is all about :)

 

I feel stupid to have missed that, though. I should have noticed that you were missing a common proxy function.

BEWARE OF GOD

---

Co-author of Pentachoron Labs' SBFP Tech.

Link to comment
Share on other sites

Thank you Community, I finally have my inventory working correctly, I had looked everywhere about what was wrong with my container, tileentity and my GUI bit I couldn't find anything that related to/fixed my issue. 

 

It wasn't until I got to this thread when someone mentioned that @NetworkMod was missing from their base mod class.  I added that and boom, all working. (I am sure I had that at some stage)

 

Again I would like to say thanks and love this community and love Open source. (will publish my code to github when closer to public release.)

Neoublie

Author of Codename: Project Shadow

 

if you do models and textures pm me. looking for some assistance.

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.



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • KILAT77 : Waspada Situs Scam dengan Withdraw Yang Tidak Dibayar Di era digital saat ini, banyak orang yang mencari keberuntungan melalui situs perjudian online. Namun, dibalik gemerlap janji-janji manis kemenangan, ada bahaya yang mengintai. Salah satu situs yang patut diwaspadai adalah KILAT77. Situs ini mendapat reputasi buruk karena banyak laporan dari pengguna yang mengklaim bahwa mereka tidak bisa menarik dana kemenangan mereka. Dalam artikel ini, kita akan membahas mengapa ROTER88 dianggap sebagai situs scam dan bagaimana Anda bisa melindungi diri dari penipuan serupa. Pengalaman Pengguna: Penarikan Tidak Dibayar Beberapa pengguna telah melaporkan pengalaman buruk mereka dengan KILAT77. Mereka mengaku bahwa setelah memenangkan sejumlah uang dan mencoba menariknya, proses penarikan mereka ditolak tanpa alasan yang jelas. Bahkan, beberapa pengguna melaporkan bahwa akun mereka tiba-tiba diblokir setelah mencoba melakukan penarikan, sehingga mereka kehilangan akses ke dana mereka sama sekali.
    • It is a dupe mod issue Remove Rubidium - you are already using Embeddium which is a fork of Rubidium
    • I made a block entity in forge 1.20.1, I want to prevent hopper from taking input slot item, i tried to override the extractItem method, it prevented hopper from taking input slot item, but the player also unable to take/change the item in input slot unless the slot is empty. public class FluidSeparatorBlockEntity extends BlockEntity implements MenuProvider { private static final int INPUT_SLOT = 0; private final CustomItemHandler itemHandler = new CustomItemHandler(3){ @Override protected void onContentsChanged(int slot) { setChanged(); } @Override public boolean isItemValid(int slot, @NotNull ItemStack stack) { return slot == INPUT_SLOT; } @Override public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) { if (slot == INPUT_SLOT) { return ItemStack.EMPTY; } return super.extractItem(slot, amount, simulate); } }; private LazyOptional<IItemHandler> lazyItemHandler = LazyOptional.empty(); protected final ContainerData data; private int progress = 0; private int maxProgress = 78; public FluidSeparatorBlockEntity(BlockPos pPos, BlockState pBlockState) { super(ModBlockEntities.FLUID_SEPARATOR_BE.get(), pPos, pBlockState); this.data = new ContainerData() { @Override public int get(int pIndex) { return switch (pIndex) { case 0 -> FluidSeparatorBlockEntity.this.progress; case 1, 2 -> FluidSeparatorBlockEntity.this.maxProgress; default -> 0; }; } @Override public void set(int pIndex, int pValue) { switch (pIndex) { case 0 -> FluidSeparatorBlockEntity.this.progress = pValue; case 1, 2 -> FluidSeparatorBlockEntity.this.maxProgress = pValue; } } @Override public int getCount() { return 3; } }; } @Override public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) { if(cap == ForgeCapabilities.ITEM_HANDLER) { return lazyItemHandler.cast(); } return super.getCapability(cap, side); } @Override public void onLoad() { super.onLoad(); lazyItemHandler = LazyOptional.of(() -> itemHandler); } @Override public void invalidateCaps() { super.invalidateCaps(); lazyItemHandler.invalidate(); } public void drops() { SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots()); for(int i = 0; i < itemHandler.getSlots(); i++) { inventory.setItem(i, itemHandler.getStackInSlot(i)); } Containers.dropContents(this.level, this.worldPosition, inventory); } @Override public Component getDisplayName() { return Component.translatable("block.chemmaster.fluid_separator"); } @Nullable @Override public AbstractContainerMenu createMenu(int pContainerId, Inventory pPlayerInventory, Player pPlayer) { return new FluidSeparatorMenu(pContainerId, pPlayerInventory, this, this.data); } @Override protected void saveAdditional(CompoundTag pTag) { pTag.put("inventory", itemHandler.serializeNBT()); pTag.putInt("fluid_separator.progress", progress); super.saveAdditional(pTag); } @Override public void load(CompoundTag pTag) { super.load(pTag); itemHandler.deserializeNBT(pTag.getCompound("inventory")); progress = pTag.getInt("fluid_separator.progress"); } public void tick(Level pLevel, BlockPos pPos, BlockState pState) { ItemStack inputStack = this.itemHandler.getStackInSlot(INPUT_SLOT); if (inputStack.getCount() < 2) { resetProgress(); return; } if(hasRecipe()) { increaseCraftingProgress(); setChanged(pLevel, pPos, pState); if(hasProgressFinished()) { craftItem(); resetProgress(); } } else { resetProgress(); } } private void resetProgress() { progress = 0; } private void craftItem() { Optional<FluidSeparatingRecipe> recipe = getCurrentRecipe(); if (recipe.isPresent()) { List<ItemStack> results = recipe.get().getOutputs(); ItemStack inputStack = this.itemHandler.getStackInSlot(INPUT_SLOT); if (inputStack.getCount() < 2) { // If there are not enough items, do not proceed with crafting return; } // Extract the input item from the input slot this.itemHandler.internalExtractItem(INPUT_SLOT, 2, false); // Loop through each result item and find suitable output slots for (ItemStack result : results) { int outputSlot = findSuitableOutputSlot(result); if (outputSlot != -1) { this.itemHandler.setStackInSlot(outputSlot, new ItemStack(result.getItem(), this.itemHandler.getStackInSlot(outputSlot).getCount() + result.getCount())); } else { // Handle the case where no suitable output slot is found // This can be logging an error, throwing an exception, or any other handling logic System.err.println("No suitable output slot found for item: " + result); } } } } private int findSuitableOutputSlot(ItemStack result) { // Implement logic to find a suitable output slot for the given result // Return the slot index or -1 if no suitable slot is found for (int i = 0; i < this.itemHandler.getSlots(); i++) { // Ensure we do not place the output item in the input slot if (i == INPUT_SLOT) { continue; } ItemStack stackInSlot = this.itemHandler.getStackInSlot(i); if (stackInSlot.isEmpty() || (stackInSlot.getItem() == result.getItem() && stackInSlot.getCount() + result.getCount() <= stackInSlot.getMaxStackSize())) { return i; } } return -1; } private boolean hasRecipe() { Optional<FluidSeparatingRecipe> recipe = getCurrentRecipe(); if (recipe.isEmpty()) { return false; } List<ItemStack> results = recipe.get().getOutputs(); for (ItemStack result : results) { if (!canInsertAmountIntoOutputSlot(result) || !canInsertItemIntoOutputSlot(result.getItem())) { return false; } } return true; } private Optional<FluidSeparatingRecipe> getCurrentRecipe(){ SimpleContainer inventory = new SimpleContainer(this.itemHandler.getSlots()); for (int i = 0; i < itemHandler.getSlots(); i++) { inventory.setItem(i, this.itemHandler.getStackInSlot(i)); } return this.level.getRecipeManager().getRecipeFor(FluidSeparatingRecipe.Type.INSTANCE, inventory, level); } private boolean canInsertAmountIntoOutputSlot(ItemStack result) { for (int i = 1; i < this.itemHandler.getSlots(); i++) { ItemStack stackInSlot = this.itemHandler.getStackInSlot(i); if (stackInSlot.isEmpty() || (stackInSlot.getItem() == result.getItem() && stackInSlot.getCount() + result.getCount() <= stackInSlot.getMaxStackSize())) { return true; } } return false; } private boolean canInsertItemIntoOutputSlot(Item item) { for (int i = 1; i < this.itemHandler.getSlots(); i++) { ItemStack stackInSlot = this.itemHandler.getStackInSlot(i); if (stackInSlot.isEmpty() || stackInSlot.getItem() == item) { return true; } } return false; } private boolean hasProgressFinished() { return progress >= maxProgress; } private void increaseCraftingProgress() { progress++; } }  
    • No dice. Unfortunately this fix didn't work, thank you though.
  • Topics

×
×
  • Create New...

Important Information

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