Jump to content

Recommended Posts

Posted

I've added fences to my mod, and they work almost perfectly, but there is one minor visual problem. When breaking (or after breaking) the fences, the particles that appear are based off of the default variant of the fence, rather than on the variant that's being broken. For example, my fence_of_red (with a "shade" property with the possible values of "normal", "light", "lighter", "dark", and "darker") always uses the "normal" texture for the breaking particles, regardless of what variant is being broken. I have a feeling this has something to do with the fence .json models that I'm using, but I'm not sure how to get it working...

 

BlockColoreFence.java (custom fence class that extends BlockFence)

package com.supergeniuszeb.colore.common.blocks;

import com.supergeniuszeb.colore.common.init.ModCreativeTabs;

import net.minecraft.block.BlockFence;
import net.minecraft.block.material.MapColor;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;

public class BlockColoreFence extends BlockFence implements IBlockName, IBlockSpecialName {
public BlockColoreFence(String name, MapColor mapColor) {
	super(Material.rock, mapColor);
	this.setHardness(1.5f);
	this.setHarvestLevel("pickaxe", 0);
	this.setResistance(10.0f);
	this.setBlockName(this, name);
	this.setDefaultState(this.blockState.getBaseState().withProperty(SHADE, EnumType.NORMAL));
	this.setCreativeTab(ModCreativeTabs.fenceTab);
}

public enum EnumType implements IStringSerializable {
	NORMAL(0, "normal"),
	LIGHT(1, "light"),
	LIGHTER(2, "lighter"),
	DARK(3, "dark"),
	DARKER(4, "darker");

	private int ID;
	private String name;

	private EnumType(int ID, String name) {
		this.ID = ID;
		this.name = name;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public String toString() {
		return getName();
	}

	public int getID() {
        return ID;
    }

}

public static final PropertyEnum SHADE = PropertyEnum.create("shade", BlockColoreFence.EnumType.class);

@Override
protected BlockStateContainer createBlockState() {
	return new BlockStateContainer(this, new IProperty[] {SHADE, NORTH, EAST, SOUTH, WEST});
}

//Converts an metadata into an IBlockState.
@Override
public IBlockState getStateFromMeta(int meta) {
	switch (meta) {
		case 0:
			return getDefaultState().withProperty(SHADE, EnumType.NORMAL);
		case 1:
			return getDefaultState().withProperty(SHADE, EnumType.LIGHT);
		case 2:
			return getDefaultState().withProperty(SHADE, EnumType.LIGHTER);
		case 3:
			return getDefaultState().withProperty(SHADE, EnumType.DARK);
		case 4:
			return getDefaultState().withProperty(SHADE, EnumType.DARKER);
		default:
			return null;
	}
}

//Converts an IBlockState into metadata.
@Override
public int getMetaFromState(IBlockState state) {
    EnumType shade = (EnumType) state.getValue(SHADE);
    return shade.getID();
}

//So the meta block drops a block with the same metadata when mined.
@Override
public int damageDropped(IBlockState state) {
    return getMetaFromState(state);
}

//Used to get the last part of the unlocalized name for the item-block.
//The structure of the unlocalized name is: tile.blockname.specialname.name
@Override
public String getSpecialName(ItemStack stack) {
	switch (stack.getItemDamage()) {
		case 0:
			return "normal";
		case 1:
			return "light";
		case 2:
			return "lighter";
		case 3:
			return "dark";
		case 4:
			return "darker";
		default:
			return "normal";
	}
}

//This ensures that the pick-block button (normally middle-click) will give
//an item-block with the correct metadata.
@Override
public ItemStack getPickBlock(IBlockState state, RayTraceResult target, World world, BlockPos pos, EntityPlayer player) {
    return new ItemStack(Item.getItemFromBlock(this), 1, this.getMetaFromState(world.getBlockState(pos)));
}
}

 

BlockRenders.java (class that handles registration of item-block models)

package com.supergeniuszeb.colore.client.render;

import com.supergeniuszeb.colore.Reference;
import com.supergeniuszeb.colore.common.init.ModBlocks;
import com.supergeniuszeb.colore.utility.ModUtilities;

import net.minecraft.block.Block;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.registry.ForgeRegistries;

//All this handles are the item-block models, not the actual block models, which are
//defined in the .json files.
public class BlockRenders {

//This method is called by the preInit method every time it adds an item-block model without metadata specified.
public static void registerRender(Block block) {
	Item item = Item.getItemFromBlock(block);
	ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(block.getRegistryName(), "inventory"));
}

//This method is called by the preInit method every time it adds an item-block model with metadata specified.
public static void registerRender(Block block, int meta, String metaName) {
	Item item = Item.getItemFromBlock(block);
	ModelLoader.setCustomModelResourceLocation(item, meta, new ModelResourceLocation(block.getRegistryName() + "_" + metaName, "inventory"));
}

public static void preInit() {
	int i = 0;
	for (String shade : ModUtilities.shadeList) {
		for (String color : ModUtilities.colorList) {
			for (String blockType : ModUtilities.itemBlockTypeWShadeMetaList) {
				//standard blocks, half slabs, double slabs, & fences
				registerRender(ForgeRegistries.BLOCKS.getValue(new ResourceLocation(Reference.MOD_ID, blockType + "_of_" + color)), i, shade);
			}
			//stairs
			registerRender(ForgeRegistries.BLOCKS.getValue(new ResourceLocation(Reference.MOD_ID, "stairs_of_" + color + "_" + shade)));
		}
		i++;
	}

	i = 0;
	for (String color : ModUtilities.baseColorList) {
		//ore blocks
		registerRender(ModBlocks.essence_ore, i, color);
		i++;
	}
}

public static void init() {

}

}

 

