mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
v 1.0.0
This commit is contained in:
parent
0828ecd037
commit
2998865184
9821 changed files with 90 additions and 90 deletions
186
Source/Assets/Scripts/AnimationComponents/Actor.cs
Normal file
186
Source/Assets/Scripts/AnimationComponents/Actor.cs
Normal file
|
@ -0,0 +1,186 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class Actor
|
||||
{
|
||||
// Data to/from animationDef
|
||||
[XmlArray("defNames"), XmlArrayItem("li")] public List<string> defNames;
|
||||
[XmlArray("bodyDefTypes"), XmlArrayItem("li")] public List<string> bodyDefTypes;
|
||||
[XmlArray("requiredGenitals"), XmlArrayItem("li")] public List<string> requiredGenitals;
|
||||
[XmlArray("raceOffsets"), XmlArrayItem("li")] public List<PawnRaceOffset> raceOffsets;
|
||||
[XmlArray("tags"), XmlArrayItem("li")] public List<string> tags;
|
||||
public BodyTypeOffset bodyTypeOffset;
|
||||
public bool? initiator = false;
|
||||
public bool? controlGenitalAngle;
|
||||
public bool? isFucking;
|
||||
public bool? isFucked;
|
||||
|
||||
// Data serialization control
|
||||
public bool ShouldSerializedefNames() { return defNames.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializebodyDefTypes() { return bodyDefTypes.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializerequiredGenitals() { return requiredGenitals.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializeraceOffsets() { return raceOffsets.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializetags() { return tags.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializebodyTypeOffset() { return bodyTypeOffset?.AllOffsetsEmpty() == false; }
|
||||
public bool ShouldSerializeinitiator() { return initiator == true; }
|
||||
public bool ShouldSerializecontrolGenitalAngle() { return controlGenitalAngle == true; }
|
||||
public bool ShouldSerializeisFucking() { return isFucking == true; }
|
||||
public bool ShouldSerializeisFucked() { return isFucked == true; }
|
||||
|
||||
// Data helper functions
|
||||
[XmlIgnore] public List<string> DefNames
|
||||
{
|
||||
get { return defNames.NullOrEmpty() ? defNames = new List<string>() : defNames; }
|
||||
set { defNames = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<string> BodyDefTypes
|
||||
{
|
||||
get { return bodyDefTypes.NullOrEmpty() ? bodyDefTypes = new List<string>() : bodyDefTypes; }
|
||||
set { bodyDefTypes = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<string> RequiredGenitals
|
||||
{
|
||||
get { return requiredGenitals.NullOrEmpty() ? requiredGenitals = new List<string>() : requiredGenitals; }
|
||||
set { requiredGenitals = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<PawnRaceOffset> RaceOffsets {
|
||||
get { return raceOffsets.NullOrEmpty() ? raceOffsets = new List<PawnRaceOffset>() : raceOffsets; }
|
||||
set { raceOffsets = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<string> Tags
|
||||
{
|
||||
get { return tags.NullOrEmpty() ? tags = new List<string>() : tags; }
|
||||
set { tags = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public BodyTypeOffset BodyTypeOffset
|
||||
{
|
||||
get { return bodyTypeOffset == null ? bodyTypeOffset = new BodyTypeOffset() : bodyTypeOffset; }
|
||||
set { bodyTypeOffset = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public bool Initiator
|
||||
{
|
||||
get { return initiator == true; }
|
||||
set { if (value) { initiator = true; } else initiator = null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public bool ControlGenitalAngle
|
||||
{
|
||||
get { return controlGenitalAngle == true; }
|
||||
set { if (value) { controlGenitalAngle = true; } else controlGenitalAngle = null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public bool IsFucking
|
||||
{
|
||||
get { return isFucking == true; }
|
||||
set { if (value) { isFucking = true; } else isFucking = null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public bool IsFucked
|
||||
{
|
||||
get { return isFucked == true; }
|
||||
set { if (value) { isFucked = true; } else isFucked = null; }
|
||||
}
|
||||
|
||||
// Local data
|
||||
[XmlIgnore] public string bodyType = "Male";
|
||||
[XmlIgnore] private PawnRaceDef pawnRaceDef;
|
||||
|
||||
// Methods
|
||||
public PawnRaceDef GetPawnRaceDef()
|
||||
{
|
||||
if (pawnRaceDef == null)
|
||||
{ pawnRaceDef = PawnRaceDefs.GetNamed("Human"); }
|
||||
|
||||
return pawnRaceDef;
|
||||
}
|
||||
|
||||
public void SetPawnRaceDef(string pawnRaceDefName)
|
||||
{
|
||||
PawnRaceDef pawnRaceDef = PawnRaceDefs.GetNamed(pawnRaceDefName);
|
||||
|
||||
if (pawnRaceDef != null)
|
||||
{
|
||||
this.pawnRaceDef = pawnRaceDef;
|
||||
EventsManager.OnActorChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetPawnRaceOffset()
|
||||
{
|
||||
if (pawnRaceDef == null)
|
||||
{ pawnRaceDef = PawnRaceDefs.GetNamed("Human"); }
|
||||
|
||||
PawnRaceOffset raceOffset = RaceOffsets.FirstOrDefault(x => x.defName == pawnRaceDef.defName);
|
||||
|
||||
if (raceOffset == null)
|
||||
{
|
||||
raceOffset = new PawnRaceOffset(pawnRaceDef.defName);
|
||||
RaceOffsets.Add(raceOffset);
|
||||
}
|
||||
|
||||
return raceOffset.GetOffset();
|
||||
}
|
||||
|
||||
public void SetPawnRaceOffset(Vector2 offset)
|
||||
{
|
||||
if (pawnRaceDef == null)
|
||||
{ return; }
|
||||
|
||||
PawnRaceOffset raceOffset = RaceOffsets.FirstOrDefault(x => x.defName == pawnRaceDef.defName);
|
||||
|
||||
if (raceOffset == null)
|
||||
{
|
||||
raceOffset = new PawnRaceOffset(pawnRaceDef.defName);
|
||||
RaceOffsets.Add(raceOffset);
|
||||
|
||||
EventsManager.OnActorChanged(this);
|
||||
}
|
||||
|
||||
raceOffset.SetOffset(offset);
|
||||
}
|
||||
|
||||
public Vector3 GetFinalTransformOffset()
|
||||
{
|
||||
Vector3 offset = GetPawnRaceOffset() + (GetPawnRaceDef().isHumanoid ? BodyTypeOffset.GetOffset(bodyType) : new Vector3());
|
||||
|
||||
return new Vector3(offset.x, offset.z, offset.y);
|
||||
}
|
||||
|
||||
public int GetActorID()
|
||||
{
|
||||
if (Workspace.animationDef == null) return -1;
|
||||
return Workspace.animationDef.Actors.IndexOf(this);
|
||||
}
|
||||
|
||||
public ActorPosition GetCurrentPosition()
|
||||
{
|
||||
return GetPositionAtTick(Workspace.StageTick);
|
||||
}
|
||||
|
||||
public ActorPosition GetPositionAtTick(int atTick)
|
||||
{
|
||||
return new ActorPosition(GetActorID(), atTick);
|
||||
}
|
||||
|
||||
// Pre-save / post-load
|
||||
public void OnPreSave()
|
||||
{
|
||||
BodyDefTypes = BodyDefTypes.Intersect(DefaultTags.bodyDefTypes.Concat(CustomTags.bodyDefTypes))?.ToList();
|
||||
RequiredGenitals = RequiredGenitals.Intersect(DefaultTags.bodyParts.Concat(CustomTags.bodyParts))?.ToList();
|
||||
RaceOffsets = RaceOffsets.Except(RaceOffsets.Where(x => x.OffsetIsZero()))?.ToList();
|
||||
}
|
||||
|
||||
public void OnPostLoad() { }
|
||||
}
|
||||
}
|
11
Source/Assets/Scripts/AnimationComponents/Actor.cs.meta
Normal file
11
Source/Assets/Scripts/AnimationComponents/Actor.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 63a9fd7a0256e9849bc2bc07403528e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
78
Source/Assets/Scripts/AnimationComponents/ActorAddon.cs
Normal file
78
Source/Assets/Scripts/AnimationComponents/ActorAddon.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class ActorAddon
|
||||
{
|
||||
// Data to/from animationDef
|
||||
public string addonName;
|
||||
public int? anchoringActor;
|
||||
public string anchorName;
|
||||
public string layer = "Pawn";
|
||||
public GraphicData graphicData;
|
||||
public bool? render;
|
||||
|
||||
// Data serialization control
|
||||
public bool ShouldSerializeanchorName() { return string.IsNullOrEmpty(anchorName) == false && anchorName.ToLower() != "none"; }
|
||||
public bool ShouldSerializeanchoringActor() { return anchoringActor.HasValue; }
|
||||
public bool ShouldSerializerender() { return render == true; }
|
||||
|
||||
// Data helper functions
|
||||
[XmlIgnore] public string AddonName
|
||||
{
|
||||
get { return addonName; }
|
||||
set { addonName = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public int AnchoringActor
|
||||
{
|
||||
get { return anchoringActor.HasValue ? anchoringActor.Value : 0; }
|
||||
set { anchoringActor = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public string AnchorName
|
||||
{
|
||||
get { return anchorName; }
|
||||
set { anchorName = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public string Layer
|
||||
{
|
||||
get { return layer; }
|
||||
set { layer = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public GraphicData GraphicData
|
||||
{
|
||||
get { return graphicData; }
|
||||
set { graphicData = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public bool Render
|
||||
{
|
||||
get { return render == true; }
|
||||
set { render = value; }
|
||||
}
|
||||
|
||||
// Simple curves
|
||||
[XmlIgnore] public SimpleCurve PosX = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve PosZ = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve Rotation = new SimpleCurve();
|
||||
|
||||
// Constructors
|
||||
public ActorAddon() { }
|
||||
|
||||
public ActorAddon(ActorAddonDef actorAddonDef)
|
||||
{
|
||||
this.AddonName = actorAddonDef.addonName;
|
||||
this.GraphicData = actorAddonDef.graphicData.Copy();
|
||||
}
|
||||
}
|
||||
}
|
11
Source/Assets/Scripts/AnimationComponents/ActorAddon.cs.meta
Normal file
11
Source/Assets/Scripts/AnimationComponents/ActorAddon.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3759e796f4f62b044b9a652e746d79a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
17
Source/Assets/Scripts/AnimationComponents/ActorAddonDef.cs
Normal file
17
Source/Assets/Scripts/AnimationComponents/ActorAddonDef.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class ActorAddonDef
|
||||
{
|
||||
public string addonName;
|
||||
public string label;
|
||||
public float scale = 1f;
|
||||
|
||||
public GraphicData graphicData;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6d836663c2196924eab4a00f4f4ceb3d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
55
Source/Assets/Scripts/AnimationComponents/AddonKeyFrame.cs
Normal file
55
Source/Assets/Scripts/AnimationComponents/AddonKeyFrame.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class AddonKeyframe
|
||||
{
|
||||
// Data to/from animationDef
|
||||
public string addonName;
|
||||
public float? posX;
|
||||
public float? posZ;
|
||||
public float? rotation;
|
||||
|
||||
// Data serialization control
|
||||
public bool ShouldSerializeposX() { return posX.HasValue; }
|
||||
public bool ShouldSerializeposZ() { return posZ.HasValue; }
|
||||
public bool ShouldSerializerotation() { return rotation.HasValue; }
|
||||
|
||||
|
||||
// Data helper functions
|
||||
[XmlIgnore] public string AddonName
|
||||
{
|
||||
get { return addonName; }
|
||||
set { addonName = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public float PosX
|
||||
{
|
||||
get { return posX.HasValue ? posX.Value : 0f; }
|
||||
set { posX = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public float PosZ
|
||||
{
|
||||
get { return posZ.HasValue ? posZ.Value : 0f; }
|
||||
set { posZ = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public float Rotation
|
||||
{
|
||||
get { return rotation.HasValue ? rotation.Value : 0f; }
|
||||
set { rotation = value; }
|
||||
}
|
||||
|
||||
// Constructors
|
||||
public AddonKeyframe() { }
|
||||
|
||||
public AddonKeyframe(string addonName)
|
||||
{
|
||||
this.AddonName = addonName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 339d47b209f50f545a84a8e8c7948ae1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
177
Source/Assets/Scripts/AnimationComponents/AnimationDef.cs
Normal file
177
Source/Assets/Scripts/AnimationComponents/AnimationDef.cs
Normal file
|
@ -0,0 +1,177 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class AnimationDef
|
||||
{
|
||||
// Data to/from animationDef
|
||||
public string defName;
|
||||
public string label;
|
||||
public bool sounds = true;
|
||||
[XmlArray("sexTypes"), XmlArrayItem("li")] public List<string> sexTypes;
|
||||
[XmlArray("interactionDefTypes"), XmlArrayItem("li")] public List<string> interactionDefTypes;
|
||||
[XmlArray("actors"), XmlArrayItem("li")] public List<Actor> actors;
|
||||
[XmlArray("animationStages"), XmlArrayItem("li")] public List<AnimationStage> animationStages;
|
||||
|
||||
// Data serialization control
|
||||
public bool ShouldSerializesexTypes() { return sexTypes.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializeinteractionDefTypes() { return interactionDefTypes.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializeactors() { return actors.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializeanimationStages() { return animationStages.NotNullOrEmpty(); }
|
||||
|
||||
// Data helper functions
|
||||
[XmlIgnore] public string DefName
|
||||
{
|
||||
get { return defName != null && defName != "" ? defName : "newAnimation"; }
|
||||
set { defName = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public string Label
|
||||
{
|
||||
get { return label != null && label != "" ? label : "newAnimation"; }
|
||||
set { label = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<string> SexTypes
|
||||
{
|
||||
get { return sexTypes.NullOrEmpty() ? sexTypes = new List<string>() : sexTypes; }
|
||||
set { sexTypes = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<string> InteractionDefTypes
|
||||
{
|
||||
get { return interactionDefTypes.NullOrEmpty() ? interactionDefTypes = new List<string>() : interactionDefTypes; }
|
||||
set { interactionDefTypes = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<Actor> Actors
|
||||
{
|
||||
get { return actors.NullOrEmpty() ? actors = new List<Actor>() : actors; }
|
||||
set { actors = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<AnimationStage> AnimationStages
|
||||
{
|
||||
get { if (animationStages.NullOrEmpty()){ animationStages = new List<AnimationStage>(); } return animationStages; }
|
||||
set { animationStages = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
// Local data
|
||||
[XmlIgnore] public int animationTimeTicks { get { return AnimationStages.Sum(x => x.PlayTimeTicks); } }
|
||||
[XmlIgnore] public int animationTimeTicksQuick { get { return AnimationStages.Sum(x => x.PlayTimeTicksQuick); } }
|
||||
|
||||
// Methods
|
||||
public void Initialize()
|
||||
{
|
||||
foreach (AnimationStage stage in AnimationStages)
|
||||
{ stage.Initialize(); }
|
||||
}
|
||||
|
||||
public void AddActor()
|
||||
{
|
||||
if (Workspace.animationDef.Actors.Count >= 8)
|
||||
{
|
||||
Debug.LogWarning("Cannot add actor - the animation can only contain a maximum of eight actors.");
|
||||
return;
|
||||
}
|
||||
|
||||
Actor actor = new Actor();
|
||||
Actors.Add(actor);
|
||||
|
||||
foreach (AnimationStage stage in Workspace.animationDef.AnimationStages)
|
||||
{ stage.AddAnimationClip(Workspace.animationDef.Actors.Count - 1); }
|
||||
|
||||
Initialize();
|
||||
Workspace.ActorID = Workspace.animationDef.Actors.Count - 1;
|
||||
|
||||
EventsManager.OnActorCountChanged();
|
||||
Workspace.RecordEvent("Actor addition");
|
||||
}
|
||||
|
||||
public void RemoveActor()
|
||||
{
|
||||
if (Workspace.animationDef.Actors.Count == 1)
|
||||
{
|
||||
Debug.LogWarning("Cannot delete actor - the animation must contain at least one actor.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (AnimationStage stage in Workspace.animationDef.AnimationStages)
|
||||
{ stage.AnimationClips.RemoveAt(Workspace.ActorID); }
|
||||
|
||||
Workspace.animationDef.Actors.RemoveAt(Workspace.ActorID);
|
||||
Workspace.ActorID--;
|
||||
|
||||
EventsManager.OnActorCountChanged();
|
||||
Workspace.RecordEvent("Actor deletion");
|
||||
}
|
||||
|
||||
public void AddAnimationStage()
|
||||
{
|
||||
AnimationStage stage = new AnimationStage();
|
||||
AnimationStages.Add(stage);
|
||||
|
||||
foreach (Actor actor in Workspace.animationDef.Actors)
|
||||
{ stage.AddAnimationClip(actor.GetActorID()); }
|
||||
|
||||
Initialize();
|
||||
Workspace.StageID = Workspace.animationDef.AnimationStages.Count - 1;
|
||||
|
||||
EventsManager.OnStageCountChanged();
|
||||
Workspace.RecordEvent("Stage addition");
|
||||
}
|
||||
|
||||
public void CloneAnimationStage()
|
||||
{
|
||||
AnimationStage stage = Workspace.GetCurrentAnimationStage().GetClone();
|
||||
stage.StageName += " (Clone)";
|
||||
|
||||
Workspace.animationDef.AnimationStages.Insert(Workspace.StageID + 1, stage);
|
||||
Initialize();
|
||||
|
||||
EventsManager.OnStageCountChanged();
|
||||
Workspace.RecordEvent("Stage clone");
|
||||
}
|
||||
|
||||
public void MoveAnimationStage(int startIndex, int delta)
|
||||
{
|
||||
if (startIndex + delta < 0 || startIndex + delta >= AnimationStages.Count) return;
|
||||
|
||||
AnimationStage stage = AnimationStages[startIndex];
|
||||
AnimationStages[startIndex] = Workspace.animationDef.AnimationStages[startIndex + delta];
|
||||
AnimationStages[startIndex + delta] = stage;
|
||||
|
||||
Workspace.StageID = startIndex + delta;
|
||||
Workspace.RecordEvent("Stage move");
|
||||
}
|
||||
|
||||
public void RemoveAnimationStage()
|
||||
{
|
||||
if (Workspace.animationDef.AnimationStages.Count == 1)
|
||||
{
|
||||
Debug.LogWarning("Cannot delete animation stage - the animation must contain at least one animation stage.");
|
||||
return;
|
||||
}
|
||||
|
||||
AnimationStages.RemoveAt(Workspace.StageID);
|
||||
Workspace.StageID--;
|
||||
|
||||
EventsManager.OnStageCountChanged();
|
||||
Workspace.RecordEvent("Stage deletion");
|
||||
}
|
||||
|
||||
// Pre-save / post-load
|
||||
public void OnPreSave()
|
||||
{
|
||||
SexTypes = SexTypes.Intersect(DefaultTags.sexTypes.Concat(CustomTags.sexTypes))?.ToList();
|
||||
InteractionDefTypes = InteractionDefTypes.Intersect(DefaultTags.interactionDefTypes.Concat(CustomTags.interactionDefTypes))?.ToList();
|
||||
}
|
||||
|
||||
public void OnPostLoad() { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 37ec1f5f150928e42bda942fe97046b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
182
Source/Assets/Scripts/AnimationComponents/AnimationStage.cs
Normal file
182
Source/Assets/Scripts/AnimationComponents/AnimationStage.cs
Normal file
|
@ -0,0 +1,182 @@
|
|||
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<PawnAnimationClip> 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<PawnAnimationClip> AnimationClips
|
||||
{
|
||||
get { return animationClips.NullOrEmpty() ? animationClips = new List<PawnAnimationClip>() : 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()
|
||||
{
|
||||
foreach (PawnAnimationClip clip in AnimationClips)
|
||||
{ clip.OnPostLoad(); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9270822a570a06f41afa00e169af500c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
50
Source/Assets/Scripts/AnimationComponents/BodyTypeOffset.cs
Normal file
50
Source/Assets/Scripts/AnimationComponents/BodyTypeOffset.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class BodyTypeOffset
|
||||
{
|
||||
public string Male;
|
||||
public string Female;
|
||||
public string Thin;
|
||||
public string Hulk;
|
||||
public string Fat;
|
||||
|
||||
public bool AllOffsetsEmpty()
|
||||
{
|
||||
return string.IsNullOrEmpty(Male) && string.IsNullOrEmpty(Female) && string.IsNullOrEmpty(Thin) && string.IsNullOrEmpty(Hulk) && string.IsNullOrEmpty(Fat);
|
||||
}
|
||||
|
||||
public void SetOffset(string bodyType, Vector2 bodyOffset)
|
||||
{
|
||||
FieldInfo bodyTypeOffsetInfo = typeof(BodyTypeOffset).GetField(bodyType);
|
||||
|
||||
if (bodyTypeOffsetInfo == null)
|
||||
{ return; }
|
||||
|
||||
string _bodyOffset = "(" + bodyOffset.x + ", " + bodyOffset.y + ")";
|
||||
bodyTypeOffsetInfo.SetValue(this, _bodyOffset);
|
||||
}
|
||||
|
||||
public Vector3 GetOffset(string bodyType)
|
||||
{
|
||||
FieldInfo bodyTypeOffsetInfo = typeof(BodyTypeOffset).GetField(bodyType);
|
||||
|
||||
if (bodyTypeOffsetInfo == null)
|
||||
{ return new Vector2(); }
|
||||
|
||||
string bodyTypeOffsetString = (string)bodyTypeOffsetInfo.GetValue(this);
|
||||
|
||||
if (bodyTypeOffsetString == null || bodyTypeOffsetString == "")
|
||||
{ return new Vector2(); }
|
||||
|
||||
bodyTypeOffsetString = bodyTypeOffsetString.Trim();
|
||||
bodyTypeOffsetString = bodyTypeOffsetString.Replace("(", "");
|
||||
bodyTypeOffsetString = bodyTypeOffsetString.Replace(")", "");
|
||||
var bodyTypeOffsetStrings = bodyTypeOffsetString.Split(',');
|
||||
|
||||
return new Vector3(float.Parse(bodyTypeOffsetStrings[0]), 0f, float.Parse(bodyTypeOffsetStrings[1]));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1dfd90f8aa6d0e04086e2b4983d42ab6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
363
Source/Assets/Scripts/AnimationComponents/PawnAnimationClip.cs
Normal file
363
Source/Assets/Scripts/AnimationComponents/PawnAnimationClip.cs
Normal file
|
@ -0,0 +1,363 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class PawnAnimationClip
|
||||
{
|
||||
// Data to/from animationDef
|
||||
public string layer = "Pawn";
|
||||
[XmlArray("addons"), XmlArrayItem("li")] public List<ActorAddon> addons;
|
||||
[XmlAttribute("Class")] public string className = "Rimworld_Animations.PawnAnimationClip";
|
||||
[XmlArray("keyframes"), XmlArrayItem("li")] public List<PawnKeyframe> keyframes;
|
||||
[XmlArray("tags"), XmlArrayItem("li")] public List<string> tags;
|
||||
|
||||
// Data serialization control
|
||||
public bool ShouldSerializeaddons() { return addons.Where(x => x.Render)?.Any() == true; }
|
||||
public bool ShouldSerializekeyframes() { return keyframes.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializetags() { return tags.NotNullOrEmpty(); }
|
||||
|
||||
// Data helper functions
|
||||
[XmlIgnore] public string Layer
|
||||
{
|
||||
get { return layer; }
|
||||
set { layer = value; EventsManager.OnPawnAnimationClipChanged(this); }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<ActorAddon> Addons
|
||||
{
|
||||
get { return addons.NullOrEmpty() ? addons = new List<ActorAddon>() : addons; }
|
||||
set { addons = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<PawnKeyframe> Keyframes
|
||||
{
|
||||
get { return keyframes.NullOrEmpty() ? keyframes = new List<PawnKeyframe>() : keyframes; }
|
||||
set { keyframes = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public List<string> Tags
|
||||
{
|
||||
get { return tags.NullOrEmpty() ? tags = new List<string>() : tags; }
|
||||
set { tags = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
// Local data
|
||||
[XmlIgnore] public int duration { get { return Keyframes.Max(x => x.atTick.Value); } }
|
||||
|
||||
[XmlIgnore] public SimpleCurve GenitalAngle = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve BodyAngle = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve HeadAngle = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve HeadBob = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve BodyOffsetX = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve BodyOffsetZ = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve HeadFacing = new SimpleCurve();
|
||||
[XmlIgnore] public SimpleCurve BodyFacing = new SimpleCurve();
|
||||
|
||||
// Methods
|
||||
public void BuildSimpleCurves()
|
||||
{
|
||||
// Add addon data (if missing)
|
||||
foreach (ActorAddonDef actorAddonDef in ActorAddonDefs.allDefs)
|
||||
{ AddActorAddon(actorAddonDef); }
|
||||
|
||||
// Clear simple curve data
|
||||
BodyAngle.Clear();
|
||||
HeadAngle.Clear();
|
||||
BodyOffsetX.Clear();
|
||||
BodyOffsetZ.Clear();
|
||||
HeadFacing.Clear();
|
||||
BodyFacing.Clear();
|
||||
HeadBob.Clear();
|
||||
GenitalAngle.Clear();
|
||||
|
||||
foreach (ActorAddon addon in Addons)
|
||||
{
|
||||
addon.PosX.Clear();
|
||||
addon.PosZ.Clear();
|
||||
addon.Rotation.Clear();
|
||||
}
|
||||
|
||||
// Start building simple curves
|
||||
int keyframePosition = 0;
|
||||
int duration = 0;
|
||||
|
||||
Keyframes[Keyframes.Count - 1].TickDuration = 1;
|
||||
|
||||
foreach (PawnKeyframe frame in Keyframes)
|
||||
{ duration += frame.TickDuration; }
|
||||
|
||||
for (int i = 0; i < Keyframes.Count; i++)
|
||||
{
|
||||
PawnKeyframe keyframe = Keyframes[i];
|
||||
|
||||
if (keyframe.HasValidKeyframeID() == false)
|
||||
{ keyframe.GenerateKeyframeID(GetOwningActorID()); }
|
||||
|
||||
if (keyframe.atTick.HasValue)
|
||||
{
|
||||
if (i + 1 < Keyframes.Count)
|
||||
{ Keyframes[i].TickDuration = Keyframes[i + 1].atTick.Value - Keyframes[i].atTick.Value; }
|
||||
|
||||
// Safeguard - if two keys end up in having the same atTick, the duration of the first will be 0 and should be deleted
|
||||
if (Keyframes[i].TickDuration == 0)
|
||||
{
|
||||
Keyframes.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
BodyAngle.Add((float)keyframe.atTick / (float)duration, keyframe.BodyAngle, true);
|
||||
HeadAngle.Add((float)keyframe.atTick / (float)duration, keyframe.HeadAngle, true);
|
||||
BodyOffsetX.Add((float)keyframe.atTick / (float)duration, keyframe.BodyOffsetX, true);
|
||||
BodyOffsetZ.Add((float)keyframe.atTick / (float)duration, keyframe.BodyOffsetZ, true);
|
||||
HeadFacing.Add((float)keyframe.atTick / (float)duration, keyframe.HeadFacing, true);
|
||||
BodyFacing.Add((float)keyframe.atTick / (float)duration, keyframe.BodyFacing, true);
|
||||
HeadBob.Add((float)keyframe.atTick / (float)duration, keyframe.HeadBob, true);
|
||||
GenitalAngle.Add((float)keyframe.atTick / (float)duration, keyframe.GenitalAngle, true);
|
||||
|
||||
foreach (ActorAddon addon in Addons)
|
||||
{
|
||||
if (keyframe.AddonKeyframes.Any(x => x.AddonName == addon.AddonName) == false)
|
||||
{ keyframe.AddonKeyframes.Add(new AddonKeyframe(addon.AddonName)); }
|
||||
|
||||
addon.PosX.Add((float)keyframe.atTick / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).PosX, true);
|
||||
addon.PosZ.Add((float)keyframe.atTick / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).PosZ, true);
|
||||
addon.Rotation.Add((float)keyframe.atTick / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).Rotation, true);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
BodyAngle.Add((float)keyframePosition / (float)duration, keyframe.BodyAngle, true);
|
||||
HeadAngle.Add((float)keyframePosition / (float)duration, keyframe.HeadAngle, true);
|
||||
BodyOffsetX.Add((float)keyframePosition / (float)duration, keyframe.BodyOffsetX, true);
|
||||
BodyOffsetZ.Add((float)keyframePosition / (float)duration, keyframe.BodyOffsetZ, true);
|
||||
HeadFacing.Add((float)keyframePosition / (float)duration, keyframe.HeadFacing, true);
|
||||
BodyFacing.Add((float)keyframePosition / (float)duration, keyframe.BodyFacing, true);
|
||||
HeadBob.Add((float)keyframePosition / (float)duration, keyframe.HeadBob, true);
|
||||
GenitalAngle.Add((float)keyframePosition / (float)duration, keyframe.GenitalAngle, true);
|
||||
|
||||
foreach (ActorAddon addon in Addons)
|
||||
{
|
||||
if (keyframe.AddonKeyframes.Any(x => x.AddonName == addon.AddonName) == false)
|
||||
{ keyframe.AddonKeyframes.Add(new AddonKeyframe(addon.AddonName)); }
|
||||
|
||||
addon.PosX.Add((float)keyframePosition / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).PosX, true);
|
||||
addon.PosZ.Add((float)keyframePosition / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).PosZ, true);
|
||||
addon.Rotation.Add((float)keyframePosition / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).Rotation, true);
|
||||
}
|
||||
|
||||
keyframe.atTick = keyframePosition + Constants.minTick;
|
||||
keyframePosition += keyframe.TickDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddActorAddon(ActorAddonDef actorAddonDef)
|
||||
{
|
||||
if (Addons.Any(x => x.AddonName == actorAddonDef.addonName) == false)
|
||||
{ Addons.Add(new ActorAddon(actorAddonDef)); }
|
||||
|
||||
foreach (PawnKeyframe keyframe in Keyframes)
|
||||
{
|
||||
if (keyframe.AddonKeyframes.Any(x => x.AddonName == actorAddonDef.addonName) == false)
|
||||
{ keyframe.AddonKeyframes.Add(new AddonKeyframe(actorAddonDef.addonName)); }
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowOrHideActorAddon(string addonName, bool flag)
|
||||
{
|
||||
ActorAddon addon = GetActorAddon(addonName);
|
||||
|
||||
if (addon != null)
|
||||
{ addon.Render = flag; }
|
||||
}
|
||||
|
||||
public bool IsActorAddonVisible(string addonName)
|
||||
{
|
||||
ActorAddon addon = GetActorAddon(addonName);
|
||||
|
||||
if (addon != null)
|
||||
{ return addon.Render; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ActorAddon GetActorAddon(string addonName)
|
||||
{
|
||||
return Addons.FirstOrDefault(x => x.AddonName == addonName);
|
||||
}
|
||||
|
||||
public int GetOwningActorID()
|
||||
{
|
||||
if (Workspace.animationDef == null) return -1;
|
||||
|
||||
return Workspace.GetCurrentAnimationStage().AnimationClips.IndexOf(this);
|
||||
}
|
||||
|
||||
public void AddPawnKeyframe()
|
||||
{
|
||||
if (Keyframes == null)
|
||||
{ Debug.LogWarning("Cannot add pawn keyframe - the AnimationDef is invalid"); return; }
|
||||
|
||||
if (Keyframes.FirstOrDefault(x => x.atTick == Workspace.StageTick) != null)
|
||||
{ Debug.LogWarning("Cannot add pawn keyframe - a keyframe already exists at this tick"); return; }
|
||||
|
||||
float clipPercent = (float)(Workspace.StageTick % duration) / duration;
|
||||
|
||||
PawnKeyframe keyframe = new PawnKeyframe();
|
||||
keyframe.BodyAngle = BodyAngle.Evaluate(clipPercent);
|
||||
keyframe.HeadAngle = HeadAngle.Evaluate(clipPercent);
|
||||
keyframe.HeadBob = HeadBob.Evaluate(clipPercent);
|
||||
keyframe.BodyOffsetX = BodyOffsetX.Evaluate(clipPercent);
|
||||
keyframe.BodyOffsetZ = BodyOffsetZ.Evaluate(clipPercent);
|
||||
keyframe.HeadFacing = (int)HeadFacing.Evaluate(clipPercent);
|
||||
keyframe.BodyFacing = (int)BodyFacing.Evaluate(clipPercent);
|
||||
keyframe.GenitalAngle = GenitalAngle.Evaluate(clipPercent);
|
||||
|
||||
keyframe.atTick = Workspace.StageTick;
|
||||
|
||||
PawnKeyframe nextKeyframe = Keyframes.FirstOrDefault(x => x.atTick > Workspace.StageTick);
|
||||
|
||||
if (nextKeyframe != null)
|
||||
{ keyframes.Insert(keyframes.IndexOf(nextKeyframe), keyframe); }
|
||||
|
||||
else
|
||||
{ keyframes.Add(keyframe); }
|
||||
|
||||
BuildSimpleCurves();
|
||||
|
||||
EventsManager.OnKeyframeCountChanged(this);
|
||||
Workspace.RecordEvent("Keyframe addition");
|
||||
}
|
||||
|
||||
public void CopyPawnKeyframes()
|
||||
{
|
||||
Workspace.copiedKeyframes.Clear();
|
||||
|
||||
List<PawnKeyframe> keyframesToClone = Workspace.GetPawnKeyframesByID(Workspace.keyframeID);
|
||||
|
||||
foreach (PawnKeyframe keyframe in keyframesToClone)
|
||||
{ Workspace.copiedKeyframes.Add(keyframe.GetClone()); }
|
||||
}
|
||||
|
||||
public void PastePawnKeyframes()
|
||||
{
|
||||
int originalWindowSize = Workspace.StageWindowSize;
|
||||
|
||||
List<int> actorsInvolved = Workspace.copiedKeyframes.Select(x => x.actorID)?.ToList();
|
||||
actorsInvolved = actorsInvolved?.Distinct()?.ToList();
|
||||
|
||||
if (actorsInvolved.NullOrEmpty()) { Debug.Log("Cannot paste keyframes - there were no copied keyframes to paste"); return; }
|
||||
if (actorsInvolved.Count > 1 && actorsInvolved.Contains(Workspace.ActorID) == false) { Debug.Log("Cannot paste keyframes - keyframes copied across multiple timelines can only be pasted back into these source timelines"); return; }
|
||||
|
||||
int earliestTick = actorsInvolved.Count == 1 ? Workspace.GetEarliestAtTickInCopiedKeyframes(actorsInvolved[0]) : Workspace.GetEarliestAtTickInCopiedKeyframes(Workspace.ActorID);
|
||||
if (earliestTick < 1) { Debug.Log("Unknown error occured during keyframe paste operation"); return; }
|
||||
|
||||
foreach (PawnKeyframe copiedKeyframe in Workspace.copiedKeyframes)
|
||||
{
|
||||
int tickToPasteAt = Workspace.StageTick + (copiedKeyframe.atTick.Value - earliestTick);
|
||||
|
||||
if (tickToPasteAt < 1) continue;
|
||||
if (tickToPasteAt > Workspace.StageWindowSize)
|
||||
{
|
||||
if (Workspace.stretchKeyframes)
|
||||
{ Workspace.GetCurrentAnimationStage().ResizeStageWindow(tickToPasteAt); }
|
||||
|
||||
else continue;
|
||||
}
|
||||
|
||||
int targetActorID = actorsInvolved.Count == 1 ? Workspace.ActorID : copiedKeyframe.actorID;
|
||||
|
||||
if (Workspace.DoesPawnKeyframeExistAtTick(Workspace.StageID, targetActorID, tickToPasteAt))
|
||||
{
|
||||
PawnKeyframe oldKeyframe = Workspace.GetPawnAnimationClip(targetActorID).Keyframes.First(x => x.atTick == tickToPasteAt);
|
||||
Workspace.GetAnimationClipThatOwnsKeyframe(oldKeyframe.keyframeID).RemovePawnKeyframe(oldKeyframe.keyframeID, true);
|
||||
}
|
||||
|
||||
PawnKeyframe clonedKeyframe = copiedKeyframe.GetClone();
|
||||
clonedKeyframe.GenerateKeyframeID(targetActorID);
|
||||
clonedKeyframe.atTick = tickToPasteAt;
|
||||
|
||||
PawnAnimationClip clip = Workspace.animationDef.AnimationStages[Workspace.StageID].AnimationClips[targetActorID];
|
||||
PawnKeyframe nextKeyframe = clip.Keyframes.FirstOrDefault(x => x.atTick > tickToPasteAt);
|
||||
|
||||
if (nextKeyframe != null)
|
||||
{ clip.Keyframes.Insert(clip.Keyframes.IndexOf(nextKeyframe), clonedKeyframe); }
|
||||
|
||||
else
|
||||
{ clip.Keyframes.Add(clonedKeyframe); }
|
||||
|
||||
clip.BuildSimpleCurves();
|
||||
|
||||
EventsManager.OnKeyframeCountChanged(clip);
|
||||
}
|
||||
|
||||
if (originalWindowSize != Workspace.StageWindowSize)
|
||||
{
|
||||
Workspace.GetCurrentAnimationStage().StretchStageWindow(originalWindowSize);
|
||||
Workspace.GetCurrentAnimationStage().ResizeStageWindow(originalWindowSize);
|
||||
}
|
||||
|
||||
Workspace.RecordEvent("Keyframe pasted");
|
||||
}
|
||||
|
||||
public void RemovePawnKeyframe(int keyframeID, bool force = false)
|
||||
{
|
||||
PawnKeyframe keyframe = Workspace.GetPawnKeyframe(keyframeID);
|
||||
if (keyframe == null || IsOwnerOfKeyframe(keyframeID) == false) return;
|
||||
|
||||
Keyframes.Remove(keyframe);
|
||||
|
||||
if (Workspace.GetAllPawnKeyframesAtTick(GetOwningActorID(), Constants.minTick).NullOrEmpty())
|
||||
{
|
||||
PawnKeyframe newKeyframe = new PawnKeyframe();
|
||||
newKeyframe.GenerateKeyframeID(GetOwningActorID());
|
||||
newKeyframe.atTick = Constants.minTick;
|
||||
Keyframes.Insert(0, newKeyframe);
|
||||
}
|
||||
|
||||
// Add missing second keyframe (if needed)
|
||||
if (Keyframes.Count == 1)
|
||||
{
|
||||
PawnKeyframe newKeyframe = Workspace.GetAllPawnKeyframesAtTick(GetOwningActorID(), Constants.minTick).First().GetClone();
|
||||
newKeyframe.atTick = 10;
|
||||
Keyframes.Add(newKeyframe);
|
||||
}
|
||||
|
||||
BuildSimpleCurves();
|
||||
|
||||
EventsManager.OnKeyframeCountChanged(this);
|
||||
Workspace.RecordEvent("Keyframe deletion");
|
||||
}
|
||||
|
||||
public bool IsOwnerOfKeyframe(int keyframeID)
|
||||
{
|
||||
return Keyframes.Any(x => x.keyframeID == keyframeID);
|
||||
}
|
||||
|
||||
// Pre-save / post-load
|
||||
public void OnPreSave()
|
||||
{
|
||||
var temp = Addons.Copy();
|
||||
Addons.Clear();
|
||||
|
||||
foreach (ActorAddon addon in temp)
|
||||
{
|
||||
if (addon.Render)
|
||||
{ addons.Add(addon); }
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPostLoad()
|
||||
{
|
||||
foreach (PawnKeyframe keyframe in Keyframes)
|
||||
{ keyframe.OnPostLoad(); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bd5a477338567fb4cbb26b913a52ca65
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
241
Source/Assets/Scripts/AnimationComponents/PawnKeyframe.cs
Normal file
241
Source/Assets/Scripts/AnimationComponents/PawnKeyframe.cs
Normal file
|
@ -0,0 +1,241 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
public class PawnKeyframe
|
||||
{
|
||||
// Data to/from animationDef
|
||||
public float? bodyAngle;
|
||||
public float? headAngle;
|
||||
public float? headBob;
|
||||
public float? bodyOffsetX;
|
||||
public float? bodyOffsetZ;
|
||||
public float? headFacing;
|
||||
public float? bodyFacing;
|
||||
public float? genitalAngle;
|
||||
public bool? quiver;
|
||||
public int? tickDuration;
|
||||
public string soundEffect;
|
||||
public List<string> tags;
|
||||
[XmlArray("addonKeyframes"), XmlArrayItem("li")] public List<AddonKeyframe> addonKeyframes;
|
||||
|
||||
// Data serialization control
|
||||
public bool ShouldSerializebodyAngle() { return bodyAngle.HasValue && bodyAngle.Value != 0f; }
|
||||
public bool ShouldSerializeheadAngle() { return headAngle.HasValue && headAngle.Value != 0f; }
|
||||
public bool ShouldSerializeheadBob() { return headBob.HasValue && headBob.Value != 0f; }
|
||||
public bool ShouldSerializebodyOffsetX() { return bodyOffsetX.HasValue && bodyOffsetX.Value != 0f; }
|
||||
public bool ShouldSerializebodyOffsetZ() { return bodyOffsetZ.HasValue && bodyOffsetZ.Value != 0f; }
|
||||
public bool ShouldSerializegenitalAngle() { return genitalAngle.HasValue && genitalAngle.Value != 0f; }
|
||||
public bool ShouldSerializequiver() { return quiver == true; }
|
||||
public bool ShouldSerializetags() { return tags.NotNullOrEmpty(); }
|
||||
public bool ShouldSerializeaddonKeyframes() { return addonKeyframes.NotNullOrEmpty(); }
|
||||
|
||||
// Data helper functions
|
||||
[XmlIgnore] public float BodyAngle
|
||||
{
|
||||
get { return bodyAngle.HasValue ? bodyAngle.Value : (float)(bodyAngle = 0f); }
|
||||
set { bodyAngle = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public float HeadAngle
|
||||
{
|
||||
get { return headAngle.HasValue ? headAngle.Value : (float)(headAngle = 0f); }
|
||||
set { headAngle = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public float HeadBob
|
||||
{
|
||||
get { return headBob.HasValue ? headBob.Value : (float)(headBob = 0f); }
|
||||
set { headBob = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public float BodyOffsetX
|
||||
{
|
||||
get { return bodyOffsetX.HasValue ? bodyOffsetX.Value : (float)(bodyOffsetX = 0f); }
|
||||
set { bodyOffsetX = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public float BodyOffsetZ
|
||||
{
|
||||
get { return bodyOffsetZ.HasValue ? bodyOffsetZ.Value : (float)(bodyOffsetZ = 0f); }
|
||||
set { bodyOffsetZ = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public int HeadFacing
|
||||
{
|
||||
get { return headFacing.HasValue ? (int)headFacing.Value : (int)(headFacing = 2); }
|
||||
set { headFacing = (int)value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public int BodyFacing
|
||||
{
|
||||
get { return bodyFacing.HasValue ? (int)bodyFacing.Value : (int)(bodyFacing = 2); }
|
||||
set { bodyFacing = (int)value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public float GenitalAngle
|
||||
{
|
||||
get { return genitalAngle.HasValue ? genitalAngle.Value : (float)(genitalAngle = 0f); }
|
||||
set { genitalAngle = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public bool Quiver
|
||||
{
|
||||
get { return quiver == true; }
|
||||
set { quiver = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public int TickDuration
|
||||
{
|
||||
get { return tickDuration.HasValue ? tickDuration.Value : (int)(tickDuration = 0); }
|
||||
set { tickDuration = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public string SoundEffect
|
||||
{
|
||||
get { return soundEffect; }
|
||||
set { soundEffect = value; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<string> Tags
|
||||
{
|
||||
get { return tags.NullOrEmpty() ? tags = new List<string>() : tags; }
|
||||
set { tags = value.NotNullOrEmpty() ? value : null; }
|
||||
}
|
||||
|
||||
[XmlIgnore] public List<AddonKeyframe> AddonKeyframes
|
||||
{
|
||||
get { return addonKeyframes.NullOrEmpty() ? addonKeyframes = new List<AddonKeyframe>() : addonKeyframes; }
|
||||
set { addonKeyframes = value.NotNullOrEmpty()? value : null; }
|
||||
}
|
||||
|
||||
// Local data
|
||||
[XmlIgnore] public int keyframeID;
|
||||
[XmlIgnore] public int actorID = -1;
|
||||
[XmlIgnore] public int? atTick;
|
||||
|
||||
// Methods
|
||||
public void GenerateKeyframeID(int actorID)
|
||||
{
|
||||
this.actorID = actorID;
|
||||
int _keyframeID = UnityEngine.Random.Range(100000, 1000000);
|
||||
|
||||
if (Workspace.animationDef.AnimationStages.Any(x => x.AnimationClips.Any(y => y.Keyframes.Any(z => z.keyframeID == _keyframeID))))
|
||||
{
|
||||
GenerateKeyframeID(actorID);
|
||||
return;
|
||||
}
|
||||
|
||||
keyframeID = _keyframeID;
|
||||
}
|
||||
|
||||
public bool HasValidKeyframeID()
|
||||
{ return keyframeID >= 100000 && keyframeID < 1000000; }
|
||||
|
||||
public KeyframeSlider GetKeyframeSlider()
|
||||
{
|
||||
return Selectable.allSelectablesArray.FirstOrDefault(x => x.GetComponent<KeyframeSlider>()?.keyframeID == keyframeID)?.GetComponent< KeyframeSlider>();
|
||||
}
|
||||
|
||||
public AddonKeyframe GetAddonKeyframe(string addonName)
|
||||
{
|
||||
return AddonKeyframes.FirstOrDefault(x => x.AddonName == addonName);
|
||||
}
|
||||
|
||||
public void AdjustActor(Vector2 deltaOffset)
|
||||
{
|
||||
float deltaAngle = -deltaOffset.x * 33.3333f + deltaOffset.y * 33.3333f;
|
||||
int facing = deltaOffset.x < 0 ? 3 : deltaOffset.y < 0 ? 2 : deltaOffset.x > 0 ? 1 : 0;
|
||||
|
||||
switch (Workspace.actorManipulationMode)
|
||||
{
|
||||
case ActorManipulationMode.Pan: MoveActor(deltaOffset); break;
|
||||
case ActorManipulationMode.Rotate: RotateActor(deltaAngle); break;
|
||||
case ActorManipulationMode.Face: FaceActor(facing); break;
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveActor(Vector2 deltaOffset)
|
||||
{
|
||||
if (Workspace.selectedBodyPart == null)
|
||||
{
|
||||
BodyOffsetX += deltaOffset.x;
|
||||
BodyOffsetZ += deltaOffset.y;
|
||||
}
|
||||
|
||||
else if (Workspace.selectedBodyPart.bodyPart.ToLower() == "head")
|
||||
{ HeadBob += deltaOffset.y; }
|
||||
|
||||
Workspace.GetCurrentPawnAnimationClip().BuildSimpleCurves();
|
||||
Workspace.RecordEvent("Actor position / orientation");
|
||||
}
|
||||
|
||||
public void RotateActor(float deltaAngle)
|
||||
{
|
||||
if (Workspace.selectedBodyPart == null)
|
||||
{ BodyAngle += deltaAngle; }
|
||||
|
||||
else if (Workspace.selectedBodyPart.bodyPart.ToLower() == "head")
|
||||
{ HeadAngle += deltaAngle; }
|
||||
|
||||
else if (Workspace.selectedBodyPart.bodyPart.ToLower() == "appendage")
|
||||
{ GenitalAngle -= deltaAngle; }
|
||||
|
||||
Workspace.GetCurrentPawnAnimationClip().BuildSimpleCurves();
|
||||
Workspace.RecordEvent("Actor position / orientation");
|
||||
}
|
||||
|
||||
public void FaceActor(int facing)
|
||||
{
|
||||
PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
|
||||
|
||||
if (Workspace.selectedBodyPart == null)
|
||||
{ keyframe.BodyFacing = facing; }
|
||||
|
||||
else if (Workspace.selectedBodyPart.bodyPart.ToLower() == "head")
|
||||
{ keyframe.HeadFacing = facing; }
|
||||
|
||||
Workspace.GetCurrentPawnAnimationClip().BuildSimpleCurves();
|
||||
Workspace.RecordEvent("Actor position / orientation");
|
||||
}
|
||||
|
||||
public PawnKeyframe GetClone()
|
||||
{
|
||||
PawnKeyframe clone = this.Copy();
|
||||
clone.GenerateKeyframeID(actorID);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Pre-save / post-load
|
||||
public void OnPreSave()
|
||||
{
|
||||
SoundEffect = DefaultTags.soundDefs.Concat(CustomTags.soundDefs).Contains(SoundEffect) ? SoundEffect : null;
|
||||
|
||||
if (addonKeyframes.NotNullOrEmpty())
|
||||
{
|
||||
var temp = AddonKeyframes.Copy();
|
||||
addonKeyframes.Clear();
|
||||
|
||||
foreach (AddonKeyframe addonKeyframe in temp)
|
||||
{
|
||||
ActorAddon addon = Workspace.GetAnimationClipThatOwnsKeyframe(keyframeID).GetActorAddon(addonKeyframe.AddonName);
|
||||
|
||||
if (addon.Render)
|
||||
{ addonKeyframes.Add(addonKeyframe.Copy()); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPostLoad()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8ced38490f6b174984453dc3336a543
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
151
Source/Assets/Scripts/AnimationComponents/PawnRaceDef.cs
Normal file
151
Source/Assets/Scripts/AnimationComponents/PawnRaceDef.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
[Serializable]
|
||||
public class PawnRaceDef
|
||||
{
|
||||
// Local data
|
||||
public string defName;
|
||||
public bool isHumanoid = true;
|
||||
public float scale = 1f;
|
||||
|
||||
public List<MultiDirectionalGraphic> bodyTypeGraphics = new List<MultiDirectionalGraphic>();
|
||||
public MultiDirectionalGraphic headGraphics = new MultiDirectionalGraphic();
|
||||
|
||||
// Constructors
|
||||
public PawnRaceDef() { }
|
||||
|
||||
public PawnRaceDef(string defName)
|
||||
{
|
||||
this.defName = defName;
|
||||
}
|
||||
|
||||
// Methods
|
||||
public Sprite GetHeadGraphic(CardinalDirection facing)
|
||||
{
|
||||
if (HasValidHeadGraphicPath(facing) == false)
|
||||
{ return null; }
|
||||
|
||||
switch (facing)
|
||||
{
|
||||
case CardinalDirection.North: return headGraphics.northGraphic.sprite;
|
||||
case CardinalDirection.East: return headGraphics.eastGraphic.sprite;
|
||||
case CardinalDirection.South: return headGraphics.southGraphic.sprite;
|
||||
default: return headGraphics.eastGraphic.sprite;
|
||||
}
|
||||
}
|
||||
|
||||
public Sprite GetBodyTypeGraphic(CardinalDirection facing, string bodyType = "None")
|
||||
{
|
||||
if (HasValidBodyTypeGraphicPath(facing, bodyType) == false)
|
||||
{ return null; }
|
||||
|
||||
MultiDirectionalGraphic bodyTypeGraphic = bodyTypeGraphics.FirstOrDefault(x => x.bodyType == bodyType);
|
||||
|
||||
if (bodyTypeGraphic == null)
|
||||
{
|
||||
bodyTypeGraphic = new MultiDirectionalGraphic(bodyType);
|
||||
bodyTypeGraphics.Add(bodyTypeGraphic);
|
||||
}
|
||||
|
||||
switch (facing)
|
||||
{
|
||||
case CardinalDirection.North: return bodyTypeGraphic.northGraphic.sprite;
|
||||
case CardinalDirection.East: return bodyTypeGraphic.eastGraphic.sprite;
|
||||
case CardinalDirection.South: return bodyTypeGraphic.southGraphic.sprite;
|
||||
default: return bodyTypeGraphic.eastGraphic.sprite;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetHeadGraphicPath(CardinalDirection facing)
|
||||
{
|
||||
if (HasValidHeadGraphicPath(facing) == false)
|
||||
{ return "Invalid file path"; }
|
||||
|
||||
switch (facing)
|
||||
{
|
||||
case CardinalDirection.North: return headGraphics.northGraphic.path;
|
||||
case CardinalDirection.East: return headGraphics.eastGraphic.path;
|
||||
case CardinalDirection.South: return headGraphics.southGraphic.path;
|
||||
default: return headGraphics.eastGraphic.path;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetBodyTypeGraphicPath(CardinalDirection facing, string bodyType = "None")
|
||||
{
|
||||
if (HasValidBodyTypeGraphicPath(facing, bodyType) == false)
|
||||
{ return "Invalid file path"; }
|
||||
|
||||
MultiDirectionalGraphic bodyTypeGraphic = bodyTypeGraphics.FirstOrDefault(x => x.bodyType == bodyType);
|
||||
|
||||
if (bodyTypeGraphic == null)
|
||||
{
|
||||
bodyTypeGraphic = new MultiDirectionalGraphic(bodyType);
|
||||
bodyTypeGraphics.Add(bodyTypeGraphic);
|
||||
}
|
||||
|
||||
switch (facing)
|
||||
{
|
||||
case CardinalDirection.North: return bodyTypeGraphic.northGraphic.path;
|
||||
case CardinalDirection.East: return bodyTypeGraphic.eastGraphic.path;
|
||||
case CardinalDirection.South: return bodyTypeGraphic.southGraphic.path;
|
||||
default: return bodyTypeGraphic.eastGraphic.path;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHeadGraphicPath(string path, CardinalDirection facing)
|
||||
{
|
||||
switch (facing)
|
||||
{
|
||||
case CardinalDirection.North: headGraphics.northGraphic.SetPath(path); break;
|
||||
case CardinalDirection.East: headGraphics.eastGraphic.SetPath(path); break;
|
||||
case CardinalDirection.South: headGraphics.southGraphic.SetPath(path); break;
|
||||
default: headGraphics.eastGraphic.SetPath(path); break;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBodyTypeGraphicPath(string path, CardinalDirection facing, string bodyType = "None")
|
||||
{
|
||||
MultiDirectionalGraphic bodyTypeGraphic = bodyTypeGraphics.FirstOrDefault(x => x.bodyType == bodyType);
|
||||
|
||||
if (bodyTypeGraphic == null)
|
||||
{
|
||||
bodyTypeGraphic = new MultiDirectionalGraphic(bodyType);
|
||||
bodyTypeGraphics.Add(bodyTypeGraphic);
|
||||
}
|
||||
|
||||
switch (facing)
|
||||
{
|
||||
case CardinalDirection.North: bodyTypeGraphic.northGraphic.SetPath(path); break;
|
||||
case CardinalDirection.East: bodyTypeGraphic.eastGraphic.SetPath(path); break;
|
||||
case CardinalDirection.South:bodyTypeGraphic.southGraphic.SetPath(path); break;
|
||||
default: bodyTypeGraphic.eastGraphic.SetPath(path); break;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasValidHeadGraphicPath(CardinalDirection facing)
|
||||
{
|
||||
return headGraphics.HasValidPathForDirection(facing);
|
||||
}
|
||||
|
||||
public bool HasValidBodyTypeGraphicPath(CardinalDirection facing, string bodyType = "None")
|
||||
{
|
||||
MultiDirectionalGraphic bodyTypeGraphic = bodyTypeGraphics.FirstOrDefault(x => x.bodyType == bodyType);
|
||||
|
||||
if (bodyTypeGraphic == null)
|
||||
{
|
||||
bodyTypeGraphic = new MultiDirectionalGraphic(bodyType);
|
||||
bodyTypeGraphics.Add(bodyTypeGraphic);
|
||||
}
|
||||
|
||||
return bodyTypeGraphic.HasValidPathForDirection(facing);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 187aef38ea296184b93265071536969c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
49
Source/Assets/Scripts/AnimationComponents/PawnRaceOffset.cs
Normal file
49
Source/Assets/Scripts/AnimationComponents/PawnRaceOffset.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RimWorldAnimationStudio
|
||||
{
|
||||
[Serializable]
|
||||
public class PawnRaceOffset
|
||||
{
|
||||
// Local data
|
||||
public string defName = "Human";
|
||||
public string offset = "(0, 0)";
|
||||
|
||||
// SHoulda serialize
|
||||
public bool ShouldSerializedefName() { return OffsetIsZero() == false; }
|
||||
public bool ShouldSerializeoffset() { return OffsetIsZero() == false; }
|
||||
|
||||
// Constructors
|
||||
public PawnRaceOffset() { }
|
||||
|
||||
public PawnRaceOffset(string defName)
|
||||
{
|
||||
this.defName = defName;
|
||||
}
|
||||
|
||||
// Methods
|
||||
public void SetOffset(Vector2 raceOffset)
|
||||
{
|
||||
offset = "(" + raceOffset.x + ", " + raceOffset.y + ")";
|
||||
}
|
||||
|
||||
public Vector3 GetOffset()
|
||||
{
|
||||
string raceOffset = offset;
|
||||
raceOffset = raceOffset.Trim();
|
||||
raceOffset = raceOffset.Replace("(", "");
|
||||
raceOffset = raceOffset.Replace(")", "");
|
||||
var raceOffsets = raceOffset.Split(',');
|
||||
|
||||
return new Vector3(float.Parse(raceOffsets[0]), 0f, float.Parse(raceOffsets[1]));
|
||||
}
|
||||
|
||||
public bool OffsetIsZero()
|
||||
{
|
||||
Vector3 vec = GetOffset();
|
||||
return Mathf.Approximately(vec.x, 0f) && Mathf.Approximately(vec.y, 0f) && Mathf.Approximately(vec.x, 0f);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 24eafaf092974414ca90bfd4a8d2e4ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue