mirror of
				https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
				synced 2024-08-15 00:43:27 +00:00 
			
		
		
		
	Code refactor
This commit is contained in:
		
							parent
							
								
									757badf4f6
								
							
						
					
					
						commit
						a55ba7b95b
					
				
					 232 changed files with 1282 additions and 936 deletions
				
			
		
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -75,6 +75,7 @@
 | 
			
		|||
    <Compile Include="Assets\Scripts\AnimationComponents\PawnKeyframe.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\AnimationComponents\PawnRaceDef.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\AnimationComponents\PawnRaceOffset.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\Data\ActorPosition.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\Data\Constants.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\Data\DefaultTags.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\Data\Enums.cs" />
 | 
			
		||||
| 
						 | 
				
			
			@ -87,12 +88,15 @@
 | 
			
		|||
    <Compile Include="Assets\Scripts\GUI\Actors\ActorBody.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Actors\ActorBodyPart.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\AddSoundDefButton.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\AnimationLengthDisplay.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\AnimationTimeline.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Cards\ActorAddonCard.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Cards\ActorAddonKeyframeCard.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Cards\ActorCard.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Cards\ActorKeyframeCard.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Cards\AnimationControlCard.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Cards\AnimationDefCard.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Cards\StageCard.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Cards\StageLoopsCard.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\DialogBoxes\ConsoleMessagesDialog.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\DialogBoxes\DialogBox.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\DialogBoxes\RaceSettingsDialog.cs" />
 | 
			
		||||
| 
						 | 
				
			
			@ -109,15 +113,16 @@
 | 
			
		|||
    <Compile Include="Assets\Scripts\GUI\KeybindLabel.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\KeyframeSlider.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\LinearScale.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Props\SexProp.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Props\SexPropManager.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\QuiverToggle.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SelectActorLayerButton.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SelfContained\ActorManipulator.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SelfContained\ButtonWithKeyCode.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SelfContained\Chaser.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SelfContained\InactiveDuringAnimationPreview.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SelfContained\RequiresAnimationDef.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SelfContained\SnapToKeyframe.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SexProps\SexProp.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\SexProps\SexPropManager.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Tooltips\Tooltip.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\GUI\Tooltips\TooltipMessage.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\Graphics\MultiDirectionalGraphic.cs" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -173,9 +173,7 @@ MonoBehaviour:
 | 
			
		|||
  m_EditorClassIdentifier: 
 | 
			
		||||
  bodyPartRenderer: {fileID: 3345967395353432914}
 | 
			
		||||
  parent: {fileID: -4411442180840688308}
 | 
			
		||||
  isHead: 0
 | 
			
		||||
  addonName: right hand
 | 
			
		||||
  isSelected: 0
 | 
			
		||||
  bodyPart: right hand
 | 
			
		||||
--- !u!1 &2846713953308910856
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -340,9 +338,7 @@ MonoBehaviour:
 | 
			
		|||
  m_EditorClassIdentifier: 
 | 
			
		||||
  bodyPartRenderer: {fileID: 4070361490379091543}
 | 
			
		||||
  parent: {fileID: -4411442180840688308}
 | 
			
		||||
  isHead: 0
 | 
			
		||||
  addonName: left hand
 | 
			
		||||
  isSelected: 0
 | 
			
		||||
  bodyPart: left hand
 | 
			
		||||
--- !u!1 &3158459618386162366
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -658,9 +654,7 @@ MonoBehaviour:
 | 
			
		|||
  m_EditorClassIdentifier: 
 | 
			
		||||
  bodyPartRenderer: {fileID: 7367385255154626542}
 | 
			
		||||
  parent: {fileID: -4411442180840688308}
 | 
			
		||||
  isHead: 0
 | 
			
		||||
  addonName: dildo
 | 
			
		||||
  isSelected: 0
 | 
			
		||||
  bodyPart: dildo
 | 
			
		||||
--- !u!1 &7929422519883802246
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -818,9 +812,7 @@ MonoBehaviour:
 | 
			
		|||
  m_EditorClassIdentifier: 
 | 
			
		||||
  bodyPartRenderer: {fileID: 7929422519883802244}
 | 
			
		||||
  parent: {fileID: -4411442180840688308}
 | 
			
		||||
  isHead: 1
 | 
			
		||||
  addonName: 
 | 
			
		||||
  isSelected: 0
 | 
			
		||||
  bodyPart: head
 | 
			
		||||
--- !u!1 &7929422520673851210
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -871,10 +863,7 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  actorID: 0
 | 
			
		||||
  isSelected: 0
 | 
			
		||||
  bodyRenderer: {fileID: 5996161745621340017}
 | 
			
		||||
  headRenderer: {fileID: 7929422519883802244}
 | 
			
		||||
  appendageRenderer: {fileID: 4251726083449519904}
 | 
			
		||||
--- !u!1 &9122292209377678227
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,6 +1037,4 @@ MonoBehaviour:
 | 
			
		|||
  m_EditorClassIdentifier: 
 | 
			
		||||
  bodyPartRenderer: {fileID: 4251726083449519904}
 | 
			
		||||
  parent: {fileID: -4411442180840688308}
 | 
			
		||||
  isHead: 0
 | 
			
		||||
  addonName: 
 | 
			
		||||
  isSelected: 0
 | 
			
		||||
  bodyPart: appendage
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ MonoBehaviour:
 | 
			
		|||
    m_HorizontalOverflow: 0
 | 
			
		||||
    m_VerticalOverflow: 0
 | 
			
		||||
    m_LineSpacing: 1
 | 
			
		||||
  m_Text: New Stage
 | 
			
		||||
  m_Text: Empty
 | 
			
		||||
--- !u!1 &533195464737222177
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -207,18 +207,7 @@ MonoBehaviour:
 | 
			
		|||
  m_CharacterLimit: 0
 | 
			
		||||
  m_OnEndEdit:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 2278168916950142456}
 | 
			
		||||
        m_MethodName: OnNameChange
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
 | 
			
		||||
          m_IntArgument: 0
 | 
			
		||||
          m_FloatArgument: 0
 | 
			
		||||
          m_StringArgument: 
 | 
			
		||||
          m_BoolArgument: 0
 | 
			
		||||
        m_CallState: 2
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
  m_OnValueChanged:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -133,7 +133,6 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 11575770}
 | 
			
		||||
  - component: {fileID: 11575769}
 | 
			
		||||
  - component: {fileID: 11575768}
 | 
			
		||||
  - component: {fileID: 11575767}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: SelectRaceDropdown
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -163,21 +162,6 @@ RectTransform:
 | 
			
		|||
  m_AnchoredPosition: {x: 10, y: -150}
 | 
			
		||||
  m_SizeDelta: {x: 120, y: 30}
 | 
			
		||||
  m_Pivot: {x: 0, y: 1}
 | 
			
		||||
--- !u!114 &11575767
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 11575765}
 | 
			
		||||
  m_Enabled: 0
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 0ba5b69d448f9434ca7d74d4022f3dcd, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  dropdown: {fileID: 0}
 | 
			
		||||
  label: {fileID: 0}
 | 
			
		||||
  hashcode: -1
 | 
			
		||||
--- !u!114 &11575768
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -454,6 +438,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 40289126}
 | 
			
		||||
  - component: {fileID: 40289125}
 | 
			
		||||
  - component: {fileID: 40289124}
 | 
			
		||||
  - component: {fileID: 40289128}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: posOffsetXField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -606,6 +591,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 40289122}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &40289128
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 40289122}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &40775274
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -3563,6 +3560,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 254347859}
 | 
			
		||||
  - component: {fileID: 254347858}
 | 
			
		||||
  - component: {fileID: 254347862}
 | 
			
		||||
  - component: {fileID: 254347863}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: headBobField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -3622,18 +3620,7 @@ MonoBehaviour:
 | 
			
		|||
  m_CharacterLimit: 0
 | 
			
		||||
  m_OnEndEdit:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 629081417}
 | 
			
		||||
        m_MethodName: OnValueChanged
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
 | 
			
		||||
          m_IntArgument: 0
 | 
			
		||||
          m_FloatArgument: 0
 | 
			
		||||
          m_StringArgument: 
 | 
			
		||||
          m_BoolArgument: 0
 | 
			
		||||
        m_CallState: 2
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
  m_OnValueChanged:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
| 
						 | 
				
			
			@ -3715,6 +3702,18 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  valiationType: 2
 | 
			
		||||
--- !u!114 &254347863
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 254347857}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &257134980
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -7825,6 +7824,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 444811204}
 | 
			
		||||
  - component: {fileID: 444811203}
 | 
			
		||||
  - component: {fileID: 444811202}
 | 
			
		||||
  - component: {fileID: 444811206}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: rotationField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -7977,6 +7977,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 444811200}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &444811206
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 444811200}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &448745871
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -8253,8 +8265,9 @@ GameObject:
 | 
			
		|||
  serializedVersion: 6
 | 
			
		||||
  m_Component:
 | 
			
		||||
  - component: {fileID: 468781281}
 | 
			
		||||
  - component: {fileID: 468781282}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: StageCycleCard
 | 
			
		||||
  m_Name: StageLoopsCard
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
  m_Icon: {fileID: 0}
 | 
			
		||||
  m_NavMeshLayer: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -8281,6 +8294,20 @@ RectTransform:
 | 
			
		|||
  m_AnchoredPosition: {x: 155, y: -315}
 | 
			
		||||
  m_SizeDelta: {x: 310, y: 70}
 | 
			
		||||
  m_Pivot: {x: 0.5, y: 0.5}
 | 
			
		||||
--- !u!114 &468781282
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 468781280}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 38691dc973d99734f8f0f2a240df73fe, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  stageLoopsNormalField: {fileID: 74082975}
 | 
			
		||||
  stageLoopsQuickField: {fileID: 1463915054}
 | 
			
		||||
--- !u!1 &476324336
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -9638,23 +9665,9 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  isAnimating: 0
 | 
			
		||||
  stageTimelineSlider: {fileID: 1289465655}
 | 
			
		||||
  stageLoopDropdown: {fileID: 429161118}
 | 
			
		||||
  cyclesNormalField: {fileID: 74082975}
 | 
			
		||||
  cyclesFastField: {fileID: 1463915054}
 | 
			
		||||
  animationClipTimeField: {fileID: 760297267}
 | 
			
		||||
  animationClipLengthField: {fileID: 1676585155}
 | 
			
		||||
  actorCard: {fileID: 0}
 | 
			
		||||
  animationTimelines: {fileID: 1100016168}
 | 
			
		||||
  actorBodies: {fileID: 1828035561}
 | 
			
		||||
  stretchKeyframesToggle: {fileID: 462332576}
 | 
			
		||||
  playBackSpeedField: {fileID: 1579799916}
 | 
			
		||||
  playToggleButton: {fileID: 79733375}
 | 
			
		||||
  stageLengthText: {fileID: 1137451986}
 | 
			
		||||
  animationLengthText: {fileID: 1293297801}
 | 
			
		||||
  handLeftControls: {fileID: 374385281}
 | 
			
		||||
  handRightControls: {fileID: 613856053}
 | 
			
		||||
  sexToyControls: {fileID: 2069775739}
 | 
			
		||||
  stageLoopDropdown: {fileID: 429161118}
 | 
			
		||||
  actorBodyPrefab: {fileID: -4411442180840688308, guid: dc4c8b005322f3b46a2f122a55f38db2,
 | 
			
		||||
    type: 3}
 | 
			
		||||
  animationTimelinePrefab: {fileID: 3541467645058788217, guid: eac2d5e7275f9064facfeb818ee30308,
 | 
			
		||||
| 
						 | 
				
			
			@ -10201,8 +10214,9 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 539052777}
 | 
			
		||||
  - component: {fileID: 539052779}
 | 
			
		||||
  - component: {fileID: 539052781}
 | 
			
		||||
  - component: {fileID: 539052778}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: AnimControlPanel
 | 
			
		||||
  m_Name: AnimControlCard
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
  m_Icon: {fileID: 0}
 | 
			
		||||
  m_NavMeshLayer: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -10236,6 +10250,25 @@ RectTransform:
 | 
			
		|||
  m_AnchoredPosition: {x: 10, y: -22.5}
 | 
			
		||||
  m_SizeDelta: {x: 1375.8606, y: 45}
 | 
			
		||||
  m_Pivot: {x: 0, y: 0.5}
 | 
			
		||||
--- !u!114 &539052778
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 539052776}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 6b414452bfd6c9b4bb99542a51d77468, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  stageLoopDropdown: {fileID: 429161118}
 | 
			
		||||
  animationClipTimeField: {fileID: 760297267}
 | 
			
		||||
  animationClipLengthField: {fileID: 1676585155}
 | 
			
		||||
  stretchKeyframesToggle: {fileID: 462332576}
 | 
			
		||||
  playBackSpeedField: {fileID: 1579799916}
 | 
			
		||||
  playToggleButton: {fileID: 79733375}
 | 
			
		||||
  stageTimelineSlider: {fileID: 1289465655}
 | 
			
		||||
--- !u!222 &539052779
 | 
			
		||||
CanvasRenderer:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -10916,8 +10949,8 @@ MonoBehaviour:
 | 
			
		|||
  m_OnClick:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 542629604}
 | 
			
		||||
        m_MethodName: OnNewStage
 | 
			
		||||
      - m_Target: {fileID: 1335076905}
 | 
			
		||||
        m_MethodName: AddStage
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
| 
						 | 
				
			
			@ -12096,6 +12129,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 619777500}
 | 
			
		||||
  - component: {fileID: 619777499}
 | 
			
		||||
  - component: {fileID: 619777498}
 | 
			
		||||
  - component: {fileID: 619777502}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: posOffsetZField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -12237,6 +12271,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 619777496}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &619777502
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 619777496}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &620055138
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -12823,9 +12869,9 @@ RectTransform:
 | 
			
		|||
  m_Father: {fileID: 935483303140078260}
 | 
			
		||||
  m_RootOrder: 1
 | 
			
		||||
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
 | 
			
		||||
  m_AnchorMin: {x: 0, y: 0}
 | 
			
		||||
  m_AnchorMax: {x: 0, y: 0}
 | 
			
		||||
  m_AnchoredPosition: {x: 0, y: 0}
 | 
			
		||||
  m_AnchorMin: {x: 0, y: 1}
 | 
			
		||||
  m_AnchorMax: {x: 0, y: 1}
 | 
			
		||||
  m_AnchoredPosition: {x: 155, y: -166.98029}
 | 
			
		||||
  m_SizeDelta: {x: 310, y: 65.97644}
 | 
			
		||||
  m_Pivot: {x: 0.5, y: 0.5}
 | 
			
		||||
--- !u!1 &658284331
 | 
			
		||||
| 
						 | 
				
			
			@ -14056,6 +14102,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 725162533}
 | 
			
		||||
  - component: {fileID: 725162532}
 | 
			
		||||
  - component: {fileID: 725162535}
 | 
			
		||||
  - component: {fileID: 725162536}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: rotationField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -14135,18 +14182,7 @@ MonoBehaviour:
 | 
			
		|||
  m_CharacterLimit: 0
 | 
			
		||||
  m_OnEndEdit:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 629081417}
 | 
			
		||||
        m_MethodName: OnValueChanged
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
 | 
			
		||||
          m_IntArgument: 0
 | 
			
		||||
          m_FloatArgument: 0
 | 
			
		||||
          m_StringArgument: 
 | 
			
		||||
          m_BoolArgument: 0
 | 
			
		||||
        m_CallState: 2
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
  m_OnValueChanged:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
| 
						 | 
				
			
			@ -14208,6 +14244,18 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  valiationType: 2
 | 
			
		||||
--- !u!114 &725162536
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 725162530}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &726027038
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -14651,6 +14699,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 760297268}
 | 
			
		||||
  - component: {fileID: 760297267}
 | 
			
		||||
  - component: {fileID: 760297270}
 | 
			
		||||
  - component: {fileID: 760297271}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: AnimationClipTimeField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -14803,6 +14852,18 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  valiationType: 1
 | 
			
		||||
--- !u!114 &760297271
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 760297265}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &763620509
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -16809,6 +16870,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 891720216}
 | 
			
		||||
  - component: {fileID: 891720215}
 | 
			
		||||
  - component: {fileID: 891720218}
 | 
			
		||||
  - component: {fileID: 891720219}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: posOffsetXField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -16888,18 +16950,7 @@ MonoBehaviour:
 | 
			
		|||
  m_CharacterLimit: 0
 | 
			
		||||
  m_OnEndEdit:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 629081417}
 | 
			
		||||
        m_MethodName: OnValueChanged
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
 | 
			
		||||
          m_IntArgument: 0
 | 
			
		||||
          m_FloatArgument: 0
 | 
			
		||||
          m_StringArgument: 
 | 
			
		||||
          m_BoolArgument: 0
 | 
			
		||||
        m_CallState: 2
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
  m_OnValueChanged:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
| 
						 | 
				
			
			@ -16961,6 +17012,18 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  valiationType: 2
 | 
			
		||||
--- !u!114 &891720219
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 891720213}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &898059650
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -17256,6 +17319,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 906179602}
 | 
			
		||||
  - component: {fileID: 906179601}
 | 
			
		||||
  - component: {fileID: 906179600}
 | 
			
		||||
  - component: {fileID: 906179604}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: rotationField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -17408,6 +17472,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 906179598}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &906179604
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 906179598}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &911162557
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -17648,7 +17724,7 @@ RectTransform:
 | 
			
		|||
  m_RootOrder: 0
 | 
			
		||||
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
 | 
			
		||||
  m_AnchorMin: {x: 0, y: 0}
 | 
			
		||||
  m_AnchorMax: {x: 1, y: 0.99997056}
 | 
			
		||||
  m_AnchorMax: {x: 1, y: 1}
 | 
			
		||||
  m_AnchoredPosition: {x: 0, y: 0}
 | 
			
		||||
  m_SizeDelta: {x: 20, y: 20}
 | 
			
		||||
  m_Pivot: {x: 0.5, y: 0.5}
 | 
			
		||||
| 
						 | 
				
			
			@ -21067,6 +21143,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1152532962}
 | 
			
		||||
  - component: {fileID: 1152532961}
 | 
			
		||||
  - component: {fileID: 1152532960}
 | 
			
		||||
  - component: {fileID: 1152532964}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: posOffsetXField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -21219,6 +21296,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1152532958}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &1152532964
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1152532958}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &1153227822
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -21301,7 +21390,7 @@ MonoBehaviour:
 | 
			
		|||
  m_HandleRect: {fileID: 922060209}
 | 
			
		||||
  m_Direction: 2
 | 
			
		||||
  m_Value: 0
 | 
			
		||||
  m_Size: 0.99997056
 | 
			
		||||
  m_Size: 1
 | 
			
		||||
  m_NumberOfSteps: 0
 | 
			
		||||
  m_OnValueChanged:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
| 
						 | 
				
			
			@ -21667,8 +21756,8 @@ MonoBehaviour:
 | 
			
		|||
  m_OnClick:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 542629604}
 | 
			
		||||
        m_MethodName: OnRemoveStage
 | 
			
		||||
      - m_Target: {fileID: 1335076905}
 | 
			
		||||
        m_MethodName: RemoveStage
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
| 
						 | 
				
			
			@ -22802,9 +22891,9 @@ RectTransform:
 | 
			
		|||
  m_Father: {fileID: 935483303140078260}
 | 
			
		||||
  m_RootOrder: 2
 | 
			
		||||
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
 | 
			
		||||
  m_AnchorMin: {x: 0, y: 0}
 | 
			
		||||
  m_AnchorMax: {x: 0, y: 0}
 | 
			
		||||
  m_AnchoredPosition: {x: 0, y: 0}
 | 
			
		||||
  m_AnchorMin: {x: 0, y: 1}
 | 
			
		||||
  m_AnchorMax: {x: 0, y: 1}
 | 
			
		||||
  m_AnchoredPosition: {x: 155, y: -337.8237}
 | 
			
		||||
  m_SizeDelta: {x: 310, y: 275.7104}
 | 
			
		||||
  m_Pivot: {x: 0.5, y: 0.5}
 | 
			
		||||
