Jump to content

[solved][1.12.2] Saving Hashset to NBT


Lambda

Recommended Posts

Hey everyone.

 

So I have this block that takes enchants from items and turns it into "enchant essence", this part of the block works great, however I also want the block to "learn" the enchants given, so it can be applied to a different item using said essence. I have most of that system figured out; the only part I don't is:

  • Saving all given enchants to a hashset, then storing it to NBT
  • Have a list of buttons (with a scroll menu) for the user to select their enchant, and have another set of buttons to display what level of enchant (have this  figured out other than the scroll menu )

So my question is: How can I save the array list to NBT & create a list of buttons (via scroll menu) to display all enchants?

 

 

Edited by Lambda
dog jumped on keyboard and did a lot of shit LOL

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

A HashSet is just a collection of values, so you can save it to an NBTTagList. If all you're storing in the HashSet is the enchantment types (i.e. Enchantment instances), you can save the registry names to the NBTTagList.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I quite literally just did this the othe day. Feel free to take a look at the code. What it does is generate two numbers and stores them. It coverts one of the number to the string value which acts as the key (since that works for my uses) and then it simply stores the whole set in a tag list. 

 

https://hastebin.com/netoleheya.cpp

 

You can ignore the commented HashMap as I used that originally to make sure that no values were getting lost and calculated incorrectly. I commented it out but just forgot to remove it from the code base. Feel free to take an edit as you need for your uses.

Edited by HalestormXV
Link to comment
Share on other sites

Okay, so I got completely rid of the hashmap and I'm now using:

	public NBTTagList enchantNBT = new NBTTagList();

and every time an Item is used by the machine -- this line runs:

							this.enchantNBT.appendTag(itemInput.getEnchantmentTagList());

 

However, I'm having issues with finding how to save this NBTListTag to the TE's NBT.

 

thanks for the help!

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

You should not be using NBT for runtime data.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Oh yeah, for some reason that totally slipped my mind.

 

So still have the hashmap, still save to it every time it needs to. However, how do I write to it then? Do I iterate through the hashmap and append it to the TagList within the write NBT method? Then how would I read it and assign it back to the map?

 

Thanks

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

When writing to NBT, iterate through the HashSet and add a tag for each entry to the NBTTagList. When reading from NBT, iterate through the NBTTagList and add an entry for each tag to the HashSet. Note that you don't need to store the NBTTagList in a field or use it at runtime in any way, just read it from/write it to the NBTTagCompound argument of the TileEntity#readFromNBT/writeToNBT methods.

 

Forge patches NBTTagList to implement Iterable<NBTTagBase>, but you can't really do much with an NBTTagBase without casting it to the appropriate subtype so it's not all that useful. Instead, you'll probably want to use a numeric for loop with NBTTagList#tagCount and NBTTagList#getStringTagAt.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

ok, so I think I have it mostly right, however I'm getting a crash:

Spoiler

[11:36:36] [Server thread/ERROR]: Encountered an unexpected exception
net.minecraft.util.ReportedException: Exception ticking world
	at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:835) ~[MinecraftServer.class:?]
	at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:741) ~[MinecraftServer.class:?]
	at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:192) ~[IntegratedServer.class:?]
	at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:590) [MinecraftServer.class:?]
	at java.lang.Thread.run(Unknown Source) [?:1.8.0_111]
Caused by: java.lang.NullPointerException
	at com.unassigned.customenchants.blocks.tile.TileEntityEnchantmentFab.writeSyncableNBT(TileEntityEnchantmentFab.java:71) ~[TileEntityEnchantmentFab.class:?]
	at com.unassigned.customenchants.blocks.tile.base.TileEntityBase.getUpdateTag(TileEntityBase.java:111) ~[TileEntityBase.class:?]
	at net.minecraft.network.play.server.SPacketChunkData.<init>(SPacketChunkData.java:51) ~[SPacketChunkData.class:?]
	at net.minecraft.server.management.PlayerChunkMapEntry.sendToPlayers(PlayerChunkMapEntry.java:161) ~[PlayerChunkMapEntry.class:?]
	at net.minecraft.server.management.PlayerChunkMap.tick(PlayerChunkMap.java:212) ~[PlayerChunkMap.class:?]
	at net.minecraft.world.WorldServer.tick(WorldServer.java:236) ~[WorldServer.class:?]
	at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:829) ~[MinecraftServer.class:?]
	... 4 more

 

Which points to this line:

        	enRegStorage.setString(e.getRegistryName().toString(), e.getRegistryName().toString());

