Jump to content

Recommended Posts

Posted (edited)

I'm having two issues with my custom item, both of which I suspect are related to NBT data.

 

Firstly, the addInformation method crashes the game on loading. This might have to do with some of the necessary variables not being initialized at that point in loading but I can't find anything that could help with that issue.

 

Second, right-clicking with the item for some reason causes the entire stack to disappear. Just to make sure it wasn't just using up only one of them, I changed the max stack size and it still removed the entire stack.

 

public class ItemStandArrow extends Item{
	
	private static final String name = "standArrow";
	public ItemStandArrow()
    {
		super();
        setUnlocalizedName(name);
        setCreativeTab(CreativeTabs.TOOLS);
        setMaxStackSize(1);
    }
	
	@Override
	public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand)
	{
	    NBTTagCompound nbt;
	    ItemStack stack = player.getActiveItemStack();
	    NBTTagList nbttaglist;

	    if (stack.hasTagCompound())
	    {
	        nbt = stack.getTagCompound();
	    }
	    else
	    {
	        nbt = new NBTTagCompound();
	    }
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    	for (int i = 0; i<nbttaglist.tagCount(); i++){
	    		if (nbttaglist.getStringTagAt(i) == player.getUniqueID().toString()){
	    			System.out.println("Failed to use arrow");
	    			return new ActionResult<ItemStack>(EnumActionResult.FAIL, stack);
	    		}
	    	}
	    }
	    StandHandlingMethods.grantRandomStandFromTable(player, null);
	    System.out.println("Successfully used arrow");
	    return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
	}
	
	public void addEntityToBlacklist(Entity entity, NBTTagCompound nbt, ItemStack stack){
	    NBTTagList nbttaglist;
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    }
	    else{
	    	nbttaglist = new NBTTagList();
	    }
	    
	    String entityId = entity.getUniqueID().toString();
	    NBTTagCompound compound = new NBTTagCompound();
	    compound.setString("name", entityId);
	    
	    nbttaglist.appendTag(compound);
	    
	    nbt.setTag("usedOn", nbttaglist);
	    
	    stack.setTagCompound(nbt);
	}

	@Override
	@SideOnly(Side.CLIENT)
	public void addInformation(ItemStack stack, @Nullable World worldIn,
			java.util.List<String> tooltip, ITooltipFlag flagIn) {
		NBTTagCompound nbt = stack.getTagCompound();
		NBTTagList nbttaglist;
		EntityPlayer player = Minecraft.getMinecraft().player;
		
		super.addInformation(stack, worldIn, tooltip, flagIn);
		
		if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    	for (int i = 0; i<nbttaglist.tagCount(); i++){
	    		if (nbttaglist.getStringTagAt(i) == player.getUniqueID().toString()){
	    			tooltip.add("Already used by " + player.getDisplayName());
	    		}
	    	}
	    }
	}
}

 

Edited by MythicalChromosome
Posted
12 minutes ago, MythicalChromosome said:

NBTTagList nbttaglist;

 

13 minutes ago, MythicalChromosome said:

if (nbt.hasKey("usedOn")){ nbttaglist = (NBTTagList) nbt.getTag("usedOn"); for (int i = 0; i<nbttaglist.tagCount(); i++){ if (nbttaglist.getStringTagAt(i) == player.getUniqueID().toString()){ tooltip.add("Already used by " + player.getDisplayName()); } } }

What if it doesn't have "usedOn"? "nbttaglist" is null. That's a NullPointerException.

Posted

Hey,

 

Looks like you forgot to check if the NBT tag is null in addInformation (or call stack.hasTagCompound()).

 

For the right click one, you should use the player.getHeldItem(hand) instead of getActiveItem(), which is for items you're using over a time period, like food and bows. That is probably empty when that right click is called, which is returning an empty item in the result. 

  • Like 2
