Jump to content

[1.11.2][Solved] No TE special renderer for tessellating


nexusrightsi

Recommended Posts

So, I've decided to finally update my mod to 1.11.2 from 1.7.10. It wasn't really my choice entirely but still this gave me the opportunity to clean up my code/project. Here is the actual question:

in my 1.7.10 project I had a working compost bin that had a tileentity assigned to it just for the custom renderer now the actual part that is in question as to if it is possible to recreate without having to assign it a TE is the actual compost layer that would not be present if the bin is empty but slightly gets raised depending on the fullness of the bin. I got a working TE renderer for this in 1.7.10 but since you don't need a TE anymore for custom models in 1.11.2 I was wondering if it was possible to just use the metadata of the block to calculate the position of the compost layer with and where the rendering of the compost layer would take place? (the compost layer was just a single sided tessellated UV texture)

Edited by nexusrightsi
Link to comment
Share on other sites

If the data your TE is storing can fit within 4 bits, then absolutely you can compress that into metadata.

You'll be having to create a BlockState for it anyway.

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

18 minutes ago, Draco18s said:

If the data your TE is storing can fit within 4 bits, then absolutely you can compress that into metadata.

You'll be having to create a BlockState for it anyway.

Thank you for the fast reply, is there any documentation on this because I'm still quite left in the blue as how block states work?

Link to comment
Share on other sites

3 minutes ago, nexusrightsi said:

Thank you for the fast reply, is there any documentation on this because I'm still quite left in the blue as how block states work?

 

Forge's documentation has an introduction to block states here.

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

Alright, so I roughly get the jest as to what blockstates are applicable to. How would I go about the rendering part in this case? I want to avoid the usage of TE's as much as possible and since I can check the amount of content in the bin with metadata I don't really need a TE other then for the rendering part as far as I am aware right now.

Link to comment
Share on other sites

You make custom JSON files that act as models. Look at the vanilla Cauldron.json it would be the most similar to your case.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

20 minutes ago, nexusrightsi said:

Okay so I've found the cauldron blockstate and models, it appears that there are 4 different models for each of the heights of the water. the thing is I can't read them since Eclipse isn't allowing me to open them in any viewer/editor, so I can't really tell whats going on inside either of them.

 

Open them in a text editor or download and install a plugin for JSON files from the eclipse marketplace. I recommend the second option cause it gives syntax errors.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

Alright, so I mostly succeeded into doing what I originally intended to do although I still need this "if the compost finished breaking down" sort of status so people can actually use buckets on them to retrieve a filled bucket. I figured that I might as well use a PropertyBool for this however I have no clue on how to edit the blockstate json so it gets the correct model. Also, if I say decrease the level metadata(see the cauldron for example of what I mean) does it also just automatically carry over the previous bool or will I have to set it manually each time I decrease or increase the level metadata?

 

 

EDIT: Nevermind, I'm such an idiot for actually not paying attention as to what the top of the block reads. It was a pretty obvious solution on what to change to the BlockState json file for it to work. Thank you all for the help but this is solved ^^

Edited by nexusrightsi
Link to comment
Share on other sites

When you set the BlockState you will use IBlockAccess#setBlockState(BlockPos, IBlockState). To get the IBlockState you will do Block#getDefaultState() which you will set to something in your constructor, but if you want to use a different value than the default you do Block#getDefaultState().withProperty(IProperty, value). The IProperty must be the same instance you used for setting the Default and the BlockStateContainer, if you do not change the value with a IBlockState.withProperty then it will stay at it's default value. It will decrease if you manually change it in the state, and not change the state though this will only happen on the side you change it on so it is better to do it in the way described above also know as changing the state. I recommend a Forge BlockState JSON for this; read about it here.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

1 hour ago, Animefan8888 said:

When you set the BlockState you will use IBlockAccess#setBlockState(BlockPos, IBlockState). To get the IBlockState you will do Block#getDefaultState() which you will set to something in your constructor, but if you want to use a different value than the default you do Block#getDefaultState().withProperty(IProperty, value). The IProperty must be the same instance you used for setting the Default and the BlockStateContainer, if you do not change the value with a IBlockState.withProperty then it will stay at it's default value. It will decrease if you manually change it in the state, and not change the state though this will only happen on the side you change it on so it is better to do it in the way described above also know as changing the state. I recommend a Forge BlockState JSON for this; read about it here.

Thank you for explaining it once again, although I already figured this out and edited my original reply. The only thing I seem to be having an issue with is that the boolean won't switch back to false unless you exit to the main menu and log back into the world. When I set the boolean to true it just works fine without having to re-enter the world weirdly enough...

 

This is my adaption to the method in the cauldron block class which gets called every time you either use an empty bucket or a full bucket on it(works fine)

