Jump to content

[1.9.4] Render Items in TESR


XFactHD

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

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

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

#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

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

What's the point of the custom ModelLoader then?

 

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's the performance benefit of storing an obscene amount of models in comparison to rendering the block every frame?

 

Link to comment
Share on other sites

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

What's the point of the custom ModelLoader then?

 

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's the performance benefit of storing an obscene amount of models in comparison to rendering the block every frame?

 

Link to comment
Share on other sites

If you are not rendering the block every frame, the block does not have to be rendered every frame (duh). Using some RAM does not reduce FPS.

Does this also apply if I have to regenerate the model(s) very often because the ItemStacks metadata or NBT data has changed and the ItemStack gotten from the extended block state is not equal to the reference stored in the Map as a key for the model?

Link to comment
Share on other sites

If you are not rendering the block every frame, the block does not have to be rendered every frame (duh). Using some RAM does not reduce FPS.

Does this also apply if I have to regenerate the model(s) very often because the ItemStacks metadata or NBT data has changed and the ItemStack gotten from the extended block state is not equal to the reference stored in the Map as a key for the model?

Link to comment
Share on other sites

I can't know beforehand what people (or myself) are doing to their ItemStacks (like making the ItemStack tick to simulate the half-life of an isotope) that could possibly be put into this chest.

 

EDIT: Also, I have no knowledge of the models/items that are to be put into my chest because they only need to implement an API interface to be able to put them into the chest.

Link to comment
Share on other sites

I can't know beforehand what people (or myself) are doing to their ItemStacks (like making the ItemStack tick to simulate the half-life of an isotope) that could possibly be put into this chest.

 

EDIT: Also, I have no knowledge of the models/items that are to be put into my chest because they only need to implement an API interface to be able to put them into the chest.

Link to comment
Share on other sites

I meant that I have no idea how to make the model work with what you told me above. I am understanding the reasoning of some of the parts of the puzzle now but overall I don't get how this is gonna work together. I have some questions again:

[*]The position of the item models depends on the rotation of the container and if I recall correctly (I am not at the computer right now), I do not have access to a block state in an IModel, how can I solve this?

[*]How is the TRSRTransformation supposed to work, this class just confuses me.

[*]Caching the models would mean saving the model in a Map with the ArrayList of stored items as a key, right?

Link to comment
Share on other sites

I meant that I have no idea how to make the model work with what you told me above. I am understanding the reasoning of some of the parts of the puzzle now but overall I don't get how this is gonna work together. I have some questions again:

[*]The position of the item models depends on the rotation of the container and if I recall correctly (I am not at the computer right now), I do not have access to a block state in an IModel, how can I solve this?

[*]How is the TRSRTransformation supposed to work, this class just confuses me.

[*]Caching the models would mean saving the model in a Map with the ArrayList of stored items as a key, right?

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

    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
    • It is an issue with quark - update it to this build: https://www.curseforge.com/minecraft/mc-mods/quark/files/3642325
  • Topics

×
×
  • Create New...

Important Information

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