Posted (edited)
    @Override
    @SideOnly(Side.CLIENT)
    public void addInformation(ItemStack stack, World worldIn, List<String> tooltip, ITooltipFlag flagIn) 
    {
        EntityPlayer playerIn = Minecraft.getMinecraft().player;	
        super.addInformation(stack, worldIn, tooltip, flagIn);
		
        if (stack.getTagCompound() != null && nbt.hasKey("usedOn"))
        {
            NBTTagCompound nbt = stack.getTagCompound();

            if (nbt.getTag("usedOn") != null
            {
                NBTTagList list = (NBTTagList) nbt.getTag("usedOn");
        
                for (int i = 0; i < list.tagCount(); ++i)
                {
                    if (list.getStringTagAt(i) == playerIn.getUniqueID().toString())
                    {
                        tooltip.add("Already used by " + playerIn.getDisplayName());
                    }
                }
            }
        }
    }

There, that's better.

You have to add null checks, not everything is present all the time.

Edited by Differentiation
  • Like 1
Posted (edited)
12 hours ago, Differentiation said:

    @Override
    @SideOnly(Side.CLIENT)
    public void addInformation(ItemStack stack, World worldIn, List<String> tooltip, ITooltipFlag flagIn) 
    {
        EntityPlayer playerIn = Minecraft.getMinecraft().player;	
        super.addInformation(stack, worldIn, tooltip, flagIn);
		
        if (stack.getTagCompound() != null && nbt.hasKey("usedOn"))
        {
            NBTTagCompound nbt = stack.getTagCompound();

            if (nbt.getTag("usedOn") != null
            {
                NBTTagList list = (NBTTagList) nbt.getTag("usedOn");
        
                for (int i = 0; i < list.tagCount(); ++i)
                {
                    if (list.getStringTagAt(i) == playerIn.getUniqueID().toString())
                    {
                        tooltip.add("Already used by " + playerIn.getDisplayName());
                    }
                }
            }
        }
    }

There, that's better.

You have to add null checks, not everything is present all the time.

I'm going to assume this is a typo, but you have nbt.hasKey() being called before nbt is initialized.

Edited by MythicalChromosome
I just realized nbt could be moved to be initialized earlier and just nullcheck that instead of stack.getTagCompound(), derp
  • Like 1
Posted (edited)
19 minutes ago, MythicalChromosome said:

I'm going to assume this is a typo, but you have nbt.hasKey() being called before nbt is initialized.

    @Override
    @SideOnly(Side.CLIENT)
    public void addInformation(ItemStack stack, World worldIn, List<String> tooltip, ITooltipFlag flag) 
    {
        EntityPlayer playerIn = Minecraft.getMinecraft().player;	
        super.addInformation(stack, worldIn, tooltip, flag);
		
        if (stack.getTagCompound() != null)
        {
            NBTTagCompound nbt = stack.getTagCompound();

            if (nbt.getTag("usedOn") != null && nbt.hasKey("usedOn"))
            {
                NBTTagList list = (NBTTagList) nbt.getTag("usedOn");
        
                for (int i = 0; i < list.tagCount(); ++i)
                {
                    if (list.getStringTagAt(i) == playerIn.getUniqueID().toString())
                    {
                        tooltip.add("Already used by " + playerIn.getDisplayName());
                    }
                }
            }
        }
    }

Sorry, that's better.

Edited by Differentiation
  • Like 1
Posted

Argh, NBT with itemstacks is confusing...

 

Both of my original issues were fixed, but now I have a new one showing up. The item reports a successful usage whenever it's right-clicked with, rather than only the first time it's right-clicked as it's supposed to. The method that's supposed to blacklist entities from using it is definitely being called, but it doesn't seem to be doing anything. I imagine this has something to do with problems reading from or writing to NBT, how would I go about fixing this?

 

@Override
	public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand)
	{
	    NBTTagCompound nbt;
	    ItemStack stack = player.getHeldItem(hand);
	    NBTTagList nbttaglist;

	    if (stack.hasTagCompound())
	    {
	        nbt = stack.getTagCompound();
	    }
	    else
	    {
	        nbt = new NBTTagCompound();
	    }
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    	for (int i = 0; i<nbttaglist.tagCount(); i++){
	    		if (nbttaglist.getStringTagAt(i) == player.getUniqueID().toString()){
	    			System.out.println("Failed to use arrow");
	    			return new ActionResult<ItemStack>(EnumActionResult.FAIL, stack);
	    		}
	    	}
	    }
	    StandHandlingMethods.grantRandomStandFromTable(player, null); //stub so far
	    addEntityToBlacklist(player, nbt, stack);
	    System.out.println("Successfully used arrow");
	    return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
	}
	
	public void addEntityToBlacklist(Entity entity, NBTTagCompound nbt, ItemStack stack){
	    NBTTagList nbttaglist;
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    }
	    else{
	    	nbttaglist = new NBTTagList();
	    }
	    
	    String entityId = entity.getUniqueID().toString();
	    NBTTagCompound compound = new NBTTagCompound();
	    compound.setString("name", entityId);
	    
	    nbttaglist.appendTag(compound);
	    
	    nbt.setTag("usedOn", nbttaglist);
	    
	    System.out.println("Blacklisted " + entityId + " from using this Arrow");
	    
	    stack.setTagCompound(nbt);
	}

	@Override
	@SideOnly(Side.CLIENT)
	public void addInformation(ItemStack stack, @Nullable World worldIn,
			java.util.List<String> tooltip, ITooltipFlag flagIn) {
		
		NBTTagList nbttaglist;
		EntityPlayer player = Minecraft.getMinecraft().player;
		
		
		super.addInformation(stack, worldIn, tooltip, flagIn);
		
		if (stack.getTagCompound() != null){
			NBTTagCompound nbt = stack.getTagCompound();
			if (nbt.getTag("usedOn") != null && nbt.hasKey("usedOn")){
		    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
		    	for (int i = 0; i<nbttaglist.tagCount(); i++){
		    		if (nbttaglist.getStringTagAt(i) == player.getUniqueID().toString()){
		    			tooltip.add("Already used by " + player.getDisplayName());
		    		}
		    	}
		    }
		}
	}