within this block of code in the writeNBT:

    	NBTTagList enchantList = new NBTTagList();
    	NBTTagCompound enRegStorage = new NBTTagCompound();
        
        for(Enchantment e : knownEnchants) {
        	enRegStorage.setString(e.getRegistryName().toString(), e.getRegistryName().toString());
        }
        enchantList.appendTag(enRegStorage);
        compound.setTag("enchantList", enchantList);

 

Now I know the line I wrote is wrong, because visually it doesn't look right, however thinking about it, it makes since.

and for reading I'm doing this:

        NBTTagList list = compound.getTagList("enchantList", 10);
        if(list != null) {
        	for(int i = 0; i < list.tagCount(); i++) {
        		Enchantment theEnch = Enchantment.getEnchantmentByLocation(list.getStringTagAt(i));
        		knownEnchants.add(theEnch);
        	}
        }

 

 

thanks.

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

Yeah, and I thought this when coding it, but I'm so inexperienced within NBT that I can't figure out whats wrong.

 

So instead of creating a new NBTTagCompound, I'm going to use the one within the method itself.

How would my write method be written as then? I find all enchants within the hashmap, get their registry name then how would I write it to an NBTTagList then store it to the compound?

 

Thanks.

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

For some reason, I thought setting it would be like "NBTTagString.setString()", however I did realize it is set in the contructor

 

So something like this?

    	NBTTagList enchantList = new NBTTagList();

        for(Enchantment e : knownEnchants) {
        	NBTTagString eString = new NBTTagString(e.getRegistryName().toString());
        	enchantList.appendTag(eString);
        }
        compound.setTag("enchantList", enchantList);

 

Edited by Lambda

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

Tip: I highly recommend that when implementing tag functionality, especially if you're not highly familiar with it, that you print out the compounds to the console/logger throughout your code that reads and writes it. It can much more quickly get you a sense of what is going on.

 

NBT is technically very simple, but I think it can be confusing (for beginners) because you can "nest" them in different ways. You can have compounds of mixed types, lists of compounds, compounds of lists, and so forth. Furthermore, the reading and writing need to be perfectly "reciprocal" which a lot of people mess up. So seeing the compounds in print statements I find is extremely helpful to track what is going on.

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

Link to comment
Share on other sites

Yeah, I understand the basic concept of NBT, however when it comes down to other types of things (like creating NBTLists or strings) it just gets confusing, I only know writing to a compound values of my TE and having them saved and loaded back in. Thanks for the tip.

 

Also, I test my code above and still got the same crash, on this line however:

        	NBTTagString eString = new NBTTagString(e.getRegistryName().toString());

and I still cant see what I'm doing wrong

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

Okay now I check if e!=null and it doesn't crash anymore, however the list still resets when I leave and join the game:

[13:40:56] [Server thread/INFO] [STDOUT]: [com.unassigned.customenchants.blocks.tile.TileEntityEnchantmentFab:update:111]: [net.minecraft.enchantment.EnchantmentLootBonus@5d98364c, net.minecraft.enchantment.EnchantmentDurability@cea67b1]

rejoins:

[13:41:04] [Server thread/INFO] [STDOUT]: [com.unassigned.customenchants.blocks.tile.TileEntityEnchantmentFab:update:111]: []

here is updated code:

write:

    	NBTTagList enchantList = new NBTTagList();

        for(Enchantment e : knownEnchants) {
        	if(e != null) {
        		NBTTagString eString = new NBTTagString(e.getRegistryName().toString());
        		enchantList.appendTag(eString);
        	}
        }
        compound.setTag("enchantList", enchantList);

read:

        NBTTagList list = compound.getTagList("enchantList", 10);
        if(list != null) {
        	for(int i = 0; i < list.tagCount(); i++) {
        		Enchantment theEnch = Enchantment.getEnchantmentByLocation(list.getStringTagAt(i));
        		knownEnchants.add(theEnch);
        	}
        }

 

 

thanks for your help!

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

I'm still confused:

		NBTTagList list = compound.getTagList("enchantList", Constants.NBT.TAG_COMPOUND);

So is the issue, correct? 

And what I'm trying to see is that the main reason why this isn't working is because i'm asking for a TAG_COMPOUND when I really want a Tag List? As you mentioned, minecraft ignores the different type, so how would I end up doing this then?

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Link to comment
Share on other sites

Join the conversation

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

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

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

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

×   Your previous content has been restored.   Clear editor

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

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

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