Jump to content

How can I tell which properties are not saved to disk?


Captain_Chaos

Recommended Posts

Hello everyone,

I'm writing a mod to dump Minecraft's block database to a file, to get canonical data to use in WorldPainter (a map generator I've created). I'm using Block.getBlockById(int) to get each block, then getStateFromMeta(int) to get all the possible states and then getProperties() to get the properties of each state.

I'm most of the way there, but one hiccup  I'm encountering is that some of the block state properties are transient/runtime properties which are not saved to disk (if I understand correctly). Examples would be the snowy property of Dirt blocks and the occupied property of Bed blocks. These properties are not of interest to WorldPainter, so I would like to filter them out. Is there a way to tell which properties are transient/runtime and will not be saved to disk, so I can skip those?

Many thanks in advance for any assistance!

Cheers,
Captain_Chaos

Link to comment
Share on other sites

14 minutes ago, Captain_Chaos said:

I'm using Block.getBlockById(int) to get each block, then getStateFromMeta(int) to get all the possible states

Bad modder, no cookie.

Integer block IDs are not guaranteed to always be the same from save to save, you must iterate over Blocks.REGISTRY.  Additionally, not all integer states are "valid" blocks.


Here's how you can get all valid block states for a given block:

BlockStateContainer bsc = block.getBlockState();
ImmutableList<IBlockState> values = bsc.getValidStates();

 

  • Like 1

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

@Draco18s thanks for your reply! I should perhaps clarify what I'm trying to do. For vanilla blocks, the block ID's and data values are guaranteed to be the same from save to save, because that's how Minecraft stores them on disk (for now). The reason I'm getting the blocks and block states this way is because I need a mapping from vanilla block ID and data value to block name and properties.

 

This is not relevant to my actual question however, which is if there is a way to know which properties are runtime or transient properties which are not stored in the chunks. BlockStateContainer.getValidStates() returns all of them, including transient properties.

Link to comment
Share on other sites

@diesieben07, let me explain in more detail what I'm doing. I'm the author of WorldPainter, a map generator for Minecraft. It's a stand-alone program that generates Minecraft chunks directly to create a Minecraft map according to your own design which you can then load in Minecraft to play in. Minecraft (up to now) stores blocks and their states on disk as block IDs and data values. There are no block names or properties (at least not in a vanilla map), so I couldn't use those if I wanted to. I really do need to touch integer IDs.

Minecraft 1.13 however will store blocks by their names and properties. I would like WorldPainter to provide continuity between pre- and post 1.13 versions of Minecraft, so I want to correlate the pre-1.13 block ID and data values with their corresponding post-1.13 block names and states. For vanilla blocks only, I'm not trying to support mod blocks.

This mod I'm creating isn't intended as an actual mod to be used by anyone, I'm just using it as the quickest and easiest way to invoke the Minecraft API and interrogate its block database to establish this mapping (on the assumption that the names and states already used at runtime by MC 1.12.2 will be how they will be stored on disk by MC 1.13, which seems reasonable). I've already implemented the part everybody keeps telling me won't ever work, which is retrieving all the block names and states for every valid combo of block ID and data value and writing them to a file.

This just leaves the actual question I asked, which is if there is a way of determining which of the properties contained in the block states are ephemeral properties that are not stored on disk but calculated at runtime, such as the two examples I gave?

Edited by Captain_Chaos
linkify WorldPainter
Link to comment
Share on other sites

@diesieben07, that implies that WorldPainter would just have to keep creating 1.12.2 maps forever, relying on Minecraft to convert them to 1.13 and later and never supporting any new blocks or other features past version 1.12.2. I hope you can see that that would not be very satisfactory.

Perhaps it would clarify things to take a look at WorldPainter (I've linked it in my previous message) to see what it does exactly, and why I might like to map the block IDs and data values currently used on disk by Minecraft to the names and properties it will use from version 1.13, for instance so that it can load existing worlds yet export them to MC 1.13, keep supporting exports to pre-1.13 MC, etc., etc.

Link to comment
Share on other sites

 First of all, your assumption that vanilla block ids don't change is wrong. As mentioned above you need converters (and those come built-in) from older versions to newer versions. If you are worried about having your mod's users sharing older painted world files you can just run the same conversion code or copy it as a feature in your mod.

 

Within a version, you should use registry name as the unique, guaranteed-to-work key for each block, both vanilla and modded.

 

An important thing with any save / asset format is to have a versioning system. If you include the version of Minecraft used during the initial painting in your save file then it should be easy to key off that when your mod loads it.

 

Alternatively, you can save the results as a normal world save and it will all just work out on its own. Do you really need your own file format?

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

Link to comment
Share on other sites

@jabelar, thanks. WorldPainter (which is not a mod) has existed since 2011 and you can still load world files from back then, and it can still export worlds to Minecraft 1.1 (not a typo), so I know a little bit about versioning, converting block IDs, etc.

I want to use registry names within a version, but I also want to correlate them to the block IDs and data values of previous versions, for various valid reasons which I've tried to explain, and are of no relevance here anyway. I'm only using Forge temporarily in order to get this information from Minecraft.

None of this is relevant to my actual question, which has nothing to do with integers, converters, etc.. I just gave this information for background, which I can now see was a mistake. I'm also not looking for programming advice. Would it be possible for someone to address the question I'm actually asking? Many thanks in advance!

  • Like 1
Link to comment
Share on other sites

1 hour ago, diesieben07 said:

If you want to generate 1.13 worlds, generate 1.13 worlds.

 

5 hours ago, diesieben07 said:

Do not touch integer IDs. Ever.

 

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

Alright, I give up. What a disappointing response. This is the most cliquish, unhelpful, dismissive forum I've encountered in a long time. Not one of you took the time to understand the context, or gave me the benefit of the doubt and answered a simple question about the Forge API. All I got was high and mighty second guessing based on a cursory skim of my question as if I'm some kind of noob writing My First Mod.

You'll all be glad to know that in the mean time I figured out an alternate way to achieve my goal and I now have the complete ID to name mapping which according to you would either be impossible to get, or herald the End Times.

Thanks for your time.

  • Like 1
Link to comment
Share on other sites

@Captain_Chaos We totally understand the context of your question. But you're not understanding our reservations in giving an answer.

 

Firstly, the problem is that the decision on what properties gets converted to meta (and thus saved) is hard-coded in the source for each block in the getStateFromMeta() and the getMetaFromState() methods. I suppose someone somewhere might have generated a complete table but I haven't seen it. If you really wanted this, I think you'd have to do the following:

  1. Iterate through the registry to get all registered blocks.
  2. Take a block state instance and loop through all the valid values of all the valid properties. I'm not sure the exact methods, but I've seen them before and you seem good enough with coding to track these down. 
  3. Print out the block and property values along with the getMetaFromState().
  4. Identity duplicate meta values and infer that the property that changes does not affect meta there is not saved.

I hope you understand what I mean. Basically you need to do a brute force dump because there isn't a simple mapping. That can give you the full list for the actually saved possible combinations for the current version.

 

But the next problem is that there isn't necessarily a one-to-one or even a "closed form" (like a simple table) mapping between any two Minecraft versions. As an example, fences which currently use transient states for connecting visually are apparently moving to saved block states (or maybe even separate blocks) with the 1.13 flattening. 

 

So personally, I would rely on the Minecraft world save converter code (once available) as the definitive approach to converting. Presumably they will think through all the conversions and special cases. 

Edited by jabelar
  • Like 1

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

Link to comment
Share on other sites

As you know, for any given block, only states returned by getStateFromMeta(int) are stored to disk.  Additional states returned by getValidStates() are not.  Your best bet would be to see what properties in the set of states returned by iterating through metadata 0-15 never change (and do change in getValidsStates()).  All 16 states returned for the dirt block from getStateFromMeta for instance will be snowy=false, as that is not stored.

 

This will not be true in 1.13, where blocks will not be limited to 16 (storable) states.  Presumably every possible state will be stored.

 

I'm not getting the pushback here.  His mod deals with stored world data files, and the integers are still heavily used in the anvil files.  This will change of course, but is totally applicable for a program that runs without even having Minecraft (with its nice int to blockstate mapping) running.  If you're going to deal with savefiles, there's going to be some numbers involved.  Of course things will get more complex in 1.13!  Which will of course include the numbers to blockstate mappings in the savefiles, but those are not yet in 1.12 and below, so again I really don't get the pushback against using the numbers.  You simply have to when dealing with (generating, editing) savefiles without Minecraft running.

Edited by MamiyaOtaru
  • Like 2
Link to comment
Share on other sites

1 hour ago, MamiyaOtaru said:

If you're going to deal with savefiles, there's going to be some numbers involved.  Of course things will get more complex in 1.13! 

The point is, in 1.13, because of The Flattening, integer IDs may not be used at all. Dirt and Coarse Dirt will be saved as separate blocks (!)

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

I think OP should talk a bit with MCEdit devs, since this tool is known to work with vastly different save format (alpha, beta, anvil).
Anyway, the way he "give up" here and talking about "finding another solution" makes me sure i will never use WorldPainter anymore. I'm not going to risk lose my saves due to miscommunication from him.

Link to comment
Share on other sites

15 hours ago, MamiyaOtaru said:

I'm not getting the pushback here. 

 

I agree. While I think his approach to invent a new format is unnecessary and therefore unadvised, there is nothing "dangerous" about what he's doing and it is his "loss" if he wants to face the extra effort and bugs.

 

In case he or other people encounter this thread in the future, the general answer to "what is complete list of all saved block properties" is what both MamiyaOtaru and I said -- you have to do your own iteration through all the getMetaFromState() methods because the properties that are saved are hard-coded. There is no simple field in the property and no master map.

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

Link to comment
Share on other sites

Draco18s, diesieben07, maybe instead of being dicks you could write a few paragraphs on a wiki page somewhere about why people shouldn't use IDs and what they can do as an alternative.
Then when you run into this situation again you can point people toward something constructive and helpful that they can digest and understand, so that everyone has the same information before continuing the conversation.

Then Captain_Chaos or MamiyaOtaru can contribute a new section to the wiki page and everyone can learn something.

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.