GeckoLib

GeckoLib

243M Downloads

Animation fails to switch if it was changed when entity cannot be rendered

Closed this issue ยท 4 comments

commented

Geckolib 5.0, in Geckolib 4 this wasn't the case

2025-04-16.20-23-24.2.mp4

Entity on video has special animation when it has vehicle (player in this case): https://github.com/NordAct/useless-reptile/blob/88d0cbea59e4e6bcc2effa031576aebd29aa4a7a/src/main/java/nordmods/uselessreptile/common/entity/RiverPikehornEntity.java#L116

To prevent obscuring the vision, entity is not rendered in first person (this is the base class for its renderer): https://github.com/NordAct/useless-reptile/blob/88d0cbea59e4e6bcc2effa031576aebd29aa4a7a/src/main/java/nordmods/uselessreptile/client/renderer/base/HeadMountDragonEntityRenderer.java#L49

As seen on video, when mounting on player in third person, animation switches normally. But when entity is first put on player when it's in first person, then it just keeps animation it had before.

I've tried to see with debugger what's happening. Animation, that supposed to play, does get in controller's animationQueue, but never gets polled. I didn't check conditions when it supposed to poll, so can't say what's wrong here

commented

I mean this sounds like intended behaviour to me?

If it's not rendering, it won't be animating?

commented

Shouldn't it switch animation anyway when render is called again? I mean, from controller, it supposed to play other animation, but it keeps playing the animation that was before it stopped rendering.
Taking the same entity as on video as example.

This is how it's controller looks like:

    private <A extends GeoEntity> PlayState mainController(AnimationTest<A> event) {
        event.controller().setAnimationSpeed(animationSpeed);
        if (hasVehicle()) return loopAnim("sit.head", event);
        if (isFlying()) {
            if (isMoving() || event.isMoving()) {
                if (getTiltState() == 1) return loopAnim("fly.straight.up", event);
                if (getTiltState() == 2) return loopAnim("fly.dive", event);
                if (shouldGlide) return loopAnim("fly.glide", event);
                return loopAnim("fly.straight", event);
            }
            event.controller().setAnimationSpeed(Math.max(animationSpeed, 1));
            return loopAnim("fly.idle", event);
        }
        if (getIsSitting() && !isDancing()) return loopAnim("sit", event);
        if (event.isMoving()) return loopAnim("walk", event);
        event.controller().setAnimationSpeed(1);
        if (isDancing()) return loopAnim("dance", event);
        return loopAnim("idle", event);
    }

loopAnim() is just shortcut method here because I love early returns

    protected <A extends GeoEntity> PlayState loopAnim(String anim, AnimationTest<A> event) {
        event.controller().setAnimation(RawAnimation.begin().thenLoop(anim)); return PlayState.CONTINUE;
    }

So i.e., when entity has no vehicle and is moving, it'll play animation called walk. When entity has vehicle, it's supposed to play animation sit.head. Yet, what happens, if entity gets vehicle and at the same moment gets prevented from rendering, it keeps current animation as walk rather than changing it to sit.head even after it starts to be rendered again.

Below is what debugger shows for this controller. So like animation does get put in queue, but it never gets to be current animation because animation was added in queue when entity couldn't be rendered.

Image

commented

Might have found culprit.
The way I cancel renderer is by overriding defaultRender() method. Yet, before it's called, fillRenderState() called first, since it's within vanilla's method of filling render state (extractRenderState() in mojmap) within GeoEntityRenderer. Calling it always causes the call of prepareForRenderPass() within controller, which causes switch of animation state from transition to running. Yet, because entity is not rendering, tickAnimation() within animation processor is never called (since it called from model during actuallyRender()), thus beginTick() within controller cannot be called, thus making impossible for controller to change current animation. And since animation state was already changed to running, it will not attempt to get new animation when entity is rendered again without changing current animation.

On pic below entity is already not rendered, but yet its controller's prepareForRenderPass() is triggered
Image

As I can see prepareForRenderPass() is called after geckolib data is filled, so maybe it can be fixed by adding some data ticket that would prevent animation processing or just tell the whole renderer "hey, please don't render this, thanks" and also make animation controller not to be triggered?

commented

Or just cancel the render properly? lol