Ghost frames fix plus undo redo system

This commit is contained in:
AbstractConcept 2022-09-18 19:07:44 -05:00
parent 591b176924
commit b0a965e0b2
163 changed files with 948 additions and 214 deletions

View file

@ -9,8 +9,10 @@ namespace RimWorldAnimationStudio
public string layer = "Pawn";
public List<string> tags;
[XmlIgnore] public int duration;
[XmlIgnore] public Dictionary<int, string> SoundEffects = new Dictionary<int, string>();
//[XmlIgnore] public Dictionary<int, string> SoundEffects = new Dictionary<int, string>();
//[XmlIgnore] public int duration;
public virtual int duration { get { return 0; } }
public abstract void BuildSimpleCurves();

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using UnityEngine;
@ -20,6 +21,8 @@ namespace RimWorldAnimationStudio
[XmlIgnore] public SimpleCurve HeadFacing = new SimpleCurve();
[XmlIgnore] public SimpleCurve BodyFacing = new SimpleCurve();
public override int duration { get { return keyframes.Max(x => x.atTick.Value); } }
public override void BuildSimpleCurves()
{
BodyAngle.Clear();
@ -36,7 +39,6 @@ namespace RimWorldAnimationStudio
foreach (PawnKeyframe frame in keyframes)
{ duration += frame.tickDuration; }
this.duration = duration;
int keyframePosition = 0;
for (int i = 0; i < keyframes.Count; i++)

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
@ -13,9 +14,12 @@ namespace RimWorldAnimationStudio
[XmlIgnore] public SimpleCurve PositionZ = new SimpleCurve();
[XmlIgnore] public SimpleCurve Rotation = new SimpleCurve();
public override int duration { get { return keyframes.Max(x => x.atTick.Value); } }
public override void BuildSimpleCurves()
{
int duration = 0;
//getting the length of the whole clip
foreach (ThingKeyframe frame in keyframes)
{
@ -23,7 +27,7 @@ namespace RimWorldAnimationStudio
}
//guarantees loops don't get cut off mid-anim
this.duration = duration;
//this.duration = duration;
int keyframePosition = 0;
foreach (ThingKeyframe frame in keyframes)
@ -33,9 +37,6 @@ namespace RimWorldAnimationStudio
PositionX.Add((float)frame.atTick / (float)duration, frame.positionX, true);
PositionZ.Add((float)frame.atTick / (float)duration, frame.positionZ, true);
Rotation.Add((float)frame.atTick / (float)duration, frame.rotation, true);
if (frame.soundEffect != null)
{ SoundEffects.Add((int)frame.atTick, frame.soundEffect); }
}
else
@ -44,9 +45,6 @@ namespace RimWorldAnimationStudio
PositionZ.Add((float)keyframePosition / (float)duration, frame.positionZ, true);
Rotation.Add((float)keyframePosition / (float)duration, frame.rotation, true);
if (frame.soundEffect != null)
{ SoundEffects.Add(keyframePosition, frame.soundEffect); }
keyframePosition += frame.tickDuration;
}
}

View file

@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using UnityEngine;
namespace RimWorldAnimationStudio
{
@ -27,5 +29,53 @@ namespace RimWorldAnimationStudio
animationTimeTicks += stage.playTimeTicks;
}
}
public void RunPreSaveOperations()
{
// Stage edits
for (int i = 0; i < animationStages.Count; i++)
{
AnimationStage stage = animationStages[i];
// Sort keyframes by atTick
foreach (PawnAnimationClip clip in stage.animationClips)
{ clip.keyframes = clip.keyframes.OrderBy(x => x.atTick).ToList(); }
// Check if looping
int stageWindowSize = animationStages[i].stageWindowSize > 0 ? animationStages[i].stageWindowSize : animationStages[i].animationClips.Select(x => x.duration).Max();
int cycles = Mathf.CeilToInt(animationStages[i].playTimeTicks / stageWindowSize);
Debug.Log(animationStages[i].playTimeTicks);
Debug.Log(animationStages[i].stageWindowSize);
Debug.Log(cycles);
stage.isLooping = cycles > 1;
}
// Body part list edit
foreach (Actor actor in actors)
{
actor.isFucking = actor.requiredGenitals.Contains("Any appendage");
if (actor.isFucking == true)
{ actor.requiredGenitals.Remove("Any appendage"); }
actor.isFucked= actor.requiredGenitals.Contains("Any orifice");
if (actor.isFucked == true)
{ actor.requiredGenitals.Remove("Any orifice"); }
}
}
public void RunPostLoadOperations()
{
foreach (Actor actor in actors)
{
if (actor.isFucking == true)
{ actor.requiredGenitals.Add("Any appendage"); }
if (actor.isFucked == true)
{ actor.requiredGenitals.Add("Any orifice"); }
}
}
}
}

View file

@ -18,7 +18,7 @@ namespace RimWorldAnimationStudio
public void Initialize()
{
foreach (AnimationClip clip in animationClips)
foreach (PawnAnimationClip clip in animationClips)
{
clip.BuildSimpleCurves();

View file

@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
@ -13,6 +14,9 @@ namespace RimWorldAnimationStudio
public InputField bodyOffsetZField;
public Toggle initiatorToggle;
private int actorID = -1;
private bool isDirty = false;
public void Initialize()
{
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
@ -24,15 +28,30 @@ namespace RimWorldAnimationStudio
bodyOffsetZField.text = actor.bodyTypeOffset.GetOffset(bodyType).z.ToString();
}
public void UpdateAnimationDef()
public void OnBodyTypeChanged()
{
if (Workspace.animationDef == null) return;
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
string bodyType = bodyTypeDropdown.options[bodyTypeDropdown.value].text;
bodyType = bodyType == null || bodyType == "" ? "Male" : bodyType;
Debug.Log(bodyType);
AnimationController.Instance.transform.GetChild(Workspace.actorID).GetComponent<ActorBody>().bodyType = bodyType;
AnimationController.Instance.GetComponentsInChildren<ActorBody>()[Workspace.actorID].bodyType = bodyType;
bodyOffsetXField.text = actor.bodyTypeOffset.GetOffset(bodyType).x.ToString();
bodyOffsetZField.text = actor.bodyTypeOffset.GetOffset(bodyType).z.ToString();
}
public void UpdateAnimationDef()
{
if (Workspace.animationDef == null || isDirty) return;
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
string bodyType = bodyTypeDropdown.options[bodyTypeDropdown.value].text;
bodyType = bodyType == null || bodyType == "" ? "Male" : bodyType;
float.TryParse(bodyOffsetXField.text, out float x);
float.TryParse(bodyOffsetZField.text, out float z);
actor.bodyTypeOffset.SetOffset(bodyType, new Vector2(x, z));
@ -42,6 +61,8 @@ namespace RimWorldAnimationStudio
public void OpenSelectBodyPartsDialog()
{
if (Workspace.animationDef == null) return;
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
var dialog = Resources.FindObjectsOfTypeAll(typeof(SelectBodyPartsDialog)) as SelectBodyPartsDialog[];
@ -51,6 +72,8 @@ namespace RimWorldAnimationStudio
public void OpenSelectDefNamesDialog()
{
if (Workspace.animationDef == null) return;
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
var dialog = Resources.FindObjectsOfTypeAll(typeof(SelectDefNamesDialog)) as SelectDefNamesDialog[];
@ -60,11 +83,42 @@ namespace RimWorldAnimationStudio
public void OpenSelectBodyDefTypesDialog()
{
if (Workspace.animationDef == null) return;
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
var dialog = Resources.FindObjectsOfTypeAll(typeof(SelectBodyDefTypesDialog)) as SelectBodyDefTypesDialog[];
if (dialog != null)
{ dialog[0].Initialize(actor); dialog[0].Pop(); }
}
public void Update()
{
if (Workspace.animationDef == null) return;
if (actorID != Workspace.actorID)
{
isDirty = true;
if (Workspace.actorID >= AnimationController.Instance.GetComponentsInChildren<ActorBody>().Count())
{ Debug.Log("Waiting for actors to initialize..."); return; }
Actor actor = Workspace.animationDef.actors[Workspace.actorID];
ActorBody actorBody = AnimationController.Instance.GetComponentsInChildren<ActorBody>()[Workspace.actorID];
string bodyType = actorBody.bodyType;
bodyType = bodyType == null || bodyType == "" ? "Male" : bodyType;
bodyTypeDropdown.value = bodyTypeDropdown.options.IndexOf(bodyTypeDropdown.options.First(x => x.text == bodyType));
bodyOffsetXField.text = actor.bodyTypeOffset.GetOffset(bodyType).x.ToString();
bodyOffsetZField.text = actor.bodyTypeOffset.GetOffset(bodyType).z.ToString();
initiatorToggle.isOn = actor.initiator;
actorID = Workspace.actorID;
isDirty = false;
}
}
}
}

View file

@ -63,5 +63,10 @@ namespace RimWorldAnimationStudio
else
{ GetComponent<Image>().color = Constants.ColorGrey; }
}
public void InitiateUpdateOfGhostFrames()
{
BroadcastMessage("UpdateGhostFrames");
}
}
}