blockstates/fence_of_red.json

{
    "multipart": [
	{   "when": { "shade": "normal" },
            "apply": { "model": "colore:fence_of_red_normal_post", "uvlock": true }
        },
	{   "when": { "shade": "light" },
            "apply": { "model": "colore:fence_of_red_light_post", "uvlock": true }
        },
	{   "when": { "shade": "lighter" },
            "apply": { "model": "colore:fence_of_red_lighter_post", "uvlock": true }
        },
	{   "when": { "shade": "dark" },
            "apply": { "model": "colore:fence_of_red_dark_post", "uvlock": true }
        },
	{   "when": { "shade": "darker" },
            "apply": { "model": "colore:fence_of_red_darker_post", "uvlock": true }
        },
        {   "when": { "north": "true", "shade": "normal" },
            "apply": { "model": "colore:fence_of_red_normal_side", "uvlock": true }
        },
        {   "when": { "east": "true", "shade": "normal" },
            "apply": { "model": "colore:fence_of_red_normal_side", "y": 90, "uvlock": true }
        },
        {   "when": { "south": "true", "shade": "normal" },
            "apply": { "model": "colore:fence_of_red_normal_side", "y": 180, "uvlock": true }
        },
        {   "when": { "west": "true", "shade": "normal" },
            "apply": { "model": "colore:fence_of_red_normal_side", "y": 270, "uvlock": true }
        },
	{   "when": { "north": "true", "shade": "light" },
            "apply": { "model": "colore:fence_of_red_light_side", "uvlock": true }
        },
        {   "when": { "east": "true", "shade": "light" },
            "apply": { "model": "colore:fence_of_red_light_side", "y": 90, "uvlock": true }
        },
        {   "when": { "south": "true", "shade": "light" },
            "apply": { "model": "colore:fence_of_red_light_side", "y": 180, "uvlock": true }
        },
        {   "when": { "west": "true", "shade": "light" },
            "apply": { "model": "colore:fence_of_red_light_side", "y": 270, "uvlock": true }
        },
	{   "when": { "north": "true", "shade": "lighter" },
            "apply": { "model": "colore:fence_of_red_lighter_side", "uvlock": true }
        },
        {   "when": { "east": "true", "shade": "lighter" },
            "apply": { "model": "colore:fence_of_red_lighter_side", "y": 90, "uvlock": true }
        },
        {   "when": { "south": "true", "shade": "lighter" },
            "apply": { "model": "colore:fence_of_red_lighter_side", "y": 180, "uvlock": true }
        },
        {   "when": { "west": "true", "shade": "lighter" },
            "apply": { "model": "colore:fence_of_red_lighter_side", "y": 270, "uvlock": true }
        },
	{   "when": { "north": "true", "shade": "dark" },
            "apply": { "model": "colore:fence_of_red_dark_side", "uvlock": true }
        },
        {   "when": { "east": "true", "shade": "dark" },
            "apply": { "model": "colore:fence_of_red_dark_side", "y": 90, "uvlock": true }
        },
        {   "when": { "south": "true", "shade": "dark" },
            "apply": { "model": "colore:fence_of_red_dark_side", "y": 180, "uvlock": true }
        },
        {   "when": { "west": "true", "shade": "dark" },
            "apply": { "model": "colore:fence_of_red_dark_side", "y": 270, "uvlock": true }
        },
	{   "when": { "north": "true", "shade": "darker" },
            "apply": { "model": "colore:fence_of_red_darker_side", "uvlock": true }
        },
        {   "when": { "east": "true", "shade": "darker" },
            "apply": { "model": "colore:fence_of_red_darker_side", "y": 90, "uvlock": true }
        },
        {   "when": { "south": "true", "shade": "darker" },
            "apply": { "model": "colore:fence_of_red_darker_side", "y": 180, "uvlock": true }
        },
        {   "when": { "west": "true", "shade": "darker" },
            "apply": { "model": "colore:fence_of_red_darker_side", "y": 270, "uvlock": true }
        }
    ]
}

 

