Floogen / AlternativeTextures

Framework which allows for placeable objects, buildings and entities to have texture variety in Stardew Valley.
GNU General Public License v3.0
14 stars 13 forks source link

Farm Animals don't use Swimming Frames #65

Open Jolly-Alpaca opened 1 week ago

Jolly-Alpaca commented 1 week ago

This is already documented as a bug on Nexus, but I wanted to add some detail as I decided to investigate why swimming frames weren't being used.

In FarmAnimalPatch.DrawPrefix, if there are no alternative textures or only disabled alternative textures, the farm animals AnimatedSprite object's loadedTexture field is set to an empty string:

FarmAnimalPatch.cs

__instance.Sprite.loadedTexture = String.Empty;

That's it. However, after commenting out this line of code, swimming frames were working again.

The reason this line of code is causing swimming frames from being used is because the swim offset is applied to the source rectangle in FarmAnimal.updateWhenCurrentLocation, not in AnimatedSprite's code. So at the time of draw, the swim offset has already been applied to the source rectangle.

FarmAnimal.cs

public virtual bool updateWhenCurrentLocation(GameTime time, GameLocation location)
{
    ...
    if (this.IsActuallySwimming())
    {
        FarmAnimalData data = this.GetAnimalData();
    this.Sprite.UpdateSourceRect();
    Microsoft.Xna.Framework.Rectangle source_rect = this.Sprite.SourceRect;
    source_rect.Offset(data?.SwimOffset ?? new Point(0, 112));
    this.Sprite.SourceRect = source_rect;
    }
}

While setting loadedTexture to an empty string doesn't trigger the source rectangle to be updated, the getter for this.Texture in AnimatedSprite.draw does.

AnimatedSprite.cs

public Texture2D Texture
{
    get
    {
        this.loadTexture();
    return this.spriteTexture;
    }
}

...

private void loadTexture()
{
    if (!(this.loadedTexture == this.textureName.Value))
    {
        if (this.textureName.Value == null)
    {
        this.spriteTexture = null;
    }
    else
    {
        this.spriteTexture = this.contentManager.Load<Texture2D>(this.textureName.Value);
    }
    this.loadedTexture = this.textureName.Value;
    if (this.spriteTexture != null)
    {
        this.UpdateSourceRect();
    }
    }
}

Since loadedTexture is an empty string when loadTexture is called from the draw, it does not equal this.textureName.Value, causing the condition to evaluate as true, eventually resulting in this.UpdateSourceRect to be called. This overwrites the source rectangle with the swim offset applied resulting in farm animals using their walking frames instead of their swimming frames when swimming.

Removing the line of code setting loadedTexture to an emptry string fixes the issue, but I do not know what purpose that line of code serves, so I hesitate to propose this as the fix.