(Reuploaded code because I changed it somewhat significantly in the interrim)

Posted (edited)
5 hours ago, MythicalChromosome said:

Argh, NBT with itemstacks is confusing...

 

Both of my original issues were fixed, but now I have a new one showing up. The item reports a successful usage whenever it's right-clicked with, rather than only the first time it's right-clicked as it's supposed to. The method that's supposed to blacklist entities from using it is definitely being called, but it doesn't seem to be doing anything. I imagine this has something to do with problems reading from or writing to NBT, how would I go about fixing this?

 


@Override
	public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand)
	{
	    NBTTagCompound nbt;
	    ItemStack stack = player.getHeldItem(hand);
	    NBTTagList nbttaglist;

	    if (stack.hasTagCompound())
	    {
	        nbt = stack.getTagCompound();
	    }
	    else
	    {
	        nbt = new NBTTagCompound();
	    }
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    	for (int i = 0; i<nbttaglist.tagCount(); i++){
	    		if (nbttaglist.getStringTagAt(i) == player.getUniqueID().toString()){
	    			System.out.println("Failed to use arrow");
	    			return new ActionResult<ItemStack>(EnumActionResult.FAIL, stack);
	    		}
	    	}
	    }
	    StandHandlingMethods.grantRandomStandFromTable(player, null); //stub so far
	    addEntityToBlacklist(player, nbt, stack);
	    System.out.println("Successfully used arrow");
	    return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
	}
	
	public void addEntityToBlacklist(Entity entity, NBTTagCompound nbt, ItemStack stack){
	    NBTTagList nbttaglist;
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    }
	    else{
	    	nbttaglist = new NBTTagList();
	    }
	    
	    String entityId = entity.getUniqueID().toString();
	    NBTTagCompound compound = new NBTTagCompound();
	    compound.setString("name", entityId);
	    
	    nbttaglist.appendTag(compound);
	    
	    nbt.setTag("usedOn", nbttaglist);
	    
	    System.out.println("Blacklisted " + entityId + " from using this Arrow");
	    
	    stack.setTagCompound(nbt);
	}

	@Override
	@SideOnly(Side.CLIENT)
	public void addInformation(ItemStack stack, @Nullable World worldIn,
			java.util.List<String> tooltip, ITooltipFlag flagIn) {
		
		NBTTagList nbttaglist;
		EntityPlayer player = Minecraft.getMinecraft().player;
		
		
		super.addInformation(stack, worldIn, tooltip, flagIn);
		
		if (stack.getTagCompound() != null){
			NBTTagCompound nbt = stack.getTagCompound();
			if (nbt.getTag("usedOn") != null && nbt.hasKey("usedOn")){
		    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
		    	for (int i = 0; i<nbttaglist.tagCount(); i++){
		    		if (nbttaglist.getStringTagAt(i) == player.getUniqueID().toString()){
		    			tooltip.add("Already used by " + player.getDisplayName());
		    		}
		    	}
		    }
		}
	}

