Jump to content

[SOLVED][1.10.2] The Nightmare of Variants registering


Koward

Recommended Posts

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

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

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.

Link to comment
Share on other sites

Register each

Block

or

Item

instance once, regardless of whether or not it uses metadata. There's nothing more to it.

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

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..

Link to comment
Share on other sites

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 ?

 

 

Link to comment
Share on other sites

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.

 

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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 ]
        }
    }
}

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

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 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.

Link to comment
Share on other sites

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.

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

  • 1 month later...
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...).

Link to comment
Share on other sites

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).

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Did you read the ItemMultiTexture class and its constructors? Just instantiate one as your iblock and give one of the constructors what it wants.

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.

Link to comment
Share on other sites

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 =(

Link to comment
Share on other sites

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.

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.

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.