using System; using System.Collections.Generic; using System.Linq; using System.Xml; using System.Xml.Serialization; using UnityEngine; namespace RimWorldAnimationStudio { public class AnimationStage { // Data to/from animationDef public string stageName; public int? playTimeTicks; public int? playTimeTicksQuick; public bool? isLooping; [XmlArray("animationClips"), XmlArrayItem("li")] public List animationClips; // Data serialization control public bool ShouldSerializeanimationClips() { return animationClips.NotNullOrEmpty(); } // Data helper functions [XmlIgnore] public string StageName { get { return string.IsNullOrEmpty(stageName) ? stageName = "NewStage" : stageName; } set { stageName = value; } } [XmlIgnore] public int PlayTimeTicks { get { return playTimeTicks.HasValue ? playTimeTicks.Value : 0; } set { playTimeTicks = value; } } [XmlIgnore] public int PlayTimeTicksQuick { get { return playTimeTicksQuick.HasValue ? playTimeTicksQuick.Value : 0; } set { playTimeTicksQuick = value; } } [XmlIgnore] public bool IsLooping { get { return isLooping == true; } set { isLooping = value; } } [XmlIgnore] public List AnimationClips { get { return animationClips.NullOrEmpty() ? animationClips = new List() : animationClips; } set { animationClips = value.NotNullOrEmpty() ? value : null; } } [XmlIgnore] public int StageLoopsNormal { get { return Mathf.CeilToInt(PlayTimeTicks / Workspace.StageWindowSize); } set { value = Math.Max(1, value); PlayTimeTicks = value * Workspace.StageWindowSize; IsLooping = value > 1; } } [XmlIgnore] public int StageLoopsQuick { get { return Mathf.CeilToInt(PlayTimeTicksQuick / Workspace.StageWindowSize); } set { value = Math.Max(0, Math.Min(value, StageLoopsNormal)); PlayTimeTicksQuick = value * Workspace.StageWindowSize; } } // Local data [XmlIgnore] public int stageWindowSize = -1; // Methods public void Initialize() { foreach (PawnAnimationClip clip in AnimationClips) { clip.BuildSimpleCurves(); if (clip.duration > PlayTimeTicks) { PlayTimeTicks = clip.duration; } } } public int GetStageID() { if (Workspace.animationDef == null) return -1; return Workspace.animationDef.AnimationStages.IndexOf(this); } public void StretchStageWindow(int newStageWindowSize) { ResizeStageWindow(newStageWindowSize); float scale = (float)newStageWindowSize / Workspace.StageWindowSize; foreach (PawnAnimationClip clip in AnimationClips) { foreach (PawnKeyframe keyframe in clip.Keyframes) { keyframe.atTick = keyframe.atTick == Constants.minTick ? Constants.minTick : Mathf.CeilToInt((float)keyframe.atTick.Value * scale); keyframe.TickDuration = 0; } clip.BuildSimpleCurves(); } EventsManager.OnStageWindowSizeChanged(this); } public void ResizeStageWindow(int newStageWindowSize) { Workspace.GetCurrentAnimationStage().PlayTimeTicks = newStageWindowSize * StageLoopsNormal; Workspace.GetCurrentAnimationStage().PlayTimeTicksQuick = newStageWindowSize * StageLoopsQuick; Workspace.GetCurrentAnimationStage().stageWindowSize = newStageWindowSize; EventsManager.OnStageWindowSizeChanged(this); } public void AddAnimationClip(int actorID = -1) { PawnAnimationClip clip = new PawnAnimationClip(); PawnKeyframe lastkeyframe = null; if (actorID >= 0) { lastkeyframe = Workspace.GetPawnAnimationClip(actorID)?.Keyframes?.Last(); } if (lastkeyframe != null) { PawnKeyframe keyframeA = lastkeyframe.GetClone(); keyframeA.GenerateKeyframeID(actorID); keyframeA.atTick = null; keyframeA.TickDuration = Constants.defaultAnimationClipLength - 1; clip.Keyframes.Add(keyframeA); PawnKeyframe keyframeB = lastkeyframe.GetClone(); keyframeB.GenerateKeyframeID(actorID); keyframeB.atTick = null; keyframeB.TickDuration = 1; clip.Keyframes.Add(keyframeB); } else { PawnKeyframe keyframeA = new PawnKeyframe(); keyframeA.TickDuration = Constants.defaultAnimationClipLength - 1; clip.Keyframes.Add(keyframeA); PawnKeyframe keyframeB = new PawnKeyframe(); clip.Keyframes.Add(keyframeB); } animationClips.Add(clip); } public AnimationStage GetClone() { AnimationStage clone = this.Copy(); foreach (PawnAnimationClip clip in clone.animationClips) { foreach (PawnKeyframe keyframe in clip.Keyframes) { keyframe.GenerateKeyframeID(keyframe.actorID); } } return clone; } // Pre-save / post-load public void OnPreSave() { foreach (PawnAnimationClip clip in AnimationClips) { clip.Keyframes = clip.Keyframes.OrderBy(x => x.atTick).ToList(); } } public void OnPostLoad() { } } }