Jump to content

[1.9.4] MultiModel Renderers with Builtin Models


infinitegde

Recommended Posts

Hey All,

 

I am actually pretty new to the MC code base so if I am missing something obvious please feel free to point me in the right direction. I am trying to create an item which captures blocks (and associated metadata and nbt). The functionality is mostly there but I wanted to have the item icon render the block which was captured. So far I have it rendering things like stone and granite (though grass is rendering a bit gray *Fixed this issue, see note at bottom* I imagine theres some tint or particle texture i have to apply somewhere, if someone could knows a reference off the top of their head in the vanilla or forge code base i can dive into that would be much appreciated), but I am having an issue with rendering things that use the builtin renderer like Chests. Here's the code I am using for my multi model renderer. It's essentially a copy n paste from the vanilla multipartbakedmodel with some minor tweaks to store persistent blockstates rather than using blockstates as predicates.

 

Forge version: 12.17.0.1965

public class CompressorItemModel implements IBakedModel{
private IBakedModel lowerModel, upperModel;
private final static ModelResourceLocation lowerLocation = new ModelResourceLocation(String.format("%s:%s", Reference.MOD_ID, "compressorLower"), "inventory");
private final static ModelResourceLocation upperLocation = new ModelResourceLocation(String.format("%s:%s", Reference.MOD_ID, "compressorUpper"), "inventory");
public CompressorItemModel() {
	lowerModel = getBakedModel(lowerLocation);
	upperModel = getBakedModel(upperLocation);
}

private static IBakedModel getBakedModel(ModelResourceLocation location){
	IModel model = ModelLoaderRegistry.getModelOrMissing(location);
	return model.bake(model.getDefaultState(), DefaultVertexFormats.ITEM, ModelLoader.defaultTextureGetter());
}
@Override
public List<BakedQuad> getQuads(IBlockState state, EnumFacing side, long rand) {
	return null;
}

@Override
public boolean isAmbientOcclusion() {
	return false;
}

@Override
public boolean isGui3d() {
	return false;
}

@Override
public boolean isBuiltInRenderer() {
	return false;
}

@Override
public TextureAtlasSprite getParticleTexture() {
	return null;
}

@Override
public ItemCameraTransforms getItemCameraTransforms() {
	return null;
}

@Override
public ItemOverrideList getOverrides() {
	return new ItemOverrideList(new ArrayList<ItemOverride>()){
		@Override
		public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world,
				EntityLivingBase entity) {
			if(stack.getItem() != ModItems.compressorItemBlock){
				throw new RuntimeException("Compressor Item Model should only be used ");
			}
			MultipartBakedModel.Builder builder = new MultipartBakedModel.Builder();

			NBTTagCompound nbt = stack.getTagCompound();
			if(nbt != null){
				Block storedBlk = (Block.getBlockById(nbt.getInteger(ItemBlockCompressor.NBT_KEY_BLOCK_ID)));
				int damage = nbt.getInteger(ItemBlockCompressor.NBT_KEY_BLOCK_META);
				ItemStack storedBlkStack = new ItemStack(storedBlk, 0, damage);
				IBakedModel storedBlkModel = Minecraft.getMinecraft().getRenderItem().getItemModelWithOverrides(storedBlkStack, world, entity);
				builder.putModel(storedBlk.getStateFromMeta(storedBlkStack.getItem().getMetadata(damage)), storedBlkModel);
			}
			else{
				builder.putModel(null, lowerModel);
			}
			/*builder.putModel(null, upperModel);*/
			return builder.makeMultipartModel();
		}
	};
}




@SideOnly(Side.CLIENT)
public static class MultipartBakedModel implements IBakedModel
{
    private final List<Pair<IBlockState, IBakedModel>> selectors;
    protected final boolean ambientOcclusion;
    protected final boolean gui3D;
    protected final TextureAtlasSprite particleTexture;
    protected final ItemCameraTransforms cameraTransforms;

    public MultipartBakedModel(List<Pair<IBlockState, IBakedModel>> selectorsIn)
    {
        this.selectors = selectorsIn;
        IBakedModel ibakedmodel = (IBakedModel)selectorsIn.iterator().next().second();
        this.ambientOcclusion = ibakedmodel.isAmbientOcclusion();
        this.gui3D = ibakedmodel.isGui3d();
        this.particleTexture = ibakedmodel.getParticleTexture();
        this.cameraTransforms = ibakedmodel.getItemCameraTransforms();
    }

    public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
    {
        List<BakedQuad> list = Lists.<BakedQuad>newArrayList();
        for (Pair<IBlockState, IBakedModel> entry : this.selectors)
        {
        	list.addAll(entry.second().getQuads(entry.first(), side, rand++));
        }
        return list;
    }

    public boolean isAmbientOcclusion()
    {
        return this.ambientOcclusion;
    }

    public boolean isGui3d()
    {
        return this.gui3D;
    }

    public boolean isBuiltInRenderer()
    {
        return false;
    }

    public TextureAtlasSprite getParticleTexture()
    {
        return this.particleTexture;
    }

    public ItemCameraTransforms getItemCameraTransforms()
    {
        return this.cameraTransforms;
    }

    public ItemOverrideList getOverrides()
    {
        return ItemOverrideList.NONE;
    }

    @SideOnly(Side.CLIENT)
    public static class Builder
    {
    	private List<Pair<IBlockState, IBakedModel>> builderSelectors = Lists.<Pair<IBlockState, IBakedModel>>newArrayList();
    	public void putModel(IBlockState state, IBakedModel model)
    	{
    		this.builderSelectors.add(Pair.of(state, model));
    	}

    	public IBakedModel makeMultipartModel()
    	{
    		return new MultipartBakedModel(this.builderSelectors);
    	}
    }
}

}

 

I know there are some optimizations i can make. (like caching the baked quads since the blockstate doesn't change) I'm currently just trying to get it to work. I know the issue lies in the fact that BuiltInModel's like Chest's defer to the tileentityrenderer to draw the icon however it seems to be hardcoded in MC RenderItem class (see method renderItem(ItemStack stack, IBakedModel model)). Forge seems to allow one to register a TileEntitySpecialRenderer in ForgeHooksClient.registerTESRItemStack but the method is deprecated and it is a rather round about method of gaining access to the render pipeline of items. I was curious is there something obvious I'm missing, am I going about it the wrong way, or does the functionality just not exist?

 

 

[Edit]

Earlier I mentioned I was having issue with grass being a bit gray. For anyone who may stumble across this post, the issue I had was that colors for certain items are determined by a class ItemColors. You can register your own itemcolor for your item (which is passed an itemstack so it can be NBT aware).

 

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.