I'm trying to make so that only one class is needed to name the subblocks from any metablock that uses this class registration, i.e., naming them as if they were a parameter value, but without using one.
As you know, a metablock is composed of subblocks. Each subblock needs a name to identify it. So, in my mod, these names are listed in the class ExampleItemBlock in a String[], and then are named in the format MetablockName.SubBlockName (e.g.: ExampleMetablock.blue, ExampleMetablock.green, etc.), using
// ExampleItemBlock Class
public static final String[] SUBNAMES = new String[] {"blue", "green", "yellow"};
@Override
public String getUnlocalizedName(ItemStack itemStack)
{
int i = itemStack.getItemDamage();
return getUnlocalizedName() + "." + SUBNAMES[i];
}
Then, the metablock ExampleMetablock is instantiated and registered using
// Class where the registrations are made
public static Block ExampleMetablock = new ExampleMetablock();
GameRegistry.registerBlock(ExampleMetablock, ExampleItemBlock.class, "ExampleMetablock");
After this, everything works with no problem, however I have to create a new *ItemBlock class for each new metablock I make, and I don't think this is a good or appropriate thing to do, and I think it's better to create one single class that will be used by any future metablock.
As you know, the second parameter of the GameRegistry.registerBlock() method for metablocks requires a value of type Class. And that's the problem: how would I turn the ExampleItemBlock class dynamic without using instances?
I even tried to add a String[] parameter in ExampleItemBlock constructor and then use an instance with the names in place of the class, but just as expected it stated type mismatch.
I searched everywhere for someway to achieve that, but I only found two ways:
1. create an ItemBlock class for each new metablock; 2. use a for inside getUnlocalizedName() and name the subblocks as numbers instead of names (e.g.: ExampleMetablock.0, ExampleMetablock.1, etc.), not needing to use String[] or anything, and making it an universal class. However, this way is also very impractical, because this complicates a lot when identifying which subblock is which.
I also searched through some mods on GitHub, but didn't found anything related to this in the code (that I know).
So my question is: is there someway to make an universal *ItemBlock class, but still naming subblocks with names (words)?
You're overthinking this, your existing code will work fine.
You don't pass an instance of ExampleItemBlock to GameRegistry#registerBlock(), you pass it a Class object that contains ExampleItemBlock and it instantiates ExampleItemBlock for you.
Also, a for loop inside getUnlocalisedName, would do absolutely nothing; the result would be an instance of the String class, just like the result of your current implementation of getUnlocalisedName.
Rollback Post to RevisionRollBack
Please don't PM me asking for help, I will just redirect you to the appropriate forum, where there are others who are far more skilled than me.
You're overthinking this, your existing code will work fine.
Also, a for loop inside [i]getUnlocalisedName[/i], would do absolutely nothing; the result would be an instance of the String class, just like the result of your current implementation of [i]getUnlocalisedName.[/i]
Yes, I know it works fine, but I'm trying to find a way to do it using only one class, instead of a new one for each metablock.
Regarding the for loop, forget what I said, my bad, I checked again now and actually it has nothing to do with for, but actually just replacing SUBNAMES[i] with i or itemStack.getItemDamage();
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Vanilla already has a class that does this: ItemMultiTexture. Look at how it stores and uses its array of names.
So ItemMultiTexture would be a replacement for ItemBlockWithMetadata? And to use it I need to extend it, right? And so the super() would have three parameters instead of two. But how will I set the value of the String[] parameter if I can't instantiate it?
You don't need to extend it, just use GameRegistry.registerBlock(Block, Class<? extends ItemBlock>, String, Object...) to pass arguments (the Object vararg) to the constructor. In this case, you need to pass the Block and the array of names.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Note that you will still be restricted to a maximum of 16 sub-blocks per item due to the way the GameRegistry and Blocks function in Minecraft.
Note also that unlike most other cases, you have to explicitly declare the 'new Object[]{new String[]{}}' when registering the block, at least from my experience.
GameRegistry.registerBlock(yourBlock, ItemMultiTexture.class, "base_name", new Object[]{new String[]{"subtype_a", "subtype_b"}});
Also, I ended up extending ItemMultiTexture due to issues with the constructor requiring 2 Block instances - for whatever reason, Forge wasn't having it (probably just needed to pass an extra argument to #registerBlock or something, but couldn't be bothered to fuss with it too much at the time).
You don't need to extend it, just use GameRegistry.registerBlock(Block, Class, String, Object...) to pass arguments (the Object vararg) to the constructor. In this case, you need to pass the Block and the array of names.
But what about the expressions inside getUnlocalizedName()? They need to have access to the Object[]'s values set in the parameter. Do I need to add an Object[] parameter to ExampleItemBlock's constructor? Would it get the values just like it does with the block parameter?
Note also that unlike most other cases, you have to explicitly declare the 'new Object[]{new String[]{}}' when registering the block, at least from my experience.
GameRegistry.registerBlock(yourBlock, ItemMultiTexture.class, "base_name", new Object[]{new String[]{"subtype_a", "subtype_b"}});
Oh, now I get it, I have to change the class in the parameter to ItemMultiTexture, as it does the same thing and more than ExampleItemBlock, and is compatible.
I'll finish it up then test to see if everything goes well.
But what about the expressions inside getUnlocalizedName()? They need to have access to the Object[]'s values set in the parameter. Do I need to add an Object[] parameter to ExampleItemBlock's constructor? Would it get the values just like it does with the block parameter?
GameRegistry finds the constructor matching the types of the values in the object array and calls that, you don't need a constructor with an Object[] argument. The ItemMultiTexture constructor stores the name array in an instance field, then getUnlocalizedName uses that field.
This code:
GameRegistry.registerBlock(block, ItemBlockFooBar.class, "foobar", new Foo(), new Bar());
Will call this constructor:
ItemBlockFooBar(Block block, Foo foo, Bar bar)
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
OK, bad news... Forge crashes in preInit stage and throws the error
java.lang.NoSuchMethodException: net.minecraft.item.ItemMultiTexture.<init>(net.minecraft.block.Block, [Ljava.lang.String;)
at exampleMod.init.ModBlocks.init(ModBlocks.java:42) // Line 42 is where the ExampleMetaBlock is registered.
The relevant lines:
public static final String[] SubNames = new String[] {"blue", "green", "yellow", "red"};
public static Block ExampleMetablock = new ExampleMetablock(Material.rock, "ExampleMetablock", Tabs.ExampleModTab, SubNames);
// The line below is where the error occurs.
GameRegistry.registerBlock(ExampleMetablock, ItemMultiTexture.class, "ExampleMetablock", new Object[]{SubNames});
That's because there's no ItemMultiTexture(Block, String[]) constructor, only ItemMultiTexture(Block, Block, String[]). I don't know why it needs the same Block twice, maybe it's a leftover from older versions.
Either pass the Block in the vararg before the name array or create a class that extends ItemMultiTexture and has a (Block, String[]) constructor that calls the ItemMultiTexture(Block, Block, String[]) constructor.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
That's because there's no ItemMultiTexture(Block, String[]) constructor, only ItemMultiTexture(Block, Block, String[]).
(...) or create a class that extends ItemMultiTexture and has a (Block, String[]) constructor that calls the ItemMultiTexture(Block, Block, String[]) constructor.
Alright, I created an alternative class that supers ItemMultiTexture, aaaand it worked! \o/ Finally metablocks using a dynamic class.
Thank you very much for you guy's help and patience! =D
public static final String[] SubNames = new String[] {"blue", "green", "yellow", "red"};
public static Block ExampleMetablock = new ExampleMetablock(Material.rock, "ExampleMetablock", Tabs.ExampleModTab, SubNames);
GameRegistry.registerBlock(ExampleMetablock, ItemMultiTextureHelper.class, "ExampleMetablock", new Object[]{SubNames});
ItemMultiTextureHelper class:
public class ItemMultiTextureHelper extends ItemMultiTexture
{
public ItemMultiTextureHelper(Block block, String[] names)
{
super(block, block, names);
}
}
getSubBlocks only specifies which sub-blocks show in creative tabs. You still need to have an ItemBlock class like ItemMultiTexture that returns the appropriate unlocalised name for each sub-block.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
I thought it was done by overriding ",monospace">hasSubBlocks and ",monospace">getSubBlocks ... then naming is done in the .lang file.
That's what this tutorial says anyway. Maybe I misunderstood the question.
That's one way to do it, but as you can see also you have to override #getUnlocalizedName to append the item stack damage, and then you have non-descriptive language translation strings such as 'block_1', whereas with the examples given above you can have 'block_red', 'block_blue', etc. instead.
I'm trying to make so that only one class is needed to name the subblocks from any metablock that uses this class registration, i.e., naming them as if they were a parameter value, but without using one.
As you know, a metablock is composed of subblocks. Each subblock needs a name to identify it. So, in my mod, these names are listed in the class ExampleItemBlock in a String[], and then are named in the format MetablockName.SubBlockName (e.g.: ExampleMetablock.blue, ExampleMetablock.green, etc.), using
Then, the metablock ExampleMetablock is instantiated and registered using
After this, everything works with no problem, however I have to create a new *ItemBlock class for each new metablock I make, and I don't think this is a good or appropriate thing to do, and I think it's better to create one single class that will be used by any future metablock.
As you know, the second parameter of the GameRegistry.registerBlock() method for metablocks requires a value of type Class. And that's the problem: how would I turn the ExampleItemBlock class dynamic without using instances?
I even tried to add a String[] parameter in ExampleItemBlock constructor and then use an instance with the names in place of the class, but just as expected it stated type mismatch.
I searched everywhere for someway to achieve that, but I only found two ways:
1. create an ItemBlock class for each new metablock;
2. use a for inside getUnlocalizedName() and name the subblocks as numbers instead of names (e.g.: ExampleMetablock.0, ExampleMetablock.1, etc.), not needing to use String[] or anything, and making it an universal class. However, this way is also very impractical, because this complicates a lot when identifying which subblock is which.
I also searched through some mods on GitHub, but didn't found anything related to this in the code (that I know).
So my question is: is there someway to make an universal *ItemBlock class, but still naming subblocks with names (words)?
Classes content: ExampleMetablock, ExampleItemBlock.
You're overthinking this, your existing code will work fine.
You don't pass an instance of ExampleItemBlock to GameRegistry#registerBlock(), you pass it a Class object that contains ExampleItemBlock and it instantiates ExampleItemBlock for you.
Also, a for loop inside getUnlocalisedName, would do absolutely nothing; the result would be an instance of the String class, just like the result of your current implementation of getUnlocalisedName.
Please don't PM me asking for help, I will just redirect you to the appropriate forum, where there are others who are far more skilled than me.
This is not the signature you are looking for.
Banners and such things
Yes, I know it works fine, but I'm trying to find a way to do it using only one class, instead of a new one for each metablock.
Regarding the for loop, forget what I said, my bad, I checked again now and actually it has nothing to do with for, but actually just replacing SUBNAMES[i] with i or itemStack.getItemDamage();
Vanilla already has a class that does this: ItemMultiTexture. Look at how it stores and uses its array of names.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
So ItemMultiTexture would be a replacement for ItemBlockWithMetadata? And to use it I need to extend it, right? And so the super() would have three parameters instead of two. But how will I set the value of the String[] parameter if I can't instantiate it?
You don't need to extend it, just use GameRegistry.registerBlock(Block, Class<? extends ItemBlock>, String, Object...) to pass arguments (the Object vararg) to the constructor. In this case, you need to pass the Block and the array of names.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Note also that unlike most other cases, you have to explicitly declare the 'new Object[]{new String[]{}}' when registering the block, at least from my experience. Also, I ended up extending ItemMultiTexture due to issues with the constructor requiring 2 Block instances - for whatever reason, Forge wasn't having it (probably just needed to pass an extra argument to #registerBlock or something, but couldn't be bothered to fuss with it too much at the time).
But what about the expressions inside getUnlocalizedName()? They need to have access to the Object[]'s values set in the parameter. Do I need to add an Object[] parameter to ExampleItemBlock's constructor? Would it get the values just like it does with the block parameter?
Oh, now I get it, I have to change the class in the parameter to ItemMultiTexture, as it does the same thing and more than ExampleItemBlock, and is compatible.
I'll finish it up then test to see if everything goes well.
GameRegistry finds the constructor matching the types of the values in the object array and calls that, you don't need a constructor with an Object[] argument. The ItemMultiTexture constructor stores the name array in an instance field, then getUnlocalizedName uses that field.
This code:
Will call this constructor:
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
OK, bad news... Forge crashes in preInit stage and throws the error
The relevant lines:
That's because there's no ItemMultiTexture(Block, String[]) constructor, only ItemMultiTexture(Block, Block, String[]). I don't know why it needs the same Block twice, maybe it's a leftover from older versions.
Either pass the Block in the vararg before the name array or create a class that extends ItemMultiTexture and has a (Block, String[]) constructor that calls the ItemMultiTexture(Block, Block, String[]) constructor.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Alright, I created an alternative class that supers ItemMultiTexture, aaaand it worked! \o/ Finally metablocks using a dynamic class.
Thank you very much for you guy's help and patience! =D
______________________________________________________
The resulting code to whoever need it:
Block registration:
ItemMultiTextureHelper class:
ExampleMetablock beggining:
I thought it was done by overriding hasSubBlocks and getSubBlocks ... then naming is done in the .lang file.
That's what this tutorial says anyway. Maybe I misunderstood the question.
getSubBlocks only specifies which sub-blocks show in creative tabs. You still need to have an ItemBlock class like ItemMultiTexture that returns the appropriate unlocalised name for each sub-block.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
That's one way to do it, but as you can see also you have to override #getUnlocalizedName to append the item stack damage, and then you have non-descriptive language translation strings such as 'block_1', whereas with the examples given above you can have 'block_red', 'block_blue', etc. instead.
I think you misunderstood the "naming sub-blocks", that means the block names on the left side in the .lang file, not the ones on the right.