(Reuploaded code because I changed it somewhat significantly in the interrim)

I tried playing with it myself and it just doesn't seem to work. 
You can do it my way by just adding to player capability. I do it this way:

public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand hand)
{
  DinocraftPlayer player = DinocraftPlayer.getEntityPlayer(playerIn);
  
  if (!player.getActions().hasUsedItem1())
  {
    player.setHasUsedItem1(true);
    return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
  }
  else
  {
    return new ActionResult<ItemStack>(EnumActionResult.FAIL, stack);
  }
}

Now the player can't use this item until they die. And then the process repeats.

 

For your case, it is best to use player capabilities since the item usage data is unique to the player itself and not the item.

Edited by Differentiation
Posted

I thought of using capabilities, but from what I see that makes it so that the item can only be used once in total. The idea I was going for was that the player could find more than one of those items, and could only use each one on themselves once. Your solution isn't quite what I'm going for, but I can't figure out how to make it so that each of the items can only be used once EACH without using NBT... hmm.

Posted (edited)
38 minutes ago, MythicalChromosome said:

I thought of using capabilities, but from what I see that makes it so that the item can only be used once in total. The idea I was going for was that the player could find more than one of those items, and could only use each one on themselves once. Your solution isn't quite what I'm going for, but I can't figure out how to make it so that each of the items can only be used once EACH without using NBT... hmm.

Wait, wait, wait, wait!! Are you trying to make it so that you can use the item once PER PLAYER?? Or every player can use that item once. So for example, if I use the item and I give it to another player, should they be able to use it?

Edited by Differentiation
Posted

Yeah. I probably should've made that clear earlier, but it should be like this:

1. Each individual item can only be used once per player, i.e. if a player finds another one they can use that item even if they've already used a different one.

2. Each item can be used an infinite number of times, but only once by any individual player, meaning they're reusable by a different person. So yes, if you give it to another player after using it they should also be able to use it.

Posted (edited)
15 minutes ago, MythicalChromosome said:

Yeah. I probably should've made that clear earlier, but it should be like this:

1. Each individual item can only be used once per player, i.e. if a player finds another one they can use that item even if they've already used a different one.

2. Each item can be used an infinite number of times, but only once by any individual player, meaning they're reusable by a different person. So yes, if you give it to another player after using it they should also be able to use it.

Yeah, I see that's why you used the UUID. I couldn't figure it out myself since I'm not that good at NBTs.

Best of luck figuring out the solution!

Edited by Differentiation
  • Like 1
Posted
20 minutes ago, Differentiation said:

Yeah, I see that's why you used the UUID. I couldn't figure it out myself since I'm not that good at NBTs.

Best of luck figuring out the solution!

Heh, well, thanks for your support anyways. If I figure out a solution to what I was looking for I'll post it here.

 

