Bug fixes plus extra features

- Insert adds a new keyframe to the selected timeline
- New stages have frames cloned from the last frame of current stage
- Existing key are now replaced when another key is dropped on them
- Fixed bug where starting a new animation could result in errors
This commit is contained in:
AbstractConcept 2022-10-18 21:57:43 -05:00
parent ca22fa0c18
commit 2989d9a72c
137 changed files with 527 additions and 668 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,116 @@
fileFormatVersion: 2
guid: 656b64fca82a9e14bbafce96bf8b5cbf
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: -1
mipBias: -100
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 0
spriteMeshType: 0
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -121,5 +121,12 @@ namespace RimWorldAnimationStudio
return true;
}
public int GetActorID()
{
if (Workspace.animationDef == null) return -1;
return Workspace.animationDef.actors.IndexOf(this);
}
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
@ -89,17 +90,46 @@ namespace RimWorldAnimationStudio
public override void ValidateData() { }
public bool MakeNew()
public int GetOwningActorID()
{
PawnKeyframe keyframeA = new PawnKeyframe();
keyframeA.tickDuration = Constants.defaultAnimationClipLength - 1;
keyframes.Add(keyframeA);
if (Workspace.animationDef == null) return -1;
PawnKeyframe keyframeB = new PawnKeyframe();
keyframes.Add(keyframeB);
return Workspace.animationDef.animationStages[Workspace.stageID].animationClips.IndexOf(this);
}
public bool MakeNew(int actorID = -1)
{
PawnKeyframe lastkeyframe = null;
if (actorID >= 0)
{ lastkeyframe = Workspace.animationDef.animationStages[Workspace.stageID].animationClips[actorID]?.keyframes?.Last(); }
if (lastkeyframe != null)
{
PawnKeyframe keyframeA = lastkeyframe.Copy();
keyframeA.atTick = null;
keyframeA.tickDuration = Constants.defaultAnimationClipLength - 1;
keyframeA.GenerateKeyframeID(actorID);
keyframes.Add(keyframeA);
PawnKeyframe keyframeB = lastkeyframe.Copy();
keyframeB.atTick = null;
keyframeB.tickDuration = 1;
keyframeB.GenerateKeyframeID(actorID);
keyframes.Add(keyframeB);
}
else
{
PawnKeyframe keyframeA = new PawnKeyframe();
keyframeA.tickDuration = Constants.defaultAnimationClipLength - 1;
keyframes.Add(keyframeA);
PawnKeyframe keyframeB = new PawnKeyframe();
keyframes.Add(keyframeB);
}
BuildSimpleCurves();
return true;
}
}

View File

@ -36,23 +36,31 @@ namespace RimWorldAnimationStudio
{ clip.keyframes = clip.keyframes.OrderBy(x => x.atTick).ToList(); }
}
public int GetStageID()
{
if (Workspace.animationDef == null) return -1;
return Workspace.animationDef.animationStages.IndexOf(this);
}
public bool MakeNew()
{
if (Workspace.animationDef == null)
{ Debug.LogWarning("Cannot make new animation stage - there is no AnimationDef"); return false; }
foreach(Actor actor in Workspace.animationDef.actors)
Workspace.animationDef.animationStages.Add(this);
foreach (Actor actor in Workspace.animationDef.actors)
{
PawnAnimationClip clip = new PawnAnimationClip();
if (clip.MakeNew())
if (clip.MakeNew(actor.GetActorID()))
{ animationClips.Add(clip); }
}
Initialize();
playTimeTicksQuick = playTimeTicks;
Workspace.animationDef.animationStages.Add(this);
return true;
}
}

View File

@ -31,10 +31,8 @@ namespace RimWorldAnimationStudio
public void LogMessage(string logString, string stackTrace, LogType type)
{
if (currentMessages > maxMessages)
{ return; }
currentMessages++;
if (currentMessages > maxMessages) return;
currentMessages++;
currentMessage.text = logString;

View File

@ -17,7 +17,7 @@ namespace RimWorldAnimationStudio
public void Start()
{
keybindLabel = GetComponent<Text>();
keybindLabel.text = KeybindConfig.Instance.GetKeybindLabel(command);
keybindLabel.text = KeybindConfig.GetKeybindLabel(command);
}
}
}

View File