--- !u!114 &1216651061
 | 
			
		||||
| 
						 | 
				
			
			@ -23154,12 +23243,12 @@ PrefabInstance:
 | 
			
		|||
        type: 3}
 | 
			
		||||
      propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[1].m_Target
 | 
			
		||||
      value: 
 | 
			
		||||
      objectReference: {fileID: 1567848590}
 | 
			
		||||
      objectReference: {fileID: 0}
 | 
			
		||||
    - target: {fileID: 7715503544528335667, guid: 8b89f6c9e5f696c4997760829c45a505,
 | 
			
		||||
        type: 3}
 | 
			
		||||
      propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[2].m_Target
 | 
			
		||||
      value: 
 | 
			
		||||
      objectReference: {fileID: 11575767}
 | 
			
		||||
      objectReference: {fileID: 0}
 | 
			
		||||
    - target: {fileID: 7715503544528335667, guid: 8b89f6c9e5f696c4997760829c45a505,
 | 
			
		||||
        type: 3}
 | 
			
		||||
      propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[1].m_CallState
 | 
			
		||||
| 
						 | 
				
			
			@ -25222,7 +25311,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1335076900}
 | 
			
		||||
  - component: {fileID: 1335076905}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: Workspace
 | 
			
		||||
  m_Name: WorkspaceAndGUI
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
  m_Icon: {fileID: 0}
 | 
			
		||||
  m_NavMeshLayer: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -29764,8 +29853,8 @@ MonoBehaviour:
 | 
			
		|||
  m_OnClick:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 542629604}
 | 
			
		||||
        m_MethodName: OnCloneStage
 | 
			
		||||
      - m_Target: {fileID: 1335076905}
 | 
			
		||||
        m_MethodName: CloneStage
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
| 
						 | 
				
			
			@ -29825,6 +29914,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1518099309}
 | 
			
		||||
  - component: {fileID: 1518099308}
 | 
			
		||||
  - component: {fileID: 1518099311}
 | 
			
		||||
  - component: {fileID: 1518099312}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: posOffsetZField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -29904,18 +29994,7 @@ MonoBehaviour:
 | 
			
		|||
  m_CharacterLimit: 0
 | 
			
		||||
  m_OnEndEdit:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 629081417}
 | 
			
		||||
        m_MethodName: OnValueChanged
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
 | 
			
		||||
          m_IntArgument: 0
 | 
			
		||||
          m_FloatArgument: 0
 | 
			
		||||
          m_StringArgument: 
 | 
			
		||||
          m_BoolArgument: 0
 | 
			
		||||
        m_CallState: 2
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
  m_OnValueChanged:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
| 
						 | 
				
			
			@ -29977,6 +30056,18 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  valiationType: 2
 | 
			
		||||
--- !u!114 &1518099312
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1518099306}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &1522728394
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -30299,6 +30390,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1560400021}
 | 
			
		||||
  - component: {fileID: 1560400020}
 | 
			
		||||
  - component: {fileID: 1560400019}
 | 
			
		||||
  - component: {fileID: 1560400023}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: posOffsetZField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -30451,6 +30543,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1560400017}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &1560400023
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1560400017}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &1561986055
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -30697,7 +30801,6 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1567848593}
 | 
			
		||||
  - component: {fileID: 1567848592}
 | 
			
		||||
  - component: {fileID: 1567848591}
 | 
			
		||||
  - component: {fileID: 1567848590}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: RaceSelectDropdown
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -30727,21 +30830,6 @@ RectTransform:
 | 
			
		|||
  m_AnchoredPosition: {x: 178, y: 0}
 | 
			
		||||
  m_SizeDelta: {x: 160, y: 30}
 | 
			
		||||
  m_Pivot: {x: 0.5, y: 0.5}
 | 
			
		||||
--- !u!114 &1567848590
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1567848588}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 0ba5b69d448f9434ca7d74d4022f3dcd, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  dropdown: {fileID: 0}
 | 
			
		||||
  label: {fileID: 0}
 | 
			
		||||
  hashcode: -1
 | 
			
		||||
--- !u!114 &1567848591
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -31888,6 +31976,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1668270819}
 | 
			
		||||
  - component: {fileID: 1668270818}
 | 
			
		||||
  - component: {fileID: 1668270821}
 | 
			
		||||
  - component: {fileID: 1668270822}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: appendageRotationField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -32040,6 +32129,18 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  valiationType: 2
 | 
			
		||||
--- !u!114 &1668270822
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1668270816}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &1670013372
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -32245,6 +32346,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1676585156}
 | 
			
		||||
  - component: {fileID: 1676585155}
 | 
			
		||||
  - component: {fileID: 1676585158}
 | 
			
		||||
  - component: {fileID: 1676585159}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: AnimationClipLengthField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -32397,6 +32499,18 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  valiationType: 1
 | 
			
		||||
--- !u!114 &1676585159
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1676585153}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &1685703671
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -33698,6 +33812,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1767445798}
 | 
			
		||||
  - component: {fileID: 1767445797}
 | 
			
		||||
  - component: {fileID: 1767445801}
 | 
			
		||||
  - component: {fileID: 1767445802}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: headRotationField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -33757,18 +33872,7 @@ MonoBehaviour:
 | 
			
		|||
  m_CharacterLimit: 0
 | 
			
		||||
  m_OnEndEdit:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls:
 | 
			
		||||
      - m_Target: {fileID: 629081417}
 | 
			
		||||
        m_MethodName: OnValueChanged
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
          m_ObjectArgument: {fileID: 0}
 | 
			
		||||
          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
 | 
			
		||||
          m_IntArgument: 0
 | 
			
		||||
          m_FloatArgument: 0
 | 
			
		||||
          m_StringArgument: 
 | 
			
		||||
          m_BoolArgument: 0
 | 
			
		||||
        m_CallState: 2
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
  m_OnValueChanged:
 | 
			
		||||
    m_PersistentCalls:
 | 
			
		||||
      m_Calls: []
 | 
			
		||||
| 
						 | 
				
			
			@ -33850,6 +33954,18 @@ MonoBehaviour:
 | 
			
		|||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
  valiationType: 2
 | 
			
		||||
--- !u!114 &1767445802
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1767445796}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &1776904761
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -36271,6 +36387,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1899457113}
 | 
			
		||||
  - component: {fileID: 1899457112}
 | 
			
		||||
  - component: {fileID: 1899457111}
 | 
			
		||||
  - component: {fileID: 1899457115}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: rotationField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -36412,6 +36529,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1899457109}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &1899457115
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1899457109}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &1900570404
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -36981,6 +37110,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 1925610721}
 | 
			
		||||
  - component: {fileID: 1925610720}
 | 
			
		||||
  - component: {fileID: 1925610719}
 | 
			
		||||
  - component: {fileID: 1925610723}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: posOffsetZField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -37133,6 +37263,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1925610717}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &1925610723
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 1925610717}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &1928565389
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -39224,6 +39366,7 @@ GameObject:
 | 
			
		|||
  - component: {fileID: 2114146443}
 | 
			
		||||
  - component: {fileID: 2114146442}
 | 
			
		||||
  - component: {fileID: 2114146441}
 | 
			
		||||
  - component: {fileID: 2114146445}
 | 
			
		||||
  m_Layer: 5
 | 
			
		||||
  m_Name: posOffsetXField
 | 
			
		||||
  m_TagString: Untagged
 | 
			
		||||
| 
						 | 
				
			
			@ -39365,6 +39508,18 @@ CanvasRenderer:
 | 
			
		|||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 2114146439}
 | 
			
		||||
  m_CullTransparentMesh: 0
 | 
			
		||||
--- !u!114 &2114146445
 | 
			
		||||
MonoBehaviour:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
  m_CorrespondingSourceObject: {fileID: 0}
 | 
			
		||||
  m_PrefabInstance: {fileID: 0}
 | 
			
		||||
  m_PrefabAsset: {fileID: 0}
 | 
			
		||||
  m_GameObject: {fileID: 2114146439}
 | 
			
		||||
  m_Enabled: 1
 | 
			
		||||
  m_EditorHideFlags: 0
 | 
			
		||||
  m_Script: {fileID: 11500000, guid: 92068b39ed172084296a595f5a09e54b, type: 3}
 | 
			
		||||
  m_Name: 
 | 
			
		||||
  m_EditorClassIdentifier: 
 | 
			
		||||
--- !u!1 &2114503331
 | 
			
		||||
GameObject:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -39679,9 +39834,9 @@ RectTransform:
 | 
			
		|||
  m_Father: {fileID: 935483303140078260}
 | 
			
		||||
  m_RootOrder: 0
 | 
			
		||||
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
 | 
			
		||||
  m_AnchorMin: {x: 0, y: 0}
 | 
			
		||||
  m_AnchorMax: {x: 0, y: 0}
 | 
			
		||||
  m_AnchoredPosition: {x: 0, y: 0}
 | 
			
		||||
  m_AnchorMin: {x: 0, y: 1}
 | 
			
		||||
  m_AnchorMax: {x: 0, y: 1}
 | 
			
		||||
  m_AnchoredPosition: {x: 155, y: -66.99603}
 | 
			
		||||
  m_SizeDelta: {x: 310, y: 133.99207}
 | 
			
		||||
  m_Pivot: {x: 0.5, y: 0.5}
 | 
			
		||||
--- !u!114 &2130812670
 | 
			
		||||
| 
						 | 
				
			
			@ -40435,7 +40590,7 @@ GameObject:
 | 
			
		|||
  m_Icon: {fileID: 0}
 | 
			
		||||
  m_NavMeshLayer: 0
 | 
			
		||||
  m_StaticEditorFlags: 0
 | 
			
		||||
  m_IsActive: 1
 | 
			
		||||
  m_IsActive: 0
 | 
			
		||||
--- !u!222 &935483303140078262
 | 
			
		||||