models/item/fence_of_red_darker.json (item-block model)

{
    "parent": "colore:block/fence_of_red_darker_inventory"
}

 

models/block/fence_of_red_darker_inventory.json

{
    "parent": "block/fence_inventory",
    "textures": {
        "texture": "colore:blocks/block_of_red_darker"
    }
}

 

models/block/fence_of_red_darker_post.json

{
    "parent": "block/fence_post",
    "textures": {
        "texture": "colore:blocks/block_of_red_darker"
    }
}

 

models/block/fence_of_red_darker_side.json

{
    "parent": "block/fence_side",
    "textures": {
        "texture": "colore:blocks/block_of_red_darker"
    }
}

 

I've looked in the fence model .jsons, but I'm not sure what's causing the problem... I do know that vanilla fences don't have to worry about metadata since every wood-variant of fence is a separate block altogether.

 

To clarify, there are no error messages of any sort in the Forge logs when I start up the game, and everything else about the fences and their textures/models works flawlessly. It's just the breaking particles that aren't being assigned according to the blockstate. Any ideas? Thanks in advance for your time and help. :)

Colore - The mod that adds monochrome blocks in every color of the rainbow!

http://www.minecraftforge.net/forum/index.php?topic=35149

 

If you're looking to learn how to make mods for 1.9.4, I wrote a helpful article with links to a lot of useful resources for learning Minecraft 1.9.4 modding!

 

http://supergeniuszeb.com/mods/a-helpful-list-of-minecraft-1-9-4-modding-resources/

Posted

Why are you using the multipart stuff?

Because I couldn't derive from the vanilla fence blockstates .json as it wouldn't work with my fences since they had additonal metadata that vanilla fences don't.

 

I also tried to use the Forge blockstates format but I couldn't figure out how to use "submodel" properly. Is it possible to use multiple conditions (as in if X & Y then use this_model) in the Forge blockstates format similar to the vanilla method?

Colore - The mod that adds monochrome blocks in every color of the rainbow!

http://www.minecraftforge.net/forum/index.php?topic=35149

 

If you're looking to learn how to make mods for 1.9.4, I wrote a helpful article with links to a lot of useful resources for learning Minecraft 1.9.4 modding!

 

http://supergeniuszeb.com/mods/a-helpful-list-of-minecraft-1-9-4-modding-resources/

Posted

Well, I've played around some more with the Forge blockstates format and figured out how to use "submodel" properly... here is the working blockstates .json for those with similar problems:

 

{
"forge_marker": 1,
"defaults": {
	"textures": {
		"texture": "colore:blocks/block_of_red_normal"
	},
	"model": "fence_post",
	"uvlock": true
},
"variants": {
	"shade": {
		"normal": {
			"textures": {
				"texture": "colore:blocks/block_of_red_normal"
			}
		},
		"light": {
			"textures": {
				"texture": "colore:blocks/block_of_red_light"
			}
		},
		"lighter": {
			"textures": {
				"texture": "colore:blocks/block_of_red_lighter"
			}
		},
		"dark": {
			"textures": {
				"texture": "colore:blocks/block_of_red_dark"
			}
		},
		"darker": {
			"textures": {
				"texture": "colore:blocks/block_of_red_darker"
			}
		}
	},
	"north": {
		"true": {
			"submodel": "fence_side"
		},
		"false": {
		}
	},
	"east": {
		"true": {
			"submodel": {
				"sideeast": { "model": "fence_side", "y": 90 }
			}
		},
		"false": {
		}
	},
	"south": {
		"true": {
			"submodel": {
				"sidesouth": { "model": "fence_side", "y": 180 }
			}
		},
		"false": {
		}
	},
	"west": {
		"true": {
			"submodel": {
				"sidewest": { "model": "fence_side", "y": 270 }
			}
		},
		"false": {
		}
	}
}
}

 

Note that "sideeast", "sidesouth", & "sidewest" can be named anything you like and are not named after anything in the code or any other .json. You just have to make sure they all have different names from each other. Also, as you can see with the first use of "submodel", there's a short way of defining a submodel to use if you don't need to rotate it. Using the Forge blockstates format has also made the custom "side" and "post" block model .jsons that I was using unnecessary.

 

The break particles are now working properly, so my fences are now working perfectly! Hopefully my working blockstates .json will provide a good reference example to others confused about using submodels in the Forge blockstates .json format. :)

Colore - The mod that adds monochrome blocks in every color of the rainbow!

http://www.minecraftforge.net/forum/index.php?topic=35149

 

If you're looking to learn how to make mods for 1.9.4, I wrote a helpful article with links to a lot of useful resources for learning Minecraft 1.9.4 modding!

 

http://supergeniuszeb.com/mods/a-helpful-list-of-minecraft-1-9-4-modding-resources/

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.