Jump to content

[SOLVED] [1.8] Blocks with MetaData


Zootaxz

Recommended Posts

Hey Forge-Community,

 

first of all i want to excusme me for my bad english, but i will try it :)

 

The thread will be divided into three parts, first my problem, second my solution and at least my research why the problem exists!?

 

If it is not possible to read, please write it.. and i retry it!

 

Problem

I want to create one block with 18 different subtypes. This should be a ore, an ore with always the same texture but different ore colors (coloring by code),

and also diffent hardness values, harvestLevels and dropRates.

The problem is the meta... i have in game 18 different items with diffent colors.. yay! But if i place one of these items i place always the same block with it.

Always the block with meta = 0!

 

Solution (I write my full code..!)

1) Create a base class for all my blocks which inherits from Block (I need it for easier .json registration!)

public class BlockBase extends Block{
    public BlockBase(Material material){
        super(material);
    }
}

 

2) Create a base class for all my meta-based blocks which inherits from BlockBase.

This class has a abstract method to get the item color for the ItemBlock! (I know, i can do it by the same way as for the block, but i will need it for later use!!).

The enum "JSON" is for my different registration types.. i can say:"Only one json for the block (by name)" or "For each meta in the block, ignore base-name, one json" or "one json for each name + subtype"! This shouldnt be relevant for this thread, but if anyone asks.. this is why i do this!

The methods "getSubTypes()", "getJSON()", "getBasicName()" and "getMetaName()" are also relevant for my own json registering and the ItemBlock class!

At last this blockClass overwrites the methods "damageDropped(IBlockState state)" and "getSubBlocks(Item item, CreativeTabs tab, List list)" like in 1.7!

public abstract class BlockBaseMeta extends BlockBase{

    @SideOnly(Side.CLIENT)
    public abstract int getColorFromItemStack(ItemStack itemStack, int layer);

    public enum JSON{
        /** Requires for each basic name plus subType a json file.
         * The file is located at items/[basicname + subType].json*/
        BASICNAME_AND_SUBTYPE,
        /** Requires only for each basicname a json file.
         * The file is located at items/[basicname].json */
        BASICNAME,
        /** Requires for each subType a json file, basic name will be ignored.
         * The file is located at items/[subType].json */
        SUBTYPE;
    }
    private JSON json;
    private String[] subTypes;
    private String basicName;

    public BlockBaseMeta(Material material, String basicName, String[] subTypes, JSON json){
        super(material);
        this.setUnlocalizedName(this.basicName = basicName);
        this.subTypes = subTypes;
        this.json = json;
    }

    public String[] getSubTypes(){
        return this.subTypes;
    }

    public JSON getJSON(){
        return this.json;
    }

    public String getBasicName(){
        return this.basicName;
    }

    public String getMetaName(int meta){
        return this.subTypes[meta];
    }

    @Override
    public int damageDropped(IBlockState state) {
        return this.getMetaFromState(state);
    }

    @Override
    public Item getItemDropped(IBlockState state, Random random, int fortune){
        return new ItemStack(this).getItem();
    }

    @Override
    public void getSubBlocks(Item item, CreativeTabs tab, List list) {
        for(int i = 0; i < this.subTypes.length; i++) {
            list.add(new ItemStack(item, 1, i));
        }
    }
}

 

3) Create a class which inherits from ItemBlock, for the different items for the meta-block!

(Here you can the calls to the methods to the class before!)

public class BlockBaseMetaItem extends ItemBlock {

    private final BlockBaseMeta blockBaseMeta;

    public BlockBaseMetaItem(Block blockBaseMeta){
        super(blockBaseMeta);
        this.setHasSubtypes(true);
        this.blockBaseMeta = (BlockBaseMeta)blockBaseMeta;

        if (this.blockBaseMeta.getJSON() == BlockBaseMeta.JSON.SUBTYPE){
            for(String subType : this.blockBaseMeta.getSubTypes()){
                ModelBakery.addVariantName(this, subType);
            }
        }

        if (this.blockBaseMeta.getJSON() == BlockBaseMeta.JSON.BASICNAME_AND_SUBTYPE){
            for(String subType : this.blockBaseMeta.getSubTypes()){
                ModelBakery.addVariantName(this, this.blockBaseMeta.getBasicName() + subType);
            }
        }
    }