@ -117,7 +117,7 @@ namespace RimWorldAnimationStudio
if (Workspace.keyframeID.NullOrEmpty() || Workspace.keyframeID.Contains(keyframeID) == false)
{ Workspace.keyframeID = new List<int> { keyframeID }; }
List<PawnKeyframe> selectedKeyframes = Workspace.Instance.GetPawnKeyframes(Workspace.keyframeID).Except(new List<PawnKeyframe>() { keyframe })?.ToList();
List<PawnKeyframe> selectedKeyframes = Workspace.Instance.GetPawnKeyframesByID(Workspace.keyframeID).Except(new List<PawnKeyframe>() { keyframe })?.ToList();
// Link other slected keyframes to the movement of this one
if (selectedKeyframes.NotNullOrEmpty())
@ -170,12 +170,39 @@ namespace RimWorldAnimationStudio
if (keyframe.atTick == Constants.minTick)
{ value = Constants.minTick; return; }
foreach (Selectable linkedSlider in Selectable.allSelectablesArray)
List<PawnKeyframe> keyframesToCheck = Workspace.Instance.GetPawnKeyframesAtTick(actorID, keyframe.atTick.Value);
if (keyframesToCheck.NotNullOrEmpty())
{
if (linkedSlider is KeyframeSlider)
{
(linkedSlider as KeyframeSlider).linkedSlider = null;
(linkedSlider as KeyframeSlider).pivotKeyframe = null;
foreach (PawnKeyframe _keyframe in keyframesToCheck)
{
if (_keyframe != keyframe)
{ AnimationController.Instance.RemovePawnKeyframe(actorID, _keyframe.keyframeID); }
}
}
foreach (Selectable selectable in Selectable.allSelectablesArray)
{
if (selectable is KeyframeSlider)
{
KeyframeSlider linkedSlider = selectable.GetComponent<KeyframeSlider>();
PawnKeyframe linkedKeyframe = linkedSlider.keyframe;
if (linkedSlider.linkedSlider != null)
{
keyframesToCheck = Workspace.Instance.GetPawnKeyframesAtTick(actorID, linkedKeyframe.atTick.Value);
if (keyframesToCheck.NotNullOrEmpty() && keyframesToCheck.Count > 1)
{
foreach (PawnKeyframe _keyframe in keyframesToCheck)
{
if (_keyframe.keyframeID != linkedKeyframe.keyframeID)
{ AnimationController.Instance.RemovePawnKeyframe(actorID, _keyframe.keyframeID); Debug.Log("delete"); }
}
}
}
linkedSlider.linkedSlider = null;
linkedSlider.pivotKeyframe = null;
}
}

View File

@ -8,26 +8,30 @@ using UnityEngine;
namespace RimWorldAnimationStudio
{
public class KeybindConfig : Singleton<KeybindConfig>
public class KeybindConfig
{
private static List<Keybind> keybinds = new List<Keybind>();
private static bool initialized = false;
public void Awake()
public static void Initialize()
{
string path = Path.Combine(Application.streamingAssetsPath, "keybindConfig.xml");
keybinds = XmlUtility.ReadXML<List<Keybind>>(path);
initialized = true;
}
public List<Keybind> GetAllKeybinds()
public static List<Keybind> GetAllKeybinds()
{
if (initialized == false)
{ Initialize(); }
return keybinds;
}
public string GetKeybindLabel(string command)
public static string GetKeybindLabel(string command)
{
string label = "";
Keybind keybind = keybinds.FirstOrDefault(x => x.command == command);
Keybind keybind = GetAllKeybinds()?.FirstOrDefault(x => x.command == command);
if (keybind == null) return label;

View File

@ -44,7 +44,7 @@ namespace RimWorldAnimationStudio
private float playBackSpeed = 1f;
public void MakeDirty()
{ isDirty = true; }
{ isDirty = true; isTimelineDirty = true; }
public void MakeTimelineDirty()
{ isTimelineDirty = true; }
@ -255,10 +255,11 @@ namespace RimWorldAnimationStudio
public void Reset()
{
Workspace.stageID = 0;
isAnimating = false;
timeSinceLastUpdate = 0;
cycleIndex = 0;
MakeDirty();
}
public void InitializeAnimationTimeline()
@ -377,7 +378,7 @@ namespace RimWorldAnimationStudio
public void ClonePawnKeyframe()
{
List<PawnKeyframe> keyframesToClone = Workspace.Instance.GetPawnKeyframes(Workspace.keyframeID);
List<PawnKeyframe> keyframesToClone = Workspace.Instance.GetPawnKeyframesByID(Workspace.keyframeID);
foreach (PawnKeyframe keyframe in keyframesToClone)
{
@ -413,7 +414,7 @@ namespace RimWorldAnimationStudio
{
Workspace.copiedKeyframes.Clear();
List<PawnKeyframe> keyframesToClone = Workspace.Instance.GetPawnKeyframes(Workspace.keyframeID);
List<PawnKeyframe> keyframesToClone = Workspace.Instance.GetPawnKeyframesByID(Workspace.keyframeID);
foreach (PawnKeyframe keyframe in keyframesToClone)
{ Workspace.copiedKeyframes.Add(keyframe.Copy()); }

View File

@ -70,10 +70,9 @@ namespace RimWorldAnimationStudio
Workspace.animationDef = animationDef;
animationDef.Initialize();
Workspace.Instance.ClearHistory();
AnimationController.Instance.Reset();
Workspace.Instance.Reset();
Workspace.Instance.RecordEvent("AnimationDef loaded");
AnimationController.Instance.MakeDirty();
}
public void RunPostLoadOperations(AnimationDef animationDef)

View File

@ -61,7 +61,7 @@ namespace RimWorldAnimationStudio
bool canRepeatThisUpdate = CanRepeatThisUpdate();
// Check keybinds
foreach (Keybind keybind in KeybindConfig.Instance.GetAllKeybinds())
foreach (Keybind keybind in KeybindConfig.GetAllKeybinds())
{
if (IsModifierKeyHeld() && keybind.keyModifiers.NullOrEmpty()) goto nextKeybind;
@ -207,6 +207,12 @@ namespace RimWorldAnimationStudio
AnimationController.Instance.ToggleAnimation();
}
public void AddKeyframe()
{
if (Workspace.animationDef == null) return;
AnimationController.Instance.AddPawnKeyframe();
}
public void CopyKeyframes()
{
if (Workspace.animationDef == null) return;

View File

@ -14,6 +14,8 @@ namespace RimWorldAnimationStudio
public string message = "Undefined";
public string executedCommand;
public float delay = 0f;
public Vector2 offset = new Vector2(5f, -15f);
public bool flipX = false;
private GameObject tooltip;
private Text tooltipText;
@ -33,12 +35,13 @@ namespace RimWorldAnimationStudio
if (isDisplayed == false)
{
tooltip.GetComponent<RectTransform>().pivot = flipX ? new Vector2(1, 1) : new Vector2(0, 1);
tooltipText.text = message;
if (executedCommand != null && executedCommand != "")
{ tooltipText.text += " (" + KeybindConfig.Instance.GetKeybindLabel(executedCommand) + ")"; }
{ tooltipText.text += " (" + KeybindConfig.GetKeybindLabel(executedCommand) + ")"; }
tooltip.transform.position = (Vector2)transform.position + new Vector2(5f, -15f);
tooltip.transform.position = (Vector2)transform.position + offset;
tooltip.gameObject.SetActive(true);
LayoutRebuilder.ForceRebuildLayoutImmediate(tooltip.GetComponent<RectTransform>());

View File

@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace RimWorldAnimationStudio
{
[Serializable]
public class HistoricRecord
public class WorkspaceRecord
{
public int recordID = 0;
public string eventDesc;

View File

@ -14,7 +14,7 @@ namespace RimWorldAnimationStudio
public static List<int> keyframeID = new List<int>();
[SerializeField] private List<HistoricRecord> workspaceHistory = new List<HistoricRecord>();
[SerializeField] private List<WorkspaceRecord> workspaceHistory = new List<WorkspaceRecord>();
[SerializeField] private int maxHistoryDepth = 100;
public static ActorManipulationMode actorManipulationMode = ActorManipulationMode.Pan;
@ -53,6 +53,11 @@ namespace RimWorldAnimationStudio
return animationDef?.animationStages[stageID]?.animationClips[actorID]?.keyframes.FirstOrDefault(x => x.atTick == stageTick);
}
public List<PawnKeyframe> GetPawnKeyframesAtTick(int actorID, int atTick)
{
return animationDef?.animationStages[stageID]?.animationClips[actorID]?.keyframes.Where(x => x.atTick == atTick)?.ToList();
}
public PawnAnimationClip GetCurrentPawnAnimationClip()
{
return animationDef.animationStages[stageID].animationClips[actorID];
@ -74,7 +79,7 @@ namespace RimWorldAnimationStudio
return animationDef.animationStages[stageID].animationClips[actorID].keyframes.FirstOrDefault(x => x.keyframeID == keyframeID);
}
public List<PawnKeyframe> GetPawnKeyframes(List<int> keyframeIDs)
public List<PawnKeyframe> GetPawnKeyframesByID(List<int> keyframeIDs)
{
List<PawnKeyframe> pawnKeyframes = new List<PawnKeyframe>();
@ -203,12 +208,23 @@ namespace RimWorldAnimationStudio
}
[SerializeField]
public LinkedList<HistoricRecord> pastSnapshots = new LinkedList<HistoricRecord>();
public LinkedList<HistoricRecord> futureSnapshots = new LinkedList<HistoricRecord>();
public LinkedList<WorkspaceRecord> pastSnapshots = new LinkedList<WorkspaceRecord>();
public LinkedList<WorkspaceRecord> futureSnapshots = new LinkedList<WorkspaceRecord>();
public void Reset()
{
actorID = 0;
stageID = 0;
keyframeID.Clear();
selectedBodyPart = null;
ClearHistory();
}
public void MakeHistoricRecord(string eventDesc)
{
HistoricRecord record = new HistoricRecord();
WorkspaceRecord record = new WorkspaceRecord();
record.recordID = pastSnapshots.Count;
record.eventDesc = eventDesc;
record.animationDef = animationDef.Copy();
@ -221,7 +237,7 @@ namespace RimWorldAnimationStudio
{ pastSnapshots.RemoveFirst(); }
}
public void RestoreToHistoricRecord(HistoricRecord record)
public void RestoreToHistoricRecord(WorkspaceRecord record)
{
animationDef = record.animationDef.Copy();
stageID = record.stageID;
@ -232,8 +248,8 @@ namespace RimWorldAnimationStudio
public void Undo()
{
HistoricRecord recordToRead = pastSnapshots.Last?.Previous?.Value;
HistoricRecord recordToStore = pastSnapshots.Last?.Value;
WorkspaceRecord recordToRead = pastSnapshots.Last?.Previous?.Value;
WorkspaceRecord recordToStore = pastSnapshots.Last?.Value;
if (recordToRead == null || recordToStore == null) return;
@ -246,7 +262,7 @@ namespace RimWorldAnimationStudio
public void Redo()
{
HistoricRecord recordToReadAndStore = futureSnapshots.Last?.Value;
WorkspaceRecord recordToReadAndStore = futureSnapshots.Last?.Value;
if (recordToReadAndStore == null) return;

View File

@ -131,6 +131,16 @@
</mac>
</Keybind>
<Keybind>
<command>AddKeyframe</command>
<win>
<keyCode>Insert</keyCode>
</win>
<mac>
<keyCode>Insert</keyCode>
</mac>
</Keybind>
<Keybind>
<command>CopyKeyframes</command>
<win>
@ -162,34 +172,34 @@
<keyCode>X</keyCode>
</mac>
</Keybind>
<Keybind>
<command>DeleteKeyframes</command>
<win>
<keyCode>Backspace</keyCode>
<keyCode>Delete</keyCode>
</win>
<mac>
<keyCode>Backspace</keyCode>
<keyCode>Delete</keyCode>
</mac>
</Keybind>
<Keybind>
<command>DeleteKeyframes</command>
<win>
<keyCode>Delete</keyCode>
<keyCode>Backspace</keyCode>
</win>
<mac>
<keyCode>Delete</keyCode>
<keyCode>Backspace</keyCode>
</mac>
</Keybind>
<Keybind>
<command>ActorMovementMode</command>
<win>
<keyCode>M</keyCode>
<keyCode>E</keyCode>
</win>
<mac>
<keyCode>M</keyCode>
<keyCode>E</keyCode>
</mac>
</Keybind>

View File

@ -131,6 +131,16 @@
</mac>
</Keybind>
<Keybind>
<command>AddKeyframe</command>
<win>
<keyCode>Insert</keyCode>
</win>
<mac>
<keyCode>Insert</keyCode>
</mac>
</Keybind>
<Keybind>
<command>CopyKeyframes</command>
<win>
@ -162,34 +172,34 @@
<keyCode>X</keyCode>
</mac>
</Keybind>
<Keybind>
<command>DeleteKeyframes</command>
<win>
<keyCode>Backspace</keyCode>
<keyCode>Delete</keyCode>
</win>
<mac>
<keyCode>Backspace</keyCode>
<keyCode>Delete</keyCode>
</mac>
</Keybind>
<Keybind>
<command>DeleteKeyframes</command>
<win>
<keyCode>Delete</keyCode>
<keyCode>Backspace</keyCode>
</win>
<mac>
<keyCode>Delete</keyCode>
<keyCode>Backspace</keyCode>
</mac>
</Keybind>
<Keybind>
<command>ActorMovementMode</command>
<win>
<keyCode>M</keyCode>
<keyCode>E</keyCode>
</win>
<mac>
<keyCode>M</keyCode>
<keyCode>E</keyCode>
</mac>
</Keybind>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More