mirror of
https://github.com/originalnicodr/CinematicUnityExplorer.git
synced 2026-10-11 01:48:07 +08:00
Added support to manually play animations of entities on the scene (only for Mono builds). Also refactored the AnimatorPanel with a pool of objects.
This commit is contained in:
1 parent
4f91fdfa66
commit
59ffa462cc
2 files changed
+229
-80
No files matched your search
@@ -4,6 +4,7 @@ using UnityExplorer.Inspectors;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UnityEngine;
|
||||
#if UNHOLLOWER
|
||||
using UnhollowerRuntimeLib;
|
||||
@@ -12,9 +13,13 @@ using UnhollowerRuntimeLib;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
#endif
|
||||
|
||||
#if CPP
|
||||
using Animator = UnityEngine.Behaviour;
|
||||
#endif
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
internal class AnimatorPanel : UEPanel
|
||||
internal class AnimatorPanel : UEPanel, ICellPoolDataSource<AnimatorCell>
|
||||
{
|
||||
public AnimatorPanel(UIBase owner) : base(owner)
|
||||
{
|
||||
@@ -23,106 +28,68 @@ namespace UnityExplorer.UI.Panels
|
||||
public override string Name => "Animator";
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.AnimatorPanel;
|
||||
public override int MinWidth => 500;
|
||||
public override int MinHeight => 500;
|
||||
public override int MinHeight => 200;
|
||||
public override Vector2 DefaultAnchorMin => new(0.4f, 0.4f);
|
||||
public override Vector2 DefaultAnchorMax => new(0.6f, 0.6f);
|
||||
public override bool NavButtonWanted => true;
|
||||
public override bool ShouldSaveActiveState => true;
|
||||
List<GameObject> UIElements = new List<GameObject>();
|
||||
|
||||
internal Dictionary<string,List<Behaviour>> animators = new Dictionary<string,List<Behaviour>>();
|
||||
internal Dictionary<string,List<Toggle>> animatorToggles = new Dictionary<string,List<Toggle>>();
|
||||
internal Dictionary<string,bool> ignoresMasterToggler = new Dictionary<string,bool>();
|
||||
Dictionary<Animator, Func<bool>> animationEndedFunctions = new Dictionary<Animator, Func<bool>>();
|
||||
|
||||
Toggle masterAnimatorToggle = new Toggle();
|
||||
|
||||
private static ScrollPool<AnimatorCell> animatorScrollPool;
|
||||
internal List<Animator> animators = new List<Animator>();
|
||||
public int ItemCount => animators.Count;
|
||||
|
||||
private static bool DoneScrollPoolInit;
|
||||
|
||||
public override void SetActive(bool active)
|
||||
{
|
||||
base.SetActive(active);
|
||||
|
||||
if (active && !DoneScrollPoolInit)
|
||||
{
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(this.Rect);
|
||||
animatorScrollPool.Initialize(this);
|
||||
DoneScrollPoolInit = true;
|
||||
}
|
||||
|
||||
animatorScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
private void FindAllAnimators(){
|
||||
// Enable all animators on refresh
|
||||
if (animators.Count != 0) {
|
||||
masterAnimatorToggle.isOn = true; // Will also trigger "MasterToggleAnimators(true)"
|
||||
animators.Clear();
|
||||
animatorToggles.Clear();
|
||||
ignoresMasterToggler.Clear();
|
||||
animationEndedFunctions.Clear();
|
||||
#if MONO
|
||||
foreach (AnimatorCell animatorCell in animatorScrollPool.CellPool)
|
||||
{
|
||||
animatorCell.ResetAnimation();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Type searchType = ReflectionUtility.GetTypeByName("UnityEngine.Animator");
|
||||
searchType = searchType is Type type ? type : searchType.GetActualType();
|
||||
List<Behaviour> animatorsList = RuntimeHelper.FindObjectsOfTypeAll(searchType).Select(obj => obj.TryCast<Behaviour>())
|
||||
animators = RuntimeHelper.FindObjectsOfTypeAll(searchType).Select(obj => obj.TryCast<Animator>())
|
||||
.Where(a => a.GetComponentsInChildren<SkinnedMeshRenderer>(false).Length != 0 && a.enabled && a.GetComponentsInChildren<Rigidbody>(false).Length != 0)
|
||||
.OrderBy(x=>x.name)
|
||||
.ToList();
|
||||
|
||||
foreach(Behaviour animator in animatorsList){
|
||||
GameObject gObj = animator.gameObject;
|
||||
string key = getNameWithoutClone(gObj.name);
|
||||
|
||||
if (!animators.ContainsKey(key)){
|
||||
animators.Add(key, new List<Behaviour>());
|
||||
}
|
||||
|
||||
animators[key].Add(animator);
|
||||
}
|
||||
|
||||
BuildAnimatorsTogglers();
|
||||
}
|
||||
|
||||
private string getNameWithoutClone(string name){
|
||||
string newName = name;
|
||||
while (newName.EndsWith("(Clone)")){
|
||||
newName = newName.Substring(0, newName.Length - 7);
|
||||
}
|
||||
|
||||
return newName;
|
||||
}
|
||||
|
||||
private void BuildAnimatorsTogglers(){
|
||||
foreach (var comp in UIElements){
|
||||
UnityEngine.Object.Destroy(comp);
|
||||
//UIElements.Remove(comp);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, List<Behaviour>> entry in animators)
|
||||
{
|
||||
// A weird canse insensitive "Contains" to identify the player
|
||||
ignoresMasterToggler[entry.Key] = entry.Key.IndexOf("play", 0, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
|
||||
GameObject horiGroup = UIFactory.CreateHorizontalGroup(ContentRoot, $"{entry.Key}_Group", false, false, true, false, 4,
|
||||
default, new Color(1, 1, 1, 0), TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(horiGroup, minHeight: 25, flexibleWidth: 9999);
|
||||
UIElements.Add(horiGroup);
|
||||
|
||||
// is Affected by Master Toggler toggle
|
||||
Toggle ignoresMasterTogglerToggle;
|
||||
GameObject ignoresMasterTogglerObj = UIFactory.CreateToggle(horiGroup, $"Toggle {entry.Key}", out ignoresMasterTogglerToggle, out Text ignoresMasterTogglerText);
|
||||
UIFactory.SetLayoutElement(ignoresMasterTogglerObj, minHeight: 25);
|
||||
ignoresMasterTogglerToggle.isOn = ignoresMasterToggler[entry.Key];
|
||||
ignoresMasterTogglerToggle.onValueChanged.AddListener(value => ignoresMasterToggler[entry.Key] = value);
|
||||
ignoresMasterTogglerText.text = entry.Key;
|
||||
|
||||
foreach (Behaviour entityAnimator in entry.Value){
|
||||
Toggle animatorToggle;
|
||||
GameObject animatorObj = UIFactory.CreateToggle(horiGroup, $"Toggle {entry.Key}", out animatorToggle, out Text animatorToggleText);
|
||||
|
||||
if (!animatorToggles.ContainsKey(entry.Key)){
|
||||
animatorToggles.Add(entry.Key, new List<Toggle>());
|
||||
}
|
||||
animatorToggles[entry.Key].Add(animatorToggle);
|
||||
|
||||
UIFactory.SetLayoutElement(animatorObj, minHeight: 25);
|
||||
animatorToggle.isOn = true;
|
||||
animatorToggle.onValueChanged.AddListener(value => entityAnimator.enabled = value);
|
||||
}
|
||||
|
||||
}
|
||||
animatorScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
public void MasterToggleAnimators(bool enable){
|
||||
// Load animators for the first time if there are not any
|
||||
if (animators.Count == 0) FindAllAnimators();
|
||||
foreach (KeyValuePair<string, List<Behaviour>> entry in animators)
|
||||
foreach (AnimatorCell animatorCell in animatorScrollPool.CellPool)
|
||||
{
|
||||
if (!ignoresMasterToggler[entry.Key]){
|
||||
foreach (Toggle animatorToggle in animatorToggles[entry.Key]){
|
||||
animatorToggle.isOn = enable;
|
||||
}
|
||||
if (animatorCell.animator != null && !animatorCell.IgnoreMasterToggle.isOn){
|
||||
animatorCell.AnimatorToggle.isOn = enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,6 +98,13 @@ namespace UnityExplorer.UI.Panels
|
||||
masterAnimatorToggle.isOn = !masterAnimatorToggle.isOn;
|
||||
}
|
||||
|
||||
#if MONO
|
||||
public override void Update(){
|
||||
foreach (Animator animator in animators){
|
||||
animationEndedFunctions[animator]();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// ~~~~~~~~ UI construction / callbacks ~~~~~~~~
|
||||
|
||||
protected override void ConstructPanelContent()
|
||||
@@ -154,11 +128,33 @@ namespace UnityExplorer.UI.Panels
|
||||
default, new Color(1, 1, 1, 0), TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(firstGroup, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
Text isPlayerLabel = UIFactory.CreateLabel(secondGroup, "IsAffectedByMasterToggler", "Ignores Master Toggler", TextAnchor.MiddleLeft, Color.white, false, 15);
|
||||
UIFactory.SetLayoutElement(isPlayerLabel.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0);
|
||||
|
||||
Text enableLabel = UIFactory.CreateLabel(secondGroup, "EnableLabel", "Enable ", TextAnchor.MiddleRight, Color.white, false, 15);
|
||||
UIFactory.SetLayoutElement(enableLabel.gameObject, minHeight: 25, minWidth: 75, flexibleWidth: 9999);
|
||||
animatorScrollPool = UIFactory.CreateScrollPool<AnimatorCell>(ContentRoot, "AnimatorsList", out GameObject scrollObj,
|
||||
out GameObject scrollContent, new Color(0.03f, 0.03f, 0.03f));
|
||||
UIFactory.SetLayoutElement(scrollObj, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
}
|
||||
|
||||
public void SetCell(AnimatorCell cell, int index)
|
||||
{
|
||||
if (index >= animators.Count)
|
||||
{
|
||||
cell.Disable();
|
||||
return;
|
||||
}
|
||||
|
||||
Animator animator = animators[index];
|
||||
if (animator == null)
|
||||
return;
|
||||
|
||||
cell.animator = animator;
|
||||
cell.name.text = animator.gameObject.name;
|
||||
|
||||
cell.MaybeSetIgnoreMasterToggleSet();
|
||||
#if MONO
|
||||
cell.DrawAnimatorPlayer();
|
||||
animationEndedFunctions[animator] = cell.IsPlayingSelectedAnimation;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnCellBorrowed(AnimatorCell cell) { }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user