public void setCompostLevel(World world, BlockPos pos, IBlockState state, int level)
    {
        int i = ((Integer)state.getValue(LEVEL)).intValue();
        boolean isReady = ((Boolean)state.getValue(READY).booleanValue());
        if(i == 0 && isReady)
        {
            world.setBlockState(pos, state.withProperty(READY, Boolean.valueOf(false))); //I even tried to set the BlockState back to the default since its pretty much just a reset of the block.
            world.updateComparatorOutputLevel(pos, this);
        }
        else
        {
            world.setBlockState(pos, state.withProperty(LEVEL, Integer.valueOf(MathHelper.clamp(level, -1, 10))), 2);
            world.updateComparatorOutputLevel(pos, this);
        }
    }

 

the setCompostLevel method doesn't change the boolean back to false until you re-enter the world while on the other hand this method does instantly change the boolean to true

	@Override
    public void updateTick(World world, BlockPos pos, IBlockState state, Random rand)
    {
        int i = ((Integer)state.getValue(LEVEL)).intValue();
        boolean isReady = ((Boolean)state.getValue(READY).booleanValue());
        if (!isReady && i == 10 && !world.isRemote)
        {
            int l;
	            for (l = 0; pos.equals(this); ++l)
            {
                ;
            }
	            if (l < 2)
            {
                world.setBlockState(pos, state.withProperty(READY, Boolean.valueOf(true)));
                world.updateComparatorOutputLevel(pos, this);
            }
        }
    }

Link to comment
Share on other sites

34 minutes ago, Choonster said:

Have you overridden Block#getStateFromMeta and Block#getMetaFromState to convert both properties to metadata and back?

to answer your question:

 

	@Override
    public IBlockState getStateFromMeta(int meta)
    {
        return this.getDefaultState().withProperty(LEVEL, Integer.valueOf(meta));
    }
	    /**
     * Convert the BlockState into the correct metadata value
     */
    @Override
    public int getMetaFromState(IBlockState state)
    {
        return ((Integer)state.getValue(LEVEL)).intValue();
    }

Link to comment
Share on other sites

10 minutes ago, Animefan8888 said:

You never save your boolean value.

I noticed after Choonster mentioning the methods, although I tried to google for examples on multiple state properties. All that I could find was that I had to convert them to bytes instead which beats me, I have no clue whatsoever when it comes to bytes.

Link to comment
Share on other sites

50 minutes ago, nexusrightsi said:

I noticed after Choonster mentioning the methods, although I tried to google for examples on multiple state properties. All that I could find was that I had to convert them to bytes instead which beats me, I have no clue whatsoever when it comes to bytes.

 

To store multiple values in a single integer, you need to use bitwise operations. There are a lot of resources available that explain these, in addition to the vanilla code that uses them.

 

I just realised that your integer property appears to have 11 values, which means that you can't store both it and the boolean property in the metadata. Metadata is limited to 4 bits (2^4 [16] potential values), but the highest value of the integer property (10) already occupies all 4 bits.

 

You'll need to store one of the values in a TileEntity instead of the metadata. If you still need it to determine the block's model, you can keep the property and set it from the TileEntity's value in Block#getActualState instead of storing it in the metadata.

 

You'll also need to override TileEntity#getUpdateTag and TileEntity#getUpdatePacket to sync this value to the client. Override TileEntity#onDataPacket to read the NBT data from the packet and call World#notifyBlockUpdate to redraw the chunk containing the block (so it draws the model for the new value).

 

Call World#notifyBlockUpdate whenever this value changes to send the update packet to the client.

 

You can see some examples of this here:

These blocks store their colour in the metadata and their facing(s) in the TileEntity.

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

6 minutes ago, Choonster said:

 

To store multiple values in a single integer, you need to use bitwise operations. There are a lot of resources available that explain these, in addition to the vanilla code that uses them.

 

I just realised that your integer property appears to have 11 values, which means that you can't store both it and the boolean property in the metadata. Metadata is limited to 4 bits (2^4 [16] potential values), but the highest value of the integer property (10) already occupies all 4 bits.

 

You'll need to store one of the values in a TileEntity instead of the metadata. If you still need it to determine the block's model, you can keep the property and set it from the TileEntity's value in Block#getActualState instead of storing it in the metadata.

 

You'll also need to override TileEntity#getUpdateTag and TileEntity#getUpdatePacket to sync this value to the client. Override TileEntity#onDataPacket to read the NBT data from the packet and call World#notifyBlockUpdate to redraw the chunk containing the block (so it draws the model for the new value).

 

Call World#notifyBlockUpdate whenever this value changes to send the update packet to the client.

 

You can see some examples of this here:

These blocks store their colour in the metadata and their facing(s) in the TileEntity.

I was actually trying to avoid using a TE as much as possible, it would have been so much easier for me If I could have used a TE instead but I don't want to for performance sake. How about I just half the integer propety to 5 to free up space for the boolean?

Link to comment
Share on other sites

Just now, nexusrightsi said:

I was actually trying to avoid using a TE as much as possible, it would have been so much easier for me If I could have used a TE instead but I don't want to for performance sake. How about I just half the integer propety to 5 to free up space for the boolean?

 