    @Override
    public String getUnlocalizedName(ItemStack itemStack){
        return this.blockBaseMeta.getUnlocalizedName() + this.blockBaseMeta.getSubTypes()[MathHelper.clamp_int(itemStack.getItemDamage(), 0, this.blockBaseMeta.getSubTypes().length - 1)];
    }

    @Override
    public void getSubItems(Item item, CreativeTabs creativeTabs, List list){
        for (int i = 0; i < this.blockBaseMeta.getSubTypes().length; i++){
            list.add(new ItemStack(this, 1, i));
        }
    }

    @Override
    public int getMetadata(int meta){
        return meta;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public int getColorFromItemStack(ItemStack itemStack, int layer){
        return this.blockBaseMeta.getColorFromItemStack(itemStack, layer);
    }

    public String getBasicName(){
        return this.blockBaseMeta.getBasicName();
    }

    public String getSimpleName(int meta){
        return this.blockBaseMeta.getMetaName(meta);
    }

}

 

4) Create a base block class for my "Minerals" (I need the same for a later use!)

This class sets overwrites now the methods "getColorFromItemStack(ItemStack itemStack, int renderPass)", "quantityDropped(IBlockState state, int fortune, Random random)", "getHarvestLevel(IBlockState state)", "getBlockHardness(World world, BlockPos pos)", "colorMultiplier(IBlockAccess blockAccess, BlockPos pos, int renderPass)"

to set the block exact to this meta i want! To do this i write another class, which saves my meta values for this.. see it at point 5!

public class BlockMineral extends BlockBaseMeta {

    private BlockMineralMetaData[] blockMetaDatas;
    public BlockMineral(String name, BlockMineralMetaData[] blockMetaDatas){
        super(Material.rock, name, BlockMineralMetaData.getNameArray(blockMetaDatas), JSON.BASICNAME);
        this.blockMetaDatas = blockMetaDatas;
        this.setCreativeTab(ZCreativeTabs.blocks);
        this.setHardness(10);
        this.setResistance(10);
        this.setHarvestLevel("pickaxe", 10);
        this.setStepSound(Block.soundTypeStone);
        ZRegistry.registerBlock(this, BlockBaseMetaItem.class);
    }

    @Override
    public int getColorFromItemStack(ItemStack itemStack, int renderPass) {
        int meta = itemStack.getItemDamage();
        if (meta > this.blockMetaDatas.length){
            return 16777215;
        }
        return blockMetaDatas[meta].getColor(renderPass);
    }

    @Override
    public int quantityDropped(IBlockState state, int fortune, Random random) {
        int meta = this.getMetaFromState(state);
        if (blockMetaDatas[meta].quantityDropMin == blockMetaDatas[meta].quantityDropMax)
            return blockMetaDatas[meta].quantityDropMin;
        int quantity = blockMetaDatas[meta].quantityDropMin + (fortune == 0 ? 0 : random.nextInt(fortune));
        return quantity > this.blockMetaDatas[meta].quantityDropMax ? this.blockMetaDatas[meta].quantityDropMin : quantity;
    }

    @Override
    public int getHarvestLevel(IBlockState state) {
        return this.blockMetaDatas[this.getMetaFromState(state)].harvestLevel;
    }

    @Override
    public float getBlockHardness(World world, BlockPos pos) {
        return this.blockMetaDatas[this.getMetaFromState(world.getBlockState(pos))].hardness;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public int colorMultiplier(IBlockAccess blockAccess, BlockPos pos, int renderPass) {
        return this.getColor(this.getMetaFromState(blockAccess.getBlockState(pos)), renderPass);
    }

    private int getColor(int meta, int renderPass){
        if (meta > this.blockMetaDatas.length){
            return 16777215;
        }
        return blockMetaDatas[meta].getColor(renderPass);
    }
}

 

5) This class only saves the different values for one meta value

public class BlockMineralMetaData extends BlockMetaData{
    public final float hardness;
    public final int harvestLevel;
    public final int quantityDropMin;
    public final int quantityDropMax;
    public BlockMineralMetaData(String name, float hardness, int harvestLevel, int quantityDropMin, int quantityDropMax, int...colors){
        super(name, colors);
        this.hardness = hardness;
        this.harvestLevel = harvestLevel;
        this.quantityDropMin = quantityDropMin;
        this.quantityDropMax = quantityDropMax;
    }
}

 