(Btw, happy new year!)

  • Like 1
Posted
7 minutes ago, MythicalChromosome said:

Heh, well, thanks for your support anyways. If I figure out a solution to what I was looking for I'll post it here.

 

(Btw, happy new year!)

I would like to see the solution if you figure it out. I myself don't have such a good experience with NBT, but I would like to see what you ended up doing.

Happy New Year to you as well. Here in New York, New Year is in 5 hours! :) 

  • Like 1
Posted
On 12/31/2017 at 6:34 PM, Differentiation said:

I would like to see the solution if you figure it out. I myself don't have such a good experience with NBT, but I would like to see what you ended up doing.

Happy New Year to you as well. Here in New York, New Year is in 5 hours! :) 

After a bit more debugging, the solution to my problem turned out to be simple (as it usually tends to be...:P)

 

I wasn't checking against the tag correctly. The method I was using was checking against the entire tag as a string, when it should've been checking against the value. Simply changing the method called made it work perfectly as intended:

public class ItemStandArrow extends Item{
	
	private static final String name = "standArrow";
	public ItemStandArrow()
    {
		super();
        setUnlocalizedName(name);
        setCreativeTab(CreativeTabs.TOOLS);
        setMaxStackSize(1);
    }
	
	@Override
	public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand)
	{
	    NBTTagCompound nbt;
	    ItemStack stack = player.getHeldItem(hand);
	    NBTTagList nbttaglist;

	    if (stack.hasTagCompound())
	    {
	        nbt = stack.getTagCompound();
	    }
	    else
	    {
	        nbt = new NBTTagCompound();
	    }
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    	for (int i = 0; i<nbttaglist.tagCount(); i++){
	    		System.out.println("Checking index " + i + ": "+ nbttaglist.getStringTagAt(i));
	    		if (nbttaglist.getCompoundTagAt(i).getString("name").equals(player.getUniqueID().toString())){
	    			System.out.println("Failed to use arrow");
	    			return new ActionResult<ItemStack>(EnumActionResult.FAIL, stack);
	    		}
	    	}
	    }
	    StandHandlingMethods.grantRandomStandFromTable(player, null); //stub so far
	    addEntityToBlacklist(player, nbt, stack);
	    System.out.println("Successfully used arrow");
	    return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
	}
	
	public void addEntityToBlacklist(Entity entity, NBTTagCompound nbt, ItemStack stack){
	    NBTTagList nbttaglist;
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    }
	    else{
	    	nbttaglist = new NBTTagList();
	    }
	    
	    String entityId = entity.getUniqueID().toString();
	    NBTTagCompound compound = new NBTTagCompound();
	    compound.setString("name", entityId);
	    
	    nbttaglist.appendTag(compound);
	    
	    nbt.setTag("usedOn", nbttaglist);
	    
	    stack.setTagCompound(nbt);
	    
	    System.out.println("Blacklisted " + entityId + " from using this Arrow");
	    
	    
	}

	@Override
	@SideOnly(Side.CLIENT)
	public void addInformation(ItemStack stack, @Nullable World worldIn,
			java.util.List<String> tooltip, ITooltipFlag flagIn) {
		
		NBTTagList nbttaglist;
		EntityPlayer player = Minecraft.getMinecraft().player;
		
		
		super.addInformation(stack, worldIn, tooltip, flagIn);
		
		if (stack.getTagCompound() != null){
			NBTTagCompound nbt = stack.getTagCompound();
			if (nbt.getTag("usedOn") != null && nbt.hasKey("usedOn")){
		    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
		    	for (int i = 0; i<nbttaglist.tagCount(); i++){
		    		if (nbttaglist.getCompoundTagAt(i).getString("name").equals(player.getUniqueID().toString())){
		    			tooltip.add("Already used by " + player.getName());
		    		}
		    	}
		    }
		}
	}
}

So the problem wasn't in writing to and reading from the ItemStack's NBT data, it was in how I was interpreting the data within the program.

 

