Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[1.9.4] Render Items in TESR


XFactHD
 Share

Recommended Posts

I am trying to render items in a blocks TESR.

This is what I tried:

package XFactHD.thermalreactors.client.render.tesr;

import XFactHD.thermalreactors.common.blocks.metal.TileEntityLeadChest;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.ModelChest;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.ItemModelMesher;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.item.ItemStack;

import java.util.ArrayList;

public class TileEntityLeadChestRenderer extends TileEntitySpecialRenderer<TileEntityLeadChest>
{
    @Override
    public void renderTileEntityAt(TileEntityLeadChest te, double x, double y, double z, float partialTicks, int destroyStage)
    {
        ItemModelMesher mesher = Minecraft.getMinecraft().getRenderItem().getItemModelMesher();
        BlockModelRenderer blockModelRenderer = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelRenderer();

        GlStateManager.pushAttrib();
        GlStateManager.pushMatrix();
        GlStateManager.translate((float)x, (float)y, (float)z);

        int angle = 90;
        switch (te.getFacing())
        {
            case NORTH: angle *= 0; break;
            case EAST: angle *= 1; break;
            case SOUTH: angle *= 2; break;
            case WEST: angle *= 3;
        }

        GlStateManager.rotate(angle, 0, 1, 0);

        if (te.isOpen())
        {
            GlStateManager.translate((float)x, (float)y, (float)z);
            GlStateManager.translate(0, 5, 0);

            int offset = 5;

            ArrayList<ItemStack> teInv = te.getInventory();
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(0)); //The x, y and z values are for testing purposes as I
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(1)); // need to get the items rendering befor I can finetune
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(2)); //them
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(3));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(4));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(5));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(6));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(7));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get();
        }

        GlStateManager.popMatrix();
        GlStateManager.popAttrib();
    }

    private void renderItemAt(BlockModelRenderer blockModelRenderer, ItemModelMesher mesher, float x, float y, float z, ItemStack stack)
    {
        GlStateManager.pushMatrix();
        GlStateManager.translate(x, y, z);
        if (stack != null)
        {
            RenderHelper.enableStandardItemLighting();
            blockModelRenderer.renderModelBrightnessColor(mesher.getItemModel(stack), 1.0F, 1.0F, 1.0F, 1.0F);
            RenderHelper.disableStandardItemLighting();
        }
        GlStateManager.popMatrix();
    }
}

but this doesn't seem to work. Either the render method doesn't like to get an item with a missing model or I am probably overlooking something really simple.

Link to comment
Share on other sites

  • Replies 64
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

I am trying to render items in a blocks TESR.

This is what I tried:

package XFactHD.thermalreactors.client.render.tesr;

import XFactHD.thermalreactors.common.blocks.metal.TileEntityLeadChest;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.ModelChest;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.ItemModelMesher;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.item.ItemStack;

import java.util.ArrayList;

public class TileEntityLeadChestRenderer extends TileEntitySpecialRenderer<TileEntityLeadChest>
{
    @Override
    public void renderTileEntityAt(TileEntityLeadChest te, double x, double y, double z, float partialTicks, int destroyStage)
    {
        ItemModelMesher mesher = Minecraft.getMinecraft().getRenderItem().getItemModelMesher();
        BlockModelRenderer blockModelRenderer = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelRenderer();

        GlStateManager.pushAttrib();
        GlStateManager.pushMatrix();
        GlStateManager.translate((float)x, (float)y, (float)z);

        int angle = 90;
        switch (te.getFacing())
        {
            case NORTH: angle *= 0; break;
            case EAST: angle *= 1; break;
            case SOUTH: angle *= 2; break;
            case WEST: angle *= 3;
        }

        GlStateManager.rotate(angle, 0, 1, 0);

        if (te.isOpen())
        {
            GlStateManager.translate((float)x, (float)y, (float)z);
            GlStateManager.translate(0, 5, 0);

            int offset = 5;

            ArrayList<ItemStack> teInv = te.getInventory();
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(0)); //The x, y and z values are for testing purposes as I
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(1)); // need to get the items rendering befor I can finetune
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(2)); //them
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(3));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(4));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(5));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(6));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get(7));
            renderItemAt(blockModelRenderer, mesher, (float) x+0, (float) y+2, (float) z+0, teInv.get();
        }

        GlStateManager.popMatrix();
        GlStateManager.popAttrib();
    }

    private void renderItemAt(BlockModelRenderer blockModelRenderer, ItemModelMesher mesher, float x, float y, float z, ItemStack stack)
    {
        GlStateManager.pushMatrix();
        GlStateManager.translate(x, y, z);
        if (stack != null)
        {
            RenderHelper.enableStandardItemLighting();
            blockModelRenderer.renderModelBrightnessColor(mesher.getItemModel(stack), 1.0F, 1.0F, 1.0F, 1.0F);
            RenderHelper.disableStandardItemLighting();
        }
        GlStateManager.popMatrix();
    }
}