View file

@ -41,7 +41,7 @@ namespace RimWorldAnimationStudio
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
for (int i = 0; i < Workspace.bodyParts.Count; i++)
for (int i = 0; i < Workspace.interactionDefTypes.Count; i++)
{
string interactionDefType = Workspace.interactionDefTypes[i];

View file

@ -43,12 +43,11 @@ namespace RimWorldAnimationStudio
public void OnValueChanged()
{
keyframe.atTick = (int)value;
UpdateGhostFrames();
clip.BuildSimpleCurves();
AnimationController.Instance.stageTick = keyframe.atTick.Value;
timeline.InitiateUpdateOfGhostFrames();
}
// Ghost sliders are non-interactable slider handle
@ -57,27 +56,25 @@ namespace RimWorldAnimationStudio
if (maxGhosts == 0)
{ return; }
int nGhosts = GetGhostFramesRequired();
int requiredGhosts = GetGhostFramesRequired();
int currentGhostCount = ghostSliders.childCount;
for (int i = 0; i < Mathf.Max(nGhosts, ghostSliders.childCount); i++)
for (int i = 0; i < Mathf.Max(requiredGhosts, currentGhostCount); i++)
{
if ((i - 1) * clip.duration + keyframe.atTick <= Workspace.StageWindowSize)
{
if (ghostSliders.childCount <= i)
{ Instantiate(ghostSliderPrefab, ghostSliders); }
int targetTick = (int)(i * clip.duration + keyframe.atTick);
GameObject ghostSliderObject = ghostSliders.GetChild(i).gameObject;
ghostSliderObject.SetActive(true);
if (ghostSliders.childCount <= i)
{ Instantiate(ghostSliderPrefab, ghostSliders); }
Slider ghostSlider = ghostSliderObject.GetComponent<Slider>();
ghostSlider.value = (int)((i + 1) * clip.duration + keyframe.atTick);
GameObject ghostSliderObject = ghostSliders.GetChild(i).gameObject;
ghostSliderObject.SetActive(i < requiredGhosts);
float mult = 1f - Mathf.Pow((float)i / maxGhosts, 2);
ghostSlider.transform.FindDeepChild("Handle").GetComponent<Image>().color = new Color(0, 0.5f, 0.5f, 0.5f * mult);
}
if (i >= nGhosts)
{ transform.GetChild(i).gameObject.SetActive(false); }
Slider ghostSlider = ghostSliderObject.GetComponent<Slider>();
ghostSlider.maxValue = Workspace.StageWindowSize;
ghostSlider.value = targetTick;
if (targetTick > ghostSlider.maxValue)
{ ghostSlider.gameObject.SetActive(false); }
}
}
@ -98,9 +95,9 @@ namespace RimWorldAnimationStudio
Workspace.keyframeID = keyframeID;
if (eventData.clickCount >= 2)
{
AnimationController.Instance.stageTick = keyframe.atTick.Value;
}
{ AnimationController.Instance.stageTick = keyframe.atTick.Value; }
Workspace.Instance.MakeDirty();
}
public void OnBeginDrag(PointerEventData eventData)
@ -126,6 +123,8 @@ namespace RimWorldAnimationStudio
public void OnEndDrag(PointerEventData eventData)
{
interactable = false;
Workspace.Instance.MakeDirty();
}
protected override void Update()