There should be a very minimal performance hit if you're using a non-ticking TileEntity to store a value for a baked model. Using a ticking TileEntity or a TESR would be more expensive.

 

Halving the integer property would allow you to store both values in the metadata.

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

40 minutes ago, Choonster said:

 

There should be a very minimal performance hit if you're using a non-ticking TileEntity to store a value for a baked model. Using a ticking TileEntity or a TESR would be more expensive.

 

Halving the integer property would allow you to store both values in the metadata.

Alright, so I halved the integer property and I actually found a thread where you were helping someone else. According to your explanation in the thread this should have worked, which it doesn't. The issue still remains(the boolean doesn't want to go back to false anymore.)

 

	/**
     * Convert the given metadata into a BlockState for this Block
     */
    @Override
    public IBlockState getStateFromMeta(int meta)
    {
        int level = meta & 7;
        boolean isReady = (meta &  != 0;
        
        return getDefaultState().withProperty(LEVEL, level).withProperty(READY, isReady);
    }
	    /**
     * Convert the BlockState into the correct metadata value
     */
    @Override
    public int getMetaFromState(IBlockState state)
    {
        int level = ((Integer) state.getValue(LEVEL)).intValue();
        int isReady = (boolean) state.getValue(READY) ? 1 : 0;
        return isReady << 3 | level;
    }
	    @Override
    protected BlockStateContainer createBlockState()
    {
        return new BlockStateContainer(this, new IProperty[] {LEVEL, READY});
    }
	

Link to comment
Share on other sites

4 hours ago, Choonster said:

That should work, I can't see any obvious errors.

 

Could you post your whole Block class and the FML log (logs/fml-client-latest.log)?

sure thing! here you go.

this is the block class:

http://pastebin.com/fu0JucJj

 

here is the FML latest client log:

http://pastebin.com/RkdbsXPh

Link to comment
Share on other sites

In setCompostLevel, you're only setting READY to false when the existing LEVEL value is 0; you should set it to false when the new LEVEL value is 0 instead. Make sure you still set the new LEVEL value, even when it's 0.
 

You're explicitly boxing, unboxing and casting the primitive values you pass to IBlockState#withProperty and receive from IBlockState#getValue; but there's no need to do this. Java will automatically box and unbox primitive values for you, there's no need to do it yourself. These methods are generic, so they will always use the IProperty's generic type argument as the parameter/return type without the need for casting.The only reason you see this in the vanilla code is because the compiler automatically generates it.

 

Why are you calling World#setBlockState with flags to prevent the comparator output updating and then updating the comparator output manually? Just use the overload without the flags parameter.

 

Why do you handle LEVEL >= 2 and LEVEL == 1 separately in onBlockActivated while doing exactly the same thing for both?

 

You can use ItemHandlerHelper.giveItemToPlayer to insert an item into a player's inventory and drop the remainder on the ground; this saves having to call InventoryPlayer#addItemStackToInventory and EntityPlayer#dropItem.

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

2 hours ago, Choonster said:

In setCompostLevel, you're only setting READY to false when the existing LEVEL value is 0; you should set it to false when the new LEVEL value is 0 instead. Make sure you still set the new LEVEL value, even when it's 0.
 

You're explicitly boxing, unboxing and casting the primitive values you pass to IBlockState#withProperty and receive from IBlockState#getValue; but there's no need to do this. Java will automatically box and unbox primitive values for you, there's no need to do it yourself. These methods are generic, so they will always use the IProperty's generic type argument as the parameter/return type without the need for casting.The only reason you see this in the vanilla code is because the compiler automatically generates it.

 

Why are you calling World#setBlockState with flags to prevent the comparator output updating and then updating the comparator output manually? Just use the overload without the flags parameter.

 

Why do you handle LEVEL >= 2 and LEVEL == 1 separately in onBlockActivated while doing exactly the same thing for both?

 

You can use ItemHandlerHelper.giveItemToPlayer to insert an item into a player's inventory and drop the remainder on the ground; this saves having to call InventoryPlayer#addItemStackToInventory and EntityPlayer#dropItem.

There, thank you for pointing out all these "issues" in my code. I fixed them right away and also noticed what is causing the block not to update properly.

in setCompostLevel I set both the int and boolean and only the last one gets actually update while the first propertie variable is being skipped, so for instance:

world.setBlockState(pos, state.withProperty(LEVEL, Integer.valueOf(MathHelper.clamp(0, 0, 5))));
            world.setBlockState(pos, state.withProperty(READY, false));

just the boolean gets updated, when I reverse that:

note how just the int gets updated now.

            world.setBlockState(pos, state.withProperty(READY, false));
	world.setBlockState(pos, state.withProperty(LEVEL, Integer.valueOf(MathHelper.clamp(0, 0, 5))));
Edited by nexusrightsi
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



×
×
  • Create New...

Important Information

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