but this doesn't seem to work. Either the render method doesn't like to get an item with a missing model or I am probably overlooking something really simple.

Link to comment
Share on other sites

This is what the chest looks like now:

This chest is made to contain radiation from fuel rods and raw uranium. If you put a fuel rod in there, it should be rendered upright (it has a max stacksize of 1) and if you insert up to 64 uranium pellets/chunks/whatever (with a max stack size of 64), they should be rendered as a pile with the height being proportional to the stack size. If I wouldn't use a TESR, how could I translate the item models to specific spots in the chest?

Link to comment
Share on other sites

This is what the chest looks like now:

This chest is made to contain radiation from fuel rods and raw uranium. If you put a fuel rod in there, it should be rendered upright (it has a max stacksize of 1) and if you insert up to 64 uranium pellets/chunks/whatever (with a max stack size of 64), they should be rendered as a pile with the height being proportional to the stack size. If I wouldn't use a TESR, how could I translate the item models to specific spots in the chest?

Link to comment
Share on other sites

Yes, you'd use

getExtendedState

in your Block to get the container ItemStack from the TileEntity to the model using an unlisted property (note you must clone the ItemStack before passing it into the state).

Then in your model you would bake the models as needed and cache the results so you don't have to rebake them constantly.

Link to comment
Share on other sites

Yes, you'd use

getExtendedState

in your Block to get the container ItemStack from the TileEntity to the model using an unlisted property (note you must clone the ItemStack before passing it into the state).

Then in your model you would bake the models as needed and cache the results so you don't have to rebake them constantly.

Link to comment
Share on other sites

I took a look at the OBJLoader and the ICustomModelLoader interface.

This is how far I got:

package XFactHD.thermalreactors.client.render.models;

import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IModel;

import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;

public enum  ModelLoaderLeadChest implements ICustomModelLoader
{
    INSTANCE;

    private IResourceManager manager;
    private final Map<ResourceLocation, IModel> cache = new HashMap<ResourceLocation, IModel>();

    @Override
    public boolean accepts(ResourceLocation modelLocation)
    {
        return modelLocation.getResourcePath().endsWith("_iRadioactive");
    }

    @Override
    public IModel loadModel(ResourceLocation modelLocation) throws Exception
    {
        ResourceLocation file = new ResourceLocation(modelLocation.getResourceDomain(), modelLocation.getResourcePath());
        if (!cache.containsKey(file))
        {
            IResource resource = null;
            try
            {
                resource = manager.getResource(file);
            }
            catch (FileNotFoundException e)
            {
                if (modelLocation.getResourcePath().startsWith("models/block/"))
                {
                    resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/item/" + file.getResourcePath().substring("models/block/".length())));
                }
                else if (modelLocation.getResourcePath().startsWith("models/item/"))
                {
                    resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/block/" + file.getResourcePath().substring("models/item/".length())));
                }
                else throw e;
            }
        }
        return cache.get(file);
    }

    @Override
    public void onResourceManagerReload(IResourceManager resourceManager)
    {
        this.manager = resourceManager;
        cache.clear();
    }

    @Override
    public String toString()
    {
        return "LeadChestLoader.INSTANCE";
    }
}

Now I've got some qestions:

[*]How do I get the IModel from an IResource? I took a look at the Vanilla Loader but I don't understand it at all.

[*]The chest can contain up to 9 different items, if the item has a stacksize higher than 1, it is even rendered multiple times. How would I go about caching that without filling up the memory with thousands of different models?

[*]What do I need to do in IModel#bake to create an IBakedModel?

Link to comment
Share on other sites

I took a look at the OBJLoader and the ICustomModelLoader interface.

This is how far I got:

package XFactHD.thermalreactors.client.render.models;

import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IModel;

import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;

public enum  ModelLoaderLeadChest implements ICustomModelLoader
{
    INSTANCE;

    private IResourceManager manager;
    private final Map<ResourceLocation, IModel> cache = new HashMap<ResourceLocation, IModel>();

    @Override
    public boolean accepts(ResourceLocation modelLocation)
    {
        return modelLocation.getResourcePath().endsWith("_iRadioactive");
    }