View file

@ -16,6 +16,10 @@ namespace RimWorldAnimationStudio
{
stageName.text = stageNameField.text;
stageNameField.gameObject.SetActive(false);
Workspace.animationDef.animationStages[Workspace.stageID].stageName = stageName.text;
Workspace.Instance.MakeDirty();
}
public void OnMoveStage(int delta)
@ -60,8 +64,7 @@ namespace RimWorldAnimationStudio
Workspace.stageID = transform.GetSiblingIndex();
//AnimationController.Instance.ResetAnimationTimeline();
//AnimationController.Instance.InitializeAnimationTimeline();
Workspace.Instance.MakeDirty();
}
}
}

View file

@ -34,14 +34,22 @@ namespace RimWorldAnimationStudio
private int lastStageTick = 1;
private float timeSinceLastUpdate = 0;
private int cycleIndex = 0;
private bool isDirty = true;
private bool isTimelineDirty = true;
public void MakeDirty()
{ isDirty = true; }
public void MakeTimelineDirty()
{ isTimelineDirty = true; }
public void Update()
{
// No animation, exit
if (Workspace.animationDef == null) { return; }
// Dirty animation, reset
if (Workspace.animationDef != null && Workspace.isDirty)
if (Workspace.animationDef != null && isDirty)
{ Initialize(); return; }
// Update tick if animating
@ -65,14 +73,11 @@ namespace RimWorldAnimationStudio
++cycleIndex;
stageTick = 1;
if ((stageLoopDropdown.value == 2 && cycleIndex > int.Parse(cyclesNormalField.text)) ||
(stageLoopDropdown.value == 3 && cycleIndex > int.Parse(cyclesFastField.text)))
if ((stageLoopDropdown.value == 2 && cycleIndex >= int.Parse(cyclesNormalField.text)) ||
(stageLoopDropdown.value == 3 && cycleIndex >= int.Parse(cyclesFastField.text)))
{
++Workspace.stageID;
cycleIndex = 0;
//ResetAnimationTimeline();
//InitializeAnimationTimeline();
}
}
@ -99,7 +104,7 @@ namespace RimWorldAnimationStudio
public void UpdateAnimation()
{
if (Workspace.Instance.AnimationTimelinesNeedUpdate())
if (AnimationTimelinesNeedUpdate())
{
ResetAnimationTimeline();
InitializeAnimationTimeline();
@ -109,6 +114,12 @@ namespace RimWorldAnimationStudio
for (int actorID = 0; actorID < actorBodies.Count; actorID++)
{
if (Workspace.stageID >= Workspace.animationDef?.animationStages.Count)
{ Debug.Log("Waiting for animation stage data to initialize..."); return; }
if (actorID >= Workspace.animationDef?.animationStages[Workspace.stageID]?.animationClips.Count)
{ Debug.Log("Waiting for animation clip data to initialize..."); return; }
PawnAnimationClip clip = Workspace.animationDef?.animationStages[Workspace.stageID]?.animationClips[actorID];
if (clip == null)
@ -162,7 +173,7 @@ namespace RimWorldAnimationStudio
InitializeAnimationTimeline();
StageCardManager.Instance.Initialize();
Workspace.isDirty = false;
isDirty = false;
}
public void InitializeAnimationTimeline()
@ -184,6 +195,8 @@ namespace RimWorldAnimationStudio
stageTimelineSlider.maxValue = Workspace.StageWindowSize;
stageTimelineSlider.value = 1;
stageTick = 1;
isTimelineDirty = false;
}
public void Reset()
@ -209,7 +222,9 @@ namespace RimWorldAnimationStudio
public bool AddAnimationStage()
{
AnimationStage stage = new AnimationStage();
Workspace.Instance.MakeDirty();
return stage.MakeNew();
}
@ -221,6 +236,8 @@ namespace RimWorldAnimationStudio
Workspace.animationDef.animationStages.Insert(Workspace.stageID + 1, stage);
Workspace.Instance.MakeDirty();
return true;
}
@ -233,6 +250,8 @@ namespace RimWorldAnimationStudio
Workspace.animationDef.animationStages[startIndex] = Workspace.animationDef.animationStages[startIndex + delta];
Workspace.animationDef.animationStages[startIndex + delta] = stage;
Workspace.Instance.MakeDirty();
return true;
}
@ -247,15 +266,17 @@ namespace RimWorldAnimationStudio
Workspace.animationDef.animationStages.RemoveAt(Workspace.stageID);
Workspace.stageID = Workspace.stageID >= Workspace.animationDef.animationStages.Count ? Workspace.stageID = Workspace.animationDef.animationStages.Count - 1 : Workspace.stageID;
Workspace.Instance.MakeDirty();
return true;
}
public void AddActor()
{
Actor actor = new Actor();
actor.MakeNew();
if (actor.MakeNew())
{ Initialize(); }
Workspace.Instance.MakeDirty();
}
public void RemoveActor()
@ -272,7 +293,7 @@ namespace RimWorldAnimationStudio
Workspace.animationDef.actors.RemoveAt(Workspace.actorID);
Workspace.actorID = Workspace.actorID >= Workspace.animationDef.actors.Count ? Workspace.actorID = Workspace.animationDef.actors.Count - 1 : Workspace.actorID;
Initialize();
Workspace.Instance.MakeDirty();
}
public void AddPawnKeyframe()
@ -311,11 +332,15 @@ namespace RimWorldAnimationStudio
clip.BuildSimpleCurves();
animationTimelines.GetComponentsInChildren<AnimationTimeline>()[Workspace.actorID].AddPawnKeyFrame(keyframe.keyframeID);
Workspace.Instance.MakeDirty();
}
public void RemovePawnKeyframe()
{
RemovePawnKeyframe(Workspace.actorID, Workspace.keyframeID);
Workspace.Instance.MakeDirty();
}
public void RemovePawnKeyframe(int actorID, int keyframeID)
@ -333,6 +358,8 @@ namespace RimWorldAnimationStudio
clip.keyframes.Remove(keyframe);
clip.BuildSimpleCurves();
}
Workspace.Instance.MakeDirty();
}
public void ToggleAnimation()
@ -363,6 +390,8 @@ namespace RimWorldAnimationStudio
int.TryParse(animationClipTimeField.text, out int newStageTick);
stageTick = Mathf.Clamp(newStageTick, 1, Workspace.StageWindowSize);
stageTimelineSlider.value = stageTick;
Workspace.Instance.MakeDirty();
}
public void OnAnimationClipLengthFieldChange()
@ -394,8 +423,7 @@ namespace RimWorldAnimationStudio
animationClipLengthField.text = newstageWindowSize.ToString();
Workspace.animationDef.animationStages[Workspace.stageID].stageWindowSize = newstageWindowSize;
//ResetAnimationTimeline();
//InitializeAnimationTimeline();
Workspace.Instance.MakeDirty();
}
public void OnCycleNormalFieldChange()
@ -404,6 +432,8 @@ namespace RimWorldAnimationStudio
if (int.TryParse(cyclesNormalField.text, out int cycles))
{ Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicks = cycles * Workspace.StageWindowSize; }
Workspace.Instance.MakeDirty();
}
public void OnCycleFastFieldChange()
@ -412,6 +442,44 @@ namespace RimWorldAnimationStudio
if (int.TryParse(cyclesFastField.text, out int cycles))
{ Workspace.animationDef.animationStages[Workspace.stageID].playTimeTicksQuick = cycles * Workspace.StageWindowSize; }
Workspace.Instance.MakeDirty();
}
private int lastactorCount = 0;
private int lastStageID = 0;
private int lastStageCount = 0;
private int lastStageWindowSize = 0;
public bool AnimationTimelinesNeedUpdate()
{
if (Workspace.animationDef == null) return false;
bool update = isTimelineDirty;
if (lastStageID != Workspace.stageID)
{ update = true; }
if (lastStageCount != Workspace.animationDef.animationStages.Count)
{ update = true; }
if (lastactorCount != Workspace.animationDef.actors.Count)
{ update = true; }
if (lastStageWindowSize != Workspace.StageWindowSize)
{ update = true; }
if (update)
{
lastStageID = Workspace.stageID;
lastStageCount = Workspace.animationDef.animationStages.Count;
lastactorCount = Workspace.animationDef.actors.Count;
lastStageWindowSize = Workspace.StageWindowSize;
return true;
}
return false;
}
}
}

