Jump to content

[Version 1.18.2, SOLVED] Change rendered mob's model under certain conditions


LeeCrafts

Recommended Posts

Hello,

I am trying to replace every rendered mob's model (not the mob itself) with the model of a custom entity, under certain conditions. This is how it would work:

@SubscribeEvent
public static void replaceMobModel(RenderLivingEvent.Pre<LivingEntity, EntityModel<LivingEntity>> event) {
    if (condition A is reached) {
        // replace every rendered mob's model with the model of a custom entity
    }
    // if condition A is not met, then every rendered mob's model reverts back to normal (e.g. villagers start looking like villagers again)
}

I was looking at this forum (https://forums.minecraftforge.net/topic/75986-114-how-to-change-rendered-entity/) and found out that I need to use EntityRenderManager#renderEntity. But since that is from a previous version, I assume it would be EntityRenderDispatcher#render. Here's what I tried to do so far:

@SubscribeEvent
public static void replaceMobModel(RenderLivingEvent.Pre<LivingEntity, EntityModel<LivingEntity>> event) {
    LocalPlayer localPlayer = Minecraft.getInstance().player;
    if (localPlayer != null && event.getEntity() instanceof Mob mob) {

        // I'll set up the conditions later once I get this working

        event.setCanceled(true);
        CustomEntity customEntity = ModEntities.CUSTOM_ENTITY.get().create(localPlayer.clientLevel);
        if (customEntity != null) {
            customEntity.setXRot(mob.getXRot());
            customEntity.setYRot(mob.getYRot());
            Minecraft.getInstance().getEntityRenderDispatcher().render(
                    customEntity,
                    mob.getX(),
                    mob.getY(),
                    mob.getZ(),
                    mob.getViewYRot(event.getPartialTick()),
                    event.getPartialTick(),
                    event.getPoseStack(),
                    event.getMultiBufferSource(),
                    event.getPackedLight()
            );
        }
    }
}

This results in a stack overflow (EntityRenderDispatcher#render seems to cause RenderLivingEvent to fire, causing an infinite recursion). Is this even the right thing to do? Or do I have to go to my CustomEntity renderer class and override render()? If that's the case, I don't know what I should put in that method.

Edited by LeeCrafts
Link to comment
Share on other sites

  • LeeCrafts changed the title to [Version 1.18.2] Change rendered mob's model under certain conditions

Although I am not exactly sure how a try-finally block would help (i.e. what code I should run even if a runtime exception is thrown), I have made some progress. The custom mob renders, but it does not rotate--even when I apply rotations to it before calling render().

private static boolean renderingCustomEntity = false;
private static CustomEntity customEntity;

private static void initializeCustomEntityIfNull(LocalPlayer localPlayer) {
    if (customEntity == null) {
        customEntity = ModEntities.CUSTOM_ENTITY.get().create(localPlayer.clientLevel);
    }
}

@SubscribeEvent
public static void replaceMobModel(RenderLivingEvent.Pre<LivingEntity, EntityModel<LivingEntity>> event) {
    LocalPlayer localPlayer = Minecraft.getInstance().player;
    if (localPlayer != null && event.getEntity() instanceof Mob mob) {
        try {
            if (!renderingCustomEntity) {
                renderingCustomEntity = true;
                event.setCanceled(true);
                initializeCustomEntityIfNull(localPlayer);

                // I try to apply rotations to the custom entity before it rendered, but it still does not rotate at all.
                customEntity.setYRot(mob.getYRot());
                customEntity.setYHeadRot(mob.getYHeadRot());

                customEntity.setPose(mob.getPose());

                // For some reason, the custom mob did not render when I called EntityRenderDispatcher#render.
                // So I called render() from EntityRenderDispatcher#getRenderer instead.
                Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(customEntity).render(
                        customEntity,
                        customEntity.getYRot(),
                        event.getPartialTick(),
                        event.getPoseStack(),
                        event.getMultiBufferSource(),
                        event.getPackedLight()
                );
            }
        } finally {
            renderingCustomEntity = false;
        }
    }
}

What would I be missing? Thank you for the help.

Edited by LeeCrafts
Link to comment
Share on other sites

Got the rotation working. I had to look at LivingEntityRenderer#render and setupRotations a little more closely, and I realized that I needed to change the custom entity's yBodyRot and yBodyRotO

private static boolean renderingCustomEntity = false;
private static CustomEntity customEntity;

private static void refreshCustomEntity(LocalPlayer localPlayer, LivingEntity livingEntity) {
    // If the level changes, remove the custom entity by assigning its reference to a new custom entity.
    // The previous custom entity will eventually be garbage collected.
    if (customEntity == null || customEntity.level != livingEntity.level) {
        customEntity = ModEntities.CUSTOM_ENTITY.get().create(localPlayer.clientLevel);
    }
}

@SubscribeEvent
public static void replaceMobModel(RenderLivingEvent.Pre<LivingEntity, EntityModel<LivingEntity>> event) {
    LocalPlayer localPlayer = Minecraft.getInstance().player;
    if (localPlayer != null && event.getEntity() instanceof Mob mob) {
        if (/* put your own condition here */) {
            if (!renderingCustomEntity) {
                try {
                    renderingCustomEntity = true;
                    event.setCanceled(true);
                    refreshCustomEntity(localPlayer, mob);

                    // (truth be told, my custom entity does not have a "head", so these lines aren't needed)
                    // customEntity.setYHeadRot(mob.getYHeadRot());
                    // customEntity.yHeadRotO = mob.yHeadRotO;

                    customEntity.setYBodyRot(mob.yBodyRot);
                    customEntity.yBodyRotO = mob.yBodyRotO;
                    customEntity.setPose(mob.getPose());
                    Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(customEntity).render(
                            customEntity,
                            customEntity.yBodyRot,
                            event.getPartialTick(),
                            event.getPoseStack(),
                            event.getMultiBufferSource(),
                            event.getPackedLight()
                    );
                } finally {
                    renderingCustomEntity = false;
                }
            }
        }
    }
}

 

On 5/25/2022 at 2:13 AM, diesieben07 said:

This will create a memory leak if the level changes. You have to unload the entity with the level and also change the entity if the level changes.

As shown in my code, if the mob whose model is replaced moves to a different dimension, I unload the custom entity with Entity#discard and then reinitialize it on the next tick. I wonder if I also have to unload the custom entity when the mob it is "replacing" dies.

^ Edit: I have changed the code due to @diesieben07's most recent comment.

Edited by LeeCrafts
i changed it a bunch of times, but hopefully this is the last edit lol
Link to comment
Share on other sites

  • LeeCrafts changed the title to [Version 1.18.2, SOLVED] Change rendered mob's model under certain conditions

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.