2018-12-30 18:00:05 +08:00
using System ;
using System.Collections.Generic ;
using Microsoft.Xna.Framework ;
2017-09-12 09:35:31 +08:00
using Microsoft.Xna.Framework.Graphics ;
2018-03-06 12:46:45 +08:00
using StardewValley ;
using StardustCore.UIUtilities ;
2017-09-12 09:35:31 +08:00
namespace StardustCore.Animations
{
2018-12-30 18:00:05 +08:00
/// <summary>Used to play animations for Stardust.CoreObject type objects and all objects that extend from it. In draw code of object make sure to use this info instead.</summary>
public class AnimationManager
2017-09-12 09:35:31 +08:00
{
2018-12-30 18:00:05 +08:00
public Dictionary < string , List < Animation > > animations = new SerializableDictionary < string , List < Animation > > ( ) ;
public string currentAnimationName ;
public int currentAnimationListIndex ;
public List < Animation > currentAnimationList = new List < Animation > ( ) ;
private Texture2DExtended objectTexture ; ///Might not be necessary if I use the CoreObject texture sheet.
public Animation defaultDrawFrame ;
public Animation currentAnimation ;
public bool enabled ;
2018-08-07 11:01:59 +08:00
public string animationDataString ;
2018-12-16 12:54:58 +08:00
2018-12-30 18:00:05 +08:00
/// <summary>Empty constructor.</summary>
public AnimationManager ( ) { }
2018-12-16 12:54:58 +08:00
2018-12-30 18:00:05 +08:00
/// <summary>Constructor for Animation Manager class.</summary>
2017-09-12 09:35:31 +08:00
/// <param name="ObjectTexture">The texture that will be used for the animation. This is typically the same as the object this class is attached to.</param>
/// <param name="DefaultFrame">This is used if no animations will be available to the animation manager.</param>
/// <param name="EnabledByDefault">Whether or not animations play by default. Default value is true.</param>
2018-12-30 18:00:05 +08:00
public AnimationManager ( Texture2DExtended ObjectTexture , Animation DefaultFrame , bool EnabledByDefault = true )
2017-09-12 09:35:31 +08:00
{
2018-12-30 18:00:05 +08:00
this . currentAnimationListIndex = 0 ;
2017-09-12 09:35:31 +08:00
this . objectTexture = ObjectTexture ;
this . defaultDrawFrame = DefaultFrame ;
this . enabled = EnabledByDefault ;
2018-12-30 18:00:05 +08:00
this . currentAnimation = this . defaultDrawFrame ;
2018-08-07 11:01:59 +08:00
this . currentAnimationName = "" ;
this . animationDataString = "" ;
2017-09-12 09:35:31 +08:00
}
2018-12-30 18:00:05 +08:00
public AnimationManager ( Texture2DExtended ObjectTexture , Animation DefaultFrame , string animationString , string startingAnimationKey , int startingAnimationFrame = 0 , bool EnabledByDefault = true )
2017-09-12 09:35:31 +08:00
{
2018-12-30 18:00:05 +08:00
this . currentAnimationListIndex = 0 ;
2017-09-12 09:35:31 +08:00
this . objectTexture = ObjectTexture ;
this . defaultDrawFrame = DefaultFrame ;
this . enabled = EnabledByDefault ;
2018-08-07 11:01:59 +08:00
this . animationDataString = animationString ;
this . animations = parseAnimationsFromXNB ( animationString ) ;
2018-12-30 18:00:05 +08:00
bool f = this . animations . TryGetValue ( startingAnimationKey , out this . currentAnimationList ) ;
if ( f )
2018-12-15 19:00:32 +08:00
{
2018-12-30 18:00:05 +08:00
this . setAnimation ( startingAnimationKey , startingAnimationFrame ) ;
2017-09-12 09:35:31 +08:00
}
2018-12-15 19:00:32 +08:00
else
{
2018-12-30 18:00:05 +08:00
this . currentAnimation = this . defaultDrawFrame ;
2018-12-15 19:00:32 +08:00
this . currentAnimationName = "" ;
}
2017-09-12 09:35:31 +08:00
}
2018-12-30 18:00:05 +08:00
public AnimationManager ( Texture2DExtended ObjectTexture , Animation DefaultFrame , Dictionary < string , List < Animations . Animation > > animationString , string startingAnimationKey , int startingAnimationFrame = 0 , bool EnabledByDefault = true )
2018-08-07 11:01:59 +08:00
{
2018-12-30 18:00:05 +08:00
this . currentAnimationListIndex = 0 ;
2018-08-07 11:01:59 +08:00
this . objectTexture = ObjectTexture ;
this . defaultDrawFrame = DefaultFrame ;
this . enabled = EnabledByDefault ;
this . animations = animationString ;
2018-12-30 18:00:05 +08:00
if ( this . animations . TryGetValue ( startingAnimationKey , out this . currentAnimationList ) )
this . setAnimation ( startingAnimationKey , startingAnimationFrame ) ;
2018-12-15 19:00:32 +08:00
else
{
2018-12-30 18:00:05 +08:00
this . currentAnimation = this . defaultDrawFrame ;
2018-12-15 19:00:32 +08:00
this . currentAnimationName = "" ;
}
2018-08-07 11:01:59 +08:00
}
2018-12-30 18:00:05 +08:00
/// <summary>Update the animation frame once after drawing the object.</summary>
2017-09-12 09:35:31 +08:00
public void tickAnimation ( )
{
try
{
2018-12-30 18:00:05 +08:00
if ( this . currentAnimation . frameDuration = = - 1 | | ! this . enabled | | this . currentAnimation = = this . defaultDrawFrame )
return ; //This is if this is a default animation or the animation stops here.
if ( this . currentAnimation . frameCountUntilNextAnimation = = 0 )
this . getNextAnimation ( ) ;
2017-09-12 09:35:31 +08:00
this . currentAnimation . tickAnimationFrame ( ) ;
}
2018-12-30 18:00:05 +08:00
catch ( Exception err )
2017-09-12 09:35:31 +08:00
{
ModCore . ModMonitor . Log ( "An internal error occured when trying to tick the animation." ) ;
ModCore . ModMonitor . Log ( err . ToString ( ) , StardewModdingAPI . LogLevel . Error ) ;
}
}
2018-12-30 18:00:05 +08:00
/// <summary>Get the next animation in the list of animations.</summary>
2017-09-12 09:35:31 +08:00
public void getNextAnimation ( )
{
2018-12-30 18:00:05 +08:00
this . currentAnimationListIndex + + ;
if ( this . currentAnimationListIndex = = this . currentAnimationList . Count ) //If the animation frame I'm tryting to get is 1 outside my list length, reset the list.
this . currentAnimationListIndex = 0 ;
//Get the next animation from the list and reset it's counter to the starting frame value.
this . currentAnimation = this . currentAnimationList [ this . currentAnimationListIndex ] ;
this . currentAnimation . startAnimation ( ) ;
2017-09-12 09:35:31 +08:00
}
2018-12-30 18:00:05 +08:00
/// <summary>Gets the animation from the dictionary of all animations available.</summary>
public bool setAnimation ( string AnimationName , int StartingFrame = 0 )
2017-09-12 09:35:31 +08:00
{
2018-12-30 18:00:05 +08:00
if ( this . animations . TryGetValue ( AnimationName , out var dummyList ) )
2017-09-12 09:35:31 +08:00
{
2018-12-30 18:00:05 +08:00
if ( dummyList . Count ! = 0 | | StartingFrame > = dummyList . Count )
2017-09-12 09:35:31 +08:00
{
2018-12-30 18:00:05 +08:00
this . currentAnimationList = dummyList ;
this . currentAnimation = this . currentAnimationList [ StartingFrame ] ;
this . currentAnimationName = AnimationName ;
2017-09-13 07:30:30 +08:00
return true ;
2017-09-12 09:35:31 +08:00
}
else
{
2018-12-30 18:00:05 +08:00
if ( dummyList . Count = = 0 ) ModCore . ModMonitor . Log ( "Error: Current animation " + AnimationName + " has no animation frames associated with it." ) ;
//if (dummyList.Count > dummyList.Count) ModCore.ModMonitor.Log("Error: Animation frame " + StartingFrame + " is outside the range of provided animations. Which has a maximum count of " + dummyList.Count);
2017-09-12 09:35:31 +08:00
return false ;
}
}
else
{
ModCore . ModMonitor . Log ( "Error setting animation: " + AnimationName + " animation does not exist in list of available animations. Did you make sure to add it in?" ) ;
return false ;
}
}
2018-12-30 18:00:05 +08:00
/// <summary>Sets the animation manager to an on state, meaning that this animation will update on the draw frame.</summary>
2017-09-12 09:35:31 +08:00
public void enableAnimation ( )
{
this . enabled = true ;
}
2018-02-06 17:27:28 +08:00
2018-12-30 18:00:05 +08:00
/// <summary>Sets the animation manager to an off state, meaning that this animation will no longer update on the draw frame.</summary>
2017-09-12 09:35:31 +08:00
public void disableAnimation ( )
{
this . enabled = false ;
}
2017-09-13 07:30:30 +08:00
public static Dictionary < string , List < Animation > > parseAnimationsFromXNB ( string s )
{
string [ ] array = s . Split ( '*' ) ;
2018-12-30 18:00:05 +08:00
Dictionary < string , List < Animation > > parsedDic = new Dictionary < string , List < Animation > > ( ) ;
foreach ( string v in array )
2017-09-13 07:30:30 +08:00
{
2018-12-30 18:00:05 +08:00
// Log.AsyncC(v);
string [ ] animationArray = v . Split ( ' ' ) ;
if ( parsedDic . ContainsKey ( animationArray [ 0 ] ) )
2017-09-13 07:30:30 +08:00
{
2018-12-30 18:00:05 +08:00
List < Animation > aniList = parseAnimationFromString ( v ) ;
foreach ( var ani in aniList )
parsedDic [ animationArray [ 0 ] ] . Add ( ani ) ;
2017-09-13 07:30:30 +08:00
}
else
{
2018-12-30 18:00:05 +08:00
parsedDic . Add ( animationArray [ 0 ] , new List < Animation > ( ) ) ;
List < Animation > aniList = parseAnimationFromString ( v ) ;
2017-11-17 18:50:22 +08:00
foreach ( var ani in aniList )
2018-12-30 18:00:05 +08:00
parsedDic [ animationArray [ 0 ] ] . Add ( ani ) ;
2017-09-13 07:30:30 +08:00
}
}
return parsedDic ;
}
2017-11-17 18:50:22 +08:00
public static List < Animation > parseAnimationFromString ( string s )
2017-09-13 07:30:30 +08:00
{
2018-12-30 18:00:05 +08:00
List < Animation > ok = new List < Animation > ( ) ;
2017-11-17 18:50:22 +08:00
string [ ] array2 = s . Split ( '>' ) ;
2018-12-30 18:00:05 +08:00
foreach ( string q in array2 )
{
2017-11-17 18:50:22 +08:00
string [ ] array = q . Split ( ' ' ) ;
try
{
Animation ani = new Animation ( new Rectangle ( Convert . ToInt32 ( array [ 1 ] ) , Convert . ToInt32 ( array [ 2 ] ) , Convert . ToInt32 ( array [ 3 ] ) , Convert . ToInt32 ( array [ 4 ] ) ) , Convert . ToInt32 ( array [ 5 ] ) ) ;
2018-12-30 18:00:05 +08:00
// ModCore.ModMonitor.Log(ani.sourceRectangle.ToString());
2017-11-17 18:50:22 +08:00
ok . Add ( ani ) ;
}
2018-12-30 18:00:05 +08:00
catch { }
2017-11-17 18:50:22 +08:00
}
return ok ;
2017-09-13 07:30:30 +08:00
}
2018-12-30 18:00:05 +08:00
/// <summary>Used to handle general drawing functionality using the animation manager.</summary>
2018-03-06 12:46:45 +08:00
/// <param name="spriteBatch">We need a spritebatch to draw.</param>
/// <param name="texture">The texture to draw.</param>
/// <param name="Position">The onscreen position to draw to.</param>
/// <param name="sourceRectangle">The source rectangle on the texture to draw.</param>
/// <param name="drawColor">The color to draw the thing passed in.</param>
/// <param name="rotation">The rotation of the animation texture being drawn.</param>
/// <param name="origin">The origin of the texture.</param>
/// <param name="scale">The scale of the texture.</param>
/// <param name="spriteEffects">Effects that get applied to the sprite.</param>
/// <param name="LayerDepth">The dept at which to draw the texture.</param>
2018-12-30 18:00:05 +08:00
public void draw ( SpriteBatch spriteBatch , Texture2D texture , Vector2 Position , Rectangle ? sourceRectangle , Color drawColor , float rotation , Vector2 origin , float scale , SpriteEffects spriteEffects , float LayerDepth )
2018-03-06 12:46:45 +08:00
{
//Log.AsyncC("Animation Manager is working!");
spriteBatch . Draw ( texture , Position , sourceRectangle , drawColor , rotation , origin , scale , spriteEffects , LayerDepth ) ;
try
{
this . tickAnimation ( ) ;
// Log.AsyncC("Tick animation");
}
catch ( Exception err )
{
ModCore . ModMonitor . Log ( err . ToString ( ) ) ;
}
}
2017-09-13 07:30:30 +08:00
2018-06-14 02:11:56 +08:00
public Texture2DExtended getExtendedTexture ( )
{
return this . objectTexture ;
}
2018-08-07 11:01:59 +08:00
public void setExtendedTexture ( Texture2DExtended texture )
{
this . objectTexture = texture ;
}
public void setEnabled ( bool enabled )
{
this . enabled = enabled ;
}
2018-06-14 02:11:56 +08:00
public Texture2D getTexture ( )
{
return this . objectTexture . getTexture ( ) ;
}
2017-09-12 09:35:31 +08:00
}
}