Hopefully you learned some more about NBT from this, as I did.

Posted
11 minutes ago, MythicalChromosome said:

After a bit more debugging, the solution to my problem turned out to be simple (as it usually tends to be...:P)

 

I wasn't checking against the tag correctly. The method I was using was checking against the entire tag as a string, when it should've been checking against the value. Simply changing the method called made it work perfectly as intended:


public class ItemStandArrow extends Item{
	
	private static final String name = "standArrow";
	public ItemStandArrow()
    {
		super();
        setUnlocalizedName(name);
        setCreativeTab(CreativeTabs.TOOLS);
        setMaxStackSize(1);
    }
	
	@Override
	public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand)
	{
	    NBTTagCompound nbt;
	    ItemStack stack = player.getHeldItem(hand);
	    NBTTagList nbttaglist;

	    if (stack.hasTagCompound())
	    {
	        nbt = stack.getTagCompound();
	    }
	    else
	    {
	        nbt = new NBTTagCompound();
	    }
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    	for (int i = 0; i<nbttaglist.tagCount(); i++){
	    		System.out.println("Checking index " + i + ": "+ nbttaglist.getStringTagAt(i));
	    		if (nbttaglist.getCompoundTagAt(i).getString("name").equals(player.getUniqueID().toString())){
	    			System.out.println("Failed to use arrow");
	    			return new ActionResult<ItemStack>(EnumActionResult.FAIL, stack);
	    		}
	    	}
	    }
	    StandHandlingMethods.grantRandomStandFromTable(player, null); //stub so far
	    addEntityToBlacklist(player, nbt, stack);
	    System.out.println("Successfully used arrow");
	    return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
	}
	
	public void addEntityToBlacklist(Entity entity, NBTTagCompound nbt, ItemStack stack){
	    NBTTagList nbttaglist;
	    
	    if (nbt.hasKey("usedOn")){
	    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
	    }
	    else{
	    	nbttaglist = new NBTTagList();
	    }
	    
	    String entityId = entity.getUniqueID().toString();
	    NBTTagCompound compound = new NBTTagCompound();
	    compound.setString("name", entityId);
	    
	    nbttaglist.appendTag(compound);
	    
	    nbt.setTag("usedOn", nbttaglist);
	    
	    stack.setTagCompound(nbt);
	    
	    System.out.println("Blacklisted " + entityId + " from using this Arrow");
	    
	    
	}

	@Override
	@SideOnly(Side.CLIENT)
	public void addInformation(ItemStack stack, @Nullable World worldIn,
			java.util.List<String> tooltip, ITooltipFlag flagIn) {
		
		NBTTagList nbttaglist;
		EntityPlayer player = Minecraft.getMinecraft().player;
		
		
		super.addInformation(stack, worldIn, tooltip, flagIn);
		
		if (stack.getTagCompound() != null){
			NBTTagCompound nbt = stack.getTagCompound();
			if (nbt.getTag("usedOn") != null && nbt.hasKey("usedOn")){
		    	nbttaglist = (NBTTagList) nbt.getTag("usedOn");
		    	for (int i = 0; i<nbttaglist.tagCount(); i++){
		    		if (nbttaglist.getCompoundTagAt(i).getString("name").equals(player.getUniqueID().toString())){
		    			tooltip.add("Already used by " + player.getName());
		    		}
		    	}
		    }
		}
	}
}

So the problem wasn't in writing to and reading from the ItemStack's NBT data, it was in how I was interpreting the data within the program.

 

Hopefully you learned some more about NBT from this, as I did.

A very silly mistake indeed :P

I'm glad you figured it out.

Happy modding!

  • Like 1

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

    • It is 1.12.2 - I have no idea if there is a 1.12 pack
    • Okay, but does the modpack works with 1.12 or just with 1.12.2, because I need the Forge client specifically for Minecraft 1.12, not 1.12.2
    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
  • Topics

×
×
  • Create New...

Important Information

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