View file

@ -46,11 +46,15 @@ namespace RimWorldAnimationStudio
public void LoadAnimation(AnimationDef animationDef)
{
animationDef.RunPostLoadOperations();
Debug.Log("Loaded AnimationDef: " + animationDef.defName);
Workspace.animationDef = animationDef;
animationDef.Initialize();
Workspace.isDirty = true;
Workspace.Instance.ClearHistory();
Workspace.Instance.MakeDirty();
AnimationController.Instance.MakeDirty();
var animationDefCards = Resources.FindObjectsOfTypeAll(typeof(AnimationDefCard)) as AnimationDefCard[];
@ -78,16 +82,8 @@ namespace RimWorldAnimationStudio
{
Debug.Log("Saving AnimationDef: " + Workspace.animationDef.defName);
AnimationDef animationDef = Workspace.animationDef;
foreach (AnimationStage stage in animationDef.animationStages)
{
foreach (PawnAnimationClip clip in stage.animationClips)
{
clip.keyframes = clip.keyframes.OrderBy(x => x.atTick).ToList();
}
}
AnimationDef animationDef = Workspace.animationDef.Copy();
animationDef.RunPreSaveOperations();
Defs defs = new Defs();
defs.animationDefs.Add(animationDef);
@ -104,7 +100,7 @@ namespace RimWorldAnimationStudio
// Add one stage, add one actor, add one clip, add one frame
Workspace.animationDef = new AnimationDef();
Workspace.isDirty = true;
Workspace.Instance.MakeDirty();
var animationDefCards = Resources.FindObjectsOfTypeAll(typeof(AnimationDefCard)) as GameObject[];

View file

@ -18,5 +18,6 @@ namespace RimWorldAnimationStudio
public static Color ColorRichOrange = new Color(1.0f, 0.4f, 0.1f);
public static Color ColorCyan = new Color(0.0f, 1.0f, 1.0f);
public static Color ColorPurple = new Color(0.85f, 0.0f, 1.0f);
public static Color ColorGhost = new Color(0.5f, 0.5f, 0.5f, 0.5f);
}
}