6) At last i only need to create an Block class for my ores.. i also can now create a class for MineralBlocks (Like IronBlock, GoldBlock e.g.).

This class inherits from my BlockMineral.class!

(You see there are currently one 6 different colors... this are only test-colors.. i dont wanna create a pink vanadium ore! :D)

public class BlockMineralOre extends BlockMineral{
     /**
     * This enumeration exists only to get the meta id (== ordinal)
     * and to get a better overview over the code, in recipes e.g.
     */
    public enum Meta{
        MANGANESE(new BlockMineralMetaData("Manganese", 5, 2, 1, 4, Color.BLUE.getRGB())),
        NICKEL(new BlockMineralMetaData("Nickel", 5, 2, 1, 4, Color.DARK_GRAY.getRGB())),
        COBALT(new BlockMineralMetaData("Cobalt", 5, 2, 1, 4, Color.GRAY.getRGB())),
        TUNGSTEN(new BlockMineralMetaData("Tungsten", 5, 2, 1, 4, Color.CYAN.getRGB())),
        MOLYBDENUM(new BlockMineralMetaData("Molybdenum", 5, 2, 1, 4, Color.GREEN.getRGB())),
        VANADIUM(new BlockMineralMetaData("Vanadium", 5, 2, 1, 4, Color.pink.getRGB())),
        COPPER(new BlockMineralMetaData("Copper", 5, 2, 1, 4)),
        SILVER(new BlockMineralMetaData("Silver", 5, 2, 1, 4)),
        LEAD(new BlockMineralMetaData("Lead", 5, 2, 1, 4)),
        TIN(new BlockMineralMetaData("Tin", 5, 2, 1, 4)),
        ZINC(new BlockMineralMetaData("Zinc", 5, 2, 1, 4)),
        ALUMINUM(new BlockMineralMetaData("Aluminum", 5, 2, 1, 4)),
        MAGNESIUM(new BlockMineralMetaData("Magnesium", 5, 2, 1, 4)),
        BERYLLIUM(new BlockMineralMetaData("Beryllium", 5, 2, 1, 4)),
        LITHIUM(new BlockMineralMetaData("Lithium", 5, 2, 1, 4)),
        MITHRIL(new BlockMineralMetaData("Mithril", 5, 2, 1, 4));

        private final BlockMineralMetaData blockMineralMetaData;
        Meta(BlockMineralMetaData blockMineralMetaData) {
            this.blockMineralMetaData = blockMineralMetaData;
        }

        public static BlockMineralMetaData[] getMetaDataArray() {
            ArrayList<BlockMineralMetaData> result = new ArrayList(Meta.values().length);
            for(Meta meta : Meta.values()){
                result.add(meta.blockMineralMetaData);
            }
            result.trimToSize();
            return result.toArray(new BlockMineralMetaData[result.size()]);
        }
    }

    public BlockMineralOre(){
        super("blockOre", Meta.getMetaDataArray());
    }
}

 

Why exists my problem?

Now.. firstly i debugged through the methods and .. what is this.. my meta in the block is always 0.

Here are some suggestions from my side!!!

 

1. I inherits in my BlockBaseMetaItem.class from ItemBlock .. and not from ItemBlockWithMetaData (like 1.7.. becauce it doesnt exists!)

2. In the "onItemUse" method in the ItemBlock.class isnt set the meta id to the block which is placed!

3. The "damageDropped(IBlockState state)" method in Block class, which i have overwritten in my BlockBaseMeta.class give me only a IBlockState... and how i can return the meta.. i found the method "getMetaFromState(IBlockState state)" in the Block class.. but the content of this method is .. i dont know.. it checks only if if the state is null and not empty, return an error - otherwise always 0... but this is not right or?

 

 

Now.. i will finish this thread.. and if you think.. omg learn english or omg youre are fcking n00b... then say it! :D

Thanks for your help.

 

Greeting

 

Zootaxz

 

 

 

 

Link to comment
Share on other sites

Problem

I want to create one block with 18 different subtypes.

 

Metadata didn't suddenly allow for more than 16 because 1.8 happened.  It's still 16, but that other types of states can exist as well, such as ones being inferred based on neighboring blocks or TileEntity data.

 

getMetaFromBlockState can not return a value greater than 15.  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

Zootaxz, I don't think you understand some of the important things about metadata. Here are some things to consider:

1) in 1.8, metadata is now sort of hidden from the code and instead you should use a Property for the block, which can vary in each block's IBlockState. There is still metadata though, so you need to have methods in your block to convert from state to metadata and from metadata to state.

2) The built-in metadata is only 4-bits per block position, so you can only have 16 variations in one block.

3) The JSONs map the property values to the models, and the models map to the textures.

 

If you implement the above three points, then Minecraft will properly save the metadata and also sync it between client and server for you.

 

It seems that you're trying to create some entirely new metadata system? How are you syncing between client and server? How is it getting saved and loaded?

 

I think the problem is that you can certainly create all sorts of classes and fields to hold extended data, but you also have to consider the syncing and saving processes.

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

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

    • did you find any solutions? i have the same problem and also that mahito doesnt transform
    • Here's a simple example to solve this particular issue: public class ModArmorMaterials { public static final DeferredRegister<ArmorMaterial> ARMORS = DeferredRegister.create(Registries.ARMOR_MATERIAL, MyModName.MOD_ID); public static final RegistryObject<ArmorMaterial> COPPER = registerArmor("copper", Util.make(new EnumMap<>(ArmorItem.Type.class), enumMap -> { enumMap.put(ArmorItem.Type.BOOTS, 1); enumMap.put(ArmorItem.Type.LEGGINGS, 4); enumMap.put(ArmorItem.Type.CHESTPLATE, 5); enumMap.put(ArmorItem.Type.HELMET, 2); enumMap.put(ArmorItem.Type.BODY, 4); }), 12, SoundEvents.ARMOR_EQUIP_IRON, 0.0F, 0.0F, () -> Ingredient.of(Items.COPPER_INGOT)); private static RegistryObject<ArmorMaterial> registerArmor(String pGroup, EnumMap<ArmorItem.Type, Integer> pEnumMap, int pEnchantmentValue, Holder<SoundEvent> pEquipSound, float pToughness, float pKnockbackResistance, Supplier<Ingredient> pRepairIngredient) { List<ArmorMaterial.Layer> pLayerList = List.of(new ArmorMaterial.Layer(new ResourceLocation(pGroup))); return registerArmor(pGroup, pEnumMap, pEnchantmentValue, pEquipSound, pToughness, pKnockbackResistance, pRepairIngredient, pLayerList); } private static RegistryObject<ArmorMaterial> registerArmor( String pGroup, EnumMap<ArmorItem.Type, Integer> pEnumMap, int pEnchantmentValue, Holder<SoundEvent> pEquipSound, float pToughness, float pKnockbackResistance, Supplier<Ingredient> pRepairIngredient, List<ArmorMaterial.Layer> pLayerList) { return ARMORS.register(pGroup, () -> new ArmorMaterial(pEnumMap, pEnchantmentValue, pEquipSound, pRepairIngredient, pLayerList, pToughness, pKnockbackResistance)); } public static void register(IEventBus eventBus) { ARMORS.register(eventBus); } } Essentially, the TierSortingRegistry has been removed and so you now need to set up your own DeferredRegister. Please see the minecraftforge GitHub for more information; I found this solution through their issues (https://github.com/MinecraftForge/MinecraftForge/issues/9961)
    • How did I even leave that in there? I’ll try it in a bit, that very well could be it.
    • Greetings, I met a problem with my Forge server (47.2.0-1.20.1) that I can't join with the following line. (singleplayer world working fine) [net.minecraft.server.network.ServerGamePacketListenerImpl/]: Sharyna lost connection: Internal Exception: io.netty.handler.codec.EncoderException: java.lang.NullPointerException: Cannot invoke "net.minecraft.resources.ResourceLocation.toString()" because "p_130086_" is null   At first it was errored with packet size error, but I fixed that with the Connectivity mod, however, after that this popped up and can't find the source of it. Since the logs are big, I couldn't upload on paste.gg or other site ... so here it is (if the files are deleted, please notice me and I'll upload again. Debug and Latest log
  • Topics

×
×
  • Create New...

Important Information

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