Jump to content

[SOLVED] [1.15.2] Resource reload causes different model caches


XFactHD

Recommended Posts

I have a gun item in my mod that uses an ItemStackTileEntityRenderer to render attachments onto the base model. To enable the ISTER I am replacing the IBakedModel in ModelBakeEvent with a wrapper model that returns true in isBuiltInRenderer(). Because I don't want the model to shift in the GUI when the player is aiming down the sights, I am also using the wrapper to "sniff" the ItemCameraTransforms.TransformType that is passed to handlePerspective() before calling my renderer and make it available to the renderer. This works perfectly until I reload the resources (F3 + T). When the resources are reloaded, the reloaded models are replaced by the wrapper again and the wrapper is cached in the ISTER. The model that is used by the ItemRenderer to determine how to render an item is retrieved from the ItemModelMesher. The problem is that it seems like the ItemModelMesher's cache is not rebuilt after a resource reload. This leads to the ItemModelMesher to return the old models while my renderer tries to retrieve necessary information from the new models.

Am I just being stupid and overlooking something simple or should I file this as a bug in Forge?

 

This is the code in ModelBakeEvent:

@SubscribeEvent
public static void onModelBake(final ModelBakeEvent event)
{
    for (EnumGun gun : EnumGun.values())
    {
        ResourceLocation loc = new ModelResourceLocation(new ResourceLocation("r6mod", gun.toItemName()), "inventory");
        IBakedModel original = event.getModelRegistry().get(loc);
        IBakedModel replacement = new BakedModelISTER(original);
        event.getModelRegistry().put(loc, replacement);
    }
    RenderGun.loadModels(event.getModelRegistry());
}

 

This is the wrapper model

package xfacthd.r6mod.client.model;

import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.Direction;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.common.model.TransformationHelper;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Random;

@SuppressWarnings("deprecation")
public class BakedModelISTER implements IBakedModel
{
    private final IBakedModel original;
    private ItemCameraTransforms.TransformType transform = ItemCameraTransforms.TransformType.NONE;

    public BakedModelISTER(IBakedModel original) { this.original = original; }

    @Nonnull
    @Override
    public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData)
    {
        return original.getQuads(state, side, rand, extraData);
    }

    @Override
    public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand)
    {
        return original.getQuads(state, side, rand);
    }

    @Override
    public TextureAtlasSprite getParticleTexture() { return original.getParticleTexture(); }

    @Override
    public IBakedModel handlePerspective(ItemCameraTransforms.TransformType type, MatrixStack matrix)
    {
        transform = type;

        TransformationMatrix tr = TransformationHelper.toTransformation(this.getItemCameraTransforms().getTransform(type));
        if (!tr.isIdentity()) { tr.push(matrix); }
        return this;
    }

    @Override
    public ItemOverrideList getOverrides() { return original.getOverrides(); }

    @Override
    public boolean isAmbientOcclusion() { return original.isAmbientOcclusion(); }

    @Override
    public boolean isGui3d() { return original.isGui3d(); }

    @Override
    public boolean func_230044_c_() { return original.func_230044_c_(); }

    @Override //INFO: Must be true for ISTERs to work
    public boolean isBuiltInRenderer() { return true; }

    public ItemCameraTransforms.TransformType getTransformType() { return transform; }

    @Override
    public ItemCameraTransforms getItemCameraTransforms() { return original.getItemCameraTransforms(); }
}

 

If you need any more code, I will be happy to provide it.

 

PS: If someone wants to suggest using overrides: I am not going to make the model system generate over 50000 models for all possible combinations

Edited by XFactHD
Link to comment
Share on other sites

Howdy

That sounds like it could be a bug, yeah.

 

I rely on something similar for my mods - i.e. finding and replacing the IBakedModels, and my code works fine even with F3+T.  My registration is subtly different for the variant ResourceLocation but everything else looks very similar.  I can't see how that would cause your problem, it might be something related to ISTER (which my code doesn't use)

 

As a workaround, you could perhaps change your base item model json to builtin/entity (so that your wrapper doesn't need to override isBuiltInRenderer()) and if necessary move your base json shape to a second model which your wrapper uses instead of the base item MRL.

 

I did put a breakpoint into both ItemModelMesherForge::rebuildCache and ItemModelMesher::rebuildCache, and when I press F3+T it does call  ItemModelMesherForge::rebuildCache so I'm not sure that your conclusion is correct: "The problem is that it seems like the ItemModelMesher's cache is not rebuilt after a resource reload."

 

-TGG

 

  // Called after all the other baked block models have been added to the modelRegistry
  // Allows us to manipulate the modelRegistry before BlockModelShapes caches them.
  @SubscribeEvent
  public static void onModelBakeEvent(ModelBakeEvent event)
  {
    // Find the existing model for ChessBoard - it will have been added automatically by vanilla due to our registration of
    //   of the item in StartupCommon.
    // Replace the mapping with our custom ChessboardModel.

    ModelResourceLocation itemModelResourceLocation = ChessboardModel.modelResourceLocation;
    IBakedModel existingModel = event.getModelRegistry().get(itemModelResourceLocation);
    if (existingModel == null) {
      LOGGER.warn("Did not find the expected vanilla baked model for ChessboardModel in registry");
    } else if (existingModel instanceof ChessboardModel) {
      LOGGER.warn("Tried to replace ChessboardModel twice");
    } else {
      ChessboardModel customModel = new ChessboardModel(existingModel);
      event.getModelRegistry().put(itemModelResourceLocation, customModel);
    }
  }

 

Link to comment
Share on other sites

13 hours ago, TheGreyGhost said:

As a workaround, you could perhaps change your base item model json to builtin/entity (so that your wrapper doesn't need to override isBuiltInRenderer()) and if necessary move your base json shape to a second model which your wrapper uses instead of the base item MRL.

That will probably not get me anywhere as the wrapper is not only used to tell the ItemRenderer to call my ISTER but also to get the ItemCameraTransforms.TransformType that the ItemRenderer was called with.

 

13 hours ago, TheGreyGhost said:

I did put a breakpoint into both ItemModelMesherForge::rebuildCache and ItemModelMesher::rebuildCache, and when I press F3+T it does call  ItemModelMesherForge::rebuildCache so I'm not sure that your conclusion is correct: "The problem is that it seems like the ItemModelMesher's cache is not rebuilt after a resource reload."

I read through the code multiple times and also came to the conclusion that there is no way the ItemModelMesher's cache is not getting rebuilt but when I put a breakpoint in RenderGun.loadModels(event.getModelRegistry()); and in ItemRenderer just before the ISTER gets called I get different instances of the model wrapper.

 

I just walked through the code in the debugger again while writing this and as it turns out Forge is doing nothing wrong and I am the idiot here because my own caching fucked me over. Because every instance of the gun item has its own instance of the ISTER, I thought it would be a good idea to get the specific model from the big cache and cache it again so I don't have to access the cache map every frame... As soon as I remove this redundant layer of caching it works 🤦‍♂️

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.