Koward Posted August 1, 2016 Posted August 1, 2016 Hi. Please correct my story if I say something weird. I have a block (let's call it "fancybrick"), with 2 variants (I'll use "blue" and "red" here), I want an item per variant. Easy, probably. I create the Block instance (only one, it's not like ores which are each a registered new instance of BlockOre). This Block has a registry name "fancybrick". I register this way : private static Block registerBlock(Block block) { GameRegistry.register(block); GameRegistry.register(new ItemBlock(block).setRegistryName(block.getRegistryName())); return block; } This has for result two block&item pairs with registry name "fancybrick". I would rather like "fancybrick_blue" and "fancybrick_red". Unlike rendering and ModelLoader.setCustomModelResourceLocation() I don't have a way to give the meta as a parameter for registering. A solution I can see is dropping completely from meta (the stone-like solution) and going to separate instances (the ore-like solution), maybe it would look cleaner and produce a code easier to maintain. But I would like to understand a bit what I'm doing and not copy pasting any snippet out there. There must be a reason these two ways coexist. Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 So the way BlockStone works (all of it here is in the end just an instance stored in Blocks.STONE) : ... STONE(0, MapColor.STONE, "stone"), GRANITE(1, MapColor.DIRT, "granite"), GRANITE_SMOOTH(2, MapColor.DIRT, "smooth_granite", "graniteSmooth"), DIORITE(3, MapColor.QUARTZ, "diorite"), DIORITE_SMOOTH(4, MapColor.QUARTZ, "smooth_diorite", "dioriteSmooth"), ANDESITE(5, MapColor.STONE, "andesite"), ANDESITE_SMOOTH(6, MapColor.STONE, "smooth_andesite", "andesiteSmooth"); ... You do not recommend it at all for modding ? I really wonder why Mojang did this instead of the ore way. Honestly this should be written somewhere because I'm pretty sure I'm not the only one to look at vanilla examples to figure out stuff and this one is pretty confusing. Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 The class BlockStone use metadata. In the end you get multiple blocks&items : Stone, Granite, Smooth Granite, Diorite, Smooth Diorite, Andesite and Smooth Andesite. The class BlockOre does not use metadata. In the end you have multiple items too, each ore (beside maybe Redstone which is in another class because of its special behaviour, but you get it). In both cases we have one class that ends up doing multiple blocks&items. But it's a different technique. - with BlockStone uses one meta value per variant, and checks this meta in its methods. Only one instance of BlockStone is created and registered. - with BlockOre for each variant a new instance is created, and methods are then applied on them to differentiate behaviour (like hardness). Before 1.9 both ways were perfectly working. Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 There is no difference for the end user between two types and two items. And for the modding part I don't see anything you could do one way and not the other. Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 Well... nothing, I'll just turn all my blocks to 1 instance : 1 item as you said. But I still feel it's less a necessity than a guideline (which I'll be happy to follow). Thanks a lot, topic solved. Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 I understand what you mean, I was trying to say 1 Block : 1 variant (no metadata). Which leads me to the question whether BlockStates are a good way to create different blocks (for the end user (who considers p.e. Stone and Diorite as different blocks)). The whole meta/blockstates thing looks more suited to changing blocks like Pistons or Doors. But it's not really the point of this topic. Quote
Draco18s Posted August 1, 2016 Posted August 1, 2016 Using metadata for related blocks is fine. Vanilla stone (diorite, etc.) and wool (red, blue, green...) are both perfect examples of using metadata for defining the "variants." The point is, even if the end user considers them different blocks, you as a coder give no fucks. Quote 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.
Koward Posted August 1, 2016 Author Posted August 1, 2016 Then I ask the question, how to properly register all the variants of a Block ? (and corresponding items). I can do standard blocks easily but with variants I end up with duplicate items in inventory. My end goal is to do two new variants of stone, and two new variants of each ore. Quote
Choonster Posted August 1, 2016 Posted August 1, 2016 Register each Block or Item instance once, regardless of whether or not it uses metadata. There's nothing more to it. Quote 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.
Koward Posted August 1, 2016 Author Posted August 1, 2016 With just a GameRegistry.register(block); GameRegistry.register(new ItemBlock(block).setRegistryName(block.getRegistryName())); it should create all possible combination item (item for the user, not talking about the class) ? Maybe I messed something somewhere else then.. Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 I did. And I registered the rendering with for blocks (and their items at the same time, I believe) : ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(block), meta, new ModelResourceLocation(modid + ":" + file, "inventory")); for items : ModelLoader.setCustomModelResourceLocation(item, meta, new ModelResourceLocation(modid + ":" + file, "inventory")); I do it for each meta, so if I read the documentation well I should not need ModelBakery at all, right ? Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 My JSON structure is probably bad. I tried to compare with vanilla stone structure and it gets weirder and weirder. For stone, each variant has its file (I'm talking about /blockstates). And the "variants" of the stone.json are "variants": { "normal": [ { "model": "stone" }, { "model": "stone_mirrored" }, { "model": "stone", "y": 180 }, { "model": "stone_mirrored", "y": 180 } ] } So it does not look related to the actual meta variants. And I did not know that so it's probably why everything is messed. I will try it a bit later but I think that will solve my problems, thank you. Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 Okay so I do have to make only one single json file with variants in the json code (as I don't use any custom mapper). For /blockstates. The blocks are fine when placed, but their inventory counter part is the classic Purple&Black, and a size of 1 block even in hand. EDIT : The rendering don't work because it tries to look for a non-existing json. For example, I have an item "bark" which use metadata to be any type of wood. I get this error (the mod is called stratification) : [00:15:24] [Client thread/ERROR] [FML]: Exception loading model for variant stratification:bark#inventory for item "stratification:bark", normal location exception: net.minecraftforge.client.model.ModelLoaderRegistry$LoaderException: Exception loading model stratification:item/bark with loader VanillaLoader.INSTANCE, skipping at net.minecraftforge.client.model.ModelLoaderRegistry.getModel(ModelLoaderRegistry.java:153) ~[ModelLoaderRegistry.class:?] at net.minecraftforge.client.model.ModelLoader.loadItemModels(ModelLoader.java:317) ~[ModelLoader.class:?] at net.minecraft.client.renderer.block.model.ModelBakery.loadVariantItemModels(ModelBakery.java:170) ~[ModelBakery.class:?] at net.minecraftforge.client.model.ModelLoader.setupModelRegistry(ModelLoader.java:147) ~[ModelLoader.class:?] at net.minecraft.client.renderer.block.model.ModelManager.onResourceManagerReload(ModelManager.java:28) [ModelManager.class:?] at net.minecraft.client.resources.SimpleReloadableResourceManager.registerReloadListener(SimpleReloadableResourceManager.java:122) [simpleReloadableResourceManager.class:?] at net.minecraft.client.Minecraft.startGame(Minecraft.java:540) [Minecraft.class:?] at net.minecraft.client.Minecraft.run(Minecraft.java:386) [Minecraft.class:?] at net.minecraft.client.main.Main.main(Main.java:118) [Main.class:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_102] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102] at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_102] at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) [launchwrapper-1.12.jar:?] at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_102] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102] at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_102] at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97) [start/:?] at GradleStart.main(GradleStart.java:26) [start/:?] Caused by: java.io.FileNotFoundException: stratification:models/item/bark.json It should never look for bark.json since it's not a possible combination (possible ones are bark_oak, bark_spruce...) Besides that I also have a few net.minecraft.client.renderer.block.model.ModelBlockDefinition$MissingVariantException Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 Here is some code. ItemBark.java : package koward.stratification.item; import java.util.List; import com.google.common.base.Predicate; import net.minecraft.block.BlockPlanks; import net.minecraft.block.properties.PropertyEnum; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class ItemBark extends Item { public static final PropertyEnum VARIANT = PropertyEnum.create("variant", BlockPlanks.EnumType.class, new Predicate() { public boolean apply(BlockPlanks.EnumType type) { return type.getMetadata() >= 4; } public boolean apply(Object p_apply_1_) { return this.apply((BlockPlanks.EnumType) p_apply_1_); } }); public ItemBark() { setHasSubtypes(true); setUnlocalizedName("bark"); setCreativeTab(CreativeTabs.MATERIALS); setRegistryName("bark"); } public String getUnlocalizedName(ItemStack stack) { String variantName; int meta = stack.getMetadata(); switch (meta){ case 0: variantName = "oak"; break; case 1: variantName = "spruce"; break; case 2: variantName = "birch"; break; case 3: variantName = "jungle"; break; case 4: variantName = "acacia"; break; case 5: variantName = "dark_oak"; break; default: variantName = "error_meta_" + Integer.toString(meta); break; } return super.getUnlocalizedName() + "." + variantName; } @SideOnly(Side.CLIENT) public void getSubItems(Item itemIn, CreativeTabs tab, List list) { list.add(new ItemStack(itemIn, 1, BlockPlanks.EnumType.OAK .getMetadata())); list.add(new ItemStack(itemIn, 1, BlockPlanks.EnumType.SPRUCE .getMetadata())); list.add(new ItemStack(itemIn, 1, BlockPlanks.EnumType.BIRCH .getMetadata())); list.add(new ItemStack(itemIn, 1, BlockPlanks.EnumType.JUNGLE .getMetadata())); list.add(new ItemStack(itemIn, 1, BlockPlanks.EnumType.ACACIA .getMetadata())); list.add(new ItemStack(itemIn, 1, BlockPlanks.EnumType.DARK_OAK .getMetadata())); } } ModItems.java (methods to register and link models) package koward.stratification.item; import koward.stratification.Stratification; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.Item; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.fml.common.registry.GameRegistry; public final class ModItems { public static final Item BARK = new ItemBark(); private ModItems(){} public static void register(){ GameRegistry.register(BARK); } public static void linkModels() { setModelLocation(ModItems.BARK, 0, "bark_oak"); setModelLocation(ModItems.BARK, 1, "bark_spruce"); setModelLocation(ModItems.BARK, 2, "bark_birch"); setModelLocation(ModItems.BARK, 3, "bark_jungle"); setModelLocation(ModItems.BARK, 4, "bark_acacia"); setModelLocation(ModItems.BARK, 5, "bark_dark_oak"); } public static void setModelLocation(Item item, int meta, String file) { ModelLoader.setCustomModelResourceLocation(item, meta, new ModelResourceLocation(Stratification.MODID + ":" + file, "inventory")); } } register() is called in my CommonProxy class at preInit() and linkModels() is called in ClientProxy at init(). bark_oak.json (others are identical besides of course the texture) { "parent":"builtin/generated", "textures": { "layer0":"minecraft:blocks/log_oak" }, "display": { "thirdperson": { "rotation": [ -90, 0, 0 ], "translation": [ 0, 1, -3 ], "scale": [ 0.55, 0.55, 0.55 ] }, "firstperson": { "rotation": [ 0, -135, 25 ], "translation": [ 0, 4, 2 ], "scale": [ 1.7, 1.7, 1.7 ] } } } Quote
Koward Posted August 1, 2016 Author Posted August 1, 2016 Yes but it tries to find a bark.json, which does not exist. It's weird because I never pointed to just "bark" in the ModelLoader method. Quote
Koward Posted August 2, 2016 Author Posted August 2, 2016 Models do show up now, thanks. My last problem is that, with one of my new types of stone, while the item is ok in inventory/hand, the block spawned is always the default state. Blocks added during World generation are okay, so both item&block exist but the item does not seem linked to it. Quote
Choonster Posted August 2, 2016 Posted August 2, 2016 If your Block uses metadata, you need to override Item#getMetadata in your ItemBlock class to return the block metadata corresponding to the supplied item metadata. In most cases these are the same, so just return the argument. Consider using ItemMultiTexture instead of ItemBlock , it overrides this method and also overrides Item#getUnlocalizedName to return a different name for each metadata value. Quote 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.
Koward Posted August 2, 2016 Author Posted August 2, 2016 I am using a simple new ItemBlock(block).setRegistryName(block.getRegistryName()), so I guess you're right, it probably does not take in account that and always return 0. Good news, ItemMultiTexture works, thanks. The constructor take two Block objects, I have no idea why, I put twice the same Block to test (I thought I would get some relevant error to help me) and it worked, which is surprising. Thank you. Quote
Choonster Posted August 2, 2016 Posted August 2, 2016 Both Block arguments of the ItemMultiTexture constructor should be the same value. I have no idea why there's two arguments, the second one is assigned to a field that's never actually used anywhere. Quote 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.
Xanderr_K Posted September 5, 2016 Posted September 5, 2016 Good news, ItemMultiTexture works, thanks. Hi there! I impacted the same problem with registering render for block with meta. Can you please explain, how you're applied this ItemMultiTexture? My situation is: I can spawn my blocks via code by pointing any proper VARIANT (using tools or items I created for this, like "Pile of Moss" to convert Chiseled Stone Brick into my new custom Chiseled Mossy Stone Brick), but in Creative inventory my blocks shown as one "empty" cell (actually no model/texture shown) and three placeholders. So I need to register render for all my metas somehow, also I need to create proper .json for it (which name I should use? no idea...). Quote
jeffryfisher Posted September 6, 2016 Posted September 6, 2016 I've just reached the same point myself. Using Eclipse's F3 function to go to the class definition, I see that "public class ItemMultiTexture extends ItemBlock". That tells us all we need to know. Just instantiate ItemMultiTexture where you would otherwise instantiate with ItemBlock (and then use your Java-sense to satisfy its demands, such as supplying it with a name array or a naming function containing an "apply(stack)" method). Quote The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
Xanderr_K Posted September 7, 2016 Posted September 7, 2016 and then use your Java-sense to satisfy its demands, such as supplying it with a name array or a naming function containing an "apply(stack)" method. My Java-sense tells me nothing, master... =( I have no idea where to take an array of names for every meta of my block, it not provides any public functions for that. Quote
jeffryfisher Posted September 7, 2016 Posted September 7, 2016 Did you read the ItemMultiTexture class and its constructors? Just instantiate one as your iblock and give one of the constructors what it wants. Quote The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
Xanderr_K Posted September 7, 2016 Posted September 7, 2016 Yes, I looked at this class but cannot understand how to obtain string[] with names by metadata (Block class are not providing methods for that) or even how to feed it's constructor with proper Function<ItemStack, String> (the Guava docs explaining this last one function, but it is too hard for me). Sorry, I'm new to Java, only used C# before and I'm not so experienced programmer =( Quote
jeffryfisher Posted September 7, 2016 Posted September 7, 2016 I may be wrong, but it looks like we're supposed to write the array of strings and then feed it into the constructor. That's how we tell the class what our variants are named. So think about what you're trying to do and then write it. Quote The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.
Recommended Posts
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.