This commit is contained in:
AbstractConcept 2022-12-09 11:40:08 -06:00
parent 0828ecd037
commit 2998865184
9821 changed files with 90 additions and 90 deletions

View file

@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class ActorManipulator : MonoBehaviour
{
public ActorManipulationMode actorManipulationMode;
private Image button;
public void Start()
{
button = GetComponent<Image>();
}
public void Update()
{
if (Workspace.actorManipulationMode == actorManipulationMode)
{ button.color = Constants.ColorGoldYellow; }
else
{ button.color = Constants.ColorWhite; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f627be313335bf748b33eea98541581d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f3c96477ef8cc42468ea6a39764a2e81
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,126 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class ActorBody : MonoBehaviour, IPointerClickHandler, IDragHandler, IEndDragHandler
{
public int actorID;
public SpriteRenderer bodyRenderer;
public ActorBodyPart actorBodyPartPrefab;
private Vector3 dragDelta = new Vector3();
private void Start()
{
EventsManager.onActorBodyPartSelected.AddListener(delegate(ActorBodyPart bodyPart) { OnActorBodyPartSelected(bodyPart); });
EventsManager.onActorBodySelected.AddListener(delegate(ActorBody actorBody) { OnActorBodySelected(actorBody); });
EventsManager.onActorIDChanged.AddListener(delegate {
if (Workspace.ActorID == actorID)
{ EventsManager.OnActorBodySelected(this); }
});
if (Workspace.ActorID == actorID)
{ Activate(); }
foreach (ActorAddonDef actorAddonDef in ActorAddonDefs.allDefs)
{
ActorBodyPart actorBodyPart = Instantiate(actorBodyPartPrefab, transform);
actorBodyPart.Initialize(this, actorAddonDef);
}
}
public void OnActorBodySelected(ActorBody actorBody)
{
if (actorBody == this)
{ bodyRenderer.color = Constants.ColorGreen; }
else
{ bodyRenderer.color = Constants.ColorWhite; }
}
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)
{
if (eventData.pointerCurrentRaycast.gameObject.GetComponent<ActorBodyPart>())
{ return; }
Activate();
}
public void OnDrag(PointerEventData eventData)
{
Activate();
PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (dragDelta == Vector3.zero)
{ dragDelta = mousePosition - transform.position; }
if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
{
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)
{
float angle = -Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
keyframe.BodyAngle = 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.BodyFacing = facing;
}
PawnAnimationClip clip = Workspace.GetPawnAnimationClip(actorID);
clip.BuildSimpleCurves();
EventsManager.OnPawnKeyframeChanged(keyframe);
}
public void OnEndDrag(PointerEventData eventData)
{
Workspace.RecordEvent("Actor position / orientation");
dragDelta = Vector3.zero;
}
public ActorBodyPart GetActorBodyPart(string bodyPart)
{
return GetComponentsInChildren<ActorBodyPart>(true)?.FirstOrDefault(x => x.bodyPart.ToLower() == bodyPart);
}
public void Activate()
{
Workspace.ActorID = actorID;
Workspace.selectedBodyPart = null;
EventsManager.OnActorBodySelected(this);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 511a9ed9093e7fc458dec8d3c657f9a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,165 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class ActorBodyPart : MonoBehaviour, IPointerClickHandler, IDragHandler, IEndDragHandler
{
public SpriteRenderer bodyPartRenderer;
public ActorBody parent;
public string bodyPart;
private Vector3 dragDelta = new Vector3();
private void Start()
{
if (parent == null) return;
EventsManager.onActorBodyPartSelected.AddListener(delegate (ActorBodyPart bodyPart) { OnActorBodyPartSelected(bodyPart); });
EventsManager.onActorBodySelected.AddListener(delegate (ActorBody actorBody) { OnActorBodySelected(actorBody); });
if (Workspace.ActorID == parent.actorID)
{ parent.Activate(); }
}
public void Initialize(ActorBody parent, ActorAddonDef actorAddonDef)
{
this.parent = parent;
this.bodyPart = actorAddonDef.addonName;
bodyPartRenderer.sprite = actorAddonDef.graphicData.GetSprite();
bodyPartRenderer.transform.localScale = (Vector3)actorAddonDef.graphicData.GetDrawSize();
Start();
}
public void OnActorAddonChange(ActorAddon actorAddon)
{
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; }
}
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.pointerCurrentRaycast.gameObject.GetComponent<ActorBodyPart>() == null)
{ return; }
Activate();
}
public void OnDrag(PointerEventData eventData)
{
Activate();
PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mousePosition = new Vector3(mousePosition.x, mousePosition.y, 0f);
if (dragDelta == Vector3.zero)
{ dragDelta = mousePosition - transform.position; }
if (bodyPart.ToLower() == "head")
{
if (Workspace.actorManipulationMode == ActorManipulationMode.Pan)
{
// It's stupid, but it works
Vector3 localPosA = transform.localPosition;
transform.position = mousePosition - dragDelta;
Vector3 localPosB = transform.localPosition;
transform.localPosition = localPosA;
keyframe.HeadBob += localPosB.y - localPosA.y;
}
else if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
{
float angle = -Vector2.SignedAngle(Vector2.down, (Vector2)mousePosition - (Vector2)transform.position);
keyframe.HeadAngle = 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 (bodyPart.ToLower() == "appendage")
{
if (Workspace.actorManipulationMode == ActorManipulationMode.Rotate)
{
float angle = -Vector2.SignedAngle(Vector2.up, (Vector2)mousePosition - (Vector2)transform.position);
keyframe.GenitalAngle = angle;
}
}
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.anchorName);
transform.position = mousePosition - dragDelta;
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");
dragDelta = Vector3.zero;
}
public void Activate()
{
Workspace.ActorID = parent.actorID;
Workspace.selectedBodyPart = this;
EventsManager.OnActorBodyPartSelected(this);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b23e33f312d52c642b86f5f2138f4030
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class AddSoundDefButton : MonoBehaviour
{
private Text text;
public void Start()
{
text = GetComponentInChildren<Text>();
}
void Update()
{
PawnKeyframe keyframe = Workspace.GetCurrentOrPreviousKeyframe(Workspace.ActorID);
if (keyframe != null)
{ text.text = string.IsNullOrEmpty(keyframe.SoundEffect) ? "None" : keyframe.SoundEffect; }
else
{ text.text = "None"; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7e9565ba13ac2e469767bcfad7da5d3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,19 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class AddonAnchorDropdown : MonoBehaviour
{
private void Start()
{
Dropdown dropdown = GetComponent<Dropdown>();
dropdown.ClearOptions();
dropdown.AddOptions(Constants.bodyPartAnchorNames.Values.ToList());
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6a0ca236433ad584998f9c7a96dc3af8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,39 @@
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 AnimationLengthsCard : MonoBehaviour
{
public Text stageLengthNormalText;
public Text stageLengthQuickText;
public Text animationLengthNormalText;
public Text animationLengthQuickText;
public float spacing = 10f;
private RectTransform rect;
private void Start()
{
rect = GetComponent<RectTransform>();
}
public void Update()
{
LayoutRebuilder.ForceRebuildLayoutImmediate(transform.parent.GetComponent<RectTransform>());
LayoutRebuilder.ForceRebuildLayoutImmediate(transform.parent.GetComponent<RectTransform>());
rect.localPosition = new Vector3(rect.localPosition.x, spacing + transform.parent.GetComponent<RectTransform>().sizeDelta.y, rect.localPosition.z);
stageLengthNormalText.text = Workspace.GetCurrentAnimationStage().PlayTimeTicks + " (" + string.Format("{0:0.00}", Workspace.GetCurrentAnimationStage().PlayTimeTicks / 60f) + " s)";
animationLengthNormalText.text = Workspace.animationDef.animationTimeTicks + " (" + string.Format("{0:0.00}", Workspace.animationDef.animationTimeTicks / 60f) + " s)";
stageLengthQuickText.text = Workspace.GetCurrentAnimationStage().PlayTimeTicksQuick + " (" + string.Format("{0:0.00}", Workspace.GetCurrentAnimationStage().PlayTimeTicksQuick / 60f) + " s)";
animationLengthQuickText.text = Workspace.animationDef.animationTimeTicksQuick + " (" + string.Format("{0:0.00}", Workspace.animationDef.animationTimeTicksQuick / 60f) + " s)";
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 060e49b40b1097e46b662059e4e29cdf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class AnimationTimeline : MonoBehaviour, IPointerClickHandler
{
public int actorID = -1;
public KeyframeSlider keyframeSliderPrefab;
private Transform anchorTransform;
private void Start()
{
EventsManager.onAnimationTimelinesChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onKeyframeCountChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onActorIDChanged.AddListener(delegate { UpdateTimelineSelection(); });
EventsManager.onStageWindowSizeChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onAnimationStageChanged.AddListener(delegate { UpdateGUI(); });
UpdateTimelineSelection();
UpdateGUI();
}
public void Initialize(int actorID)
{
anchorTransform = transform.parent;
this.actorID = actorID;
UpdateGUI();
}
public void ClearKeyframeSliders()
{
foreach (KeyframeSlider slider in GetComponentsInChildren<KeyframeSlider>())
{ Destroy(slider.gameObject); }
}
public void UpdateGUI()
{
if (actorID < 0) return;
PawnAnimationClip clip = Workspace.GetPawnAnimationClip(actorID);
if (clip == null) return;
clip.BuildSimpleCurves();
ClearKeyframeSliders();
foreach (PawnKeyframe keyframe in clip.Keyframes)
{ AddPawnKeyFrame(keyframe.keyframeID); }
InitiateUpdateOfGhostFrames();
}
public void UpdateTimelineSelection()
{
GetComponent<Image>().color = (Workspace.ActorID == actorID ? Constants.ColorGoldYellow : Constants.ColorMidGrey);
}
public void AddPawnKeyFrame(int keyframeID)
{
KeyframeSlider keyframeSlider = Instantiate(keyframeSliderPrefab, transform);
keyframeSlider.Initialize(this, actorID, keyframeID);
}
public void RemovePawnKeyFrame(int keyframeID)
{
KeyframeSlider keyframeSlider = GetComponentsInChildren<KeyframeSlider>().FirstOrDefault(x => x.keyframeID == keyframeID);
Destroy(keyframeSlider?.gameObject);
}
public void InitiateUpdateOfGhostFrames()
{
BroadcastMessage("UpdateGhostFrames");
}
public void OnMoveTimeline(int delta)
{
int? siblingIndex = anchorTransform.parent.GetComponentsInChildren<AnimationTimeline>()?.ToList()?.IndexOf(this);
int? siblingCount = anchorTransform.parent.GetComponentsInChildren<AnimationTimeline>()?.ToList()?.Count();
if (siblingIndex != null && siblingCount != null && MoveAnimationTimeline(siblingIndex.Value, delta))
{ AnimationController.Instance.Initialize(); }
}
public bool MoveAnimationTimeline(int startIndex, int delta)
{
if (startIndex + delta < 0 || startIndex + delta >= Workspace.GetCurrentAnimationStage().AnimationClips.Count)
{ Debug.Log("Cannot move animation timeline - movement would exceed bounds"); return false; }
Actor actor = Workspace.animationDef.Actors[startIndex];
Workspace.animationDef.Actors[startIndex] = Workspace.animationDef.Actors[startIndex + delta];
Workspace.animationDef.Actors[startIndex + delta] = actor;
PawnAnimationClip clip = Workspace.GetPawnAnimationClip(startIndex);
Workspace.GetCurrentAnimationStage().AnimationClips[startIndex] = Workspace.GetCurrentAnimationStage().AnimationClips[startIndex + delta];
Workspace.GetCurrentAnimationStage().AnimationClips[startIndex + delta] = clip;
Workspace.ActorID = startIndex + delta;
Workspace.RecordEvent("Timeline move");
return true;
}
public void OnPointerClick(PointerEventData eventData)
{
Workspace.ActorID = actorID;
Workspace.keyframeID.Clear();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b3dd6b099b5c67744b84a5ec7283277b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class ButtonWithKeyCode : Button
{
public KeyCode keyCode;
public void Update()
{
if (Input.GetKeyDown(keyCode))
{ onClick.Invoke(); }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1bfc022fc38c6474db2a742159e458f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c026d569e32726d4eb8821db713d0aac
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,102 @@
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 ActorAddonCard : MonoBehaviour
{
public string addonName;
public Text label;
public Toggle toggle;
public Dropdown anchorDropdown;
public InputField anchoringPawnField;
public Dropdown layerDropdown;
public ActorAddonKeyframeCard actorAddonKeyframeCard;
private ActorAddonDef actorAddonDef;
private PawnAnimationClip clip { get { return Workspace.GetCurrentPawnAnimationClip(); } }
private void Start()
{
}
public void Initialize(ActorAddonDef actorAddonDef, ActorAddonKeyframeCard actorAddonKeyframeCard)
{
this.actorAddonDef = actorAddonDef;
this.actorAddonKeyframeCard = actorAddonKeyframeCard;
addonName = actorAddonDef.addonName;
label.text = actorAddonDef.label;
EventsManager.onAnimationChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onActorIDChanged.AddListener(delegate { UpdateGUI(); });
UpdateGUI();
}
public void UpdateGUI()
{
if (Workspace.animationDef == null || string.IsNullOrEmpty(addonName)) return;
if (clip?.GetActorAddon(addonName) != null)
{
int i = Constants.bodyPartAnchorNames.Keys.ToList().IndexOf(clip.GetActorAddon(addonName).AnchorName);
anchorDropdown.SetValueWithoutNotify(i);
layerDropdown.SetValueWithoutNotify(layerDropdown.options.IndexOf(layerDropdown.options.First(x => x.text == clip.GetActorAddon(addonName).Layer)));
anchoringPawnField.SetTextWithoutNotify(clip.GetActorAddon(addonName).AnchoringActor.ToString());
toggle.SetIsOnWithoutNotify(clip.IsActorAddonVisible(addonName));
anchoringPawnField.interactable = anchorDropdown.value != 0;
}
}
public void OnToggleChanged()
{
if (clip?.GetActorAddon(addonName) != null)
{ clip.GetActorAddon(addonName).render = toggle.isOn; }
EventsManager.OnPawnKeyframeChanged(null);
UpdateGUI();
}
public void OnAnchorChanged()
{
if (clip?.GetActorAddon(addonName) != null)
{ clip.GetActorAddon(addonName).AnchorName = Constants.bodyPartAnchorNames.Keys.ElementAt(anchorDropdown.value); }
UpdateGUI();
}
public void OnLayerChanged()
{
if (clip?.GetActorAddon(addonName) != null)
{ clip.GetActorAddon(addonName).Layer = layerDropdown.options[layerDropdown.value].text; }
UpdateGUI();
}
public void OnAnchoringPawnChanged()
{
if (clip?.GetActorAddon(addonName) != null)
{
int i = int.Parse(anchoringPawnField.text);
if (i < 0) { i = clip.GetOwningActorID(); }
i = Mathf.Clamp(i, 0, Workspace.animationDef.Actors.Count - 1);
clip.GetActorAddon(addonName).AnchoringActor = i;
anchoringPawnField.SetTextWithoutNotify(i.ToString());
}
UpdateGUI();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 919aed3c4b9671c4e8dc109c7d608683
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,71 @@
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 ActorAddonKeyframeCard : MonoBehaviour
{
public string addonName;
public Text label;
public InputField xOffsetField;
public InputField zOffsetField;
public InputField rotationField;
private ActorAddonDef actorAddonDef;
public void Start()
{
}
public void Initialize(ActorAddonDef actorAddonDef)
{
this.actorAddonDef = actorAddonDef;
this.addonName = actorAddonDef.addonName;
label.text = actorAddonDef.label + ":";
EventsManager.onAnimationChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onStageIDChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onActorIDChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onStageTickChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onPawnKeyframeChanged.AddListener(delegate { UpdateGUI(); });
xOffsetField.onEndEdit.AddListener(delegate { OnValueChanged(); });
zOffsetField.onEndEdit.AddListener(delegate { OnValueChanged(); });
rotationField.onEndEdit.AddListener(delegate { OnValueChanged(); });
UpdateGUI();
}
public void OnValueChanged()
{
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);
Workspace.GetCurrentPawnAnimationClip().BuildSimpleCurves();
Workspace.RecordEvent("Actor addon position / orientation");
UpdateGUI();
}
public void UpdateGUI()
{
PawnAnimationClip clip = Workspace.GetCurrentPawnAnimationClip();
xOffsetField.SetTextWithoutNotify(string.Format("{0:0.000}", clip.GetActorAddon(addonName).PosX.Evaluate((float)Workspace.StageTick / Workspace.StageWindowSize)));
zOffsetField.SetTextWithoutNotify(string.Format("{0:0.000}", clip.GetActorAddon(addonName).PosZ.Evaluate((float)Workspace.StageTick / Workspace.StageWindowSize)));
rotationField.SetTextWithoutNotify(string.Format("{0:0.000}", clip.GetActorAddon(addonName).Rotation.Evaluate((float)Workspace.StageTick / Workspace.StageWindowSize)));
gameObject.SetActive(clip.GetActorAddon(addonName).render == true);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a63bb35c73985c46b65383f08d4afd9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,129 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class ActorCard : MonoBehaviour
{
public Toggle initiatorToggle;
public Dropdown selectActorLayerDropdown;
public Dropdown bodyTypeDropdown;
public InputField bodyOffsetXField;
public InputField bodyOffsetZField;
public Dropdown raceDropdown;
public InputField raceOffsetXField;
public InputField raceOffsetZField;
private Actor actor { get { return Workspace.GetCurrentActor(); } }
private PawnAnimationClip clip { get { return Workspace.GetCurrentPawnAnimationClip(); } }
public void Awake()
{
UpdateRaceDropdown();
}
public void Start()
{
// General events
EventsManager.onAnimationChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onActorIDChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onDefNamesChanged.AddListener(delegate { UpdateRaceDropdown(); });
// Local events
initiatorToggle.onValueChanged.AddListener(delegate {
actor.initiator = initiatorToggle.isOn;
Workspace.RecordEvent("Change in actor sex initiator status ");
});
selectActorLayerDropdown.onValueChanged.AddListener(delegate {
clip.Layer = selectActorLayerDropdown.options[selectActorLayerDropdown.value].text;
Workspace.RecordEvent("Change in actor render layer");
});
bodyTypeDropdown.onValueChanged.AddListener(delegate { OnDropdownChanged(); });
bodyOffsetXField.onEndEdit.AddListener(delegate { OnInputFieldChanged(); });
bodyOffsetZField.onEndEdit.AddListener(delegate { OnInputFieldChanged(); });
raceDropdown.onValueChanged.AddListener(delegate { OnDropdownChanged(); });
raceOffsetXField.onEndEdit.AddListener(delegate { OnInputFieldChanged(); });
raceOffsetZField.onEndEdit.AddListener(delegate { OnInputFieldChanged(); });
// Initialize
UpdateGUI();
}
public void OnInputFieldChanged()
{
string bodyType = bodyTypeDropdown.options[bodyTypeDropdown.value].text;
bodyType = string.IsNullOrEmpty(bodyType) ? "Male" : bodyType;
float.TryParse(bodyOffsetXField.text, out float x);
float.TryParse(bodyOffsetZField.text, out float z);
actor.BodyTypeOffset.SetOffset(bodyType, new Vector2(x, z));
float.TryParse(raceOffsetXField.text, out x);
float.TryParse(raceOffsetZField.text, out z);
actor.SetPawnRaceOffset(new Vector2(x, z));
Workspace.RecordEvent("Actor offset");
UpdateGUI();
}
public void OnDropdownChanged()
{
actor.bodyType = bodyTypeDropdown.options[bodyTypeDropdown.value].text;
if (raceDropdown.options[raceDropdown.value].text != actor.GetPawnRaceDef().defName)
{ Workspace.selectedBodyPart = null; }
actor.SetPawnRaceDef(raceDropdown.options[raceDropdown.value].text);
Workspace.RecordEvent("Actor body type/race change");
UpdateGUI();
}
public void UpdateRaceDropdown()
{
int index = raceDropdown.value;
raceDropdown.ClearOptions();
IEnumerable<string> optionsList = DefaultTags.defNames.Concat(CustomTags.defNames);
foreach (string defName in optionsList)
{ raceDropdown.options.Add(new Dropdown.OptionData(defName)); }
raceDropdown.value = Mathf.Clamp(index, 0, raceDropdown.options.Count - 1);
raceDropdown.captionText.text = raceDropdown.options[raceDropdown.value].text;
UpdateGUI();
}
public void UpdateGUI()
{
initiatorToggle.isOn = actor.Initiator;
string layer = clip.Layer;
selectActorLayerDropdown.SetValueWithoutNotify(selectActorLayerDropdown.options.FindIndex(x => x.text == layer));
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));
bodyOffsetZField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.BodyTypeOffset.GetOffset(bodyType).z));
bodyTypeDropdown.interactable = actor.GetPawnRaceDef().isHumanoid;
bodyOffsetXField.interactable = actor.GetPawnRaceDef().isHumanoid;
bodyOffsetZField.interactable = actor.GetPawnRaceDef().isHumanoid;
string race = actor.GetPawnRaceDef().defName;
raceDropdown.SetValueWithoutNotify(raceDropdown.options.FindIndex(x => x.text == race));
raceOffsetXField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.GetPawnRaceOffset().x));
raceOffsetZField.SetTextWithoutNotify(string.Format("{0:0.000}", actor.GetPawnRaceOffset().z));
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9731614c7527b624492dd33f9b006fcb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,87 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class ActorKeyframeCard : Singleton<ActorKeyframeCard>
{
public InputField positionXField;
public InputField positionZField;
public InputField rotationField;
public InputField headBobField;
public InputField headRotationField;
public InputField appendageRotationField;
public ActorAddonCard actorAddonCardPrefab;
public ActorAddonKeyframeCard actorAddonKeyframeCardPrefab;
public Transform actorAddonCards;
public Transform actorKeyframeCards;
public SelectActorAddonsDialog selectActorAddonsDialog;
private Actor actor { get { return Workspace.GetCurrentActor(); } }
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(); });
foreach (ActorAddonDef actorAddonDef in ActorAddonDefs.allDefs)
{
ActorAddonKeyframeCard actorAddonKeyframeCard = Instantiate(actorAddonKeyframeCardPrefab, actorKeyframeCards);
actorAddonKeyframeCard.Initialize(actorAddonDef);
ActorAddonCard actorAddonCard = Instantiate(actorAddonCardPrefab, actorAddonCards);
actorAddonCard.Initialize(actorAddonDef, actorAddonKeyframeCard);
selectActorAddonsDialog.AddActorAddonCard(actorAddonCard);
}
UpdateGUI();
}
public void OnValueChanged()
{
PawnKeyframe keyframe = Workspace.GetCurrentPawnKeyframe(true);
keyframe.BodyOffsetX = float.Parse(positionXField.text);
keyframe.BodyOffsetZ = float.Parse(positionZField.text);
keyframe.BodyAngle = float.Parse(rotationField.text);
keyframe.HeadBob = float.Parse(headBobField.text);
keyframe.HeadAngle = float.Parse(headRotationField.text);
keyframe.GenitalAngle = float.Parse(appendageRotationField.text);
Workspace.GetCurrentPawnAnimationClip().BuildSimpleCurves();
Workspace.RecordEvent("Actor position / orientation");
UpdateGUI();
}
public void UpdateGUI()
{
ActorPosition actorPosition = actor.GetCurrentPosition();
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));
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 58ad3d066d9103541806d07bc98823d6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,94 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class AnimationControlCard : MonoBehaviour
{
public InputField currentTimeField;
public InputField stageWindowLengthField;
public InputField playBackSpeedField;
public Button playToggleButton;
public Slider stageTimelineSlider;
private void Start()
{
EventsManager.onAnimationChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onStageIDChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onStageTickChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onAnimationToggled.AddListener(delegate { playToggleButton.image.color = Workspace.IsAnimating ? Constants.ColorGoldYellow : Constants.ColorWhite; });
stageTimelineSlider.onValueChanged.AddListener(delegate { OnStageTimelineSliderChange(); });
currentTimeField.onEndEdit.AddListener(delegate { OnCurrentTimeFieldChange(); });
stageWindowLengthField.onEndEdit.AddListener(delegate { OnStageWindowLengthFieldChange(); });
playBackSpeedField.onEndEdit.AddListener(delegate { OnPlayBackSpeedChange(); });
UpdateGUI();
}
public void OnStageTimelineSliderChange()
{
Workspace.StageTick = (int)stageTimelineSlider.value;
}
public void OnPlayBackSpeedChange()
{
Workspace.PlayBackSpeed = float.Parse(playBackSpeedField.text);
}
public void OnCurrentTimeFieldChange()
{
Workspace.StageTick = Mathf.Clamp(int.Parse(currentTimeField.text), Constants.minTick, Workspace.StageWindowSize);
UpdateGUI();
}
public void OnStageWindowLengthFieldChange()
{
int.TryParse(stageWindowLengthField.text, out int newStageWindowSize);
newStageWindowSize = Mathf.Clamp(newStageWindowSize, Constants.minAnimationClipLength, Constants.maxAnimationClipLength);
Debug.Log("Resizing animation clip length to " + newStageWindowSize.ToString() + " ticks.");
if (Workspace.stretchKeyframes)
{ Workspace.GetCurrentAnimationStage().StretchStageWindow(newStageWindowSize); }
else
{
Workspace.GetCurrentAnimationStage().ResizeStageWindow(newStageWindowSize);
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.RecordEvent("Stage length");
UpdateGUI();
}
public void UpdateGUI()
{
stageTimelineSlider.maxValue = Workspace.StageWindowSize;
stageTimelineSlider.SetValueWithoutNotify(Workspace.StageTick);
currentTimeField.SetTextWithoutNotify(Workspace.StageTick.ToString());
stageWindowLengthField.SetTextWithoutNotify(Workspace.StageWindowSize.ToString());
playBackSpeedField.SetTextWithoutNotify(Workspace.PlayBackSpeed.ToString());
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6b414452bfd6c9b4bb99542a51d77468
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,39 @@
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 AnimationDefCard : MonoBehaviour
{
public InputField defNameField;
public InputField labelField;
public void Start()
{
EventsManager.onAnimationChanged.AddListener(delegate { UpdateInputFields(); });
defNameField.onEndEdit.AddListener(delegate {
Workspace.animationDef.DefName = defNameField.text;
Workspace.MakeHistoricRecord("AnimationDef update");
});
labelField.onEndEdit.AddListener(delegate {
Workspace.animationDef.Label = labelField.text;
Workspace.MakeHistoricRecord("AnimationDef update");
});
UpdateInputFields();
}
public void UpdateInputFields()
{
defNameField.SetTextWithoutNotify(Workspace.animationDef.DefName);
labelField.SetTextWithoutNotify(Workspace.animationDef.Label);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e1d8f33927e6b4d44914a445362b802d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,67 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class StageCard : MonoBehaviour, IPointerClickHandler
{
public Text stageName;
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;
stageNameField.gameObject.SetActive(false);
Workspace.GetCurrentAnimationStage().StageName = stageName.text;
Workspace.RecordEvent("Stage renamed");
}
public void OnMoveStage(int delta)
{
Workspace.animationDef.MoveAnimationStage(stageID, delta);
}
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.clickCount >= 2)
{
stageNameField.text = stageName.text;
stageNameField.gameObject.SetActive(true);
}
if (Workspace.StageID != transform.GetSiblingIndex())
{ Workspace.RecordEvent("Stage selected"); }
Workspace.StageID = transform.GetSiblingIndex();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20b2be62d5fdc4b4992cede005ec2aee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,53 @@
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.onAnimationTimelinesChanged.AddListener(delegate { UpdateGUI(); });
EventsManager.onStageWindowSizeChanged.AddListener(delegate { UpdateGUI(); });
stageLoopsNormalField.onEndEdit.AddListener(delegate { OnStageLoopsNormalFieldChange(); });
stageLoopsQuickField.onEndEdit.AddListener(delegate { OnStageLoopsFastFieldChange(); });
UpdateGUI();
}
public void OnStageLoopsNormalFieldChange()
{
if (Workspace.animationDef == null) return;
Workspace.GetCurrentAnimationStage().StageLoopsNormal = int.Parse(stageLoopsNormalField.text);
EventsManager.OnAnimationStageChanged(Workspace.GetCurrentAnimationStage());
Workspace.RecordEvent("Cycle count (normal)");
}
public void OnStageLoopsFastFieldChange()
{
if (Workspace.animationDef == null) return;
Workspace.GetCurrentAnimationStage().StageLoopsQuick = int.Parse(stageLoopsQuickField.text);
EventsManager.OnAnimationStageChanged(Workspace.GetCurrentAnimationStage());
Workspace.RecordEvent("Cycle count (fast)");
}
public void UpdateGUI()
{
stageLoopsNormalField.SetTextWithoutNotify(Workspace.GetCurrentAnimationStage().StageLoopsNormal.ToString());
stageLoopsQuickField.SetTextWithoutNotify(Workspace.GetCurrentAnimationStage().StageLoopsQuick.ToString());
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38691dc973d99734f8f0f2a240df73fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,24 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace RimWorldAnimationStudio
{
public class Chaser : MonoBehaviour
{
public GameObject target;
public bool chaseAlongX = true;
public bool chaseAlongY = false;
void Update()
{
if (target == null)
{ return; }
float x = chaseAlongX ? target.transform.position.x : transform.position.x;
float y = chaseAlongY ? target.transform.position.y : transform.position.y;
transform.position = new Vector3(x, y, 0f);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9584d659e560b88409843604ae04229b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: eabe165e5b1a70744a8073c1b5b541a7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,68 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class ConsoleMessagesDialog : MonoBehaviour
{
public bool isExpanded = false;
public GameObject consoleWindow;
public Transform logContent;
public Text stackTrace;
public Text currentMessage;
public Text logMessagePrefab;
public int maxMessages = 500;
private int currentMessages = 0;
public void Start()
{
Application.logMessageReceived += LogMessage;
}
public void ToggleExpand()
{
isExpanded = !isExpanded;
consoleWindow.SetActive(isExpanded);
}
public void LogMessage(string logString, string stackTrace, LogType type)
{
if (currentMessages > maxMessages) return;
currentMessages++;
currentMessage.text = logString;
Text logMessage = Instantiate(logMessagePrefab, logContent);
logMessage.text = logString;
logMessage.GetComponent<Button>().onClick.AddListener(delegate { OpenStackTrace(stackTrace); });
if (type == LogType.Warning)
{
currentMessage.color = Constants.ColorRichOrange;
logMessage.color = Constants.ColorRichOrange;
}
else if (type == LogType.Exception || type == LogType.Error)
{
currentMessage.color = Constants.ColorRed;
logMessage.color = Constants.ColorRed;
}
else
{
currentMessage.color = Constants.ColorDarkGrey;
logMessage.color = Constants.ColorDarkGrey;
}
}
public void OpenStackTrace(string stackTrace)
{
this.stackTrace.text = stackTrace;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c62f9942e9d933848913ee2b28f65791
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class DialogBox : MonoBehaviour
{
public List<GameObject> cloneObjects;
protected virtual void OnEnable()
{
Initialize();
}
public void Pop()
{
Initialize();
gameObject.SetActive(gameObject.activeSelf == false);
}
public void RemoveCloneObjectsFromParent(Transform parent)
{
for (int i = 0; i < parent.childCount; i++)
{ Destroy(parent.transform.GetChild(i).gameObject); }
}
public GameObject AddCloneObjectToParent(Transform parent, int i = 0)
{
GameObject cloneObject = null;
if (cloneObjects != null && cloneObjects.Count > i)
{ cloneObject = Instantiate(cloneObjects[i], parent); }
return cloneObject;
}
public void AddCustomTag(InputField field, ref List<string> tags, ref List<string> customTags)
{
if (field?.text == null || field.text == "")
{ return; }
if (tags.Contains(field.text) || customTags.Contains(field.text))
{ field.text = ""; return; }
customTags.Add(field.text);
ApplicationManager.Instance.SaveCustomArrays();
Initialize(true);
}
public void RemoveCustomTag(ref List<string> customTags, string tag)
{
customTags.Remove(tag);
ApplicationManager.Instance.SaveCustomArrays();
Initialize();
}
public void AddCustomRace(InputField field)
{
if (field?.text == null || field.text == "")
{ return; }
PawnRaceDefs.AddDef(new PawnRaceDef(field.text));
ApplicationManager.Instance.SavePawnRaceDefs();
Initialize(true);
}
public virtual void Initialize(bool addedNewTag = false) { }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5a554bad525e79e4fb3dea0d391daf48
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using SFB;
using System.IO;
namespace RimWorldAnimationStudio
{
public class RaceSettingsDialog : DialogBox
{
public Dropdown raceSelectDropdown;
public Transform raceSettingsWindow;
public Toggle isHumanoidToggle;
public InputField scaleField;
protected override void OnEnable()
{
raceSelectDropdown.ClearOptions();
raceSelectDropdown.AddOptions(DefaultTags.defNames.Concat(CustomTags.defNames).ToList());
base.OnEnable();
}
public override void Initialize(bool addedNewTag = false)
{
Reset();
PawnRaceDef pawnRaceDef = GetCurrentRaceDef();
if (pawnRaceDef == null) return;
isHumanoidToggle.SetIsOnWithoutNotify(pawnRaceDef.isHumanoid);
Text bodyGraphicsTitle = AddCloneObjectToParent(raceSettingsWindow, 2).GetComponent<Text>();
bodyGraphicsTitle.text = "Body graphic filepaths";
List<string> allTags = pawnRaceDef.isHumanoid ? DefaultTags.bodyTypes : new List<string>() { "None" };
foreach (string bodyType in allTags)
{
string _bodyType = bodyType;
if (pawnRaceDef.isHumanoid)
{
Text bodyTypeTitle = AddCloneObjectToParent(raceSettingsWindow, 2).GetComponent<Text>();
bodyTypeTitle.text = bodyType;
}
for (int i = 2; i >= 0; i--)
{
CardinalDirection facing = (CardinalDirection)i;
GameObject filepath = AddCloneObjectToParent(raceSettingsWindow, 0);
filepath.GetComponent<Text>().text = facing.ToString();
filepath.transform.Find("FilepathButton").GetComponent<Button>().onClick.AddListener(delegate
{
SetBodyTypeGraphicPath(pawnRaceDef, facing, _bodyType);
});
filepath.transform.FindDeepChild("FilepathLabel").GetComponent<Text>().text = pawnRaceDef.GetBodyTypeGraphicPath(facing, _bodyType);
}
AddCloneObjectToParent(raceSettingsWindow, 3);
}
if (pawnRaceDef.isHumanoid)
{
Text headGraphics = AddCloneObjectToParent(raceSettingsWindow, 2).GetComponent<Text>();
headGraphics.text = "Head graphic filepaths";
for (int i = 2; i >= 0; i--)
{
CardinalDirection facing = (CardinalDirection)i;
GameObject filepath = AddCloneObjectToParent(raceSettingsWindow, 0);
filepath.GetComponent<Text>().text = facing.ToString();
filepath.transform.Find("FilepathButton").GetComponent<Button>().onClick.AddListener(delegate
{
SetHeadGraphicPath(pawnRaceDef, facing);
});
filepath.transform.FindDeepChild("FilepathLabel").GetComponent<Text>().text = pawnRaceDef.GetHeadGraphicPath(facing);
}
AddCloneObjectToParent(raceSettingsWindow, 3);
}
scaleField.text = string.Format("{0:0.000}", pawnRaceDef.scale);
}
public void Reset()
{
RemoveCloneObjectsFromParent(raceSettingsWindow);
}
public void SetIsHumanoid()
{
PawnRaceDef pawnRaceDef = GetCurrentRaceDef();
if (pawnRaceDef == null) return;
pawnRaceDef.isHumanoid = isHumanoidToggle.isOn;
Initialize();
}
public void SetHeadGraphicPath(PawnRaceDef pawnRaceDef, CardinalDirection direction)
{
var paths = StandaloneFileBrowser.OpenFilePanel("Select texture File", "", "png", false);
if (paths == null || paths.Any() == false || File.Exists(paths[0]) == false)
{ Debug.LogWarning("Selected file was null or invalid"); return; }
pawnRaceDef.SetHeadGraphicPath(paths[0], direction);
Initialize();
}
public void SetBodyTypeGraphicPath(PawnRaceDef pawnRaceDef, CardinalDirection direction, string bodyType)
{
var paths = StandaloneFileBrowser.OpenFilePanel("Select texture File", "", "png", false);
if (paths == null || paths.Any() == false || File.Exists(paths[0]) == false)
{ Debug.LogWarning("Selected file was null or invalid"); return; }
pawnRaceDef.SetBodyTypeGraphicPath(paths[0], direction, bodyType);
Initialize();
}
public PawnRaceDef GetCurrentRaceDef()
{
string pawnRaceDefName = raceSelectDropdown.value < raceSelectDropdown.options.Count ? raceSelectDropdown.options[raceSelectDropdown.value].text : "Human";
if (pawnRaceDefName == null || pawnRaceDefName == "") pawnRaceDefName = "Human";
return PawnRaceDefs.GetNamed(pawnRaceDefName);
}
public void SetRaceScale()
{
PawnRaceDef pawnRaceDef = GetCurrentRaceDef();
if (pawnRaceDef == null) return;
float scale = float.Parse(scaleField.text);
pawnRaceDef.scale = Mathf.Clamp(scale, 0.01f, 100f);
scaleField.text = string.Format("{0:0.000}", pawnRaceDef.scale);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 983d00d4d240d6c4780e903708f27c06
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,20 @@
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 SelectActorAddonsDialog : DialogBox
{
private List<ActorAddonCard> actorAddonCards = new List<ActorAddonCard>();
public void AddActorAddonCard(ActorAddonCard actorAddonCard)
{
actorAddonCards.Add(actorAddonCard);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 869b2cd91a545c142b38856695c4257a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,49 @@
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 SelectActorLayerDialog : DialogBox
{
public void Initialize()
{
if (Workspace.animationDef == null) return;
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
for (int i = 0; i < DefaultTags.actorLayers.Count; i++)
{
string actorLayer = DefaultTags.actorLayers[i];
Transform _optionToggle = AddCloneObjectToParent(contentWindow).transform;
_optionToggle.Find("Text").GetComponent<Text>().text = actorLayer;
Toggle toggleComp = _optionToggle.GetComponent<Toggle>();
toggleComp.isOn = Workspace.GetCurrentPawnAnimationClip().Layer == actorLayer;
toggleComp.onValueChanged.AddListener(delegate {
PawnAnimationClip clip = Workspace.GetCurrentPawnAnimationClip();
if (clip != null)
{ clip.Layer = actorLayer; }
Workspace.RecordEvent("Actor layer set");
});
toggleComp.group = contentWindow.GetComponent<ToggleGroup>();
}
}
public void Reset()
{
Transform contentWindow = transform.FindDeepChild("Content");
RemoveCloneObjectsFromParent(contentWindow);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ce4b68a13ad01b14f97697ab310a74d9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,36 @@
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 SelectAnimationDialog : DialogBox
{
public void Initialize(AnimationDefs defs)
{
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
for (int i = 0; i < defs.animationDefs.Count; i++)
{
AnimationDef animationDef = defs.animationDefs[i];
Transform _optionButton = AddCloneObjectToParent(contentWindow).transform;
_optionButton.Find("Text").GetComponent<Text>().text = animationDef.DefName;
Button buttonComp = _optionButton.GetComponent<Button>();
buttonComp.onClick.AddListener(delegate { Pop(); ApplicationManager.Instance.LoadAnimation(animationDef); });
}
}
public void Reset()
{
Transform contentWindow = transform.FindDeepChild("Content");
RemoveCloneObjectsFromParent(contentWindow);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6db038d692d34c441b171c72c78e0066
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,66 @@
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 SelectBodyDefTypesDialog : DialogBox
{
public override void Initialize(bool addedNewTag = false)
{
IEnumerable<string> allTags = DefaultTags.bodyDefTypes.Concat(CustomTags.bodyDefTypes);
string placeHolderText = "Enter new body def type...";
Actor actor = Workspace.animationDef.Actors[Workspace.ActorID];
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
for (int i = 0; i < allTags.Count(); i++)
{
string tag = allTags.ElementAt(i);
Transform _optionToggle = AddCloneObjectToParent(contentWindow).transform;
_optionToggle.Find("Text").GetComponent<Text>().text = tag;
Toggle toggleComp = _optionToggle.GetComponent<Toggle>();
toggleComp.isOn = actor.BodyDefTypes.Contains(tag);
toggleComp.onValueChanged.AddListener(delegate
{
if (toggleComp.isOn && actor.BodyDefTypes.Contains(tag) == false)
{ actor.BodyDefTypes.Add(tag); }
else if (toggleComp.isOn == false && actor.BodyDefTypes.Contains(tag))
{ actor.BodyDefTypes.Remove(tag); }
Workspace.RecordEvent("Actor bodyDef type");
});
if (CustomTags.bodyDefTypes.Contains(tag))
{
Button deleteButton = _optionToggle.Find("DeleteButton").GetComponent<Button>();
deleteButton.gameObject.SetActive(true);
deleteButton.onClick.AddListener(delegate { RemoveCustomTag(ref CustomTags.bodyDefTypes, tag); });
}
if (addedNewTag && i == allTags.Count() - 1)
{ toggleComp.isOn = true; }
}
Transform _optionField = AddCloneObjectToParent(contentWindow, 1).transform;
_optionField.Find("Placeholder").GetComponent<Text>().text = placeHolderText;
InputField fieldComp = _optionField.GetComponent<InputField>();
fieldComp.onEndEdit.AddListener(delegate { AddCustomTag(fieldComp, ref DefaultTags.bodyDefTypes, ref CustomTags.bodyDefTypes); });
}
public void Reset()
{
Transform contentWindow = transform.FindDeepChild("Content");
RemoveCloneObjectsFromParent(contentWindow);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b66fb83b0bed5a0438f6fbe11f0c35e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,80 @@
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 SelectBodyPartsDialog : DialogBox
{
public override void Initialize(bool addedNewTag = false)
{
IEnumerable<string> allTags = DefaultTags.bodyParts.Concat(CustomTags.bodyParts);
string placeHolderText = "Enter new body part name...";
Actor actor = Workspace.animationDef.Actors[Workspace.ActorID];
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
Transform _appendageToggle = AddCloneObjectToParent(contentWindow).transform;
_appendageToggle.Find("Text").GetComponent<Text>().text = "Any appendage";
Toggle appendageToggleComp = _appendageToggle.GetComponent<Toggle>();
appendageToggleComp.isOn = actor.IsFucking;
appendageToggleComp.onValueChanged.AddListener(delegate { actor.IsFucking = appendageToggleComp.isOn; Workspace.RecordEvent("Actor required body part");});
Transform _orificeToggle = AddCloneObjectToParent(contentWindow).transform;
_orificeToggle.Find("Text").GetComponent<Text>().text = "Any orifice";
Toggle orificeToggleComp = _orificeToggle.GetComponent<Toggle>();
orificeToggleComp.isOn = actor.IsFucked;
orificeToggleComp.onValueChanged.AddListener(delegate { actor.IsFucked = orificeToggleComp.isOn; Workspace.RecordEvent("Actor required body part"); });
for (int i = 0; i < allTags.Count(); i++)
{
string tag = allTags.ElementAt(i);
Transform _optionToggle = AddCloneObjectToParent(contentWindow).transform;
_optionToggle.Find("Text").GetComponent<Text>().text = tag;
Toggle toggleComp = _optionToggle.GetComponent<Toggle>();
toggleComp.isOn = actor.RequiredGenitals.Contains(tag);
toggleComp.onValueChanged.AddListener(delegate
{
if (toggleComp.isOn && actor.RequiredGenitals.Contains(tag) == false)
{ actor.RequiredGenitals.Add(tag); }
else if (toggleComp.isOn == false && actor.RequiredGenitals.Contains(tag))
{ actor.RequiredGenitals.Remove(tag); }
Workspace.RecordEvent("Actor required body part");
});
if (CustomTags.bodyParts.Contains(tag))
{
Button deleteButton = _optionToggle.Find("DeleteButton").GetComponent<Button>();
deleteButton.gameObject.SetActive(true);
deleteButton.onClick.AddListener(delegate { RemoveCustomTag(ref CustomTags.bodyParts, tag); });
}
if (addedNewTag && i == allTags.Count() - 1)
{ toggleComp.isOn = true; }
}
Transform _optionField = AddCloneObjectToParent(contentWindow, 1).transform;
_optionField.Find("Placeholder").GetComponent<Text>().text = placeHolderText;
InputField fieldComp = _optionField.GetComponent<InputField>();
fieldComp.onEndEdit.AddListener(delegate { AddCustomTag(fieldComp, ref DefaultTags.bodyParts, ref CustomTags.bodyParts); });
}
public void Reset()
{
Transform contentWindow = transform.FindDeepChild("Content");
RemoveCloneObjectsFromParent(contentWindow);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 459a1b2a918e12f468445853ea5821e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,74 @@
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 SelectDefNamesDialog : DialogBox
{
public override void Initialize(bool addedNewTag = false)
{
IEnumerable<string> allTags = DefaultTags.defNames.Concat(CustomTags.defNames);
string placeHolderText = "Enter new def name...";
Actor actor = Workspace.animationDef.Actors[Workspace.ActorID];
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
for (int i = 0; i < allTags.Count(); i++)
{
string tag = allTags.ElementAt(i);
Transform _optionToggle = AddCloneObjectToParent(contentWindow).transform;
_optionToggle.Find("Text").GetComponent<Text>().text = tag;
Toggle toggleComp = _optionToggle.GetComponent<Toggle>();
toggleComp.isOn = actor.DefNames.Contains(tag);
toggleComp.onValueChanged.AddListener(delegate
{
if (toggleComp.isOn && actor.DefNames.Contains(tag) == false)
{ actor.DefNames.Add(tag); }
else if (toggleComp.isOn == false && actor.DefNames.Contains(tag))
{ actor.DefNames.Remove(tag); }
Workspace.RecordEvent("Actor def name");
});
if (CustomTags.defNames.Contains(tag))
{
Button deleteButton = _optionToggle.Find("DeleteButton").GetComponent<Button>();
deleteButton.gameObject.SetActive(true);
deleteButton.onClick.AddListener(delegate {
RemoveCustomTag(ref CustomTags.defNames, tag);
EventsManager.OnDefNamesChanged();
});
}
if (addedNewTag && i == allTags.Count() - 1)
{ toggleComp.isOn = true; }
}
Transform _optionField = AddCloneObjectToParent(contentWindow, 1).transform;
_optionField.Find("Placeholder").GetComponent<Text>().text = placeHolderText;
InputField fieldComp = _optionField.GetComponent<InputField>();
fieldComp.onEndEdit.AddListener(delegate
{
AddCustomTag(fieldComp, ref DefaultTags.defNames, ref CustomTags.defNames);
AddCustomRace(fieldComp);
EventsManager.OnDefNamesChanged();
});
}
public void Reset()
{
Transform contentWindow = transform.FindDeepChild("Content");
RemoveCloneObjectsFromParent(contentWindow);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9842b9e0fd45d4643af5bed7ba2de307
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,67 @@
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 SelectInteractionDefsDialog : DialogBox
{
public override void Initialize(bool addedNewTag = false)
{
IEnumerable<string> allTags = DefaultTags.interactionDefTypes.Concat(CustomTags.interactionDefTypes);
string placeHolderText = "Enter new interaction def type...";
if (Workspace.animationDef == null) return;
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
for (int i = 0; i < allTags.Count(); i++)
{
string tag = allTags.ElementAt(i);
Transform _optionToggle = AddCloneObjectToParent(contentWindow).transform;
_optionToggle.Find("Text").GetComponent<Text>().text = tag;
Toggle toggleComp = _optionToggle.GetComponent<Toggle>();
toggleComp.isOn = Workspace.animationDef.InteractionDefTypes.Contains(tag);
toggleComp.onValueChanged.AddListener(delegate
{
if (toggleComp.isOn && Workspace.animationDef.InteractionDefTypes.Contains(tag) == false)
{ Workspace.animationDef.InteractionDefTypes.Add(tag); }
else if (toggleComp.isOn == false && Workspace.animationDef.InteractionDefTypes.Contains(tag))
{ Workspace.animationDef.InteractionDefTypes.Remove(tag); }
Workspace.RecordEvent("Animation InteractionDef");
});
if (CustomTags.interactionDefTypes.Contains(tag))
{
Button deleteButton = _optionToggle.Find("DeleteButton").GetComponent<Button>();
deleteButton.gameObject.SetActive(true);
deleteButton.onClick.AddListener(delegate { RemoveCustomTag(ref CustomTags.interactionDefTypes, tag); });
}
if (addedNewTag && i == allTags.Count() - 1)
{ toggleComp.isOn = true; }
}
Transform _optionField = AddCloneObjectToParent(contentWindow, 1).transform;
_optionField.Find("Placeholder").GetComponent<Text>().text = placeHolderText;
InputField fieldComp = _optionField.GetComponent<InputField>();
fieldComp.onEndEdit.AddListener(delegate { AddCustomTag(fieldComp, ref DefaultTags.interactionDefTypes, ref CustomTags.interactionDefTypes); });
}
public void Reset()
{
Transform contentWindow = transform.FindDeepChild("Content");
RemoveCloneObjectsFromParent(contentWindow);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cace588a3682dc649b94355d8eee4a77
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,67 @@
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 SelectSexTypesDialog : DialogBox
{
public override void Initialize(bool addedNewTag = false)
{
IEnumerable<string> allTags = DefaultTags.sexTypes.Concat(CustomTags.sexTypes);
string placeHolderText = "Enter new sex type...";
if (Workspace.animationDef == null) return;
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
for (int i = 0; i < allTags.Count(); i++)
{
string tag = allTags.ElementAt(i);
Transform _optionToggle = AddCloneObjectToParent(contentWindow).transform;
_optionToggle.Find("Text").GetComponent<Text>().text = tag;
Toggle toggleComp = _optionToggle.GetComponent<Toggle>();
toggleComp.isOn = Workspace.animationDef.SexTypes.Contains(tag);
toggleComp.onValueChanged.AddListener(delegate
{
if (toggleComp.isOn && Workspace.animationDef.SexTypes.Contains(tag) == false)
{ Workspace.animationDef.SexTypes.Add(tag); }
else if (toggleComp.isOn == false && Workspace.animationDef.SexTypes.Contains(tag))
{ Workspace.animationDef.SexTypes.Remove(tag); }
Workspace.RecordEvent("Animation sex type");
});
if (CustomTags.sexTypes.Contains(tag))
{
Button deleteButton = _optionToggle.Find("DeleteButton").GetComponent<Button>();
deleteButton.gameObject.SetActive(true);
deleteButton.onClick.AddListener(delegate { RemoveCustomTag(ref CustomTags.sexTypes, tag); });
}
if (addedNewTag && i == allTags.Count() - 1)
{ toggleComp.isOn = true; }
}
Transform _optionField = AddCloneObjectToParent(contentWindow, 1).transform;
_optionField.Find("Placeholder").GetComponent<Text>().text = placeHolderText;
InputField fieldComp = _optionField.GetComponent<InputField>();
fieldComp.onEndEdit.AddListener(delegate { AddCustomTag(fieldComp, ref DefaultTags.sexTypes, ref CustomTags.sexTypes); });
}
public void Reset()
{
Transform contentWindow = transform.FindDeepChild("Content");
RemoveCloneObjectsFromParent(contentWindow);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1d4b7a5a5ddb7d744b726c3c13e2fc5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,68 @@
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 SelectSoundDefDialog : DialogBox
{
public override void Initialize(bool addedNewTag = false)
{
IEnumerable<string> allTags = DefaultTags.soundDefs.Concat(CustomTags.soundDefs);
string placeHolderText = "Enter new sound def...";
if (Workspace.animationDef == null) return;
Transform contentWindow = transform.FindDeepChild("Content");
Reset();
for (int i = 0; i < allTags.Count(); i++)
{
string tag = allTags.ElementAt(i);
Transform _optionToggle = AddCloneObjectToParent(contentWindow).transform;
_optionToggle.Find("Text").GetComponent<Text>().text = tag;
Toggle toggleComp = _optionToggle.GetComponent<Toggle>();
toggleComp.isOn = Workspace.GetCurrentOrPreviousKeyframe(Workspace.ActorID)?.SoundEffect == tag;
toggleComp.onValueChanged.AddListener(delegate
{
PawnKeyframe keyframe = Workspace.GetCurrentOrPreviousKeyframe(Workspace.ActorID);
if (keyframe != null)
{ keyframe.SoundEffect = tag; }
Workspace.RecordEvent("Keyframe sound effect");
});
if (CustomTags.soundDefs.Contains(tag))
{
Button deleteButton = _optionToggle.Find("DeleteButton").GetComponent<Button>();
deleteButton.gameObject.SetActive(true);
deleteButton.onClick.AddListener(delegate { RemoveCustomTag(ref CustomTags.soundDefs, tag); });
}
if (addedNewTag && i == allTags.Count() - 1)
{ toggleComp.isOn = true; }
toggleComp.group = contentWindow.GetComponent<ToggleGroup>();
}
Transform _optionField = AddCloneObjectToParent(contentWindow, 1).transform;
_optionField.Find("Placeholder").GetComponent<Text>().text = placeHolderText;
InputField fieldComp = _optionField.GetComponent<InputField>();
fieldComp.onEndEdit.AddListener(delegate { AddCustomTag(fieldComp, ref DefaultTags.soundDefs, ref CustomTags.soundDefs); });
}
public void Reset()
{
Transform contentWindow = transform.FindDeepChild("Content");
RemoveCloneObjectsFromParent(contentWindow);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7cc6afc7ba6ae0f42b3a2df6e73c5b16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class DropdownMenu : MonoBehaviour, IDeselectHandler
{
public Transform dropdownMenu;
public void OpenMenu()
{
dropdownMenu.gameObject.SetActive(true);
EventSystem.current.SetSelectedGameObject(this.gameObject);
}
public void CloseMenu()
{
if (EventSystem.current.currentSelectedGameObject != null)
{
Transform child = transform.FindDeepChild(EventSystem.current.currentSelectedGameObject.name);
if (child != null)
{
EventSystem.current.SetSelectedGameObject(this.gameObject);
return;
}
}
dropdownMenu.gameObject.SetActive(false);
}
public void OnDeselect(BaseEventData eventData)
{
Invoke("CloseMenu", 0.15f);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7367efff96a6a9043ac1c6b3a25dcc39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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 = Workspace.IsAnimating == false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 92068b39ed172084296a595f5a09e54b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,23 @@
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 KeybindLabel : MonoBehaviour
{
public string command;
private Text keybindLabel;
public void Start()
{
keybindLabel = GetComponent<Text>();
keybindLabel.text = KeybindConfig.GetKeybindLabel(command);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2aa5d5fba80ba8346882964ef3756de3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,261 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class KeyframeSlider : Slider, IPointerClickHandler, IBeginDragHandler, IEndDragHandler
{
public int keyframeID;
public AnimationTimeline timeline;
public Transform ghostSliders;
public Slider ghostSliderPrefab;
public Image handleImage;
public GameObject soundIcon;
public int maxGhosts = 4;
public KeyframeSlider linkedSlider;
public PawnKeyframe pivotKeyframe;
public int linkedOffset;
private PawnAnimationClip clip { get { return Workspace.GetPawnAnimationClip(actorID); } }
private PawnKeyframe keyframe { get { return Workspace.GetPawnKeyframe(keyframeID); } }
private int actorID;
private float dragTimeStart = -1f;
private int dragTickStart = -1;
protected override void Start()
{
base.Start();
onValueChanged.AddListener(delegate (float value) { OnValueChanged(); });
}
public void Initialize(AnimationTimeline timeline, int actorID, int keyframeID)
{
this.timeline = timeline;
this.actorID = actorID;
this.keyframeID = keyframeID;
maxValue = Workspace.StageWindowSize;
value = keyframe.atTick.Value;
}
public void OnValueChanged()
{
keyframe.atTick = (int)value;
clip.BuildSimpleCurves();
timeline.InitiateUpdateOfGhostFrames();
}
// Ghost sliders are non-interactable slider handle
public void UpdateGhostFrames()
{
if (maxGhosts == 0)
{ return; }
int requiredGhosts = GetGhostFramesRequired();
int currentGhostCount = ghostSliders.childCount;
for (int i = 0; i < Mathf.Max(requiredGhosts, currentGhostCount); i++)
{
if (clip == null || keyframe == null) continue;
int targetTick = (int)(i * clip.duration + keyframe.atTick);
if (ghostSliders.childCount <= i)
{ Instantiate(ghostSliderPrefab, ghostSliders); }
GameObject ghostSliderObject = ghostSliders.GetChild(i).gameObject;
ghostSliderObject.SetActive(i < requiredGhosts);
Slider ghostSlider = ghostSliderObject.GetComponent<Slider>();
ghostSlider.maxValue = Workspace.StageWindowSize;
ghostSlider.value = targetTick;
if (targetTick > ghostSlider.maxValue)
{ ghostSlider.gameObject.SetActive(false); }
}
}
public int GetGhostFramesRequired()
{
if (Workspace.animationDef.AnimationStages[Workspace.StageID].IsLooping == false)
{ return 0; }
if (clip.duration <= 1)
{ return 0; }
return Math.Min(Mathf.CeilToInt((float)Workspace.StageWindowSize / clip.duration), maxGhosts);
}
public void OnPointerClick(PointerEventData eventData)
{
Workspace.ActorID = actorID;
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftCommand))
{ Workspace.keyframeID.Add(keyframeID); }
else if (Workspace.keyframeID.NullOrEmpty() || Workspace.keyframeID.Contains(keyframeID) == false)
{ Workspace.keyframeID = new List<int> { keyframeID }; }
if (eventData.clickCount >= 2)
{ Workspace.StageTick = keyframe.atTick.Value; }
}
public void OnBeginDrag(PointerEventData eventData)
{
// Select key
Workspace.ActorID = actorID;
dragTimeStart = Time.unscaledTime;
dragTickStart = keyframe.atTick.Value;
if (Workspace.keyframeID.NullOrEmpty() || Workspace.keyframeID.Contains(keyframeID) == false)
{ Workspace.keyframeID = new List<int> { keyframeID }; }
// The first key can't be moved though
if (keyframe.atTick == Constants.minTick)
{ interactable = false; return; }
interactable = true;
List<PawnKeyframe> selectedKeyframes = Workspace.GetPawnKeyframesByID(Workspace.keyframeID).Except(new List<PawnKeyframe>() { keyframe })?.ToList();
// Link other selected keyframes to the movement of this one
if (selectedKeyframes.NotNullOrEmpty())
{
pivotKeyframe = keyframe.atTick <= selectedKeyframes.Min(x => x.atTick) ?
selectedKeyframes.FirstOrDefault(x => x.atTick >= selectedKeyframes.Max(y => y.atTick)) :
selectedKeyframes.FirstOrDefault(x => x.atTick <= selectedKeyframes.Min(y => y.atTick));
foreach (PawnKeyframe selectedKeyframe in selectedKeyframes)
{
KeyframeSlider unlinkedSlider = selectedKeyframe.GetKeyframeSlider();
if (unlinkedSlider != null)
{
if (selectedKeyframe.atTick == Constants.minTick) continue;
if (Workspace.stretchKeyframes && unlinkedSlider.keyframe.atTick == pivotKeyframe.atTick) continue;
unlinkedSlider.linkedSlider = this;
unlinkedSlider.linkedOffset = unlinkedSlider.keyframe.atTick.Value - keyframe.atTick.Value;
}
}
}
}
public override void OnDrag(PointerEventData eventData)
{
Workspace.ActorID = actorID;
// Sticky drag
if (Time.unscaledTime - dragTimeStart < 0.05f) return;
base.OnDrag(eventData);
// Snap to nearest keyframe (on another timeline)
int targetTick = Workspace.FindClosestKeyFrameAtTick(keyframe.atTick.Value, Mathf.CeilToInt(Workspace.StageWindowSize * 0.01f), actorID);
if (Input.GetKey(KeyCode.LeftShift) && Workspace.DoesPawnKeyframeExistAtTick(Workspace.StageID, actorID, targetTick) == false)
{ value = (float)targetTick; }
}
public void OnEndDrag(PointerEventData eventData)
{
List<PawnKeyframe> keyframesToCheck = Workspace.GetAllPawnKeyframesAtTick(actorID, keyframe.atTick.Value);
if (keyframesToCheck.NotNullOrEmpty())
{
foreach (PawnKeyframe _keyframe in keyframesToCheck)
{
if (_keyframe != keyframe)
{ Workspace.GetAnimationClipThatOwnsKeyframe(_keyframe.keyframeID).RemovePawnKeyframe(_keyframe.keyframeID); }
}
}
foreach (Selectable selectable in Selectable.allSelectablesArray)
{
if (selectable is KeyframeSlider)
{
KeyframeSlider linkedSlider = selectable.GetComponent<KeyframeSlider>();
PawnKeyframe linkedKeyframe = linkedSlider.keyframe;
if (linkedSlider.linkedSlider != null)
{
keyframesToCheck = Workspace.GetAllPawnKeyframesAtTick(actorID, linkedKeyframe.atTick.Value);
if (keyframesToCheck.NotNullOrEmpty() && keyframesToCheck.Count > 1)
{
foreach (PawnKeyframe _keyframe in keyframesToCheck)
{
if (_keyframe.keyframeID != linkedKeyframe.keyframeID)
{ Workspace.GetAnimationClipThatOwnsKeyframe(_keyframe.keyframeID).RemovePawnKeyframe(_keyframe.keyframeID); }
}
}
}
linkedSlider.linkedSlider = null;
linkedSlider.pivotKeyframe = null;
}
}
interactable = false;
Workspace.RecordEvent("Keyframe move");
}
protected override void Update()
{
base.Update();
if (keyframe == null) return;
// Update outdated values
if (Workspace.keyframeID.NullOrEmpty() || Workspace.keyframeID.Contains(keyframeID) == false)
{ linkedSlider = null; }
else if (Workspace.stretchKeyframes && linkedSlider != null)
{ value = Mathf.CeilToInt(linkedSlider.keyframe.atTick.Value + linkedOffset * linkedSlider.ScaledOffsetFromPivot()); }
else if (Workspace.stretchKeyframes == false && linkedSlider != null)
{ value = Mathf.Clamp(linkedSlider.keyframe.atTick.Value + linkedOffset, Constants.minTick, Workspace.StageWindowSize); }
else if (keyframe.atTick.Value != value)
{ value = keyframe.atTick.Value; }
// Update key color
if (keyframe.atTick.HasValue && Workspace.keyframeID.Contains(keyframeID) && Workspace.StageTick == keyframe.atTick.Value)
{ handleImage.color = Constants.ColorPurple; }
else if (Workspace.keyframeID.Contains(keyframeID))
{ handleImage.color = Constants.ColorCyan; }
else if (Workspace.StageTick == keyframe.atTick.Value)
{ handleImage.color = Constants.ColorPink; }
else
{ handleImage.color = Constants.ColorGrey; }
// Show sound symbol
string soundDef = Workspace.GetPawnKeyframe(keyframeID)?.SoundEffect;
soundIcon.SetActive(soundDef != null && soundDef != "" && soundDef != "None");
}
public float ScaledOffsetFromPivot()
{
if (dragTickStart == pivotKeyframe.atTick.Value) return 0f;
return (float)(keyframe.atTick.Value - pivotKeyframe.atTick.Value) / (dragTickStart - pivotKeyframe.atTick.Value);
}
public bool IsPivotKeyframe(PawnKeyframe otherKeyframe)
{
return pivotKeyframe == otherKeyframe;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c733f5218a2b4a449e3115b2bef26f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,67 @@
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 LinearScale : Singleton<LinearScale>
{
public Transform animationTimelines;
public int targetDivisions = 30;
public List<int> divisionBands = new List<int>() { 5, 10, 25, 50, 100, 250, 500, 1000 };
public GameObject linearScaleTickPrefab;
private List<int> divisions = new List<int>();
private float minDiff = -1f;
public void Start()
{
EventsManager.onAnimationChanged.AddListener(delegate { UpdateLinearScale(); });
EventsManager.onStageIDChanged.AddListener(delegate { UpdateLinearScale(); });
EventsManager.onStageWindowSizeChanged.AddListener(delegate { UpdateLinearScale(); });
UpdateLinearScale();
}
public void UpdateLinearScale()
{
if (Workspace.animationDef == null) return;
LayoutRebuilder.ForceRebuildLayoutImmediate(animationTimelines.GetComponent<RectTransform>());
minDiff = -1f;
foreach (int division in divisionBands)
{
float numDivisions = (float)Workspace.StageWindowSize / division;
if (minDiff >= 0f && Mathf.Abs(targetDivisions - numDivisions) > minDiff) continue;
minDiff = Mathf.Abs(targetDivisions - numDivisions);
int i = 0;
divisions.Clear();
while (i + division <= Workspace.StageWindowSize)
{
i += division;
divisions.Add(i);
}
}
foreach (Transform child in transform)
{ Destroy(child.gameObject); }
foreach (int division in divisions)
{
GameObject obj = Instantiate(linearScaleTickPrefab, transform);
obj.GetComponentInChildren<Text>().text = division.ToString();
float xOffset = ((float)(division - Constants.minTick) / (Workspace.StageWindowSize - Constants.minTick)) * transform.parent.GetComponent<RectTransform>().rect.width;
obj.GetComponent<RectTransform>().localPosition = new Vector3(xOffset, 0, 0);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4264bb913f7501844bf60529d6b59b8a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9171c89c691f71d4eb37426db074efc8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,12 @@
using System;
using UnityEngine;
namespace RimWorldAnimationStudio
{
[Serializable]
public class SexProp
{
public string label;
public Sprite sprite;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94f6b7ad49adabe428c011abfcf4da53
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class SexPropManager : MonoBehaviour
{
public List<SexProp> sexProps = new List<SexProp>();
public Dropdown sexPropDropdown;
private SpriteRenderer spriteRenderer;
public void OnEnable()
{
spriteRenderer = GetComponent<SpriteRenderer>();
foreach (SexProp sexProp in sexProps)
{ sexPropDropdown.options.Add(new Dropdown.OptionData(sexProp.label)); }
}
public void OnOptionChanged()
{
spriteRenderer.sprite = sexProps[sexPropDropdown.value].sprite;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 587f7397b0c3ecf4495edb8af5dbd777
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,26 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class QuiverToggle : MonoBehaviour
{
public void Update()
{
PawnKeyframe keyframe = Workspace.GetCurrentOrPreviousKeyframe(Workspace.ActorID);
GetComponent<Toggle>().isOn = keyframe != null && keyframe.Quiver;
}
public void OnValueChanged()
{
PawnKeyframe keyframe = Workspace.GetCurrentOrPreviousKeyframe(Workspace.ActorID);
if (keyframe != null)
{ keyframe.Quiver = GetComponent<Toggle>().isOn; }
Workspace.RecordEvent("Actor quiver");
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1aaf656fd4e788245accc65162730545
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class RequiresAnimationDef : MonoBehaviour
{
private Button button;
private List<Text> buttonText;
private List<Color> buttonTextColor = new List<Color>();
private void Start()
{
button = GetComponent<Button>();
buttonText = GetComponentsInChildren<Text>()?.ToList();
if (buttonText != null)
{
for (int i = 0; i < buttonText.Count; i++)
{ buttonTextColor.Add(buttonText[i].color); }
}
}
private void Update()
{
button.interactable = Workspace.animationDef != null;
for (int i = 0; i < buttonText.Count; i++)
{ buttonText[i].color = button.interactable ? buttonTextColor[i] : Constants.ColorMidGrey; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7903694afa5d7ba429917c147e222781
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,30 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace RimWorldAnimationStudio
{
public class SelectActorLayerButton : MonoBehaviour
{
private Text text;
public void Start()
{
text = GetComponentInChildren<Text>();
}
void Update()
{
if (Workspace.animationDef == null) return;
PawnAnimationClip clip = Workspace.GetCurrentPawnAnimationClip();
if (clip != null)
{ text.text = clip.Layer; }
else
{ text.text = "Pawn"; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 329a2ecc35813f94fa879c7f434c8fb7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,26 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class SnapToKeyframe : MonoBehaviour, IDragHandler
{
private Slider slider;
public void Start()
{
slider = GetComponent<Slider>();
}
public void OnDrag(PointerEventData eventData)
{
int targetTick = Workspace.FindClosestKeyFrameAtTick((int)slider.value, Mathf.CeilToInt(Workspace.StageWindowSize * 0.01f));
if (Input.GetKey(KeyCode.LeftShift))
{ slider.value = (float)targetTick; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 09b43781ddbab9c49b81b88c7a8b4076
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3b338b9ecc1c2584d82563578794ad43
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RimWorldAnimationStudio
{
public class Tooltip : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public string message = "Undefined";
public string executedCommand;
public float delay = 0f;
public Vector2 offset = new Vector2(5f, -15f);
public bool flipX = false;
public GameObject tooltip;
public Text tooltipText;
private bool isActive;
private bool isDisplayed;
private float activeTime = -1f;
public void Start()
{
tooltip = Resources.FindObjectsOfTypeAll<TooltipMessage>()?.FirstOrDefault().gameObject;
tooltipText = tooltip?.GetComponentInChildren<Text>();
}
public void Update()
{
if (tooltip == null || isActive == false || (activeTime + delay) > Time.unscaledTime) return;
if (isDisplayed == false)
{
tooltip.GetComponent<RectTransform>().pivot = flipX ? new Vector2(1, 1) : new Vector2(0, 1);
tooltipText.text = message;
if (executedCommand != null && executedCommand != "")
{ tooltipText.text += " (" + KeybindConfig.GetKeybindLabel(executedCommand) + ")"; }
tooltip.transform.position = (Vector2)transform.position + offset;
tooltip.gameObject.SetActive(true);
LayoutRebuilder.ForceRebuildLayoutImmediate(tooltip.GetComponent<RectTransform>());
isDisplayed = true;
}
}
public void OnDisable()
{
if (isActive)
{ OnPointerExit(new PointerEventData(EventSystem.current)); }
}
public void OnPointerEnter(PointerEventData pointerEventData)
{
isActive = true;
activeTime = Time.unscaledTime;
}
public void OnPointerExit(PointerEventData pointerEventData)
{
isActive = false;
isDisplayed = false;
tooltip.gameObject.SetActive(false);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c05e9ac2a2f311549b12f094d2785a20
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TooltipMessage : MonoBehaviour
{
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec8ec1002bf0dda4aa55bfb75b152066
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: