Jump to content

[SOLVED][1.12.1] Question about how ItemStack NBT data including capability data for player inventory items is saved / loaded


Recommended Posts

Posted (edited)

So I'm still having trouble with a custom item that holds fluid. Based on a lot of debug tracing, console print statements, and rewriting my code again from scratch, I feel pretty confident that client and server are syncing generally. I see a lot of packets going back and forth, with the itemstacks containing the expected fluid values.

 

However, if I save and then load again, all items that are full of fluid in the player inventory show up as empty.

 

I looked at how other fluid items work such as Universal Bucket and some other mods, but they all seem to use a "two item" system where the empty bucket is a separate item. That doesn't really work for me because I don't want to just be empty/full but want to retain other fluid levels in between. Furthemore I don't see any reason why it shouldn't work -- the level is saved in the NBT.

 

It's driving me crazy. As far as I know, the ItemStack gets the capability NBT appended as part of the fluid handling system, and I explicitly write/update that NBT every time the item is used to fill or drain a block. 

 

So as far as I can say the NBT is working in game, but failing to save and load? What can be wrong?

 

My code: https://github.com/jabelar/ExampleMod-1.12/blob/master/src/main/java/com/blogspot/jabelarminecraft/examplemod/items/fluidcontainers/ItemSlimeBag.java

 

Note that right now I'm using a bucket texture for testing, but you can find the empty and full versions of the "slime bag" item in the Miscellaneous creative tab if you go through the trouble of trying to run my code.

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)

Okay, so something is definitely weird. to debug this issue I handled the PlayerEvent.SaveToFile and LoadFromFile events and printed out the player inventory in each case.

Then I started a game and put a full (amount = 1000) item slime bag in my inventory and then saved and quit. Then I loaded the game. Here is the console output:

 

[23:17:30] [Server thread/INFO]: Saving and pausing game...
Saving Player To File With main inventory: 1xitem.slime_bag@0 {Fluid:{FluidName:"slime",Amount:1000}} 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null [23:17:30] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.EventHandler:onEvent:2053]:  
[23:17:30] [Server thread/INFO]: Saving chunks for level 'Copy of Copy of Copy of Copy of'/overworld
[23:17:31] [Server thread/INFO]: Saving chunks for level 'Copy of Copy of Copy of Copy of'/the_nether
[23:17:31] [Server thread/INFO]: Saving chunks for level 'Copy of Copy of Copy of Copy of'/the_end
[23:17:32] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.MainMod:fmlLifeCycle:227]: Server stopping
[23:17:32] [Server thread/INFO]: Stopping server
[23:17:32] [Server thread/INFO]: Saving players
Saving Player To File With main inventory: 1xitem.slime_bag@0 {Fluid:{FluidName:"slime",Amount:1000}} 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null [23:17:32] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.EventHandler:onEvent:2053]:  
[23:17:32] [Server thread/INFO]: MistMaestro lost connection: Disconnected
[23:17:32] [Server thread/INFO]: MistMaestro the Wise left the game
[23:17:32] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.EventHandler:onEvent:1830]: Player logged out
Saving Player To File With main inventory: 1xitem.slime_bag@0 {Fluid:{FluidName:"slime",Amount:1000}} 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null [23:17:32] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.EventHandler:onEvent:2053]:  
[23:17:32] [Server thread/INFO]: Stopping singleplayer server as player logged out
[23:17:32] [Server thread/INFO]: Saving worlds
[23:17:32] [Server thread/INFO]: Saving chunks for level 'Copy of Copy of Copy of Copy of'/overworld
[23:17:32] [Server thread/INFO]: Saving chunks for level 'Copy of Copy of Copy of Copy of'/the_nether
[23:17:32] [Server thread/INFO]: Saving chunks for level 'Copy of Copy of Copy of Copy of'/the_end
[23:17:32] [Server thread/INFO] [FML]: Unloading dimension 0
[23:17:32] [Server thread/INFO] [FML]: Unloading dimension -1
[23:17:32] [Server thread/INFO] [FML]: Unloading dimension 1
[23:17:33] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.items.fluidcontainers.ItemSlimeBag:getSubItems:117]: Filled bag and adding as sub-item = 1xitem.slime_bag@0 with amount = 1000
[23:17:33] [Server thread/INFO] [FML]: Applying holder lookups
[23:17:33] [Server thread/INFO] [FML]: Holder lookups applied
[23:17:33] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.MainMod:fmlLifeCycle:241]: Server stopped
[23:17:37] [Server thread/INFO]: Starting integrated minecraft server version 1.12.1
[23:17:37] [Server thread/INFO]: Generating keypair
[23:17:37] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.MainMod:fmlLifeCycle:183]: Server about to start
[23:17:37] [Server thread/INFO] [FML]: Injecting existing registry data into this server instance
[23:17:37] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.items.fluidcontainers.ItemSlimeBag:getSubItems:117]: Filled bag and adding as sub-item = 1xitem.slime_bag@0 with amount = 1000
[23:17:38] [Server thread/INFO] [FML]: Applying holder lookups
[23:17:38] [Server thread/INFO] [FML]: Holder lookups applied
[23:17:38] [Server thread/INFO] [FML]: Loading dimension 0 (Copy of Copy of Copy of Copy of) (net.minecraft.server.integrated.IntegratedServer@ab956e8)
[23:17:38] [Server thread/INFO]: Loaded 488 advancements
[23:17:38] [Server thread/INFO] [FML]: Loading dimension 1 (Copy of Copy of Copy of Copy of) (net.minecraft.server.integrated.IntegratedServer@ab956e8)
[23:17:38] [Server thread/INFO] [FML]: Loading dimension -1 (Copy of Copy of Copy of Copy of) (net.minecraft.server.integrated.IntegratedServer@ab956e8)
[23:17:38] [Server thread/INFO]: Preparing start region for level 0
[23:17:38] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.MainMod:fmlLifeCycle:199]: Server starting
[23:17:38] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.MainMod:fmlLifeCycle:213]: Server started
[23:17:39] [Server thread/INFO]: Changing view distance to 12, from 10
[23:17:39] [Netty Local Client IO #1/INFO] [FML]: Server protocol version 2
[23:17:39] [Netty Server IO #3/INFO] [FML]: Client protocol version 2
[23:17:39] [Netty Server IO #3/INFO] [FML]: Client attempting to join with 5 mods : [email protected],[email protected],[email protected],[email protected],[email protected]
[23:17:39] [Netty Local Client IO #1/INFO] [FML]: [Netty Local Client IO #1] Client side modded connection established
[23:17:39] [Server thread/INFO] [FML]: [Server thread] Server side modded connection established
Loading Player from File With main inventory: 1xitem.slime_bag@0 {Fluid:{FluidName:"slime",Amount:0}} 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null 1xtile.air@0 null [23:17:39] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.EventHandler:onEvent:2069]:  
[23:17:39] [Server thread/INFO]: MistMaestro[local:E:e05009fa] logged in with entity id 5235 at (102.5, 66.0, 254.5)
[23:17:39] [Server thread/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.EventHandler:onEvent:1060]: NameFormat event for username = MistMaestro
[23:17:39] [Server thread/INFO]: MistMaestro the Wise joined the game

 

So you see that it saves with a fluid tag amount = 1000 but then it loads with amount = 0. What's going on here?

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted
1 hour ago, diesieben07 said:

The only suspicious things I can see are those static "EMPTY" fields. Those are usually a bad idea, because ItemStacks are mutable.

That's interesting. It didn't help but I understand it could be a problem. I actually did it that way because ItemStack itself has an EMPTY that is static final. But I realize now that that probably is intended to only be used for comparing things to, not to be used to be assigned to things. But even that is kinda dangerous -- like imagine a container starts with slots all set to EMPTY (common) and your code takes that stack and increases the size or adds an item, rather than replacing the whole stack.....

 

Okay, back to the problem I think I have some insight. The problem is the order of the init capabilities, or maybe I should say that the loading of NBT doesn't like it if there is already an NBT present. As far as I can tell the order of loading a saved itemstack goes like this:

  1. ItemStack is constructed using the ItemStack(NBTCompound) constructor which:
    • Reads any "capNBT" for capabilities
    • Reads other regular item stack stuff -- item, amount and metadamage
    • Checks to make sure that the information is valid (i.e. that the item exists, amount is positive, damage is valid range)
    • calls ItemStack.ForgeInit().
  2. ForgeInit() is responsible for instantiating the capabilities. It:
    • calls the raw item's initCapabilities() which returns a new FluidHandler. During construction of the FluidHandler:
      • I set the fluid stack to "EMPTY" (now based on diesieben07's recommendation I make a copy of it).

 

So it is the problem -- I'm setting the actual fluid stack instance to empty even though the fluid NBT data has already been read in.

 

To fix it i have to modify the constructor of the fluid handler to check for existing NBT data and then instantiate the fluid stack accordingly. Sort of makes sense, but a little tricky. I think a lot of people make fluid containers that are simply full or empty and have then created a two-item approach. But if you want to preserve levels in between you need a single item that handles the loading of previous level...

 

Anyway SOLVED!

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

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



×
×
  • Create New...

Important Information

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