CanvasRenderer:
 | 
			
		||||
  m_ObjectHideFlags: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -42532,7 +42687,7 @@ MonoBehaviour:
 | 
			
		|||
          m_StringArgument: 
 | 
			
		||||
          m_BoolArgument: 0
 | 
			
		||||
        m_CallState: 2
 | 
			
		||||
      - m_Target: {fileID: 1567848590}
 | 
			
		||||
      - m_Target: {fileID: 0}
 | 
			
		||||
        m_MethodName: UpdateDropdown
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
| 
						 | 
				
			
			@ -42543,7 +42698,7 @@ MonoBehaviour:
 | 
			
		|||
          m_StringArgument: 
 | 
			
		||||
          m_BoolArgument: 0
 | 
			
		||||
        m_CallState: 2
 | 
			
		||||
      - m_Target: {fileID: 11575767}
 | 
			
		||||
      - m_Target: {fileID: 0}
 | 
			
		||||
        m_MethodName: UpdateDropdown
 | 
			
		||||
        m_Mode: 1
 | 
			
		||||
        m_Arguments:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,60 +36,60 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        [XmlIgnore] public List<string> DefNames 
 | 
			
		||||
        { 
 | 
			
		||||
            get { return defNames.NullOrEmpty() ? defNames = new List<string>() : defNames; } 
 | 
			
		||||
            set { defNames = value.NotNullOrEmpty() ? value : null; EventsManager.OnActorChanged(this); } 
 | 
			
		||||
            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; EventsManager.OnActorChanged(this); }
 | 
			
		||||
            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; EventsManager.OnActorChanged(this); }
 | 
			
		||||
            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; EventsManager.OnActorChanged(this); }
 | 
			
		||||
            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; EventsManager.OnActorChanged(this); } 
 | 
			
		||||
            set { tags = value.NotNullOrEmpty() ? value : null; } 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public BodyTypeOffset BodyTypeOffset
 | 
			
		||||
        { 
 | 
			
		||||
            get { return bodyTypeOffset == null ? bodyTypeOffset = new BodyTypeOffset() : bodyTypeOffset; } 
 | 
			
		||||
            set { bodyTypeOffset = value; EventsManager.OnActorChanged(this); } 
 | 
			
		||||
            set { bodyTypeOffset = value; } 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public bool Initiator 
 | 
			
		||||
        { 
 | 
			
		||||
            get { return initiator == true; } 
 | 
			
		||||
            set { if (value) { initiator = true; } else initiator = null; EventsManager.OnActorChanged(this); } 
 | 
			
		||||
            set { if (value) { initiator = true; } else initiator = null; } 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public bool ControlGenitalAngle
 | 
			
		||||
        { 
 | 
			
		||||
            get { return controlGenitalAngle == true; } 
 | 
			
		||||
            set { if (value) { controlGenitalAngle = true; } else controlGenitalAngle = null; EventsManager.OnActorChanged(this); }
 | 
			
		||||
            set { if (value) { controlGenitalAngle = true; } else controlGenitalAngle = null; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public bool IsFucking 
 | 
			
		||||
        { 
 | 
			
		||||
            get { return isFucking == true; } 
 | 
			
		||||
            set { if (value) { isFucking = true; } else isFucking = null; EventsManager.OnActorChanged(this); }
 | 
			
		||||
            set { if (value) { isFucking = true; } else isFucking = null; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public bool IsFucked
 | 
			
		||||
        { 
 | 
			
		||||
            get { return isFucked == true; } 
 | 
			
		||||
            set { if (value) { isFucked = true; } else isFucked = null; EventsManager.OnActorChanged(this); } 
 | 
			
		||||
            set { if (value) { isFucked = true; } else isFucked = null; } 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Local data
 | 
			
		||||
| 
						 | 
				
			
			@ -163,6 +163,16 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            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()
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,31 +28,31 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        [XmlIgnore] public int AnchoringActor
 | 
			
		||||
        {
 | 
			
		||||
            get { return anchoringActor.HasValue ? anchoringActor.Value : 0; }
 | 
			
		||||
            set { anchoringActor = value; EventsManager.OnActorAddonChanged(this); }
 | 
			
		||||
            set { anchoringActor = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public string AnchorName
 | 
			
		||||
        {
 | 
			
		||||
            get { return anchorName; }
 | 
			
		||||
            set { anchorName = value; EventsManager.OnActorAddonChanged(this); }
 | 
			
		||||
            set { anchorName = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public string Layer
 | 
			
		||||
        {
 | 
			
		||||
            get { return layer; }
 | 
			
		||||
            set { layer = value; EventsManager.OnActorAddonChanged(this); }
 | 
			
		||||
            set { layer = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public float Scale
 | 
			
		||||
        {
 | 
			
		||||
            get { return scale.HasValue ? scale.Value : 0f; }
 | 
			
		||||
            set { scale = value; EventsManager.OnActorAddonChanged(this); }
 | 
			
		||||
            set { scale = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public bool Render
 | 
			
		||||
        {
 | 
			
		||||
            get { return render == true; }
 | 
			
		||||
            set { render = value; EventsManager.OnActorAddonChanged(this); }
 | 
			
		||||
            set { render = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Simple curves
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,19 +23,19 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        [XmlIgnore] public float PosX
 | 
			
		||||
        {
 | 
			
		||||
            get { return posX.HasValue ? posX.Value : 0f; }
 | 
			
		||||
            set { posX = value; EventsManager.OnAddonKeyframeChanged(this); }
 | 
			
		||||
            set { posX = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public float PosZ
 | 
			
		||||
        {
 | 
			
		||||
            get { return posZ.HasValue ? posZ.Value : 0f; }
 | 
			
		||||
            set { posZ = value; EventsManager.OnAddonKeyframeChanged(this); }
 | 
			
		||||
            set { posZ = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public float Rotation
 | 
			
		||||
        {
 | 
			
		||||
            get { return rotation.HasValue ? rotation.Value : 0f; }
 | 
			
		||||
            set { rotation = value; EventsManager.OnAddonKeyframeChanged(this); }
 | 
			
		||||
            set { rotation = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Constructors
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,37 +28,37 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        [XmlIgnore] public string DefName
 | 
			
		||||
        {
 | 
			
		||||
            get { return defName != null && defName != "" ? defName : "newAnimation"; }
 | 
			
		||||
            set { defName = value; EventsManager.OnAnimationDefChanged(); }
 | 
			
		||||
            set { defName = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public string Label
 | 
			
		||||
        {
 | 
			
		||||
            get { return label != null && label != "" ? label : "newAnimation"; }
 | 
			
		||||
            set { label = value; EventsManager.OnAnimationDefChanged(); }
 | 
			
		||||
            set { label = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public List<string> SexTypes
 | 
			
		||||
        {
 | 
			
		||||
            get { return sexTypes.NullOrEmpty() ? sexTypes = new List<string>() : sexTypes; }
 | 
			
		||||
            set { sexTypes = value.NotNullOrEmpty() ? value : null; EventsManager.OnAnimationDefChanged(); }
 | 
			
		||||
            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; EventsManager.OnAnimationDefChanged(); }
 | 
			
		||||
            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; EventsManager.OnAnimationDefChanged(); }
 | 
			
		||||
            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; EventsManager.OnAnimationDefChanged(); }
 | 
			
		||||
            set { animationStages = value.NotNullOrEmpty() ? value : null; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Local data
 | 
			
		||||
| 
						 | 
				
			
			@ -83,12 +83,13 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            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;
 | 
			
		||||
 | 
			
		||||
            foreach (AnimationStage stage in Workspace.animationDef.AnimationStages)
 | 
			
		||||
            { stage.AddAnimationClip(Workspace.ActorID); }
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnActorCountChanged();
 | 
			
		||||
            EventsManager.OnActorCountChanged();           
 | 
			
		||||
            Workspace.RecordEvent("Actor addition");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +120,9 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            { stage.AddAnimationClip(actor.GetActorID()); }
 | 
			
		||||
 | 
			
		||||
            Initialize();
 | 
			
		||||
            Workspace.StageID = Workspace.animationDef.AnimationStages.Count - 1;
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnStageCountChanged();
 | 
			
		||||
            Workspace.RecordEvent("Stage addition");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -127,9 +130,11 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        {
 | 
			
		||||
            AnimationStage stage = Workspace.GetCurrentAnimationStage().Copy();         
 | 
			
		||||
            stage.StageName += " (Clone)";
 | 
			
		||||
            stage.Initialize();
 | 
			
		||||
 | 
			
		||||
            Workspace.animationDef.AnimationStages.Insert(Workspace.StageID + 1, stage);
 | 
			
		||||
            Initialize();
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnStageCountChanged();
 | 
			
		||||
            Workspace.RecordEvent("Stage clone");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -154,8 +159,9 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            AnimationStages.RemoveAt(Workspace.StageID);
 | 
			
		||||
 | 
			
		||||
            Workspace.StageID--;
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnStageCountChanged();
 | 
			
		||||
            Workspace.RecordEvent("Stage deletion");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,11 +10,11 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
    public class AnimationStage
 | 
			
		||||
    {
 | 
			
		||||
        // Data to/from animationDef
 | 
			
		||||
        [SerializeField] private string stageName;
 | 
			
		||||
        [SerializeField] private int? playTimeTicks;
 | 
			
		||||
        [SerializeField] private int? playTimeTicksQuick;
 | 
			
		||||
        [SerializeField] private bool? isLooping;
 | 
			
		||||
        [SerializeField, XmlArray("animationClips"), XmlArrayItem("li")] public List<PawnAnimationClip> animationClips;
 | 
			
		||||
        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(); }
 | 
			
		||||
| 
						 | 
				
			
			@ -22,32 +22,44 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        // Data helper functions
 | 
			
		||||
        [XmlIgnore] public string StageName
 | 
			
		||||
        {
 | 
			
		||||
            get { return stageName != null && stageName != "" ? stageName : "NewStage"; }
 | 
			
		||||
            set { stageName = value; EventsManager.OnAnimationStageChanged(this); }
 | 
			
		||||
            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; EventsManager.OnAnimationStageChanged(this); }
 | 
			
		||||
            set { playTimeTicks = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public int PlayTimeTicksQuick
 | 
			
		||||
        {
 | 
			
		||||
            get { return playTimeTicksQuick.HasValue ? playTimeTicksQuick.Value : 0; }
 | 
			
		||||
            set { playTimeTicksQuick = value; EventsManager.OnAnimationStageChanged(this); }
 | 
			
		||||
            set { playTimeTicksQuick = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public bool IsLooping
 | 
			
		||||
        {
 | 
			
		||||
            get { return isLooping == true; }
 | 
			
		||||
            set { isLooping = value; EventsManager.OnAnimationStageChanged(this); }
 | 
			
		||||
            set { isLooping = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public List<PawnAnimationClip> AnimationClips
 | 
			
		||||
        {
 | 
			
		||||
            get { return animationClips.NullOrEmpty() ? animationClips = new List<PawnAnimationClip>() : animationClips; }
 | 
			
		||||
            set { animationClips = value.NotNullOrEmpty() ? value : null; EventsManager.OnAnimationStageChanged(this); }
 | 
			
		||||
            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; IsLooping = value > 1; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Local data
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +75,6 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
                if (clip.duration > PlayTimeTicks)
 | 
			
		||||
                { PlayTimeTicks = clip.duration; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            PlayTimeTicksQuick = PlayTimeTicks;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int GetStageID()
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +88,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        {
 | 
			
		||||
            float scale = (float)newStageWindowSize / Workspace.StageWindowSize;
 | 
			
		||||
 | 
			
		||||
            foreach (PawnAnimationClip clip in Workspace.animationDef.AnimationStages[Workspace.StageID].AnimationClips)
 | 
			
		||||
            foreach (PawnAnimationClip clip in AnimationClips)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (PawnKeyframe keyframe in clip.Keyframes)
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -93,8 +103,8 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public void ResizeStageWindow(int newStageWindowSize)
 | 
			
		||||
        {
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().stageWindowSize = newStageWindowSize;
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().PlayTimeTicks = newStageWindowSize * Workspace.stageLoopsNormal;
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().PlayTimeTicksQuick = newStageWindowSize * Workspace.stageLoopsQuick;
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().PlayTimeTicks = newStageWindowSize * StageLoopsNormal;
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().PlayTimeTicksQuick = newStageWindowSize * StageLoopsQuick;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AddAnimationClip(int actorID = -1)
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +144,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
                clip.Keyframes.Add(keyframeB);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            clip.BuildSimpleCurves();
 | 
			
		||||
            animationClips.Add(clip);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Pre-save / post-load
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,20 +31,20 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        [XmlIgnore] public List<ActorAddon> Addons
 | 
			
		||||
        {
 | 
			
		||||
            get { return addons.NullOrEmpty() ? addons = new List<ActorAddon>() : addons; }
 | 
			
		||||
            set { addons = value.NotNullOrEmpty() ? value : null; EventsManager.OnPawnAnimationClipChanged(this); }
 | 
			
		||||
            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; EventsManager.OnPawnAnimationClipChanged(this); }
 | 
			
		||||
            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; EventsManager.OnPawnAnimationClipChanged(this); }
 | 
			
		||||
            set { tags = value.NotNullOrEmpty() ? value : null; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Local data
 | 
			
		||||
| 
						 | 
				
			
			@ -235,7 +235,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
            foreach (PawnKeyframe keyframe in keyframesToClone)
 | 
			
		||||
            {
 | 
			
		||||
                PawnAnimationClip clip = Workspace.GetAnimationClipThatOwnsKeyframe(keyframe.keyframeID, out int clipID);
 | 
			
		||||
                PawnAnimationClip clip = Workspace.GetAnimationClipThatOwnsKeyframe(keyframe.keyframeID);
 | 
			
		||||
 | 
			
		||||
                if (clip == null)
 | 
			
		||||
                { Debug.LogWarning("Cannot clone pawn keyframe - no clip owns this keyframe"); continue; }
 | 
			
		||||
| 
						 | 
				
			
			@ -244,7 +244,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
                { Debug.LogWarning("Cannot clone pawn keyframe - a keyframe already exists at this tick"); return; }
 | 
			
		||||
 | 
			
		||||
                PawnKeyframe cloneFrame = keyframe.Copy();
 | 
			
		||||
                cloneFrame.GenerateKeyframeID(clipID);
 | 
			
		||||
                cloneFrame.GenerateKeyframeID(clip.GetOwningActorID());
 | 
			
		||||
                cloneFrame.atTick = Workspace.StageTick;
 | 
			
		||||
 | 
			
		||||
                PawnKeyframe nextKeyframe = clip.Keyframes.FirstOrDefault(x => x.atTick > Workspace.StageTick);
 | 
			
		||||
| 
						 | 
				
			
			@ -301,8 +301,8 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
                if (Workspace.DoesPawnKeyframeExistAtTick(Workspace.StageID, targetActorID, tickToPasteAt))
 | 
			
		||||
                {
 | 
			
		||||
                    PawnKeyframe oldKeyframe = Workspace.animationDef.AnimationStages[Workspace.StageID].AnimationClips[targetActorID].Keyframes.First(x => x.atTick == tickToPasteAt);
 | 
			
		||||
                    RemovePawnKeyframe(targetActorID, oldKeyframe.keyframeID, true);
 | 
			
		||||
                    PawnKeyframe oldKeyframe = Workspace.GetPawnAnimationClip(targetActorID).Keyframes.First(x => x.atTick == tickToPasteAt);
 | 
			
		||||
                    Workspace.GetAnimationClipThatOwnsKeyframe(oldKeyframe.keyframeID).RemovePawnKeyframe(oldKeyframe.keyframeID, true);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                PawnKeyframe clonedKeyframe = copiedKeyframe.Copy();
 | 
			
		||||
| 
						 | 
				
			
			@ -330,34 +330,28 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            Workspace.RecordEvent("Keyframe pasted");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RemovePawnKeyframe()
 | 
			
		||||
        public void RemovePawnKeyframe(int keyframeID, bool force = false)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (int keyframeID in Workspace.keyframeID)
 | 
			
		||||
            {
 | 
			
		||||
                if (Workspace.GetAnimationClipThatOwnsKeyframe(keyframeID, out int clipID) != null)
 | 
			
		||||
                { RemovePawnKeyframe(clipID, keyframeID); }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RemovePawnKeyframe(int actorID, int keyframeID, bool force = false)
 | 
			
		||||
        {
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetPawnKeyframe(actorID, keyframeID);
 | 
			
		||||
            PawnAnimationClip clip = Workspace.animationDef.AnimationStages[Workspace.StageID].AnimationClips[actorID];
 | 
			
		||||
 | 
			
		||||
            if (keyframe == null || clip == null) return;
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetPawnKeyframe(keyframeID);
 | 
			
		||||
            if (keyframe == null || IsOwnerOfKeyframe(keyframeID) == false) return;
 | 
			
		||||
 | 
			
		||||
            if (keyframe.atTick == Constants.minTick && force == false)
 | 
			
		||||
            { Debug.LogWarning("Cannot delete key frame - the first key frame of an animation clip cannot be deleted"); return; }
 | 
			
		||||
 | 
			
		||||
            if (clip.Keyframes.Count <= 2 && force == false)
 | 
			
		||||
            if (Keyframes.Count <= 2 && force == false)
 | 
			
		||||
            { Debug.LogWarning("Cannot delete key frame - an animation clip must have two or more keyframes"); return; }
 | 
			
		||||
 | 
			
		||||
            clip.Keyframes.Remove(keyframe);
 | 
			
		||||
            clip.BuildSimpleCurves();
 | 
			
		||||
            Keyframes.Remove(keyframe);
 | 
			
		||||
            BuildSimpleCurves();
 | 
			
		||||
 | 
			
		||||
            Workspace.RecordEvent("Keyframe deletion");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool IsOwnerOfKeyframe(int keyframeID)
 | 
			
		||||
        {
 | 
			
		||||
            return Keyframes.Any(x => x.keyframeID == keyframeID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public float GetStageTickPercentage()
 | 
			
		||||
        {
 | 
			
		||||
            return (float)(Workspace.StageTick % duration) / duration;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,79 +40,79 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        [XmlIgnore] public float BodyAngle
 | 
			
		||||
        {
 | 
			
		||||
            get { return bodyAngle.HasValue ? bodyAngle.Value : 0f; }
 | 
			
		||||
            set { bodyAngle = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { bodyAngle = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public float HeadAngle
 | 
			
		||||
        {
 | 
			
		||||
            get { return headAngle.HasValue ? headAngle.Value : (float)(headAngle = 0f); }
 | 
			
		||||
            set { headAngle = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { headAngle = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public float HeadBob
 | 
			
		||||
        {
 | 
			
		||||
            get { return headBob.HasValue ? headBob.Value : (float)(headBob = 0f); }
 | 
			
		||||
            set { headBob = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { headBob = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public float BodyOffsetX
 | 
			
		||||
        {
 | 
			
		||||
            get { return bodyOffsetX.HasValue ? bodyOffsetX.Value : (float)(bodyOffsetX = 0f); }
 | 
			
		||||
            set { bodyOffsetX = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { bodyOffsetX = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public float BodyOffsetZ
 | 
			
		||||
        {
 | 
			
		||||
            get { return bodyOffsetZ.HasValue ? bodyOffsetZ.Value : (float)(bodyOffsetZ = 0f); }
 | 
			
		||||
            set { bodyOffsetZ = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { bodyOffsetZ = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public int HeadFacing
 | 
			
		||||
        {
 | 
			
		||||
            get { return headFacing.HasValue ? headFacing.Value : (int)(headFacing = 2); }
 | 
			
		||||
            set { headFacing = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { headFacing = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public int BodyFacing
 | 
			
		||||
        {
 | 
			
		||||
            get { return bodyFacing.HasValue ? bodyFacing.Value : (int)(bodyFacing = 2); }
 | 
			
		||||
            set { bodyFacing = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { bodyFacing = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public float GenitalAngle
 | 
			
		||||
        {
 | 
			
		||||
            get { return genitalAngle.HasValue ? genitalAngle.Value : (float)(genitalAngle = 0f); }
 | 
			
		||||
            set { genitalAngle = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { genitalAngle = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public bool Quiver
 | 
			
		||||
        {
 | 
			
		||||
            get { return quiver == true; }
 | 
			
		||||
            set { quiver = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { quiver = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public int TickDuration
 | 
			
		||||
        {
 | 
			
		||||
            get { return tickDuration.HasValue ? tickDuration.Value : (int)(tickDuration = 0); }
 | 
			
		||||
            set { tickDuration = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { tickDuration = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public string SoundEffect
 | 
			
		||||
        {
 | 
			
		||||
            get { return soundEffect; }
 | 
			
		||||
            set { soundEffect = value; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { soundEffect = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [XmlIgnore] public List<string> Tags
 | 
			
		||||
        {
 | 
			
		||||
            get { return tags.NullOrEmpty() ? tags = new List<string>() : tags; }
 | 
			
		||||
            set { tags = value.NotNullOrEmpty() ? value : null; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            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; EventsManager.OnPawnKeyframeChanged(this); }
 | 
			
		||||
            set { addonKeyframes = value.NotNullOrEmpty()? value : null;  }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Local data
 | 
			
		||||
| 
						 | 
				
			
			@ -148,6 +148,63 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            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");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Pre-save / post-load
 | 
			
		||||
        public void OnPreSave()
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +214,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
            foreach (AddonKeyframe addonKeyframe in AddonKeyframes)
 | 
			
		||||
            {
 | 
			
		||||
                ActorAddon addon = Workspace.GetAnimationClipThatOwnsKeyframe(keyframeID, out int clipID).GetActorAddon(addonKeyframe.AddonName);
 | 
			
		||||
                ActorAddon addon = Workspace.GetAnimationClipThatOwnsKeyframe(keyframeID).GetActorAddon(addonKeyframe.AddonName);
 | 
			
		||||
 | 
			
		||||
                if (addon.Render)
 | 
			
		||||
                { addonKeyframes.Add(addonKeyframe.Copy()); }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										44
									
								
								Assets/Scripts/Data/ActorPosition.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Assets/Scripts/Data/ActorPosition.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
 | 
			
		||||
namespace RimWorldAnimationStudio
 | 
			
		||||
{
 | 
			
		||||
    public class ActorPosition
 | 
			
		||||
    {
 | 
			
		||||
        public float bodyOffsetX;
 | 
			
		||||
        public float bodyOffsetZ;
 | 
			
		||||
        public float bodyAngle;
 | 
			
		||||
        public float headBob;
 | 
			
		||||
        public float headAngle;
 | 
			
		||||
        public float genitalAngle;
 | 
			
		||||
 | 
			
		||||
        public int bodyFacing;
 | 
			
		||||
        public int headFacing;
 | 
			
		||||
 | 
			
		||||
        public ActorPosition(int actorID, int atTick)
 | 
			
		||||
        {
 | 
			
		||||
            Actor actor = Workspace.GetActor(actorID);
 | 
			
		||||
            PawnAnimationClip clip = Workspace.GetPawnAnimationClip(actorID);
 | 
			
		||||
 | 
			
		||||
            float clipPercent = atTick / Workspace.StageWindowSize;
 | 
			
		||||
            if (atTick > Constants.minTick && atTick == clip.duration) clipPercent = 1f;
 | 
			
		||||
 | 
			
		||||
            if (Workspace.GetCurrentAnimationStage().IsLooping == false)
 | 
			
		||||
            { clipPercent = (float)atTick / clip.duration; }
 | 
			
		||||
 | 
			
		||||
            bodyOffsetX = clip.BodyOffsetX.Evaluate(clipPercent);
 | 
			
		||||
            bodyOffsetZ = clip.BodyOffsetZ.Evaluate(clipPercent);
 | 
			
		||||
            bodyAngle = clip.BodyAngle.Evaluate(clipPercent);
 | 
			
		||||
            headBob = clip.HeadBob.Evaluate(clipPercent);
 | 
			
		||||
            headAngle = clip.HeadAngle.Evaluate(clipPercent);
 | 
			
		||||
            genitalAngle = clip.GenitalAngle.Evaluate(clipPercent);
 | 
			
		||||
 | 
			
		||||
            bodyFacing = (int)clip.BodyFacing.Evaluate(clipPercent);
 | 
			
		||||
            headFacing = (int)clip.HeadFacing.Evaluate(clipPercent);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								Assets/Scripts/Data/ActorPosition.cs.meta
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Assets/Scripts/Data/ActorPosition.cs.meta
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
fileFormatVersion: 2
 | 
			
		||||
guid: e2a9b0bb71978ea49909b3e1814303a5
 | 
			
		||||
MonoImporter:
 | 
			
		||||
  externalObjects: {}
 | 
			
		||||
  serializedVersion: 2
 | 
			
		||||
  defaultReferences: []
 | 
			
		||||
  executionOrder: 0
 | 
			
		||||
  icon: {instanceID: 0}
 | 
			
		||||
  userData: 
 | 
			
		||||
  assetBundleName: 
 | 
			
		||||
  assetBundleVariant: 
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        // Colors used
 | 
			
		||||
        public static Color ColorWhite = new Color(1f, 1f, 1f);
 | 
			
		||||
        public static Color ColorGreen = new Color(0f, 1f, 0f);
 | 
			
		||||
        public static Color ColorLightGreen = new Color(0.75f, 1f, 0.75f);
 | 
			
		||||
        public static Color ColorGoldYellow = new Color(1f, 0.85f, 0f);
 | 
			
		||||
        public static Color ColorDarkGold = new Color(0.75f, 0.64f, 0f);
 | 
			
		||||
        public static Color ColorLightGrey = new Color(0.9f, 0.9f, 0.9f);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,34 +9,40 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
    public class ActorBody : MonoBehaviour, IPointerClickHandler, IDragHandler, IEndDragHandler
 | 
			
		||||
    {
 | 
			
		||||
        public int actorID;
 | 
			
		||||
        public bool isSelected = false;
 | 
			
		||||
 | 
			
		||||
        public SpriteRenderer bodyRenderer;
 | 
			
		||||
        public SpriteRenderer headRenderer;
 | 
			
		||||
        public SpriteRenderer appendageRenderer;
 | 
			
		||||
 | 
			
		||||
        private Vector3 delta = new Vector3();
 | 
			
		||||
        private Vector3 dragDelta = new Vector3();
 | 
			
		||||
 | 
			
		||||
        public bool actorBodyPartSelected { get { return GetComponentsInChildren<ActorBodyPart>().Any(x => x.isSelected); } }
 | 
			
		||||
 | 
			
		||||
        public void Initialize(int actorID)
 | 
			
		||||
        private void Start()
 | 
			
		||||
        {
 | 
			
		||||
            this.actorID = actorID;
 | 
			
		||||
            EventsManager.onActorBodyPartSelected.AddListener(delegate(ActorBodyPart bodyPart) { OnActorBodyPartSelected(bodyPart); });
 | 
			
		||||
            EventsManager.onActorBodySelected.AddListener(delegate(ActorBody actorBody) { OnActorBodySelected(actorBody); });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Update()
 | 
			
		||||
        public void OnActorBodySelected(ActorBody actorBody)
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.ActorID == actorID && Workspace.selectedBodyPart == null)
 | 
			
		||||
            if (actorBody == this)
 | 
			
		||||
            { bodyRenderer.color = Constants.ColorGreen; }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            { bodyRenderer.color = Constants.ColorWhite; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            foreach (ActorAddon addon in Workspace.GetCurrentAnimationStage().AnimationClips[actorID].Addons)
 | 
			
		||||
            {
 | 
			
		||||
                ActorBodyPart bodyPart = GetComponentsInChildren<ActorBodyPart>(true).FirstOrDefault(x => x.addonName == addon.AddonName);
 | 
			
		||||
                bodyPart?.gameObject?.SetActive(addon.Render);         
 | 
			
		||||
            }
 | 
			
		||||
        public void OnActorBodyPartSelected(ActorBodyPart bodyPart)
 | 
			
		||||
        {
 | 
			
		||||
            if (bodyPart.parent == this)
 | 
			
		||||
            { bodyRenderer.color = Constants.ColorLightGreen; }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            { bodyRenderer.color = Constants.ColorWhite; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Initialize(int actorID)
 | 
			
		||||
        {
 | 
			
		||||
            this.actorID = actorID;
 | 
			
		||||
 | 
			
		||||
            if (actorID == Workspace.ActorID)
 | 
			
		||||
            { Activate(); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnPointerClick(PointerEventData eventData)
 | 
			
		||||
| 
						 | 
				
			
			@ -52,19 +58,15 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            Activate();
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
 | 
			
		||||
            if (keyframe == null)
 | 
			
		||||
            { Debug.LogWarning("Cannot alter actor - no keyframe data available"); return; }
 | 
			
		||||
 | 
			
		||||
            Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
 | 
			
		||||
 | 
			
		||||
            if (delta == Vector3.zero)
 | 
			
		||||
            { delta = mousePosition - transform.position; }
 | 
			
		||||
            if (dragDelta == Vector3.zero)
 | 
			
		||||
            { dragDelta = mousePosition - transform.position; }
 | 
			
		||||
 | 
			
		||||
            if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
 | 
			
		||||
            {
 | 
			
		||||
                keyframe.BodyOffsetX = mousePosition.x - delta.x - Workspace.animationDef.Actors[actorID].GetFinalTransformOffset().x;
 | 
			
		||||
                keyframe.BodyOffsetZ = mousePosition.y - delta.y - Workspace.animationDef.Actors[actorID].GetFinalTransformOffset().y;
 | 
			
		||||
                keyframe.BodyOffsetX = mousePosition.x - dragDelta.x - Workspace.GetActor(actorID).GetFinalTransformOffset().x;
 | 
			
		||||
                keyframe.BodyOffsetZ = mousePosition.y - dragDelta.y - Workspace.GetActor(actorID).GetFinalTransformOffset().y;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
 | 
			
		||||
| 
						 | 
				
			
			@ -84,18 +86,27 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
            PawnAnimationClip clip = Workspace.GetPawnAnimationClip(actorID);
 | 
			
		||||
            clip.BuildSimpleCurves();
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnPawnKeyframeChanged(keyframe);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnEndDrag(PointerEventData eventData)
 | 
			
		||||
        {
 | 
			
		||||
            Workspace.RecordEvent("Actor position / orientation");
 | 
			
		||||
            delta = Vector3.zero;
 | 
			
		||||
            dragDelta = Vector3.zero;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ActorBodyPart GetBodyPart(string bodyPart)
 | 
			
		||||
        {
 | 
			
		||||
            return GetComponentsInChildren<ActorBodyPart>(true)?.FirstOrDefault(x => x.bodyPart.ToLower() == bodyPart);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Activate()
 | 
			
		||||
        {
 | 
			
		||||
            Workspace.ActorID = actorID;
 | 
			
		||||
            Workspace.selectedBodyPart = null;
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnActorBodySelected(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,22 +10,39 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
    {
 | 
			
		||||
        public SpriteRenderer bodyPartRenderer;
 | 
			
		||||
        public ActorBody parent;
 | 
			
		||||
        public bool isHead = false;
 | 
			
		||||
        public string addonName;
 | 
			
		||||
        public bool isSelected = false;
 | 
			
		||||
        public string bodyPart;
 | 
			
		||||
 | 
			
		||||
        private Vector3 delta = new Vector3();
 | 
			
		||||
        private Vector3 dragDelta = new Vector3();
 | 
			
		||||
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            //Workspace.onActorChanged.AddListener(delegate { });
 | 
			
		||||
            EventsManager.onActorBodyPartSelected.AddListener(delegate (ActorBodyPart bodyPart) { OnActorBodyPartSelected(bodyPart); });
 | 
			
		||||
            EventsManager.onActorBodySelected.AddListener(delegate (ActorBody actorBody) { OnActorBodySelected(actorBody); });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Update()
 | 
			
		||||
        public void OnActorAddonChange(ActorAddon actorAddon)
 | 
			
		||||
        {
 | 
			
		||||
            if ((Workspace.ActorID == parent.actorID && Workspace.selectedBodyPart == null) || Workspace.selectedBodyPart == this)
 | 
			
		||||
            if (actorAddon.AddonName == bodyPart)
 | 
			
		||||
            { gameObject?.SetActive(actorAddon.Render); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnActorBodySelected(ActorBody actorBody)
 | 
			
		||||
        {
 | 
			
		||||
            if (actorBody == parent)
 | 
			
		||||
            { bodyPartRenderer.color = Constants.ColorLightGreen; }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            { bodyPartRenderer.color = Constants.ColorWhite; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnActorBodyPartSelected(ActorBodyPart bodyPart)
 | 
			
		||||
        {
 | 
			
		||||
            if (bodyPart == this)
 | 
			
		||||
            { bodyPartRenderer.color = Constants.ColorGreen; }
 | 
			
		||||
 | 
			
		||||
            else if (bodyPart.parent == parent)
 | 
			
		||||
            { bodyPartRenderer.color = Constants.ColorLightGreen; }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            { bodyPartRenderer.color = Constants.ColorWhite; }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -43,71 +60,18 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            Activate();
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
 | 
			
		||||
            if (keyframe == null)
 | 
			
		||||
            { Debug.LogWarning("Cannot alter actor - no keyframe data available"); return; }
 | 
			
		||||
 | 
			
		||||
            Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
 | 
			
		||||
 | 
			
		||||
            if (delta == Vector3.zero)
 | 
			
		||||
            { delta = mousePosition - transform.position; }
 | 
			
		||||
            if (dragDelta == Vector3.zero)
 | 
			
		||||
            { dragDelta = mousePosition - transform.position; }
 | 
			
		||||
 | 
			
		||||
            if (addonName != null && addonName != "")
 | 
			
		||||
            {
 | 
			
		||||
                AddonKeyframe addonKeyframe = keyframe.GetAddonKeyframe(addonName);
 | 
			
		||||
                ActorAddon addon = Workspace.GetCurrentPawnAnimationClip().GetActorAddon(addonName);
 | 
			
		||||
 | 
			
		||||
                if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
 | 
			
		||||
                {
 | 
			
		||||
                    Vector3 anchor;
 | 
			
		||||
 | 
			
		||||
                    ActorBody anchoringActorBody = AnimationController.Instance.actorBodies.GetComponentsInChildren<ActorBody>()?.FirstOrDefault(x => x.actorID == addon.AnchoringActor); 
 | 
			
		||||
                    Vector3 bodyPos = new Vector3(anchoringActorBody.transform.position.x, anchoringActorBody.transform.position.y, 0);
 | 
			
		||||
                    PawnRaceDef pawnRaceDef = Workspace.animationDef.Actors[addon.AnchoringActor].GetPawnRaceDef();
 | 
			
		||||
                    Actor anchoringActor = Workspace.animationDef.Actors[addon.AnchoringActor];
 | 
			
		||||
                    int bodyFacing = (int)Workspace.GetCurrentAnimationStage().AnimationClips[addon.AnchoringActor].BodyFacing.Evaluate((float)Workspace.StageTick / Workspace.StageWindowSize);
 | 
			
		||||
 | 
			
		||||
                    switch (addon.AnchorName)
 | 
			
		||||
                    {
 | 
			
		||||
                        case "torso": anchor = bodyPos; break;
 | 
			
		||||
                        case "head": anchor = new Vector3(anchoringActorBody.transform.Find("ActorHead").position.x, anchoringActorBody.transform.Find("ActorHead").position.y, 0); break;
 | 
			
		||||
                        case "groin": anchor = bodyPos + Quaternion.AngleAxis(anchoringActorBody.transform.rotation.eulerAngles.z, Vector3.forward) * PawnUtility.GroinOffsetAt(anchoringActor.bodyType, bodyFacing).FlipAxes(); break;
 | 
			
		||||
                        case "left breast": anchor = bodyPos + Quaternion.AngleAxis(anchoringActorBody.transform.rotation.eulerAngles.z, Vector3.forward) * PawnUtility.BreastLeftOffsetAt(anchoringActor.bodyType, bodyFacing).FlipAxes(); break;
 | 
			
		||||
                        case "right breast": anchor = bodyPos + Quaternion.AngleAxis(anchoringActorBody.transform.rotation.eulerAngles.z, Vector3.forward) * PawnUtility.BreastRightOffsetAt(anchoringActor.bodyType, bodyFacing).FlipAxes(); break;
 | 
			
		||||
                        default: anchor = new Vector3(); break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    transform.position = new Vector3(mousePosition.x, mousePosition.y, 0f);
 | 
			
		||||
 
 | 
			
		||||
                    addonKeyframe.PosX = transform.position.x - anchor.x;
 | 
			
		||||
                    addonKeyframe.PosZ = transform.position.y - anchor.y;
 | 
			
		||||
 | 
			
		||||
                    ActorKeyframeCard.Instance.transform.GetComponentsInChildren<ActorAddonCard>()?.FirstOrDefault(x => x.addonName == addonName)?.OnKeyframeValueChanged();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
 | 
			
		||||
                {
 | 
			
		||||
                    float angle = -Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
 | 
			
		||||
                    addonKeyframe.Rotation = angle;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                else if (Workspace.actorManipulationMode == ActorManipulationMode.Face)
 | 
			
		||||
                {
 | 
			
		||||
                    //float angle = Vector2.SignedAngle(Vector2.up, (Vector2)mousePosition - (Vector2)transform.position);
 | 
			
		||||
                    //int facing = -Mathf.RoundToInt(angle / 90f);
 | 
			
		||||
                    //facing = facing < 0 ? facing + 4 : facing;
 | 
			
		||||
 | 
			
		||||
                    //keyframe.headFacing = facing;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else if (isHead)
 | 
			
		||||
            if (bodyPart.ToLower() == "head")
 | 
			
		||||
            {
 | 
			
		||||
                if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
 | 
			
		||||
                {
 | 
			
		||||
                    // It's stupid but it works
 | 
			
		||||
                    // It's stupid, but it works
 | 
			
		||||
                    Vector3 localPosA = transform.localPosition;
 | 
			
		||||
                    transform.position = mousePosition - delta;
 | 
			
		||||
                    transform.position = mousePosition - dragDelta;
 | 
			
		||||
                    Vector3 localPosB = transform.localPosition;
 | 
			
		||||
                    transform.localPosition = localPosA;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -130,31 +94,55 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            else if (bodyPart.ToLower() == "appendage")
 | 
			
		||||
            {
 | 
			
		||||
                if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
 | 
			
		||||
                {
 | 
			
		||||
                    float angle = -Vector2.SignedAngle(Vector2.up, (Vector2)mousePosition - (Vector2)transform.position);
 | 
			
		||||
                    keyframe.GenitalAngle = angle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                    Workspace.GetCurrentActor().ControlGenitalAngle = Workspace.animationDef.AnimationStages.Any(x => x.AnimationClips[Workspace.ActorID].Keyframes.Any(y => y.GenitalAngle != 0));
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                AddonKeyframe addonKeyframe = keyframe.GetAddonKeyframe(bodyPart);
 | 
			
		||||
                ActorAddon addon = Workspace.GetCurrentPawnAnimationClip().GetActorAddon(bodyPart);
 | 
			
		||||
 | 
			
		||||
                if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
 | 
			
		||||
                {
 | 
			
		||||
                    ActorBody anchoringActorBody = AnimationController.Instance.actorBodies.GetComponentsInChildren<ActorBody>()?.FirstOrDefault(x => x.actorID == addon.AnchoringActor);
 | 
			
		||||
                    Vector3 anchor = PawnUtility.GetBodyPartAnchor(anchoringActorBody, addon.addonName);
 | 
			
		||||
                    transform.position = new Vector3(mousePosition.x, mousePosition.y, 0f);
 | 
			
		||||
 | 
			
		||||
                    addonKeyframe.PosX = transform.position.x - anchor.x;
 | 
			
		||||
                    addonKeyframe.PosZ = transform.position.y - anchor.y;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
 | 
			
		||||
                {
 | 
			
		||||
                    float angle = -Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
 | 
			
		||||
                    addonKeyframe.Rotation = angle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            PawnAnimationClip clip = Workspace.GetPawnAnimationClip(parent.actorID);
 | 
			
		||||
            clip.BuildSimpleCurves();
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnPawnKeyframeChanged(keyframe);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnEndDrag(PointerEventData eventData)
 | 
			
		||||
        {
 | 
			
		||||
            Workspace.RecordEvent("Actor position / orientation");
 | 
			
		||||
            delta = Vector3.zero;
 | 
			
		||||
            dragDelta = Vector3.zero;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Activate()
 | 
			
		||||
        {
 | 
			
		||||
            Workspace.ActorID = parent.actorID;
 | 
			
		||||
            Workspace.selectedBodyPart = this;
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnActorBodyPartSelected(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										35
									
								
								Assets/Scripts/GUI/AnimationLengthDisplay.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Assets/Scripts/GUI/AnimationLengthDisplay.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using UnityEngine.UI;
 | 
			
		||||
 | 
			
		||||
namespace RimWorldAnimationStudio
 | 
			
		||||
{
 | 
			
		||||
    public class AnimationLengthDisplay : MonoBehaviour
 | 
			
		||||
    {
 | 
			
		||||
        public Text stageLengthNormalText;
 | 
			
		||||
        public Text animationLengthNormalText;
 | 
			
		||||
        public Text stageLengthQuickText;
 | 
			
		||||
        public Text animationLengthQuickText;
 | 
			
		||||
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void UpdateGUI()
 | 
			
		||||
        {
 | 
			
		||||
            stageLengthNormalText.text = "Stage length (normal): " + Workspace.GetCurrentAnimationStage().PlayTimeTicks + " (" + Workspace.GetCurrentAnimationStage().PlayTimeTicks / 60f + " s)";
 | 
			
		||||
            animationLengthNormalText.text = "Animation length (normal): " + Workspace.animationDef.animationTimeTicks + " (" + Workspace.animationDef.animationTimeTicks / 60f + " s)";
 | 
			
		||||
            
 | 
			
		||||
            stageLengthQuickText.text = "Stage length (quickie): " + Workspace.GetCurrentAnimationStage().PlayTimeTicksQuick + " (" + Workspace.GetCurrentAnimationStage().PlayTimeTicksQuick / 60f + " s)";
 | 
			
		||||
            animationLengthQuickText.text = "Animation length (quickie): " + Workspace.animationDef.animationTimeTicksQuick + " (" + Workspace.animationDef.animationTimeTicksQuick / 60f + " s)";
 | 
			
		||||
 | 
			
		||||
            LayoutRebuilder.ForceRebuildLayoutImmediate(stageLengthQuickText.GetComponent<RectTransform>());
 | 
			
		||||
            LayoutRebuilder.ForceRebuildLayoutImmediate(animationLengthQuickText.GetComponent<RectTransform>());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								Assets/Scripts/GUI/AnimationLengthDisplay.cs.meta
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Assets/Scripts/GUI/AnimationLengthDisplay.cs.meta
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
fileFormatVersion: 2
 | 
			
		||||
guid: 060e49b40b1097e46b662059e4e29cdf
 | 
			
		||||
MonoImporter:
 | 
			
		||||
  externalObjects: {}
 | 
			
		||||
  serializedVersion: 2
 | 
			
		||||
  defaultReferences: []
 | 
			
		||||
  executionOrder: 0
 | 
			
		||||
  icon: {instanceID: 0}
 | 
			
		||||
  userData: 
 | 
			
		||||
  assetBundleName: 
 | 
			
		||||
  assetBundleVariant: 
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        public void InitiateUpdateOfGhostFrames()
 | 
			
		||||
        {
 | 
			
		||||
            if (AnimationController.Instance.IsTimelineDirty()) return;
 | 
			
		||||
            //if (AnimationController.Instance.IsTimelineDirty()) return;
 | 
			
		||||
 | 
			
		||||
            BroadcastMessage("UpdateGhostFrames");
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            int? siblingCount = anchorTransform.parent.GetComponentsInChildren<AnimationTimeline>()?.ToList()?.Count();
 | 
			
		||||
 | 
			
		||||
            if (siblingIndex != null && siblingCount != null && MoveAnimationTimeline(siblingIndex.Value, delta))
 | 
			
		||||
            { AnimationController.Instance.InitializeAnimationTimeline(); }
 | 
			
		||||
            { AnimationController.Instance.Initialize(); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool MoveAnimationTimeline(int startIndex, int delta)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ using UnityEngine.UI;
 | 
			
		|||
 | 
			
		||||
namespace RimWorldAnimationStudio
 | 
			
		||||
{
 | 
			
		||||
    public class ActorAddonCard : MonoBehaviour
 | 
			
		||||
    public class ActorAddonKeyframeCard : MonoBehaviour
 | 
			
		||||
    {
 | 
			
		||||
        public string addonName;
 | 
			
		||||
        public InputField xOffsetField;
 | 
			
		||||
| 
						 | 
				
			
			@ -17,30 +17,33 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            xOffsetField.onEndEdit.AddListener(delegate { OnFieldValueChanged(); });
 | 
			
		||||
            zOffsetField.onEndEdit.AddListener(delegate { OnFieldValueChanged(); });
 | 
			
		||||
            rotationField.onEndEdit.AddListener(delegate { OnFieldValueChanged(); });
 | 
			
		||||
            EventsManager.onAnimationChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onStageIDChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onActorIDChanged.AddListener(delegate { UpdateGUI(); }); 
 | 
			
		||||
            EventsManager.onStageTickChanged.AddListener(delegate { Debug.Log("stagetick"); UpdateGUI(); });
 | 
			
		||||
 | 
			
		||||
            AnimationController.Instance.animationClipTimeField.onValueChanged.AddListener(delegate { OnKeyframeValueChanged(); });
 | 
			
		||||
            xOffsetField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
            zOffsetField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
            rotationField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
 | 
			
		||||
            UpdateGUI();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnFieldValueChanged()
 | 
			
		||||
        public void OnValueChanged()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            PawnAnimationClip clip = Workspace.GetCurrentPawnAnimationClip();
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
 | 
			
		||||
            keyframe.GetAddonKeyframe(addonName).PosX = float.Parse(xOffsetField.text);
 | 
			
		||||
            keyframe.GetAddonKeyframe(addonName).PosZ = float.Parse(zOffsetField.text);
 | 
			
		||||
            keyframe.GetAddonKeyframe(addonName).Rotation = float.Parse(rotationField.text);
 | 
			
		||||
 | 
			
		||||
            clip.BuildSimpleCurves();
 | 
			
		||||
            Workspace.GetCurrentPawnAnimationClip().BuildSimpleCurves();
 | 
			
		||||
 | 
			
		||||
            Workspace.RecordEvent("Actor addon position / orientation");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnKeyframeValueChanged()
 | 
			
		||||
        public void UpdateGUI()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            PawnAnimationClip clip = Workspace.GetCurrentPawnAnimationClip();
 | 
			
		||||
 | 
			
		||||
            xOffsetField.SetTextWithoutNotify(clip.GetActorAddon(addonName).PosX.Evaluate((float)Workspace.StageTick / Workspace.StageWindowSize).ToString());
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            // General events
 | 
			
		||||
            EventsManager.onAnimationDefChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onAnimationChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onActorIDChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onDefNamesChanged.AddListener(delegate { UpdateRaceDropdown(); });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +69,8 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            actor.SetPawnRaceOffset(new Vector2(x, z));
 | 
			
		||||
 | 
			
		||||
            Workspace.RecordEvent("Actor offset");
 | 
			
		||||
 | 
			
		||||
            UpdateGUI();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnDropdownChanged()
 | 
			
		||||
| 
						 | 
				
			
			@ -107,8 +109,8 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            string bodyType = actor.bodyType;
 | 
			
		||||
            bodyTypeDropdown.SetValueWithoutNotify(bodyTypeDropdown.options.FindIndex(x => x.text == bodyType));
 | 
			
		||||
 | 
			
		||||
            bodyOffsetXField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.BodyTypeOffset.GetOffset(bodyType).x.ToString()));
 | 
			
		||||
            bodyOffsetZField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.BodyTypeOffset.GetOffset(bodyType).z.ToString()));
 | 
			
		||||
            bodyOffsetXField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.BodyTypeOffset.GetOffset(bodyType).x));
 | 
			
		||||
            bodyOffsetZField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.BodyTypeOffset.GetOffset(bodyType).z));
 | 
			
		||||
 | 
			
		||||
            bodyTypeDropdown.interactable = actor.GetPawnRaceDef().isHumanoid;
 | 
			
		||||
            bodyOffsetXField.interactable = actor.GetPawnRaceDef().isHumanoid;
 | 
			
		||||
| 
						 | 
				
			
			@ -117,8 +119,8 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            string race = actor.GetPawnRaceDef().defName;
 | 
			
		||||
            raceDropdown.SetValueWithoutNotify(raceDropdown.options.FindIndex(x => x.text == race));
 | 
			
		||||
 | 
			
		||||
            raceOffsetXField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.GetPawnRaceOffset().x.ToString()));
 | 
			
		||||
            raceOffsetZField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.GetPawnRaceOffset().z.ToString()));
 | 
			
		||||
            raceOffsetXField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.GetPawnRaceOffset().x));
 | 
			
		||||
            raceOffsetZField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.GetPawnRaceOffset().z));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,17 +15,25 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public InputField headRotationField;
 | 
			
		||||
        public InputField appendageRotationField;
 | 
			
		||||
 | 
			
		||||
        public void Update()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null)
 | 
			
		||||
            { return; }
 | 
			
		||||
        private Actor actor { get { return Workspace.GetCurrentActor(); } }
 | 
			
		||||
 | 
			
		||||
            positionXField.interactable = AnimationController.Instance.isAnimating == false; 
 | 
			
		||||
            positionZField.interactable = AnimationController.Instance.isAnimating == false;
 | 
			
		||||
            rotationField.interactable = AnimationController.Instance.isAnimating == false;
 | 
			
		||||
            headBobField.interactable = AnimationController.Instance.isAnimating == false;
 | 
			
		||||
            headRotationField.interactable = AnimationController.Instance.isAnimating == false;
 | 
			
		||||
            appendageRotationField.interactable = AnimationController.Instance.isAnimating == false;
 | 
			
		||||
        private void Start()
 | 
			
		||||
        {
 | 
			
		||||
            EventsManager.onAnimationChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onStageIDChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onActorIDChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onStageTickChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onKeyframeCountChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
            EventsManager.onPawnKeyframeChanged.AddListener(delegate { UpdateGUI(); });
 | 
			
		||||
 | 
			
		||||
            positionXField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
            positionZField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
            rotationField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
            headBobField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
            headRotationField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
            appendageRotationField.onEndEdit.AddListener(delegate { OnValueChanged(); });
 | 
			
		||||
 | 
			
		||||
            UpdateGUI();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnValueChanged()
 | 
			
		||||
| 
						 | 
				
			
			@ -39,70 +47,21 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            keyframe.HeadAngle = float.Parse(headRotationField.text);
 | 
			
		||||
            keyframe.GenitalAngle = float.Parse(appendageRotationField.text);
 | 
			
		||||
 | 
			
		||||
            Workspace.animationDef.Actors[Workspace.ActorID].ControlGenitalAngle = keyframe.GenitalAngle != 0;
 | 
			
		||||
            Workspace.GetPawnAnimationClip(Workspace.ActorID).BuildSimpleCurves();
 | 
			
		||||
            Workspace.RecordEvent("Actor position / orientation");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
        {
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
 
 | 
			
		||||
            if (Workspace.selectedBodyPart == null)
 | 
			
		||||
            {
 | 
			
		||||
                keyframe.BodyOffsetX += deltaOffset.x;
 | 
			
		||||
                keyframe.BodyOffsetZ += deltaOffset.y;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else if (Workspace.selectedBodyPart.isHead)
 | 
			
		||||
            { keyframe.HeadBob += deltaOffset.y; }
 | 
			
		||||
 | 
			
		||||
            Workspace.GetCurrentPawnAnimationClip().BuildSimpleCurves();
 | 
			
		||||
 | 
			
		||||
            Workspace.RecordEvent("Actor position / orientation");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RotateActor(float deltaAngle)
 | 
			
		||||
        public void UpdateGUI()
 | 
			
		||||
        {
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            ActorPosition actorPosition = actor.GetCurrentPosition();
 | 
			
		||||
 | 
			
		||||
            if (Workspace.selectedBodyPart == null)
 | 
			
		||||
            { keyframe.BodyAngle += deltaAngle; }
 | 
			
		||||
 | 
			
		||||
            else if (Workspace.selectedBodyPart.isHead)
 | 
			
		||||
            { keyframe.HeadAngle += deltaAngle; }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            { keyframe.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.isHead)
 | 
			
		||||
            { keyframe.HeadFacing = facing; }
 | 
			
		||||
 | 
			
		||||
            Workspace.GetCurrentPawnAnimationClip().BuildSimpleCurves();
 | 
			
		||||
            Workspace.RecordEvent("Actor position / orientation");
 | 
			
		||||
            positionXField.SetTextWithoutNotify(string.Format("{0:0.000}", actorPosition.bodyOffsetX));
 | 
			
		||||
            positionZField.SetTextWithoutNotify(string.Format("{0:0.000}", actorPosition.bodyOffsetZ));
 | 
			
		||||
            rotationField.SetTextWithoutNotify(string.Format("{0:0.000}", actorPosition.bodyAngle));
 | 
			
		||||
            headBobField.SetTextWithoutNotify(string.Format("{0:0.000}", actorPosition.headBob));
 | 
			
		||||
            headRotationField.SetTextWithoutNotify(string.Format("{0:0.000}", actorPosition.headAngle));
 | 
			
		||||
            appendageRotationField.SetTextWithoutNotify(string.Format("{0:0.000}", actorPosition.genitalAngle));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										103
									
								
								Assets/Scripts/GUI/Cards/AnimationControlCard.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								Assets/Scripts/GUI/Cards/AnimationControlCard.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,103 @@
 | 
			
		|||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using UnityEngine.UI;
 | 
			
		||||
 | 
			
		||||
namespace RimWorldAnimationStudio
 | 
			
		||||
{
 | 
			
		||||
    public class AnimationControlCard : MonoBehaviour
 | 
			
		||||
    {
 | 
			
		||||
        public Dropdown stageLoopDropdown;
 | 
			
		||||
        public InputField animationClipTimeField;
 | 
			
		||||
        public InputField animationClipLengthField;
 | 
			
		||||
        public Toggle stretchKeyframesToggle;
 | 
			
		||||
        public InputField playBackSpeedField;
 | 
			
		||||
        public Button playToggleButton;
 | 
			
		||||
        public Slider stageTimelineSlider;
 | 
			
		||||
 | 
			
		||||
        private void Start()
 | 
			
		||||
        {
 | 
			
		||||
            EventsManager.onStageTickChanged.AddListener(delegate
 | 
			
		||||
            {
 | 
			
		||||
                animationClipTimeField.SetTextWithoutNotify(Workspace.StageTick.ToString());
 | 
			
		||||
                stageTimelineSlider.SetValueWithoutNotify(Workspace.StageTick);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            EventsManager.onAnimationToggled.AddListener(delegate
 | 
			
		||||
            {
 | 
			
		||||
                playToggleButton.image.color = Workspace.isAnimating ? Constants.ColorGoldYellow : Constants.ColorWhite;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            animationClipLengthField.text = Workspace.StageWindowSize.ToString();
 | 
			
		||||
            stageTimelineSlider.maxValue = Workspace.StageWindowSize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ToggleAnimation(bool forceOff = false)
 | 
			
		||||
        {
 | 
			
		||||
            Workspace.isAnimating = !Workspace.isAnimating;
 | 
			
		||||
            if (forceOff) Workspace.isAnimating = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnStageTimelineSliderChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            if (Workspace.StageTick != (int)stageTimelineSlider.value)
 | 
			
		||||
            {
 | 
			
		||||
                Workspace.StageTick = (int)stageTimelineSlider.value;
 | 
			
		||||
                animationClipTimeField.text = Workspace.StageTick.ToString();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnAnimationClipTimeFieldChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            int.TryParse(animationClipTimeField.text, out int newStageTick);
 | 
			
		||||
            Workspace.StageTick = Mathf.Clamp(newStageTick, Constants.minTick, Workspace.StageWindowSize);
 | 
			
		||||
            stageTimelineSlider.value = Workspace.StageTick;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnAnimationClipLengthFieldChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            int.TryParse(animationClipLengthField.text, out int newStageWindowSize);
 | 
			
		||||
            newStageWindowSize = Mathf.Clamp(newStageWindowSize, Constants.minAnimationClipLength, Constants.maxAnimationClipLength);
 | 
			
		||||
 | 
			
		||||
            Debug.Log("Resizing animation clip length to " + newStageWindowSize.ToString() + " ticks.");
 | 
			
		||||
 | 
			
		||||
            if (stretchKeyframesToggle.isOn)
 | 
			
		||||
            { Workspace.GetCurrentAnimationStage().StretchStageWindow(newStageWindowSize); }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                foreach (PawnAnimationClip clip in Workspace.GetCurrentAnimationStage().AnimationClips)
 | 
			
		||||
                {
 | 
			
		||||
                    List<PawnKeyframe> keyframes = clip.Keyframes.Where(x => x.atTick > newStageWindowSize)?.ToList();
 | 
			
		||||
 | 
			
		||||
                    if (keyframes.NullOrEmpty())
 | 
			
		||||
                    { continue; }
 | 
			
		||||
 | 
			
		||||
                    foreach (PawnKeyframe keyframe in keyframes)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (clip.Keyframes.Count <= 2)
 | 
			
		||||
                        { break; }
 | 
			
		||||
 | 
			
		||||
                        clip.RemovePawnKeyframe(keyframe.keyframeID);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().ResizeStageWindow(newStageWindowSize);
 | 
			
		||||
            Workspace.RecordEvent("Stage length");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnPlayBackSpeedChange()
 | 
			
		||||
        {
 | 
			
		||||
            Workspace.PlayBackSpeed = float.Parse(playBackSpeedField.text);
 | 
			
		||||
            playBackSpeedField.SetTextWithoutNotify(Workspace.PlayBackSpeed.ToString());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								Assets/Scripts/GUI/Cards/AnimationControlCard.cs.meta
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Assets/Scripts/GUI/Cards/AnimationControlCard.cs.meta
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
fileFormatVersion: 2
 | 
			
		||||
guid: 6b414452bfd6c9b4bb99542a51d77468
 | 
			
		||||
MonoImporter:
 | 
			
		||||
  externalObjects: {}
 | 
			
		||||
  serializedVersion: 2
 | 
			
		||||
  defaultReferences: []
 | 
			
		||||
  executionOrder: 0
 | 
			
		||||
  icon: {instanceID: 0}
 | 
			
		||||
  userData: 
 | 
			
		||||
  assetBundleName: 
 | 
			
		||||
  assetBundleVariant: 
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            EventsManager.onAnimationDefChanged.AddListener(delegate { UpdateInputFields(); });
 | 
			
		||||
            EventsManager.onAnimationChanged.AddListener(delegate { UpdateInputFields(); });
 | 
			
		||||
 | 
			
		||||
            defNameField.onEndEdit.AddListener(delegate { 
 | 
			
		||||
                Workspace.animationDef.DefName = defNameField.text;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,30 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public InputField stageNameField;
 | 
			
		||||
        public Image banner;
 | 
			
		||||
 | 
			
		||||
        private int stageID { get { return transform.GetSiblingIndex(); } }
 | 
			
		||||
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            EventsManager.onStageIDChanged.AddListener(delegate { Initialize(stageName.text); });
 | 
			
		||||
            stageNameField.onEndEdit.AddListener(delegate { OnNameChange(); });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Initialize(string stageName)
 | 
			
		||||
        {
 | 
			
		||||
            this.stageName.text = stageName;
 | 
			
		||||
 | 
			
		||||
            if (Workspace.StageID == transform.GetSiblingIndex())
 | 
			
		||||
            {
 | 
			
		||||
                banner.gameObject.SetActive(true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                banner.gameObject.SetActive(false);
 | 
			
		||||
                stageNameField.gameObject.SetActive(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnNameChange()
 | 
			
		||||
        {
 | 
			
		||||
            stageName.text = stageNameField.text;
 | 
			
		||||
| 
						 | 
				
			
			@ -23,27 +47,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        public void OnMoveStage(int delta)
 | 
			
		||||
        {        
 | 
			
		||||
            int siblingCount = transform.parent.childCount;
 | 
			
		||||
            int index = Mathf.Clamp(transform.GetSiblingIndex() + delta, 0, siblingCount - 1);
 | 
			
		||||
 | 
			
		||||
            transform.SetSiblingIndex(index);         
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Initialize(string stageName)
 | 
			
		||||
        {
 | 
			
		||||
            this.stageName.text = stageName;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Update()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.StageID == transform.GetSiblingIndex())
 | 
			
		||||
            { banner.gameObject.SetActive(true); }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            { 
 | 
			
		||||
                banner.gameObject.SetActive(false);
 | 
			
		||||
                stageNameField.gameObject.SetActive(false);
 | 
			
		||||
            }
 | 
			
		||||
            Workspace.animationDef.MoveAnimationStage(stageID, delta);        
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnPointerClick(PointerEventData eventData)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										58
									
								
								Assets/Scripts/GUI/Cards/StageLoopsCard.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								Assets/Scripts/GUI/Cards/StageLoopsCard.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using UnityEngine.UI;
 | 
			
		||||
 | 
			
		||||
namespace RimWorldAnimationStudio
 | 
			
		||||
{
 | 
			
		||||
    public class StageLoopsCard : MonoBehaviour
 | 
			
		||||
    {
 | 
			
		||||
        public InputField stageLoopsNormalField;
 | 
			
		||||
        public InputField stageLoopsQuickField;
 | 
			
		||||
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            EventsManager.onAnimationChanged.AddListener(delegate { UpdateInputFields(); });
 | 
			
		||||
            EventsManager.onStageIDChanged.AddListener(delegate { UpdateInputFields(); });
 | 
			
		||||
            EventsManager.onAnimationStageChanged.AddListener(delegate { UpdateInputFields(); });
 | 
			
		||||
 | 
			
		||||
            stageLoopsNormalField.onEndEdit.AddListener(delegate { OnStageLoopsNormalFieldChange(); });
 | 
			
		||||
            stageLoopsQuickField.onEndEdit.AddListener(delegate { OnStageLoopsFastFieldChange(); });
 | 
			
		||||
 | 
			
		||||
            UpdateInputFields();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnStageLoopsNormalFieldChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().StageLoopsNormal = int.Parse(stageLoopsNormalField.text);
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnAnimationStageChanged(Workspace.GetCurrentAnimationStage());
 | 
			
		||||
            Workspace.RecordEvent("Cycle count (normal)");
 | 
			
		||||
 | 
			
		||||
            UpdateInputFields();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnStageLoopsFastFieldChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().StageLoopsQuick = int.Parse(stageLoopsQuickField.text);
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnAnimationStageChanged(Workspace.GetCurrentAnimationStage());
 | 
			
		||||
            Workspace.RecordEvent("Cycle count (fast)");
 | 
			
		||||
 | 
			
		||||
            UpdateInputFields();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void UpdateInputFields()
 | 
			
		||||
        {
 | 
			
		||||
            stageLoopsNormalField.SetTextWithoutNotify(Workspace.GetCurrentAnimationStage().StageLoopsNormal.ToString());
 | 
			
		||||
            stageLoopsQuickField.SetTextWithoutNotify(Workspace.GetCurrentAnimationStage().StageLoopsQuick.ToString());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								Assets/Scripts/GUI/Cards/StageLoopsCard.cs.meta
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Assets/Scripts/GUI/Cards/StageLoopsCard.cs.meta
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
fileFormatVersion: 2
 | 
			
		||||
guid: 38691dc973d99734f8f0f2a240df73fe
 | 
			
		||||
MonoImporter:
 | 
			
		||||
  externalObjects: {}
 | 
			
		||||
  serializedVersion: 2
 | 
			
		||||
  defaultReferences: []
 | 
			
		||||
  executionOrder: 0
 | 
			
		||||
  icon: {instanceID: 0}
 | 
			
		||||
  userData: 
 | 
			
		||||
  assetBundleName: 
 | 
			
		||||
  assetBundleVariant: 
 | 
			
		||||
| 
						 | 
				
			
			@ -35,12 +35,12 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        {
 | 
			
		||||
            this.timeline = timeline;
 | 
			
		||||
            this.clip = Workspace.GetPawnAnimationClip(actorID);
 | 
			
		||||
            this.keyframe = Workspace.GetPawnKeyframe(actorID, keyframeID);
 | 
			
		||||
            this.keyframe = Workspace.GetPawnKeyframe(keyframeID);
 | 
			
		||||
 | 
			
		||||
            this.actorID = actorID;
 | 
			
		||||
            this.keyframeID = keyframeID;
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetPawnKeyframe(actorID, keyframeID);
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetPawnKeyframe(keyframeID);
 | 
			
		||||
            maxValue = Workspace.StageWindowSize;
 | 
			
		||||
            value = keyframe.atTick.Value;
 | 
			
		||||
           
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +132,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
                    if (unlinkedSlider != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (AnimationController.Instance.stretchKeyframesToggle.isOn && unlinkedSlider.keyframe.atTick == pivotKeyframe.atTick) continue;
 | 
			
		||||
                        if (Workspace.stretchKeyframes && unlinkedSlider.keyframe.atTick == pivotKeyframe.atTick) continue;
 | 
			
		||||
 | 
			
		||||
                        unlinkedSlider.linkedSlider = this;
 | 
			
		||||
                        unlinkedSlider.linkedOffset = unlinkedSlider.keyframe.atTick.Value - keyframe.atTick.Value;
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +176,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
                foreach (PawnKeyframe _keyframe in keyframesToCheck)
 | 
			
		||||
                {
 | 
			
		||||
                    if (_keyframe != keyframe)
 | 
			
		||||
                    { Workspace.GetCurrentPawnAnimationClip().RemovePawnKeyframe(actorID, _keyframe.keyframeID); }
 | 
			
		||||
                    { Workspace.GetAnimationClipThatOwnsKeyframe(_keyframe.keyframeID).RemovePawnKeyframe(_keyframe.keyframeID); }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +196,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
                            foreach (PawnKeyframe _keyframe in keyframesToCheck)
 | 
			
		||||
                            {
 | 
			
		||||
                                if (_keyframe.keyframeID != linkedKeyframe.keyframeID)
 | 
			
		||||
                                { Workspace.GetCurrentPawnAnimationClip().RemovePawnKeyframe(actorID, _keyframe.keyframeID); Debug.Log("delete"); }
 | 
			
		||||
                                { Workspace.GetAnimationClipThatOwnsKeyframe(_keyframe.keyframeID).RemovePawnKeyframe(_keyframe.keyframeID); }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -219,10 +219,10 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            if (Workspace.keyframeID.NullOrEmpty() || Workspace.keyframeID.Contains(keyframeID) == false)
 | 
			
		||||
            { linkedSlider = null; }
 | 
			
		||||
 | 
			
		||||
            else if (AnimationController.Instance.stretchKeyframesToggle.isOn && linkedSlider != null)
 | 
			
		||||
            else if (Workspace.stretchKeyframes && linkedSlider != null)
 | 
			
		||||
            { value = Mathf.CeilToInt(linkedSlider.keyframe.atTick.Value + linkedOffset * linkedSlider.ScaledOffsetFromPivot()); }
 | 
			
		||||
 | 
			
		||||
            else if (AnimationController.Instance.stretchKeyframesToggle.isOn == false && linkedSlider != null)
 | 
			
		||||
            else if (Workspace.stretchKeyframes == false && linkedSlider != null)
 | 
			
		||||
            { value = Mathf.Clamp(linkedSlider.keyframe.atTick.Value + linkedOffset, Constants.minTick + 1, Workspace.StageWindowSize); }
 | 
			
		||||
 | 
			
		||||
            else if (keyframe.atTick.Value != value)
 | 
			
		||||
| 
						 | 
				
			
			@ -242,7 +242,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            { handleImage.color = Constants.ColorGrey; }
 | 
			
		||||
 | 
			
		||||
            // Show sound symbol
 | 
			
		||||
            string soundDef = Workspace.GetPawnKeyframe(actorID, keyframeID)?.SoundEffect;
 | 
			
		||||
            string soundDef = Workspace.GetPawnKeyframe(keyframeID)?.SoundEffect;
 | 
			
		||||
            soundIcon.SetActive(soundDef != null && soundDef != "" && soundDef != "None");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,21 +16,10 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        private List<int> divisions = new List<int>();
 | 
			
		||||
        private float minDiff = -1f;
 | 
			
		||||
        private RectTransform rect;
 | 
			
		||||
        private int lastStageWindowSize = -1;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            rect = GetComponent<RectTransform>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Update()
 | 
			
		||||
        {
 | 
			
		||||
            if (lastStageWindowSize != Workspace.StageWindowSize)
 | 
			
		||||
            {
 | 
			
		||||
                UpdateLinearScale();
 | 
			
		||||
                lastStageWindowSize = Workspace.StageWindowSize;
 | 
			
		||||
            }
 | 
			
		||||
            EventsManager.onStageWindowSizeChanged.AddListener(delegate { UpdateLinearScale(); });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void UpdateLinearScale()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using UnityEngine.UI;
 | 
			
		||||
 | 
			
		||||
namespace RimWorldAnimationStudio
 | 
			
		||||
{
 | 
			
		||||
    public class InactiveDuringAnimationPreview : MonoBehaviour
 | 
			
		||||
    {
 | 
			
		||||
        private InputField inputfield;
 | 
			
		||||
 | 
			
		||||
        private void Start()
 | 
			
		||||
        {
 | 
			
		||||
            inputfield = GetComponent<InputField>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Update()
 | 
			
		||||
        {
 | 
			
		||||
            inputfield.interactable = AnimationController.Instance.isAnimating == false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
fileFormatVersion: 2
 | 
			
		||||
guid: 92068b39ed172084296a595f5a09e54b
 | 
			
		||||
MonoImporter:
 | 
			
		||||
  externalObjects: {}
 | 
			
		||||
  serializedVersion: 2
 | 
			
		||||
  defaultReferences: []
 | 
			
		||||
  executionOrder: 0
 | 
			
		||||
  icon: {instanceID: 0}
 | 
			
		||||
  userData: 
 | 
			
		||||
  assetBundleName: 
 | 
			
		||||
  assetBundleVariant: 
 | 
			
		||||
| 
						 | 
				
			
			@ -14,81 +14,32 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        [Header("Animation settings")]
 | 
			
		||||
        public bool isAnimating = false;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        [Header("Object references")]
 | 
			
		||||
        public Slider stageTimelineSlider;
 | 
			
		||||
        public Dropdown stageLoopDropdown;
 | 
			
		||||
        public InputField cyclesNormalField;
 | 
			
		||||
        public InputField cyclesFastField;
 | 
			
		||||
        public InputField animationClipTimeField;
 | 
			
		||||
        public InputField animationClipLengthField;
 | 
			
		||||
        public ActorCard actorCard;
 | 
			
		||||
        public Transform animationTimelines;
 | 
			
		||||
        public Transform actorBodies;
 | 
			
		||||
        public Toggle stretchKeyframesToggle;
 | 
			
		||||
        public InputField playBackSpeedField;
 | 
			
		||||
        public Button playToggleButton;
 | 
			
		||||
        public Text stageLengthText;
 | 
			
		||||
        public Text animationLengthText;
 | 
			
		||||
        public GameObject handLeftControls;
 | 
			
		||||
        public GameObject handRightControls;
 | 
			
		||||
        public GameObject sexToyControls;
 | 
			
		||||
        public Dropdown stageLoopDropdown;
 | 
			
		||||
 | 
			
		||||
        [Header("Prefabs")]
 | 
			
		||||
        public ActorBody actorBodyPrefab;
 | 
			
		||||
        public GameObject animationTimelinePrefab;
 | 
			
		||||
 | 
			
		||||
        // Private timing variables
 | 
			
		||||
        private int lastStageTick = Constants.minTick;
 | 
			
		||||
        private float timeSinceLastUpdate = 0;
 | 
			
		||||
        private int cycleIndex = 0;
 | 
			
		||||
        private bool isDirty = true;
 | 
			
		||||
        private bool isTimelineDirty = true;
 | 
			
		||||
        private int loopCount = 0;
 | 
			
		||||
        private float playBackSpeed = 1f;
 | 
			
		||||
 | 
			
		||||
        public void MakeDirty()
 | 
			
		||||
        { isDirty = true; isTimelineDirty = true; }
 | 
			
		||||
 | 
			
		||||
        public void MakeTimelineDirty()
 | 
			
		||||
        { isTimelineDirty = true; }
 | 
			
		||||
 | 
			
		||||
        public bool IsDirty()
 | 
			
		||||
        { return isDirty; }
 | 
			
		||||
 | 
			
		||||
        public bool IsTimelineDirty()
 | 
			
		||||
        { return isTimelineDirty; }
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {         
 | 
			
		||||
            EventsManager.onAnimationChanged.AddListener(delegate{ Initialize(); });
 | 
			
		||||
            EventsManager.onStageIDChanged.AddListener(delegate { Initialize(); });
 | 
			
		||||
            EventsManager.onActorCountChanged.AddListener(delegate { Initialize(); });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Update()
 | 
			
		||||
        {
 | 
			
		||||
            // No animation, exit
 | 
			
		||||
            if (Workspace.animationDef == null) { return; }
 | 
			
		||||
 | 
			
		||||
            // Dirty animation, reset
 | 
			
		||||
            if (Workspace.animationDef != null && isDirty)
 | 
			
		||||
            { Initialize(); }
 | 
			
		||||
 | 
			
		||||
            // Update animation lengths
 | 
			
		||||
            if (stageLoopDropdown.value == 3)
 | 
			
		||||
            {
 | 
			
		||||
                stageLengthText.text = "Stage length (quickie): " + Workspace.GetCurrentAnimationStage().PlayTimeTicksQuick + " (" + Workspace.animationDef.AnimationStages[Workspace.StageID].PlayTimeTicksQuick / 60f + " s)";
 | 
			
		||||
                animationLengthText.text = "Animation length (quickie): " + Workspace.animationDef.animationTimeTicksQuick + " (" + Workspace.animationDef.animationTimeTicksQuick / 60f + " s)";
 | 
			
		||||
 | 
			
		||||
                LayoutRebuilder.ForceRebuildLayoutImmediate(stageLengthText.GetComponent<RectTransform>());
 | 
			
		||||
                LayoutRebuilder.ForceRebuildLayoutImmediate(animationLengthText.GetComponent<RectTransform>());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            { 
 | 
			
		||||
                stageLengthText.text = "Stage length (normal): " + Workspace.animationDef.AnimationStages[Workspace.StageID].PlayTimeTicks + " (" + Workspace.animationDef.AnimationStages[Workspace.StageID].PlayTimeTicks / 60f + " s)";
 | 
			
		||||
                animationLengthText.text = "Animation length (normal): " + Workspace.animationDef.animationTimeTicks + " (" + Workspace.animationDef.animationTimeTicks / 60f + " s)";
 | 
			
		||||
                
 | 
			
		||||
                LayoutRebuilder.ForceRebuildLayoutImmediate(stageLengthText.GetComponent<RectTransform>());
 | 
			
		||||
                LayoutRebuilder.ForceRebuildLayoutImmediate(animationLengthText.GetComponent<RectTransform>());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Update tick if animating
 | 
			
		||||
            Workspace.StageTick = Mathf.Clamp(Workspace.StageTick, Constants.minTick, Workspace.StageWindowSize);
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            // Update stage tick / loop count if animating
 | 
			
		||||
            if (isAnimating)
 | 
			
		||||
            {
 | 
			
		||||
                timeSinceLastUpdate += Time.deltaTime;
 | 
			
		||||
| 
						 | 
				
			
			@ -101,204 +52,150 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
                if (Workspace.StageTick > Workspace.StageWindowSize)
 | 
			
		||||
                {
 | 
			
		||||
                    if (stageLoopDropdown.value == 1)
 | 
			
		||||
                    { Workspace.StageTick = Constants.minTick; }
 | 
			
		||||
 | 
			
		||||
                    else if (stageLoopDropdown.value >= 2)
 | 
			
		||||
                    switch (stageLoopDropdown.value)
 | 
			
		||||
                    {
 | 
			
		||||
                        ++cycleIndex;
 | 
			
		||||
                        Workspace.StageTick = Constants.minTick;
 | 
			
		||||
 | 
			
		||||
                        if ((stageLoopDropdown.value == 2 && cycleIndex >= int.Parse(cyclesNormalField.text)) || 
 | 
			
		||||
                            (stageLoopDropdown.value == 3 && cycleIndex >= int.Parse(cyclesFastField.text)))
 | 
			
		||||
                        {
 | 
			
		||||
                            ++Workspace.StageID;
 | 
			
		||||
                            cycleIndex = 0;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (Workspace.StageID > Workspace.animationDef.AnimationStages.Count - 1)
 | 
			
		||||
                        {
 | 
			
		||||
                            Workspace.StageID = Workspace.animationDef.AnimationStages.Count - 1;
 | 
			
		||||
                            Workspace.StageTick = Workspace.StageWindowSize;
 | 
			
		||||
                            isAnimating = false;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else
 | 
			
		||||
                    { 
 | 
			
		||||
                        //stageTick = Workspace.StageWindowSize; 
 | 
			
		||||
                        //isAnimating = false; 
 | 
			
		||||
                        case 1: Workspace.StageTick = Constants.minTick; break;
 | 
			
		||||
                        case 2: UpdateLoopCount(Workspace.GetCurrentAnimationStage().StageLoopsNormal); break;
 | 
			
		||||
                        case 3: UpdateLoopCount(Workspace.GetCurrentAnimationStage().StageLoopsQuick); break;
 | 
			
		||||
                        default: break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Update stage timeline
 | 
			
		||||
            animationClipTimeField.interactable = isAnimating == false;
 | 
			
		||||
            animationClipLengthField.interactable = isAnimating == false;
 | 
			
		||||
 | 
			
		||||
            if (lastStageTick != Workspace.StageTick)
 | 
			
		||||
            {
 | 
			
		||||
                stageTimelineSlider.value = Workspace.StageTick;
 | 
			
		||||
                animationClipTimeField.text = Workspace.StageTick.ToString();
 | 
			
		||||
                
 | 
			
		||||
                lastStageTick = Workspace.StageTick;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            playToggleButton.image.color = isAnimating ? Constants.ColorGoldYellow : Constants.ColorWhite;
 | 
			
		||||
 | 
			
		||||
            // Update animation
 | 
			
		||||
            UpdateAnimation();
 | 
			
		||||
            // Update animation preview
 | 
			
		||||
            UpdateAnimationPReview();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void UpdateAnimation()
 | 
			
		||||
        public void UpdateLoopCount(int stageLoops)
 | 
			
		||||
        {
 | 
			
		||||
            List<ActorBody> _actorBodies = actorBodies.GetComponentsInChildren<ActorBody>().ToList();
 | 
			
		||||
            ++loopCount;
 | 
			
		||||
            Workspace.StageTick = Constants.minTick;
 | 
			
		||||
 | 
			
		||||
            for (int actorID = 0; actorID < _actorBodies.Count; actorID++)
 | 
			
		||||
            if (loopCount >= stageLoops)
 | 
			
		||||
            {
 | 
			
		||||
                if (Workspace.StageID >= Workspace.animationDef?.AnimationStages.Count) return;
 | 
			
		||||
                ++Workspace.StageID;
 | 
			
		||||
                loopCount = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (Workspace.StageID >= Workspace.animationDef.AnimationStages.Count - 1)
 | 
			
		||||
            {
 | 
			
		||||
                Workspace.StageTick = Workspace.StageWindowSize;
 | 
			
		||||
                Workspace.isAnimating = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void UpdateAnimationPReview()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null || Workspace.StageID >= Workspace.animationDef?.AnimationStages.Count) return;
 | 
			
		||||
 | 
			
		||||
            List<ActorBody> actorBodiesList = actorBodies.GetComponentsInChildren<ActorBody>().ToList();
 | 
			
		||||
 | 
			
		||||
            for (int actorID = 0; actorID < actorBodiesList.Count; actorID++)
 | 
			
		||||
            {
 | 
			
		||||
                // Get the current actor and their animation clip
 | 
			
		||||
                Actor actor = Workspace.GetActor(actorID);
 | 
			
		||||
                PawnAnimationClip clip = Workspace.GetPawnAnimationClip(actorID);
 | 
			
		||||
 | 
			
		||||
                // Get flags
 | 
			
		||||
                bool quiver = isAnimating && Workspace.GetCurrentOrPreviousKeyframe(actorID).Quiver == true;
 | 
			
		||||
                bool requiresGenitals = actor.RequiredGenitals.Any(x => x == "Penis") || actor.IsFucking;
 | 
			
		||||
 | 
			
		||||
                // Get clip percentage
 | 
			
		||||
                float clipPercent = clip.GetStageTickPercentage();
 | 
			
		||||
                if (Workspace.StageTick > Constants.minTick && Workspace.StageTick == clip.duration) clipPercent = 1f;
 | 
			
		||||
 | 
			
		||||
                if (Workspace.GetCurrentAnimationStage().IsLooping == false)
 | 
			
		||||
                { clipPercent = (float)Workspace.StageTick / clip.duration; }
 | 
			
		||||
                
 | 
			
		||||
                PawnRaceDef pawnRaceDef = actor.GetPawnRaceDef();
 | 
			
		||||
                ActorBody actorBody = _actorBodies[actorID];
 | 
			
		||||
                // Get the actors race and body type
 | 
			
		||||
                PawnRaceDef pawnRaceDef = actor.GetPawnRaceDef();            
 | 
			
		||||
                string bodyType = pawnRaceDef.isHumanoid ? actor.bodyType : "None";
 | 
			
		||||
 | 
			
		||||
                Vector3 deltaPos = new Vector3(clip.BodyOffsetX.Evaluate(clipPercent), 0, clip.BodyOffsetZ.Evaluate(clipPercent));
 | 
			
		||||
                // Evalute the actor's basic offsets and facing
 | 
			
		||||
                ActorPosition actorPosition = actor.GetCurrentPosition();
 | 
			
		||||
 | 
			
		||||
                float bodyAngle = clip.BodyAngle.Evaluate(clipPercent);
 | 
			
		||||
                bodyAngle += quiver ? UnityEngine.Random.value * 2f - 1f : 0f;
 | 
			
		||||
 | 
			
		||||
                float headAngle = clip.HeadAngle.Evaluate(clipPercent);
 | 
			
		||||
 | 
			
		||||
                int bodyFacing = (int)clip.BodyFacing.Evaluate(clipPercent);
 | 
			
		||||
                int headFacing = (int)clip.HeadFacing.Evaluate(clipPercent);
 | 
			
		||||
 | 
			
		||||
                float headBob = clip.HeadBob.Evaluate(clipPercent);
 | 
			
		||||
                Vector3 headOffset = new Vector3(0, 0, headBob) + PawnUtility.BaseHeadOffsetAt(bodyType, bodyFacing);
 | 
			
		||||
 | 
			
		||||
                Vector3 bodyPos = new Vector3(deltaPos.x, deltaPos.z, 0);
 | 
			
		||||
                Vector3 headPos = new Vector3(headOffset.x, headOffset.z, 0);
 | 
			
		||||
                float bodyPosX = actorPosition.bodyOffsetX;
 | 
			
		||||
                float bodyPosZ = actorPosition.bodyOffsetZ;
 | 
			
		||||
                float bodyAngle = actorPosition.bodyAngle + (quiver ? UnityEngine.Random.value * 2f - 1f : 0f);
 | 
			
		||||
                float headBob = actorPosition.headBob;
 | 
			
		||||
                float headAngle = actorPosition.headAngle;
 | 
			
		||||
                float genitalAngle = actorPosition.genitalAngle;
 | 
			
		||||
 | 
			
		||||
                int bodyFacing = actorPosition.bodyFacing;
 | 
			
		||||
                int headFacing = actorPosition.headFacing;
 | 
			
		||||
             
 | 
			
		||||
                // Convert values to world coordinates
 | 
			
		||||
                Vector3 bodyPos = new Vector3(bodyPosX, bodyPosZ, 0f);
 | 
			
		||||
                Vector3 headPos = new Vector3(0f, headBob, 0f) + PawnUtility.BaseHeadOffsetAt(bodyType, bodyFacing);
 | 
			
		||||
                Vector3 appendagePos = PawnUtility.GroinOffsetAt(bodyType, bodyFacing);
 | 
			
		||||
                float appendageRotation = clip.GenitalAngle.Evaluate(clipPercent);
 | 
			
		||||
 | 
			
		||||
                actorBody.transform.position = bodyPos + actor.GetFinalTransformOffset();
 | 
			
		||||
                actorBody.transform.eulerAngles = new Vector3(0, 0, -bodyAngle);
 | 
			
		||||
 | 
			
		||||
                actorBody.headRenderer.transform.localPosition = headPos;
 | 
			
		||||
                actorBody.headRenderer.transform.eulerAngles = new Vector3(0, 0, -headAngle);
 | 
			
		||||
 | 
			
		||||
                actorBody.appendageRenderer.transform.localPosition = new Vector3(appendagePos.x, appendagePos.z, 0f);
 | 
			
		||||
                actorBody.appendageRenderer.transform.eulerAngles = new Vector3(0, 0, -appendageRotation);
 | 
			
		||||
 | 
			
		||||
                actorBody.bodyRenderer.sprite = pawnRaceDef.GetBodyTypeGraphic((CardinalDirection)bodyFacing, bodyType);
 | 
			
		||||
                actorBody.headRenderer.sprite = pawnRaceDef.isHumanoid ? pawnRaceDef.GetHeadGraphic((CardinalDirection)headFacing) : null;
 | 
			
		||||
                actorBody.appendageRenderer.sprite = requiresGenitals && pawnRaceDef.isHumanoid && bodyFacing != 0 ? Resources.Load<Sprite>("Textures/Humanlike/Appendages/Appendage" + bodyFacing) : null;
 | 
			
		||||
 | 
			
		||||
                actorBody.bodyRenderer.gameObject.SetActive(actorBody.bodyRenderer.sprite != null);
 | 
			
		||||
                actorBody.headRenderer.gameObject.SetActive(actorBody.headRenderer.sprite != null);
 | 
			
		||||
                actorBody.appendageRenderer.gameObject.SetActive(actorBody.appendageRenderer.sprite != null);
 | 
			
		||||
 | 
			
		||||
                actorBody.bodyRenderer.sortingLayerName = clip.Layer;
 | 
			
		||||
                actorBody.headRenderer.sortingLayerName = clip.Layer;
 | 
			
		||||
                actorBody.headRenderer.sortingOrder = bodyFacing == 0 ? -1 : 1;
 | 
			
		||||
                actorBody.appendageRenderer.sortingLayerName = clip.Layer;
 | 
			
		||||
 | 
			
		||||
                actorBody.bodyRenderer.flipX = bodyFacing == 3;
 | 
			
		||||
                actorBody.headRenderer.flipX = headFacing == 3;
 | 
			
		||||
                //actorBody.appendageRenderer.flipX = bodyFacing == 3;
 | 
			
		||||
                // Update actorbody
 | 
			
		||||
                ActorBody actorBody = actorBodiesList[actorID];
 | 
			
		||||
                ActorBodyPart actorBodypart;
 | 
			
		||||
 | 
			
		||||
                actorBody.transform.localScale = new Vector3(pawnRaceDef.scale, pawnRaceDef.scale, pawnRaceDef.scale);
 | 
			
		||||
 | 
			
		||||
                // ActorKeyframeCard update
 | 
			
		||||
                if (actorID != Workspace.ActorID) continue;
 | 
			
		||||
                if (ActorKeyframeCard.Instance.positionXField.isFocused == false) { ActorKeyframeCard.Instance.positionXField.text = bodyPos.x.ToString("0.000"); }
 | 
			
		||||
                if (ActorKeyframeCard.Instance.positionZField.isFocused == false) { ActorKeyframeCard.Instance.positionZField.text = bodyPos.y.ToString("0.000"); }
 | 
			
		||||
                if (ActorKeyframeCard.Instance.rotationField.isFocused == false) { ActorKeyframeCard.Instance.rotationField.text = bodyAngle.ToString("0.000"); }
 | 
			
		||||
                if (ActorKeyframeCard.Instance.headBobField.isFocused == false) { ActorKeyframeCard.Instance.headBobField.text = headBob.ToString("0.000"); }
 | 
			
		||||
                if (ActorKeyframeCard.Instance.headRotationField.isFocused == false) { ActorKeyframeCard.Instance.headRotationField.text = headAngle.ToString("0.000"); }
 | 
			
		||||
                if (ActorKeyframeCard.Instance.appendageRotationField.isFocused == false) { ActorKeyframeCard.Instance.appendageRotationField.text = appendageRotation.ToString("0.000"); }
 | 
			
		||||
                // Body
 | 
			
		||||
                actorBody.transform.position = bodyPos + actor.GetFinalTransformOffset();
 | 
			
		||||
                actorBody.transform.eulerAngles = new Vector3(0, 0, -bodyAngle);
 | 
			
		||||
 | 
			
		||||
                if (actorID == Workspace.ActorID)
 | 
			
		||||
                {
 | 
			
		||||
                    //handLeftControls.SetActive(clip.GetActorAddon("left hand").Render);
 | 
			
		||||
                    //handRightControls.SetActive(clip.GetActorAddon("right hand").Render);
 | 
			
		||||
                    //sexToyControls.SetActive(clip.GetActorAddon("dildo").Render);
 | 
			
		||||
                }
 | 
			
		||||
                actorBody.bodyRenderer.sortingLayerName = clip.Layer;
 | 
			
		||||
                actorBody.bodyRenderer.sprite = pawnRaceDef.GetBodyTypeGraphic((CardinalDirection)bodyFacing, bodyType);
 | 
			
		||||
                actorBody.bodyRenderer.flipX = bodyFacing == 3;
 | 
			
		||||
 | 
			
		||||
                actorBody.bodyRenderer.gameObject.SetActive(actorBody.bodyRenderer.sprite != null);
 | 
			
		||||
 | 
			
		||||
                // Head
 | 
			
		||||
                actorBodypart = actorBody.GetBodyPart("head");
 | 
			
		||||
 | 
			
		||||
                actorBodypart.transform.localPosition = headPos;
 | 
			
		||||
                actorBodypart.transform.eulerAngles = new Vector3(0, 0, -headAngle);
 | 
			
		||||
 | 
			
		||||
                actorBodypart.bodyPartRenderer.sortingLayerName = clip.Layer;
 | 
			
		||||
                actorBodypart.bodyPartRenderer.sortingOrder = bodyFacing == 0 ? -1 : 1;
 | 
			
		||||
                actorBodypart.bodyPartRenderer.sprite = pawnRaceDef.isHumanoid ? pawnRaceDef.GetHeadGraphic((CardinalDirection)headFacing) : null;
 | 
			
		||||
                actorBodypart.bodyPartRenderer.flipX = headFacing == 3;
 | 
			
		||||
 | 
			
		||||
                actorBodypart.gameObject.SetActive(actorBodypart.bodyPartRenderer.sprite != null);
 | 
			
		||||
 | 
			
		||||
                // Appendage
 | 
			
		||||
                actorBodypart = actorBody.GetBodyPart("appendage");
 | 
			
		||||
 | 
			
		||||
                actorBodypart.transform.localPosition = new Vector3(appendagePos.x, appendagePos.z, 0f);
 | 
			
		||||
                actorBodypart.transform.eulerAngles = new Vector3(0, 0, -genitalAngle);
 | 
			
		||||
 | 
			
		||||
                actorBodypart.bodyPartRenderer.sortingLayerName = clip.Layer;
 | 
			
		||||
                actorBodypart.bodyPartRenderer.sprite = requiresGenitals && pawnRaceDef.isHumanoid && bodyFacing != 0 ? Resources.Load<Sprite>("Textures/Humanlike/Appendages/Appendage" + bodyFacing) : null;
 | 
			
		||||
                //actorBody.appendageRenderer.flipX = bodyFacing == 3;
 | 
			
		||||
 | 
			
		||||
                actorBodypart.gameObject.SetActive(actorBodypart.bodyPartRenderer.sprite != null);
 | 
			
		||||
 | 
			
		||||
                // Add-ons
 | 
			
		||||
                foreach (ActorAddon addon in clip.Addons)
 | 
			
		||||
                {
 | 
			
		||||
                    ActorBodyPart bodyPart = actorBody.GetComponentsInChildren<ActorBodyPart>()?.FirstOrDefault(x => x.addonName == addon.AddonName);
 | 
			
		||||
                    if (bodyPart == null) continue;
 | 
			
		||||
 | 
			
		||||
                    Vector3 anchor;
 | 
			
		||||
 | 
			
		||||
                    actorBodypart = actorBody.GetBodyPart(addon.AddonName);
 | 
			
		||||
     
 | 
			
		||||
                    ActorBody anchoringActorBody = actorBodies.GetComponentsInChildren<ActorBody>()?.FirstOrDefault(x => x.actorID == addon.AnchoringActor);
 | 
			
		||||
                    bodyPos = new Vector3(anchoringActorBody.transform.position.x, anchoringActorBody.transform.position.y, 0);
 | 
			
		||||
                    pawnRaceDef = Workspace.animationDef.Actors[addon.AnchoringActor].GetPawnRaceDef();
 | 
			
		||||
                    Actor anchoringActor = Workspace.animationDef.Actors[addon.AnchoringActor];
 | 
			
		||||
                    bodyFacing = (int)Workspace.animationDef.AnimationStages[Workspace.StageID].AnimationClips[addon.AnchoringActor].BodyFacing.Evaluate(clipPercent);
 | 
			
		||||
                    Vector3 anchor = PawnUtility.GetBodyPartAnchor(anchoringActorBody, addon.addonName);
 | 
			
		||||
 | 
			
		||||
                    switch (addon.AnchorName)
 | 
			
		||||
                    {
 | 
			
		||||
                        case "torso": anchor = bodyPos; break;
 | 
			
		||||
                        case "head": anchor = new Vector3(anchoringActorBody.transform.Find("ActorHead").position.x, anchoringActorBody.transform.Find("ActorHead").position.y, 0); break;
 | 
			
		||||
                        case "groin": anchor = bodyPos + Quaternion.AngleAxis(anchoringActorBody.transform.rotation.eulerAngles.z, Vector3.forward) * PawnUtility.GroinOffsetAt(anchoringActor.bodyType, bodyFacing).FlipAxes(); break;
 | 
			
		||||
                        case "left breast": anchor = bodyPos + Quaternion.AngleAxis(anchoringActorBody.transform.rotation.eulerAngles.z, Vector3.forward) * PawnUtility.BreastLeftOffsetAt(anchoringActor.bodyType, bodyFacing).FlipAxes(); break;
 | 
			
		||||
                        case "right breast": anchor = bodyPos + Quaternion.AngleAxis(anchoringActorBody.transform.rotation.eulerAngles.z, Vector3.forward) * PawnUtility.BreastRightOffsetAt(anchoringActor.bodyType, bodyFacing).FlipAxes(); break;
 | 
			
		||||
                        default: anchor = new Vector3(); break;
 | 
			
		||||
                    }
 | 
			
		||||
                    actorBodypart.transform.position = anchor + new Vector3(addon.PosX.Evaluate(clipPercent), addon.PosZ.Evaluate(clipPercent), 0);
 | 
			
		||||
                    actorBodypart.transform.eulerAngles = new Vector3(0, 0, -addon.Rotation.Evaluate(clipPercent));
 | 
			
		||||
 | 
			
		||||
                    bodyPart.transform.position = anchor + new Vector3(addon.PosX.Evaluate(clipPercent), addon.PosZ.Evaluate(clipPercent), 0);
 | 
			
		||||
                    bodyPart.transform.eulerAngles = new Vector3(0, 0, -addon.Rotation.Evaluate(clipPercent));
 | 
			
		||||
                    bodyPart.GetComponent<SpriteRenderer>().sortingLayerName = addon.Layer;
 | 
			
		||||
                    actorBodypart.bodyPartRenderer.sortingLayerName = addon.Layer;
 | 
			
		||||
                    //actorBodypart.bodyPartRenderer.sprite
 | 
			
		||||
 | 
			
		||||
                    actorBodypart.gameObject.SetActive(addon.Render);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Initialize()
 | 
			
		||||
        {
 | 
			
		||||
            isDirty = true;
 | 
			
		||||
            Debug.Log("Initializing animation preview");
 | 
			
		||||
 | 
			
		||||
            foreach (Transform child in transform)
 | 
			
		||||
            { child.gameObject.SetActive(true); }
 | 
			
		||||
 | 
			
		||||
            InitializeAnimationTimeline();
 | 
			
		||||
            StageCardManager.Instance.Initialize();
 | 
			
		||||
 | 
			
		||||
            isDirty = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Reset()
 | 
			
		||||
        {
 | 
			
		||||
            isAnimating = false;
 | 
			
		||||
            timeSinceLastUpdate = 0;
 | 
			
		||||
            cycleIndex = 0;
 | 
			
		||||
 | 
			
		||||
            MakeDirty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void InitializeAnimationTimeline()
 | 
			
		||||
        {
 | 
			
		||||
            isTimelineDirty = true;
 | 
			
		||||
 | 
			
		||||
            cyclesNormalField.text = Mathf.Max(Mathf.CeilToInt((float)Workspace.animationDef.AnimationStages[Workspace.StageID].PlayTimeTicks / Workspace.StageWindowSize), 1).ToString();
 | 
			
		||||
            cyclesFastField.text = Mathf.Max(Mathf.CeilToInt((float)Workspace.animationDef.AnimationStages[Workspace.StageID].PlayTimeTicksQuick / Workspace.StageWindowSize), 0).ToString();
 | 
			
		||||
 | 
			
		||||
            Workspace.animationDef.AnimationStages[Workspace.StageID].IsLooping = int.Parse(cyclesNormalField.text) > 1 ? true : false;
 | 
			
		||||
 | 
			
		||||
            int actorCount = Workspace.animationDef.Actors.Count;
 | 
			
		||||
            int childCount = animationTimelines.GetComponentsInChildren<AnimationTimeline>().Count();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +203,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            {
 | 
			
		||||
                // Add new actors as required
 | 
			
		||||
                if (actorID >= childCount)
 | 
			
		||||
                { 
 | 
			
		||||
                {
 | 
			
		||||
                    Instantiate(animationTimelinePrefab, animationTimelines);
 | 
			
		||||
                    Instantiate(actorBodyPrefab, actorBodies.transform);
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -324,125 +221,21 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
                // Remove excess objects as required
 | 
			
		||||
                else
 | 
			
		||||
                { 
 | 
			
		||||
                {
 | 
			
		||||
                    Destroy(animationTimeline.transform.parent.gameObject);
 | 
			
		||||
                    Destroy(actorBody.gameObject);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            animationClipLengthField.text = Workspace.StageWindowSize.ToString();
 | 
			
		||||
            stageTimelineSlider.maxValue = Workspace.StageWindowSize;
 | 
			
		||||
 | 
			
		||||
            isTimelineDirty = false;
 | 
			
		||||
 | 
			
		||||
            foreach (AnimationTimeline timeline in animationTimelines.GetComponentsInChildren<AnimationTimeline>())
 | 
			
		||||
            { timeline.InitiateUpdateOfGhostFrames(); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ToggleAnimation()
 | 
			
		||||
        public void Reset()
 | 
			
		||||
        {
 | 
			
		||||
            isAnimating = !isAnimating;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnStageTimelineSliderChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            if (Workspace.StageTick != (int)stageTimelineSlider.value)
 | 
			
		||||
            {
 | 
			
		||||
                Workspace.StageTick = (int)stageTimelineSlider.value;
 | 
			
		||||
                animationClipTimeField.text = Workspace.StageTick.ToString();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnAnimationClipTimeFieldChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            int.TryParse(animationClipTimeField.text, out int newStageTick);
 | 
			
		||||
            Workspace.StageTick = Mathf.Clamp(newStageTick, Constants.minTick, Workspace.StageWindowSize);
 | 
			
		||||
            stageTimelineSlider.value = Workspace.StageTick;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnAnimationClipLengthFieldChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            int.TryParse(animationClipLengthField.text, out int newStageWindowSize);
 | 
			
		||||
            newStageWindowSize = Mathf.Clamp(newStageWindowSize, Constants.minAnimationClipLength, Constants.maxAnimationClipLength);
 | 
			
		||||
 | 
			
		||||
            Debug.Log("Resizing animation clip length to " + newStageWindowSize.ToString() + " ticks.");
 | 
			
		||||
 | 
			
		||||
            if (stretchKeyframesToggle.isOn)
 | 
			
		||||
            { Workspace.GetCurrentAnimationStage().StretchStageWindow(newStageWindowSize); }
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                for (int i = 0; i < Workspace.animationDef.AnimationStages[Workspace.StageID].AnimationClips.Count; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    PawnAnimationClip clip = Workspace.animationDef.AnimationStages[Workspace.StageID].AnimationClips[i];
 | 
			
		||||
                    List<PawnKeyframe> keyframes = clip.Keyframes.Where(x => x.atTick > newStageWindowSize)?.ToList();
 | 
			
		||||
 | 
			
		||||
                    if (keyframes.NullOrEmpty())
 | 
			
		||||
                    { continue; }
 | 
			
		||||
 | 
			
		||||
                    foreach (PawnKeyframe keyframe in keyframes)
 | 
			
		||||
                    {
 | 
			
		||||
                        clip.RemovePawnKeyframe(i, keyframe.keyframeID);
 | 
			
		||||
 | 
			
		||||
                        if (Workspace.animationDef.AnimationStages[Workspace.StageID].AnimationClips[i].Keyframes.Count <= 2)
 | 
			
		||||
                        { break; }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Workspace.GetCurrentAnimationStage().ResizeStageWindow(newStageWindowSize);
 | 
			
		||||
            Workspace.RecordEvent("Stage length");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnCycleNormalFieldChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            if (int.TryParse(cyclesNormalField.text, out int cycles))
 | 
			
		||||
            {
 | 
			
		||||
                cycles = cycles <= 0 ? 1 : cycles;
 | 
			
		||||
                cyclesNormalField.text = cycles.ToString();
 | 
			
		||||
 | 
			
		||||
                Workspace.animationDef.AnimationStages[Workspace.StageID].PlayTimeTicks = cycles * Workspace.StageWindowSize; 
 | 
			
		||||
                Workspace.animationDef.AnimationStages[Workspace.StageID].IsLooping = cycles > 1;
 | 
			
		||||
 | 
			
		||||
                foreach(AnimationTimeline animationTimeline in animationTimelines.GetComponentsInChildren<AnimationTimeline>())
 | 
			
		||||
                { animationTimeline.InitiateUpdateOfGhostFrames(); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Workspace.RecordEvent("Cycle count (normal)");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnCycleFastFieldChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            if (int.TryParse(cyclesFastField.text, out int fastCycles))
 | 
			
		||||
            {
 | 
			
		||||
                fastCycles = fastCycles < 0 ? 0 : fastCycles;
 | 
			
		||||
 | 
			
		||||
                int.TryParse(cyclesNormalField.text, out int cycles);
 | 
			
		||||
                if (fastCycles > cycles) fastCycles = cycles;
 | 
			
		||||
                cyclesFastField.text = fastCycles.ToString();
 | 
			
		||||
 | 
			
		||||
                Workspace.animationDef.AnimationStages[Workspace.StageID].PlayTimeTicksQuick = fastCycles * Workspace.StageWindowSize;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Workspace.RecordEvent("Cycle count (fast)");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OnPlayBackSpeedChange()
 | 
			
		||||
        {
 | 
			
		||||
            if (float.TryParse(playBackSpeedField.text, out playBackSpeed))
 | 
			
		||||
            { playBackSpeed = Mathf.Clamp(playBackSpeed, 0.01f, 16f); }
 | 
			
		||||
 | 
			
		||||
            playBackSpeedField.text = playBackSpeed.ToString();
 | 
			
		||||
            Workspace.isAnimating = false;
 | 
			
		||||
            timeSinceLastUpdate = 0;
 | 
			
		||||
            loopCount = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,7 +73,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            AnimationController.Instance.Reset();
 | 
			
		||||
            Workspace.Reset();
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnAnimationDefChanged();
 | 
			
		||||
            EventsManager.OnAnimationChanged();
 | 
			
		||||
            Workspace.RecordEvent("AnimationDef loaded");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -204,7 +204,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public void ToggleAnimationPreview()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            AnimationController.Instance.ToggleAnimation();
 | 
			
		||||
            Workspace.isAnimating = !Workspace.isAnimating;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AddKeyframe()
 | 
			
		||||
| 
						 | 
				
			
			@ -228,7 +228,9 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public void DeleteKeyframes()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            Workspace.GetCurrentPawnAnimationClip().RemovePawnKeyframe();
 | 
			
		||||
 | 
			
		||||
            foreach (int keyframeID in Workspace.keyframeID)
 | 
			
		||||
            { Workspace.GetAnimationClipThatOwnsKeyframe(keyframeID).RemovePawnKeyframe(keyframeID); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ActorMovementMode()
 | 
			
		||||
| 
						 | 
				
			
			@ -249,49 +251,65 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public void AdjustActorUpward()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            ActorKeyframeCard.Instance.AdjustActor(Vector2.up * largeStep);
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            keyframe.AdjustActor(Vector2.up * largeStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustActorDownward()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            ActorKeyframeCard.Instance.AdjustActor(Vector2.down * largeStep);
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            keyframe.AdjustActor(Vector2.down * largeStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustActorLeftward()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            ActorKeyframeCard.Instance.AdjustActor(Vector2.left * largeStep);
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            keyframe.AdjustActor(Vector2.left * largeStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustActorRightward()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            ActorKeyframeCard.Instance.AdjustActor(Vector2.right * largeStep);
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            keyframe.AdjustActor(Vector2.right * largeStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustActorUpwardSmall()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            ActorKeyframeCard.Instance.AdjustActor(Vector2.up * smallStep);
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            keyframe.AdjustActor(Vector2.up * smallStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustActorDownwardSmall()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            ActorKeyframeCard.Instance.AdjustActor(Vector2.down * smallStep);
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            keyframe.AdjustActor(Vector2.down * smallStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustActorLeftwardSmall()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            ActorKeyframeCard.Instance.AdjustActor(Vector2.left * smallStep);
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            keyframe.AdjustActor(Vector2.left * smallStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AdjustActorRightwardSmall()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
            ActorKeyframeCard.Instance.AdjustActor(Vector2.right * smallStep);
 | 
			
		||||
 | 
			
		||||
            PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
 | 
			
		||||
            keyframe.AdjustActor(Vector2.right * smallStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void CycleActorBodyPartSelecion()
 | 
			
		||||
| 
						 | 
				
			
			@ -407,7 +425,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        public void StretchKeyframesToggle()
 | 
			
		||||
        {
 | 
			
		||||
            AnimationController.Instance.stretchKeyframesToggle.isOn = !AnimationController.Instance.stretchKeyframesToggle.isOn;
 | 
			
		||||
            Workspace.stretchKeyframes = !Workspace.stretchKeyframes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OpenProjectHome()
 | 
			
		||||
| 
						 | 
				
			
			@ -435,5 +453,26 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
            Workspace.animationDef.RemoveActor();
 | 
			
		||||
        }    
 | 
			
		||||
 | 
			
		||||
        public void AddStage()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            Workspace.animationDef.AddAnimationStage();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void CloneStage()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            Workspace.animationDef.CloneAnimationStage();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RemoveStage()
 | 
			
		||||
        {
 | 
			
		||||
            if (Workspace.animationDef == null) return;
 | 
			
		||||
 | 
			
		||||
            Workspace.animationDef.RemoveAnimationStage();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,11 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        public void Start()
 | 
			
		||||
        {
 | 
			
		||||
            EventsManager.onAnimationChanged.AddListener(delegate { Initialize(); });
 | 
			
		||||
            EventsManager.onStageIDChanged.AddListener(delegate { Initialize(); });
 | 
			
		||||
            EventsManager.onStageCountChanged.AddListener(delegate { Initialize(); });
 | 
			
		||||
 | 
			
		||||
            Initialize();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Initialize()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,10 +24,10 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
			switch (rotation)
 | 
			
		||||
			{
 | 
			
		||||
				case 0: return new Vector3(0f, 0f, headOffset.y);
 | 
			
		||||
				case 1: return new Vector3(headOffset.x, 0f, headOffset.y);
 | 
			
		||||
				case 2: return new Vector3(0f, 0f, headOffset.y);
 | 
			
		||||
				case 3: return new Vector3(-headOffset.x, 0f, headOffset.y);
 | 
			
		||||
				case 0: return new Vector3(0f, headOffset.y, 0);
 | 
			
		||||
				case 1: return new Vector3(headOffset.x, headOffset.y, 0);
 | 
			
		||||
				case 2: return new Vector3(0f, headOffset.y, 0f);
 | 
			
		||||
				case 3: return new Vector3(-headOffset.x, headOffset.y, 0f);
 | 
			
		||||
				default: return Vector3.zero;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -161,5 +161,23 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Vector3 GetBodyPartAnchor(ActorBody anchoringActorBody, string anchorName)
 | 
			
		||||
		{
 | 
			
		||||
			Actor anchoringActor = Workspace.GetActor(anchoringActorBody.actorID);
 | 
			
		||||
			Vector3 anchoringActorBodyPos = anchoringActorBody.transform.position;
 | 
			
		||||
			Quaternion anchoringActorBodyQuad = Quaternion.AngleAxis(anchoringActorBody.transform.rotation.eulerAngles.z, Vector3.forward);
 | 
			
		||||
			int anchoringActorFacing = anchoringActor.GetCurrentPosition().bodyFacing;
 | 
			
		||||
 | 
			
		||||
			switch (anchorName)
 | 
			
		||||
			{
 | 
			
		||||
				case "torso": return anchoringActorBodyPos;
 | 
			
		||||
				case "head": return anchoringActorBody.GetComponentsInChildren<ActorBodyPart>().FirstOrDefault(x => x.bodyPart.ToLower() == "head").transform.position;
 | 
			
		||||
				case "groin": return anchoringActorBodyPos + anchoringActorBodyQuad * PawnUtility.GroinOffsetAt(anchoringActor.bodyType, anchoringActorFacing).FlipAxes();
 | 
			
		||||
				case "left breast": return anchoringActorBodyPos + anchoringActorBodyQuad * PawnUtility.BreastLeftOffsetAt(anchoringActor.bodyType, anchoringActorFacing).FlipAxes();
 | 
			
		||||
				case "right breast": return anchoringActorBodyPos + anchoringActorBodyQuad * PawnUtility.BreastRightOffsetAt(anchoringActor.bodyType, anchoringActorFacing).FlipAxes();
 | 
			
		||||
				default: return new Vector3();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,8 +18,12 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public class PawnKeyframeEvent : UnityEvent<PawnKeyframe> { }
 | 
			
		||||
        public class ActorAddonEvent : UnityEvent<ActorAddon> { }
 | 
			
		||||
        public class AddonKeyframeEvent : UnityEvent<AddonKeyframe> { }
 | 
			
		||||
        public class ActorBodyEvent : UnityEvent<ActorBody> { }
 | 
			
		||||
        public class ActorBodyPartEvent : UnityEvent<ActorBodyPart> { }
 | 
			
		||||
 | 
			
		||||
        // Event list
 | 
			
		||||
        public static UnityEvent onAnimationToggled = new UnityEvent();
 | 
			
		||||
        public static UnityEvent onAnimationChanged = new UnityEvent();
 | 
			
		||||
        public static UnityEvent onAnimationDefChanged = new UnityEvent();
 | 
			
		||||
        public static WorkspaceIntEvent onActorIDChanged = new WorkspaceIntEvent();
 | 
			
		||||
        public static WorkspaceIntEvent onStageIDChanged = new WorkspaceIntEvent();
 | 
			
		||||
| 
						 | 
				
			
			@ -29,13 +33,18 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public static WorkspaceIntEvent onKeyframeCountChanged = new WorkspaceIntEvent();
 | 
			
		||||
        public static ActorEvent onActorChanged = new ActorEvent();
 | 
			
		||||
        public static AnimationStageEvent onAnimationStageChanged = new AnimationStageEvent();
 | 
			
		||||
        public static AnimationStageEvent onStageWindowSizeChanged = new AnimationStageEvent();
 | 
			
		||||
        public static PawnAnimationClipEvent onPawnAnimationClipChanged = new PawnAnimationClipEvent();
 | 
			
		||||
        public static PawnKeyframeEvent onPawnKeyframeChanged = new PawnKeyframeEvent();
 | 
			
		||||
        public static ActorAddonEvent onActorAddonChanged = new ActorAddonEvent();
 | 
			
		||||
        public static AddonKeyframeEvent onAddonKeyframeChanged = new AddonKeyframeEvent();
 | 
			
		||||
        public static UnityEvent onDefNamesChanged = new UnityEvent();
 | 
			
		||||
        public static ActorBodyEvent onActorBodySelected = new ActorBodyEvent();
 | 
			
		||||
        public static ActorBodyPartEvent onActorBodyPartSelected = new ActorBodyPartEvent();
 | 
			
		||||
 | 
			
		||||
        // Event invoking
 | 
			
		||||
        public static void OnAnimationToggled() { onAnimationToggled.Invoke(); }
 | 
			
		||||
        public static void OnAnimationChanged() { onAnimationChanged.Invoke(); }
 | 
			
		||||
        public static void OnAnimationDefChanged() { onAnimationDefChanged.Invoke(); }
 | 
			
		||||
        public static void OnActorIDChanged() { onActorIDChanged.Invoke(Workspace.ActorID); }
 | 
			
		||||
        public static void OnStageIDChanged() { onStageIDChanged.Invoke(Workspace.ActorID); }
 | 
			
		||||
| 
						 | 
				
			
			@ -45,10 +54,13 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        public static void OnKeyframeCountChanged(PawnAnimationClip clip) { onKeyframeCountChanged.Invoke(clip.Keyframes.Count); }
 | 
			
		||||
        public static void OnActorChanged(Actor actor) { onActorChanged.Invoke(actor); }
 | 
			
		||||
        public static void OnAnimationStageChanged(AnimationStage stage) { onAnimationStageChanged.Invoke(stage); }
 | 
			
		||||
        public static void OnStageWindowSizeChanged(AnimationStage stage) { onStageWindowSizeChanged.Invoke(stage); }
 | 
			
		||||
        public static void OnPawnAnimationClipChanged(PawnAnimationClip clip) { onPawnAnimationClipChanged.Invoke(clip); }
 | 
			
		||||
        public static void OnPawnKeyframeChanged(PawnKeyframe keyframe) { onPawnKeyframeChanged.Invoke(keyframe); }
 | 
			
		||||
        public static void OnActorAddonChanged(ActorAddon actorAddon) { onActorAddonChanged.Invoke(actorAddon); }
 | 
			
		||||
        public static void OnAddonKeyframeChanged(AddonKeyframe addonKeyframe) { onAddonKeyframeChanged.Invoke(addonKeyframe); }
 | 
			
		||||
        public static void OnDefNamesChanged() { onDefNamesChanged.Invoke(); }
 | 
			
		||||
        public static void OnActorBodySelected(ActorBody actorBody) { onActorBodySelected.Invoke(actorBody); }
 | 
			
		||||
        public static void OnActorBodyPartSelected(ActorBodyPart bodyPart) { onActorBodyPartSelected.Invoke(bodyPart); }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,11 +22,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
                bool triggerEvent = stageID != value;
 | 
			
		||||
                stageID = value;
 | 
			
		||||
 | 
			
		||||
                if (triggerEvent) 
 | 
			
		||||
                {
 | 
			
		||||
                    StageTick = Constants.minTick;
 | 
			
		||||
                    EventsManager.OnStageIDChanged(); 
 | 
			
		||||
                }
 | 
			
		||||
                if (triggerEvent) { StageTick = Constants.minTick; EventsManager.OnStageIDChanged(); }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -78,12 +74,15 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
        
 | 
			
		||||
        // Current save path
 | 
			
		||||
        public static string animationSavePath;
 | 
			
		||||
  
 | 
			
		||||
        // Stage loop counts and stretching
 | 
			
		||||
        public static int stageLoopsNormal = 1;
 | 
			
		||||
        public static int stageLoopsQuick = 1;
 | 
			
		||||
 | 
			
		||||
        // Stage controls
 | 
			
		||||
        private static float playBackSpeed = 1f;
 | 
			
		||||
        public static bool isAnimating;
 | 
			
		||||
        public static bool stretchKeyframes;
 | 
			
		||||
 | 
			
		||||
        // Stage controls set / get
 | 
			
		||||
        public static float PlayBackSpeed { get { return playBackSpeed; } set { Mathf.Clamp(Workspace.playBackSpeed, 0.01f, 10f); } }
 | 
			
		||||
 | 
			
		||||
        // Animation indices
 | 
			
		||||
        private static int stageID = 0;
 | 
			
		||||
        private static int actorID = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -96,17 +95,17 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        public static Actor GetCurrentActor()
 | 
			
		||||
        {
 | 
			
		||||
            return animationDef?.Actors[ActorID];
 | 
			
		||||
            return GetActor(ActorID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static AnimationStage GetCurrentAnimationStage()
 | 
			
		||||
        {
 | 
			
		||||
            return animationDef?.AnimationStages[StageID];
 | 
			
		||||
            return GetAnimationStage(StageID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static PawnAnimationClip GetCurrentPawnAnimationClip()
 | 
			
		||||
        {
 | 
			
		||||
            return animationDef?.AnimationStages[StageID]?.AnimationClips[ActorID];
 | 
			
		||||
            return GetPawnAnimationClip(ActorID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static PawnKeyframe GetCurrentPawnKeyframe(bool makeKeyframe = false)
 | 
			
		||||
| 
						 | 
				
			
			@ -122,28 +121,47 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
 | 
			
		||||
        public static Actor GetActor(int actorID)
 | 
			
		||||
        {
 | 
			
		||||
            return animationDef?.Actors[actorID];
 | 
			
		||||
            return animationDef?.Actors.ElementAtOrDefault(actorID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static AnimationStage GetAnimationStage(int stageID)
 | 
			
		||||
        {
 | 
			
		||||
            return animationDef?.AnimationStages[stageID];
 | 
			
		||||
            return animationDef?.AnimationStages.ElementAtOrDefault(stageID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static PawnAnimationClip GetPawnAnimationClip(int actorID)
 | 
			
		||||
        {
 | 
			
		||||
            return animationDef?.AnimationStages[StageID]?.AnimationClips[actorID];
 | 
			
		||||
            return GetCurrentAnimationStage()?.AnimationClips.ElementAtOrDefault(actorID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static PawnKeyframe GetPawnKeyframe(int actorID, int keyframeID)
 | 
			
		||||
        public static PawnKeyframe GetPawnKeyframe(int keyframeID)
 | 
			
		||||
        {
 | 
			
		||||
            if (StageID < 0) return null;
 | 
			
		||||
            if (actorID < 0) return null;
 | 
			
		||||
            foreach (AnimationStage stage in animationDef?.AnimationStages)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (PawnAnimationClip clip in stage.animationClips)
 | 
			
		||||
                {
 | 
			
		||||
                    PawnKeyframe keyframe = clip.Keyframes.FirstOrDefault(x => x.keyframeID == keyframeID);
 | 
			
		||||
 | 
			
		||||
            if (StageID >= animationDef.AnimationStages.Count) return null;
 | 
			
		||||
            if (actorID >= animationDef.AnimationStages[StageID].AnimationClips.Count) return null;
 | 
			
		||||
                    if (keyframe != null) return keyframe;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return animationDef.AnimationStages[StageID].AnimationClips[actorID].Keyframes.FirstOrDefault(x => x.keyframeID == keyframeID);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static PawnAnimationClip GetAnimationClipThatOwnsKeyframe(int keyframeID)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (AnimationStage stage in animationDef?.AnimationStages)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (PawnAnimationClip clip in stage.animationClips)
 | 
			
		||||
                {
 | 
			
		||||
                    PawnKeyframe keyframe = clip.Keyframes.FirstOrDefault(x => x.keyframeID == keyframeID);
 | 
			
		||||
 | 
			
		||||
                    if (keyframe != null) return clip;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static List<PawnKeyframe> GetAllPawnKeyframesAtTick(int actorID, int atTick)
 | 
			
		||||
| 
						 | 
				
			
			@ -167,24 +185,6 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            return pawnKeyframes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static PawnAnimationClip GetAnimationClipThatOwnsKeyframe(int keyframeID, out int clipID)
 | 
			
		||||
        {
 | 
			
		||||
            clipID = -1;
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < animationDef.AnimationStages[StageID].AnimationClips.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                PawnAnimationClip clip = animationDef.AnimationStages[StageID].AnimationClips[i];
 | 
			
		||||
 | 
			
		||||
                if (clip.Keyframes.Any(x => x.keyframeID == keyframeID))
 | 
			
		||||
                {
 | 
			
		||||
                    clipID = i;
 | 
			
		||||
                    return clip; 
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool DoesPawnKeyframeExistAtTick(int stageID, int actorID, int atTick)
 | 
			
		||||
        {
 | 
			
		||||
            return animationDef.AnimationStages[stageID].AnimationClips[actorID].Keyframes.Any(x => x.atTick == atTick);
 | 
			
		||||
| 
						 | 
				
			
			@ -195,11 +195,9 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            PawnKeyframe pawnKeyframe = null;
 | 
			
		||||
            PawnAnimationClip clip = GetPawnAnimationClip(actorID);
 | 
			
		||||
 | 
			
		||||
            int stageTick = Workspace.StageTick;
 | 
			
		||||
 | 
			
		||||
            foreach (PawnKeyframe keyframe in clip.Keyframes)
 | 
			
		||||
            {
 | 
			
		||||
                if (keyframe.atTick > stageTick)
 | 
			
		||||
                if (keyframe.atTick > StageTick)
 | 
			
		||||
                { pawnKeyframe = keyframe; break; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -211,11 +209,9 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            PawnKeyframe pawnKeyframe = null;
 | 
			
		||||
            PawnAnimationClip clip = GetPawnAnimationClip(actorID);
 | 
			
		||||
 | 
			
		||||
            int stageTick = Workspace.StageTick;
 | 
			
		||||
 | 
			
		||||
            foreach (PawnKeyframe keyframe in clip.Keyframes)
 | 
			
		||||
            {
 | 
			
		||||
                if (keyframe.atTick < stageTick)
 | 
			
		||||
                if (keyframe.atTick < StageTick)
 | 
			
		||||
                { pawnKeyframe = keyframe; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -227,11 +223,9 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            PawnKeyframe pawnKeyframe = null;
 | 
			
		||||
            PawnAnimationClip clip = GetPawnAnimationClip(actorID);
 | 
			
		||||
 | 
			
		||||
            int stageTick = Workspace.StageTick;
 | 
			
		||||
 | 
			
		||||
            foreach (PawnKeyframe keyframe in clip.Keyframes)
 | 
			
		||||
            {
 | 
			
		||||
                if (keyframe.atTick <= stageTick)
 | 
			
		||||
                if (keyframe.atTick <= StageTick)
 | 
			
		||||
                { pawnKeyframe = keyframe; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -310,7 +304,6 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            animationDef = record.animationDef.Copy();
 | 
			
		||||
            StageID = record.stageID;
 | 
			
		||||
 | 
			
		||||
            AnimationController.Instance.MakeTimelineDirty();
 | 
			
		||||
            StageCardManager.Instance.Initialize();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -327,7 +320,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            RestoreToHistoricRecord(recordToRead);
 | 
			
		||||
            Debug.Log("Undoing : " + recordToStore.eventDesc);
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnAnimationDefChanged();
 | 
			
		||||
            EventsManager.OnAnimationChanged();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Redo()
 | 
			
		||||
| 
						 | 
				
			
			@ -342,7 +335,7 @@ namespace RimWorldAnimationStudio
 | 
			
		|||
            RestoreToHistoricRecord(recordToReadAndStore);
 | 
			
		||||
            Debug.Log("Redoing : " + recordToReadAndStore.eventDesc);
 | 
			
		||||
 | 
			
		||||
            EventsManager.OnAnimationDefChanged();
 | 
			
		||||
            EventsManager.OnAnimationChanged();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void ClearHistory()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/05/05ad68c281bd54caa4fa4000f5f9c92d
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/05/05ad68c281bd54caa4fa4000f5f9c92d
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/05/05d40869a880f0cdfc62d514be500749
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/05/05d40869a880f0cdfc62d514be500749
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/08/08e27f70105584f4d9ab2dc8dc9249d9
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/08/08e27f70105584f4d9ab2dc8dc9249d9
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/0a/0a7cc2dbd61b9a1657802bd704f4b7f1
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/0a/0a7cc2dbd61b9a1657802bd704f4b7f1
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/0b/0b67a1c17136bd9afa79e057edf21c7c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/0b/0b67a1c17136bd9afa79e057edf21c7c
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/0e/0ed2550ae64a07d9579a63864a809b7d
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/0e/0ed2550ae64a07d9579a63864a809b7d
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/0f/0fcf8c0d3cc76769c9837c7b6630f3f3
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/0f/0fcf8c0d3cc76769c9837c7b6630f3f3
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/13/133c1343c2be5a5ef3fae879ca5bed15
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/13/133c1343c2be5a5ef3fae879ca5bed15
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/14/1488b3d8d5e48285bc90505a763a0772
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/14/1488b3d8d5e48285bc90505a763a0772
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/17/17388a70976ec90c6b6bccd347412218
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/17/17388a70976ec90c6b6bccd347412218
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/1b/1b280738486ca03fb83f4c3d6204b407
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/1b/1b280738486ca03fb83f4c3d6204b407
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/1b/1b8228a0ec5a49534dc02236522609eb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/1b/1b8228a0ec5a49534dc02236522609eb
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/1e/1e8456072527d971fab7dbd8d841ea75
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/1e/1e8456072527d971fab7dbd8d841ea75
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/1f/1ff46d39cbf3665262f47411f1d0d2b6
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/1f/1ff46d39cbf3665262f47411f1d0d2b6
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/23/23bc926a0c6b9ba04ea361185c740f21
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/23/23bc926a0c6b9ba04ea361185c740f21
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/25/25302e2dccc0e213f900291a81c3689c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/25/25302e2dccc0e213f900291a81c3689c
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/28/28003a33a95100d9956dfbdb10ccdf10
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/28/28003a33a95100d9956dfbdb10ccdf10
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/29/2954690bf6a0166cc4c4250f458a94c4
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/29/2954690bf6a0166cc4c4250f458a94c4
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/29/29d7823a9cabaf3c81afadbec7320985
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/29/29d7823a9cabaf3c81afadbec7320985
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/2d/2d6d6d28932733e02697cded1902cc67
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/2d/2d6d6d28932733e02697cded1902cc67
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/2f/2f91f2435e3fa541a93a827e35f7f3a2
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/2f/2f91f2435e3fa541a93a827e35f7f3a2
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/32/32db8c8b40211c54a7a3d64afdf5f1ff
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/32/32db8c8b40211c54a7a3d64afdf5f1ff
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/35/35e203d048e16e9e759001f0069f891a
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/35/35e203d048e16e9e759001f0069f891a
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/38/38b774042e0ea1ef3fda8c679d1a26d6
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/38/38b774042e0ea1ef3fda8c679d1a26d6
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/39/39699d27989ae7571067707c63c95428
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/39/39699d27989ae7571067707c63c95428
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/3e/3e8f5bc95adea8eb7dc938a3a840b9b4
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/3e/3e8f5bc95adea8eb7dc938a3a840b9b4
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/3e/3ec17e71dc4a75090372b92b617b45ea
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/3e/3ec17e71dc4a75090372b92b617b45ea
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/41/419ded9da1895da224cf4f7a6c9ee227
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/41/419ded9da1895da224cf4f7a6c9ee227
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/41/41a31b67d9d9f20452c18241f45660ad
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/41/41a31b67d9d9f20452c18241f45660ad
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/42/42921da555d0fc8eb7495f8e0a710cf1
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/42/42921da555d0fc8eb7495f8e0a710cf1
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Library/Artifacts/42/42e27dc25a9bb827b9bb7edd679a1d80
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Artifacts/42/42e27dc25a9bb827b9bb7edd679a1d80
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue