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

    • I have a problem, I am trying to put two different effects to two different armors but when I run it only the emerald armor effect works. This is the code public class ModArmorItem extends ArmorItem{ private static final Map<ArmorMaterial, MobEffectInstance> MATERIAL_TO_EFFECT_MAP = (new ImmutableMap.Builder<ArmorMaterial, MobEffectInstance>()) .put(ModArmorMaterials.EMERALD, new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE,200, 1,false,false, true)) .put(ModArmorMaterials.OBSIDIAN, new MobEffectInstance(MobEffects.FIRE_RESISTANCE,200, 1,false,false, true)).build(); public ModArmorItem(ArmorMaterial pMaterial, Type pType, Properties pProperties) { super(pMaterial, pType, pProperties); } @Override public void onArmorTick(ItemStack stack, Level world, Player player){ if (!world.isClientSide()) { if (hasFullSuitOfArmorOn(player)) { evaluateArmorEffects(player); } } } private void evaluateArmorEffects(Player player) { for (Map.Entry<ArmorMaterial,MobEffectInstance> entry : MATERIAL_TO_EFFECT_MAP.entrySet()){ ArmorMaterial mapArmorMaterial = entry.getKey(); MobEffectInstance mapStatusEffect = entry.getValue(); if (hasCorrectArmorOn(mapArmorMaterial, player)) { addStatusEffectForMaterial(player, mapArmorMaterial, mapStatusEffect); } } } private void addStatusEffectForMaterial(Player player, ArmorMaterial mapArmorMaterial, MobEffectInstance mapStatusEffect) { boolean hasPlayerEffect = player.hasEffect(mapStatusEffect.getEffect()); if (hasCorrectArmorOn(mapArmorMaterial, player) && !hasPlayerEffect) { player.addEffect(new MobEffectInstance(mapStatusEffect)); } } private boolean hasCorrectArmorOn(ArmorMaterial material, Player player) { for (ItemStack armorStack : player.getInventory().armor){ if (!(armorStack.getItem() instanceof ArmorItem)) { return false; } } ArmorItem helmet = ((ArmorItem)player.getInventory().getArmor(3).getItem()); ArmorItem breastplace = ((ArmorItem)player.getInventory().getArmor(2).getItem()); ArmorItem leggins = ((ArmorItem)player.getInventory().getArmor(1).getItem()); ArmorItem boots = ((ArmorItem)player.getInventory().getArmor(0).getItem()); return helmet.getMaterial() == material && breastplace.getMaterial() == material && leggins.getMaterial() == material && boots.getMaterial() == material; } private boolean hasFullSuitOfArmorOn(Player player){ ItemStack helmet = player.getInventory().getArmor(3); ItemStack breastplace = player.getInventory().getArmor(2); ItemStack leggins = player.getInventory().getArmor(1); ItemStack boots = player.getInventory().getArmor(0); return !helmet.isEmpty() && !breastplace.isEmpty() && !leggins.isEmpty() && !boots.isEmpty(); } } Also when I place two effects on the same armor, the game crashes. Here is the crash file. The code is the same, only this part is different   private static final Map<ArmorMaterial, MobEffectInstance> MATERIAL_TO_EFFECT_MAP = (new ImmutableMap.Builder<ArmorMaterial, MobEffectInstance>()) .put(ModArmorMaterials.EMERALD, new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE,200, 1,false,false, true)) .put(ModArmorMaterials.EMERALD, new MobEffectInstance(MobEffects.FIRE_RESISTANCE,200, 1,false,false, true)).build(); I hope you guys can help me. Thanks.
    • I removed all related embeddium and oculus mods, i just tested it by disconnecting and the error happened again. heres the report https://pastebin.com/1kcR5wAt   EDIT: i tried removing xaeros and also smoothboot thinking there may be an issue there, nothing, heres that report too. https://pastebin.com/zQS7i9rM
    • Hi, I need suggestions. I am a beginner in Minecraft Modding. I would like to apply custom effects to some armors, something like: more chance to drop seeds, change zombie awareness, drop more pieces of wood when chopping logs, and things like that. How would you recommend me to do it, is there any library that has something similar and which ones would you recommend me?.
    • "downloading minecraft server failed, invalid Checksum. try again, or manually place server.jar to skip download"    
    • You have to create an Entity class called PlayerPart and use multiple of them to make the different parts of the player. See EnderDragonPart.java source code. The green hitboxes of the dragon are all EnderDragonParts
  • Topics

×
×
  • Create New...

Important Information

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