    @Override
    public IModel loadModel(ResourceLocation modelLocation) throws Exception
    {
        ResourceLocation file = new ResourceLocation(modelLocation.getResourceDomain(), modelLocation.getResourcePath());
        if (!cache.containsKey(file))
        {
            IResource resource = null;
            try
            {
                resource = manager.getResource(file);
            }
            catch (FileNotFoundException e)
            {
                if (modelLocation.getResourcePath().startsWith("models/block/"))
                {
                    resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/item/" + file.getResourcePath().substring("models/block/".length())));
                }
                else if (modelLocation.getResourcePath().startsWith("models/item/"))
                {
                    resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/block/" + file.getResourcePath().substring("models/item/".length())));
                }
                else throw e;
            }
        }
        return cache.get(file);
    }

    @Override
    public void onResourceManagerReload(IResourceManager resourceManager)
    {
        this.manager = resourceManager;
        cache.clear();
    }

    @Override
    public String toString()
    {
        return "LeadChestLoader.INSTANCE";
    }
}

Now I've got some qestions:

[*]How do I get the IModel from an IResource? I took a look at the Vanilla Loader but I don't understand it at all.

[*]The chest can contain up to 9 different items, if the item has a stacksize higher than 1, it is even rendered multiple times. How would I go about caching that without filling up the memory with thousands of different models?

[*]What do I need to do in IModel#bake to create an IBakedModel?

Link to comment
Share on other sites

How do I get the IModel from an IResource?
You don't. You simply create a class implementing IModel and return it. Your model loader does not need to load anything from disk (resources).

The chest can contain up to 9 different items, if the item has a stacksize higher than 1, it is even rendered multiple times. How would I go about caching that without filling up the memory with thousands of different models?
You have to cache it with "thousands of models". You can make it so your cache discards old models if it fills up, but if there are "thousands" of different versions of your block visible at a time then you need to have those "thousands" of models in memory.

What do I need to do in IModel#bake to create an IBakedModel?
You create a class implementing IBakedModel and return a new instance of it.
Link to comment
Share on other sites

How do I get the IModel from an IResource?
You don't. You simply create a class implementing IModel and return it. Your model loader does not need to load anything from disk (resources).

The chest can contain up to 9 different items, if the item has a stacksize higher than 1, it is even rendered multiple times. How would I go about caching that without filling up the memory with thousands of different models?
You have to cache it with "thousands of models". You can make it so your cache discards old models if it fills up, but if there are "thousands" of different versions of your block visible at a time then you need to have those "thousands" of models in memory.

What do I need to do in IModel#bake to create an IBakedModel?
You create a class implementing IBakedModel and return a new instance of it.
Link to comment
Share on other sites

#JavaQuestion

 

You have to cache it with "thousands of models". You can make it so your cache discards old models if it fills up, but if there are "thousands" of different versions of your block visible at a time then you need to have those "thousands" of models in memory.

 

As of now I am using WeakLinkedHashMap with maximum capacity (uses removeEldestEntry) which is basically LinkedHashMap that uses WeakValues (when value is not used entry is removed).

I had to do it myself since I couldn't find proper implementation.

 

Since you probably have more knowledge here - is there something in MC libs that allows such map that:

* Clears itself (values) when not used (values)

* Has max size

* Removes oldest entries when overloaded

 

I was looking into MapMaker and some of caching classes but didn't find anything to this extent.

 

In future I also want to improve mine with "waged values" since it (by logical analisys), when overloaded constantly will start recreating objects without caching them at all (since it is linked).

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

#JavaQuestion

 

You have to cache it with "thousands of models". You can make it so your cache discards old models if it fills up, but if there are "thousands" of different versions of your block visible at a time then you need to have those "thousands" of models in memory.

 

As of now I am using WeakLinkedHashMap with maximum capacity (uses removeEldestEntry) which is basically LinkedHashMap that uses WeakValues (when value is not used entry is removed).

I had to do it myself since I couldn't find proper implementation.

 

Since you probably have more knowledge here - is there something in MC libs that allows such map that:

* Clears itself (values) when not used (values)

* Has max size

* Removes oldest entries when overloaded

 

I was looking into MapMaker and some of caching classes but didn't find anything to this extent.

 

In future I also want to improve mine with "waged values" since it (by logical analisys), when overloaded constantly will start recreating objects without caching them at all (since it is linked).

1.7.10 is no longer supported by forge, you are on your own.

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

 Share




×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.