View file

@ -39,11 +39,6 @@ namespace RimWorldAnimationStudio
}
}
private void Awake()
{
DontDestroyOnLoad(this.gameObject);
}
private void OnDestroy()
{
shuttingDown = true;

View file

@ -12,18 +12,18 @@ namespace RimWorldAnimationStudio
public static AnimationDef animationDef;
public static int stageID = 0;
public static int actorID = 0;
public static int keyframeID = 0;
public static bool isDirty = false;
public static int keyframeID = 0;
public static List<string> defNames = new List<string>() { "Human" };
public static List<string> bodyParts = new List<string>() { "Penis", "Vagina", "Anus", "Breasts", "Mouth" };
public static List<string> bodyParts = new List<string>() { "Any appendage", "Any orifice", "Penis", "Vagina", "Anus", "Breasts", "Mouth" };
public static List<string> bodyDefTypes = new List<string>() { "Human" };
public static List<string> sexTypes = new List<string>() { "None", "Vaginal", "Anal", "Oral", "Masturbation", "DoublePenetration", "Boobjob", "Handjob", "Footjob", "Fingering", "Scissoring", "MutualMasturbation", "Fisting", "MechImplant", "Rimming", "Fellatio", "Cunnilingus", "Sixtynine" };
public static List<string> interactionDefTypes = new List<string>();
private static List<WorkspaceSnapShot> workspaceHistory = new List<WorkspaceSnapShot>();
private static int maxHistoryDepth = 100;
private static int historyIndex = 0;
[SerializeField] private List<WorkspaceSnapShot> workspaceHistory = new List<WorkspaceSnapShot>();
[SerializeField] private int historyIndex = 0;
[SerializeField] private int maxHistoryDepth = 100;
private bool isDirty = false;
public static ActorManipulationMode actorManipulationMode = ActorManipulationMode.Pan;
@ -41,6 +41,12 @@ namespace RimWorldAnimationStudio
}
}
public void Update()
{
if (isDirty)
{ TrackChanges(); }
}
public PawnKeyframe GetCurrentPawnKeyframe()
{
int stageTick = AnimationController.Instance.stageTick;
@ -70,21 +76,26 @@ namespace RimWorldAnimationStudio
public void TrackChanges()
{
Debug.Log("Test");
Debug.Log(historyIndex + 1);
Debug.Log(workspaceHistory.Count - historyIndex);
if (historyIndex < workspaceHistory.Count - 1)
{ workspaceHistory.RemoveRange(historyIndex + 1, workspaceHistory.Count - historyIndex); }
{ workspaceHistory.RemoveRange(historyIndex + 1, workspaceHistory.Count - historyIndex - 1); }
if (workspaceHistory.Any() && workspaceHistory.Count >= maxHistoryDepth)
{ workspaceHistory.RemoveAt(0); }
WorkspaceSnapShot workspaceSnapShot = new WorkspaceSnapShot();
workspaceSnapShot.animationDef = animationDef;
workspaceSnapShot.animationDef = animationDef.Copy();
workspaceSnapShot.stageID = stageID;
workspaceSnapShot.actorID = actorID;
workspaceSnapShot.keyframeID = keyframeID;
workspaceHistory.Add(workspaceSnapShot);
historyIndex = workspaceHistory.Count - 1;
// track bType for actors, stageID, isdirty
historyIndex++;
isDirty = false;
}
public void Undo()
@ -95,51 +106,30 @@ namespace RimWorldAnimationStudio
public void Redo()
{
historyIndex = Mathf.Clamp(historyIndex - 1, 0, workspaceHistory.Count - 1);
historyIndex = Mathf.Clamp(historyIndex + 1, 0, workspaceHistory.Count - 1);
LoadHistoricState();
}
public void LoadHistoricState()
{
animationDef = workspaceHistory[historyIndex].animationDef;
if (workspaceHistory.NullOrEmpty())
{ Debug.LogWarning("Cannot load historic state - workspace history is empty"); return; }
// All other data
animationDef = workspaceHistory[historyIndex].animationDef.Copy();
stageID = workspaceHistory[historyIndex].stageID;
actorID = workspaceHistory[historyIndex].actorID;
keyframeID = workspaceHistory[historyIndex].keyframeID;
AnimationController.Instance.MakeTimelineDirty();
}
private int lastactorCount = 0;
private int lastStageID = 0;
private int lastStageCount = 0;
private int lastStageWindowSize = 0;
public bool AnimationTimelinesNeedUpdate()
public void ClearHistory()
{
if (animationDef == null) return false;
bool update = false;
if (lastStageID != stageID)
{ update = true; }
if (lastStageCount != animationDef.animationStages.Count)
{ update = true; }
if (lastactorCount != animationDef.actors.Count)
{ update = true; }
if (lastStageWindowSize != StageWindowSize)
{ update = true; }
if (update)
{
lastStageID = stageID;
lastStageCount = animationDef.animationStages.Count;
lastactorCount = animationDef.actors.Count;
lastStageWindowSize = StageWindowSize;
return true;
}
return false;
workspaceHistory.Clear();
historyIndex = 0;
}
public void MakeDirty()
{ isDirty = true; }
}
}

View file

@ -6,9 +6,12 @@ using System.Threading.Tasks;
namespace RimWorldAnimationStudio
{
[Serializable]
public class WorkspaceSnapShot
{
public AnimationDef animationDef;
public int stageID = 0;
public int actorID = 0;
public int keyframeID = 0;
}
}