From 5bed573c2a53b421e257ba28c2c3159fe0ba1d97 Mon Sep 17 00:00:00 2001 From: Nicolas Gnyra Date: Sun, 27 Oct 2024 21:30:52 -0400 Subject: [PATCH] Move large conditional blocks to partial classes --- .../Scripts/AvatarDescriptor.Editor.cs | 99 +++++++ .../Scripts/EventManager.Editor.cs | 79 ++++++ .../Scripts/VRIKManager.Editor.cs | 79 ++++++ .../CustomAvatar/Scripts/AvatarDescriptor.cs | 99 +------ .../Scripts/EventManager.Runtime.cs | 189 +++++++++++++ Source/CustomAvatar/Scripts/EventManager.cs | 264 +----------------- Source/CustomAvatar/Scripts/VRIKManager.cs | 81 +----- 7 files changed, 451 insertions(+), 439 deletions(-) create mode 100644 Source/CustomAvatar-Editor/Scripts/AvatarDescriptor.Editor.cs create mode 100644 Source/CustomAvatar-Editor/Scripts/EventManager.Editor.cs create mode 100644 Source/CustomAvatar-Editor/Scripts/VRIKManager.Editor.cs create mode 100644 Source/CustomAvatar/Scripts/EventManager.Runtime.cs diff --git a/Source/CustomAvatar-Editor/Scripts/AvatarDescriptor.Editor.cs b/Source/CustomAvatar-Editor/Scripts/AvatarDescriptor.Editor.cs new file mode 100644 index 00000000..39249aba --- /dev/null +++ b/Source/CustomAvatar-Editor/Scripts/AvatarDescriptor.Editor.cs @@ -0,0 +1,99 @@ +using System.IO; +using System.Reflection; +using UnityEngine; + +namespace CustomAvatar +{ + public partial class AvatarDescriptor + { + private Mesh _saberMesh; + + protected void OnDrawGizmos() + { + if (!isActiveAndEnabled) return; + if (!_saberMesh) _saberMesh = LoadMesh(Assembly.GetExecutingAssembly().GetManifestResourceStream("CustomAvatar.Resources.saber.dat")); + + DrawSaber(transform.Find("LeftHand"), _saberMesh, new Color(0.78f, 0.08f, 0.08f)); + DrawSaber(transform.Find("RightHand"), _saberMesh, new Color(0, 0.46f, 0.82f)); + } + + private Mesh LoadMesh(Stream stream) + { + var mesh = new Mesh(); + + using (var reader = new BinaryReader(stream)) + { + int length = reader.ReadInt32(); + var vertices = new Vector3[length]; + + for (int i = 0; i < length; i++) + { + vertices[i] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + + length = reader.ReadInt32(); + var normals = new Vector3[length]; + + for (int i = 0; i < length; i++) + { + normals[i] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + + length = reader.ReadInt32(); + int[] triangles = new int[length]; + + for (int i = 0; i < length; i++) + { + triangles[i] = reader.ReadInt32(); + } + + mesh.SetVertices(vertices); + mesh.SetNormals(normals); + mesh.SetTriangles(triangles, 0); + } + + return mesh; + } + + internal void SaveMesh(Mesh mesh) + { + using (var writer = new BinaryWriter(File.OpenWrite("mesh.dat"))) + { + writer.Write(mesh.vertices.Length); + + foreach (Vector3 vertex in mesh.vertices) + { + writer.Write(vertex.x); + writer.Write(vertex.y); + writer.Write(vertex.z); + } + + writer.Write(mesh.normals.Length); + + foreach (Vector3 normal in mesh.normals) + { + writer.Write(normal.x); + writer.Write(normal.y); + writer.Write(normal.z); + } + + writer.Write(mesh.triangles.Length); + + foreach (int triangle in mesh.triangles) + { + writer.Write(triangle); + } + } + } + + private void DrawSaber(Transform transform, Mesh mesh, Color color) + { + if (!transform) return; + + Color prev = Gizmos.color; + Gizmos.color = color; + Gizmos.DrawMesh(mesh, transform.position, transform.rotation, Vector3.one); + Gizmos.color = prev; + } + } +} diff --git a/Source/CustomAvatar-Editor/Scripts/EventManager.Editor.cs b/Source/CustomAvatar-Editor/Scripts/EventManager.Editor.cs new file mode 100644 index 00000000..945814bf --- /dev/null +++ b/Source/CustomAvatar-Editor/Scripts/EventManager.Editor.cs @@ -0,0 +1,79 @@ +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Serialization; + +namespace CustomAvatar +{ + public partial class EventManager + { + [SerializeField] + [FormerlySerializedAs("OnSlice")] + private UnityEvent _leftGoodCut; + + [SerializeField] + [FormerlySerializedAs("OnSlice")] + private UnityEvent _rightGoodCut; + + [SerializeField] + private UnityEvent _leftBadCut; + + [SerializeField] + private UnityEvent _rightBadCut; + + [SerializeField] + private UnityEvent _leftNoteMissed; + + [SerializeField] + private UnityEvent _rightNoteMissed; + + [SerializeField] + [FormerlySerializedAs("SaberStartColliding")] + private UnityEvent _leftSaberStartedColliding; + + [SerializeField] + [FormerlySerializedAs("SaberStartColliding")] + private UnityEvent _rightSaberStartedColliding; + + [SerializeField] + [FormerlySerializedAs("SaberStopColliding")] + private UnityEvent _leftSaberStoppedColliding; + + [SerializeField] + [FormerlySerializedAs("SaberStopColliding")] + private UnityEvent _rightSaberStoppedColliding; + + [SerializeField] + [FormerlySerializedAs("OnComboChanged")] + private IntUnityEvent _comboIncreased; + + [SerializeField] + [FormerlySerializedAs("OnComboBreak")] + private UnityEvent _comboBroken; + + [SerializeField] + [FormerlySerializedAs("MultiplierUp")] + private IntUnityEvent _multiplierIncreased; + + [SerializeField] + private IntUnityEvent _multiplierDecreased; + + [SerializeField] + [FormerlySerializedAs("OnLevelStart")] + private UnityEvent _levelStarted; + + [SerializeField] + [FormerlySerializedAs("OnLevelFinish")] + private UnityEvent _levelFinished; + + [SerializeField] + [FormerlySerializedAs("OnLevelFail")] + private UnityEvent _levelFailed; + + [SerializeField] + [FormerlySerializedAs("OnMenuEnter")] + private UnityEvent _menuEntered; + + [SerializeField] + private UnityEvent _multiplayerLobbyEntered; + } +} diff --git a/Source/CustomAvatar-Editor/Scripts/VRIKManager.Editor.cs b/Source/CustomAvatar-Editor/Scripts/VRIKManager.Editor.cs new file mode 100644 index 00000000..79a1e818 --- /dev/null +++ b/Source/CustomAvatar-Editor/Scripts/VRIKManager.Editor.cs @@ -0,0 +1,79 @@ +using UnityEditor; +using UnityEngine; + +namespace CustomAvatar +{ + public partial class VRIKManager + { + private GUIStyle _redLabelStyle; + private GUIStyle _greenLabelStyle; + private GUIStyle _blueLabelStyle; + + protected void OnDrawGizmosSelected() + { + if (_redLabelStyle == null) + { + _redLabelStyle = new GUIStyle(EditorStyles.label); + _redLabelStyle.normal.textColor = Color.red; + } + + if (_greenLabelStyle == null) + { + _greenLabelStyle = new GUIStyle(EditorStyles.label); + _greenLabelStyle.normal.textColor = Color.green; + } + + if (_blueLabelStyle == null) + { + _blueLabelStyle = new GUIStyle(EditorStyles.label); + _blueLabelStyle.normal.textColor = Color.blue; + } + + DrawHandAxes(references_leftHand, solver_leftArm_wristToPalmAxis, solver_leftArm_palmToThumbAxis, true); + DrawHandAxes(references_rightHand, solver_rightArm_wristToPalmAxis, solver_rightArm_palmToThumbAxis, false); + } + + private void DrawHandAxes(Transform reference, Vector3 wristToPalmAxis, Vector3 palmToThumbAxis, bool invertNormal) + { + if (!reference) + { + return; + } + + Vector3 wristToPalmVector = default; + Vector3 palmToThumbVector = default; + + if (wristToPalmAxis.sqrMagnitude > 0) + { + wristToPalmVector = reference.rotation * wristToPalmAxis.normalized; + + Handles.color = Color.green; + Handles.ArrowHandleCap(0, reference.position, Quaternion.LookRotation(wristToPalmVector), 0.1f, EventType.Repaint); + Handles.Label(reference.position + wristToPalmVector * 0.12f, "Wrist to Palm Axis", _greenLabelStyle); + } + + if (palmToThumbAxis.sqrMagnitude > 0) + { + palmToThumbVector = reference.rotation * palmToThumbAxis.normalized; + + Handles.color = Color.red; + Handles.ArrowHandleCap(0, reference.position, Quaternion.LookRotation(palmToThumbVector), 0.1f, EventType.Repaint); + Handles.Label(reference.position + palmToThumbVector * 0.12f, "Palm to Thumb Axis", _redLabelStyle); + } + + if (wristToPalmAxis.sqrMagnitude > 0 && palmToThumbAxis.sqrMagnitude > 0) + { + Vector3 planeNormal = new Plane(reference.position, reference.position + wristToPalmVector, reference.position + palmToThumbVector).normal; + + if (invertNormal) + { + planeNormal = -planeNormal; + } + + Handles.color = Color.blue; + Handles.ArrowHandleCap(0, reference.position, Quaternion.LookRotation(planeNormal), 0.1f, EventType.Repaint); + Handles.Label(reference.position + planeNormal * 0.12f, "Palm Inside Axis", _blueLabelStyle); + } + } + } +} diff --git a/Source/CustomAvatar/Scripts/AvatarDescriptor.cs b/Source/CustomAvatar/Scripts/AvatarDescriptor.cs index e3b87a35..610e7c48 100644 --- a/Source/CustomAvatar/Scripts/AvatarDescriptor.cs +++ b/Source/CustomAvatar/Scripts/AvatarDescriptor.cs @@ -17,11 +17,6 @@ using UnityEngine; using System.Linq; -#if UNITY_EDITOR -using System.IO; -using System.Reflection; -#endif - // keeping root namespace for compatibility namespace CustomAvatar { @@ -29,7 +24,7 @@ namespace CustomAvatar /// Container for an avatar's name and other information configured before exportation. /// [DisallowMultipleComponent] - public class AvatarDescriptor : MonoBehaviour, ISerializationCallbackReceiver + public partial class AvatarDescriptor : MonoBehaviour, ISerializationCallbackReceiver { /// /// Avatar's name. @@ -74,97 +69,5 @@ public void OnAfterDeserialize() // Editor calls DoesObjectWithInstanceIDExist which doesn't exist at run time and blows up if not on the main thread, so just check the cached pointer. private T FirstNonNullUnityObject(params T[] objects) where T : Object => objects.FirstOrDefault(o => o is not null && o.GetCachedPtr() != System.IntPtr.Zero); - -#if UNITY_EDITOR - private Mesh _saberMesh; - - protected void OnDrawGizmos() - { - if (!isActiveAndEnabled) return; - if (!_saberMesh) _saberMesh = LoadMesh(Assembly.GetExecutingAssembly().GetManifestResourceStream("CustomAvatar.Resources.saber.dat")); - - DrawSaber(transform.Find("LeftHand"), _saberMesh, new Color(0.78f, 0.08f, 0.08f)); - DrawSaber(transform.Find("RightHand"), _saberMesh, new Color(0, 0.46f, 0.82f)); - } - - private Mesh LoadMesh(Stream stream) - { - var mesh = new Mesh(); - - using (var reader = new BinaryReader(stream)) - { - int length = reader.ReadInt32(); - var vertices = new Vector3[length]; - - for (int i = 0; i < length; i++) - { - vertices[i] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - } - - length = reader.ReadInt32(); - var normals = new Vector3[length]; - - for (int i = 0; i < length; i++) - { - normals[i] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - } - - length = reader.ReadInt32(); - int[] triangles = new int[length]; - - for (int i = 0; i < length; i++) - { - triangles[i] = reader.ReadInt32(); - } - - mesh.SetVertices(vertices); - mesh.SetNormals(normals); - mesh.SetTriangles(triangles, 0); - } - - return mesh; - } - - internal void SaveMesh(Mesh mesh) - { - using (var writer = new BinaryWriter(File.OpenWrite("mesh.dat"))) - { - writer.Write(mesh.vertices.Length); - - foreach (Vector3 vertex in mesh.vertices) - { - writer.Write(vertex.x); - writer.Write(vertex.y); - writer.Write(vertex.z); - } - - writer.Write(mesh.normals.Length); - - foreach (Vector3 normal in mesh.normals) - { - writer.Write(normal.x); - writer.Write(normal.y); - writer.Write(normal.z); - } - - writer.Write(mesh.triangles.Length); - - foreach (int triangle in mesh.triangles) - { - writer.Write(triangle); - } - } - } - - private void DrawSaber(Transform transform, Mesh mesh, Color color) - { - if (!transform) return; - - Color prev = Gizmos.color; - Gizmos.color = color; - Gizmos.DrawMesh(mesh, transform.position, transform.rotation, Vector3.one); - Gizmos.color = prev; - } -#endif } } diff --git a/Source/CustomAvatar/Scripts/EventManager.Runtime.cs b/Source/CustomAvatar/Scripts/EventManager.Runtime.cs new file mode 100644 index 00000000..2c3a0aea --- /dev/null +++ b/Source/CustomAvatar/Scripts/EventManager.Runtime.cs @@ -0,0 +1,189 @@ +using System.Reflection; +using CustomAvatar.Avatar; +using CustomAvatar.Logging; +using JetBrains.Annotations; +using UnityEngine; +using UnityEngine.Events; +using Zenject; + +namespace CustomAvatar +{ + public partial class EventManager + { + private static readonly FieldInfo kPersistentCallsField = typeof(UnityEventBase).GetField("m_PersistentCalls", BindingFlags.NonPublic | BindingFlags.Instance); + + #region Legacy +#pragma warning disable IDE1006 + + // these are only present because FormerlySerializedAs does not work in the game + + [SerializeField] + private UnityEvent OnSlice; + + [SerializeField] + private UnityEvent OnComboBreak; + + [SerializeField] + private UnityEvent MultiplierUp; + + [SerializeField] + private UnityEvent SaberStartColliding; + + [SerializeField] + private UnityEvent SaberStopColliding; + + [SerializeField] + private UnityEvent OnMenuEnter; + + [SerializeField] + private UnityEvent OnLevelStart; + + [SerializeField] + private UnityEvent OnLevelFail; + + [SerializeField] + private UnityEvent OnLevelFinish; + + [SerializeField] + private UnityEvent OnComboChanged; + +#pragma warning restore IDE1006 + #endregion + + [SerializeField] + private UnityEvent _leftGoodCut; + + [SerializeField] + private UnityEvent _rightGoodCut; + + [SerializeField] + private UnityEvent _leftBadCut; + + [SerializeField] + private UnityEvent _rightBadCut; + + [SerializeField] + private UnityEvent _leftNoteMissed; + + [SerializeField] + private UnityEvent _rightNoteMissed; + + [SerializeField] + private UnityEvent _leftSaberStartedColliding; + + [SerializeField] + private UnityEvent _rightSaberStartedColliding; + + [SerializeField] + private UnityEvent _leftSaberStoppedColliding; + + [SerializeField] + private UnityEvent _rightSaberStoppedColliding; + + [SerializeField] + private UnityEvent _comboIncreased; + + [SerializeField] + private UnityEvent _comboBroken; + + [SerializeField] + private UnityEvent _multiplierIncreased; + + [SerializeField] + private UnityEvent _multiplierDecreased; + + [SerializeField] + private UnityEvent _levelStarted; + + [SerializeField] + private UnityEvent _levelFinished; + + [SerializeField] + private UnityEvent _levelFailed; + + [SerializeField] + private UnityEvent _menuEntered; + + [SerializeField] + private UnityEvent _multiplayerLobbyEntered; + + public void OnBeforeSerialize() + { + } + + public void OnAfterDeserialize() + { + // find first event with serialized persistent calls since FormerlySerializedAs doesn't work + // can't do ?? since events are never deserialized as null + _leftGoodCut = FirstWithPersistentCalls(_leftGoodCut, OnSlice); + _rightGoodCut = FirstWithPersistentCalls(_rightGoodCut, OnSlice); + _comboBroken = FirstWithPersistentCalls(_comboBroken, OnComboBreak); + _multiplierIncreased = FirstWithPersistentCalls(_multiplierIncreased, MultiplierUp); + _leftSaberStartedColliding = FirstWithPersistentCalls(_leftSaberStartedColliding, SaberStartColliding); + _rightSaberStartedColliding = FirstWithPersistentCalls(_rightSaberStartedColliding, SaberStartColliding); + _leftSaberStoppedColliding = FirstWithPersistentCalls(_leftSaberStoppedColliding, SaberStopColliding); + _rightSaberStoppedColliding = FirstWithPersistentCalls(_rightSaberStoppedColliding, SaberStopColliding); + _menuEntered = FirstWithPersistentCalls(_menuEntered, OnMenuEnter); + _levelStarted = FirstWithPersistentCalls(_levelStarted, OnLevelStart); + _levelFailed = FirstWithPersistentCalls(_levelFailed, OnLevelFail); + _levelFinished = FirstWithPersistentCalls(_levelFinished, OnLevelFinish); + _comboIncreased = FirstWithPersistentCalls(_comboIncreased, OnComboChanged); + + comboIncreased = DeserializeGenericEvent(_comboIncreased); + multiplierIncreased = DeserializeGenericEvent(_multiplierIncreased); + multiplierDecreased = DeserializeGenericEvent(_multiplierDecreased); + } + + // The game won't deserialize generic events since they require a custom serializable class and Unity can't see those if they're outside the game's main assemblies. + // However, no matter the number of type parameters all UnityEvents inherit from UnityEventBase which contains all the serialized fields. + // Unity will deserialize any event into a UnityEvent so we can simply extract the calls from the UnityEvent and assign them to the proper class with type parameters. + private static T DeserializeGenericEvent(UnityEvent evt) where T : UnityEventBase, new() + { + var newEvent = new T(); + kPersistentCallsField.SetValue(newEvent, kPersistentCallsField.GetValue(evt)); + ((ISerializationCallbackReceiver)newEvent).OnAfterDeserialize(); + return newEvent; + } + + private static UnityEvent FirstWithPersistentCalls(params UnityEvent[] events) + { + foreach (UnityEvent evt in events) + { + if (evt.GetPersistentEventCount() > 0) + { + return evt; + } + } + + return events[0]; + } + +#if DEBUG + [Inject] + [UsedImplicitly] + private void Construct(ILoggerFactory loggerProvider, SpawnedAvatar avatar) + { + ILogger logger = loggerProvider.CreateLogger(avatar.prefab.descriptor.name); + leftGoodCut.AddListener(() => logger.LogTrace($"{nameof(leftGoodCut)} invoked")); + rightGoodCut.AddListener(() => logger.LogTrace($"{nameof(rightGoodCut)} invoked")); + leftBadCut.AddListener(() => logger.LogTrace($"{nameof(leftBadCut)} invoked")); + rightBadCut.AddListener(() => logger.LogTrace($"{nameof(rightBadCut)} invoked")); + leftNoteMissed.AddListener(() => logger.LogTrace($"{nameof(leftNoteMissed)} invoked")); + rightNoteMissed.AddListener(() => logger.LogTrace($"{nameof(rightNoteMissed)} invoked")); + leftSaberStartedColliding.AddListener(() => logger.LogTrace($"{nameof(leftSaberStartedColliding)} invoked")); + rightSaberStartedColliding.AddListener(() => logger.LogTrace($"{nameof(rightSaberStartedColliding)} invoked")); + leftSaberStoppedColliding.AddListener(() => logger.LogTrace($"{nameof(leftSaberStoppedColliding)} invoked")); + rightSaberStoppedColliding.AddListener(() => logger.LogTrace($"{nameof(rightSaberStoppedColliding)} invoked")); + comboIncreased.AddListener((_) => logger.LogTrace($"{nameof(comboIncreased)} invoked")); + comboBroken.AddListener(() => logger.LogTrace($"{nameof(comboBroken)} invoked")); + multiplierIncreased.AddListener((_) => logger.LogTrace($"{nameof(multiplierIncreased)} invoked")); + multiplierDecreased.AddListener((_) => logger.LogTrace($"{nameof(multiplierDecreased)} invoked")); + levelStarted.AddListener(() => logger.LogTrace($"{nameof(levelStarted)} invoked")); + levelFinished.AddListener(() => logger.LogTrace($"{nameof(levelFinished)} invoked")); + levelFailed.AddListener(() => logger.LogTrace($"{nameof(levelFailed)} invoked")); + menuEntered.AddListener(() => logger.LogTrace($"{nameof(menuEntered)} invoked")); + multiplayerLobbyEntered.AddListener(() => logger.LogTrace($"{nameof(multiplayerLobbyEntered)} invoked")); + } +#endif // DEBUG + } +} diff --git a/Source/CustomAvatar/Scripts/EventManager.cs b/Source/CustomAvatar/Scripts/EventManager.cs index 9071623c..c8992e31 100644 --- a/Source/CustomAvatar/Scripts/EventManager.cs +++ b/Source/CustomAvatar/Scripts/EventManager.cs @@ -18,22 +18,10 @@ using UnityEngine; using UnityEngine.Events; -#if UNITY_EDITOR -using UnityEngine.Serialization; -#else -using System.Reflection; -#if DEBUG -using CustomAvatar.Avatar; -using CustomAvatar.Logging; -using JetBrains.Annotations; -using Zenject; -#endif // DEBUG -#endif // UNITY_EDITOR - // keeping root namespace for compatibility namespace CustomAvatar { - public class EventManager : MonoBehaviour + public partial class EventManager : MonoBehaviour #if !UNITY_EDITOR , ISerializationCallbackReceiver #endif @@ -76,256 +64,6 @@ public class EventManager : MonoBehaviour public UnityEvent multiplayerLobbyEntered => _multiplayerLobbyEntered; -#if UNITY_EDITOR -#pragma warning disable CS0169 // none of these are used in the editor script - [SerializeField] - [FormerlySerializedAs("OnSlice")] - private UnityEvent _leftGoodCut; - - [SerializeField] - [FormerlySerializedAs("OnSlice")] - private UnityEvent _rightGoodCut; - - [SerializeField] - private UnityEvent _leftBadCut; - - [SerializeField] - private UnityEvent _rightBadCut; - - [SerializeField] - private UnityEvent _leftNoteMissed; - - [SerializeField] - private UnityEvent _rightNoteMissed; - - [SerializeField] - [FormerlySerializedAs("SaberStartColliding")] - private UnityEvent _leftSaberStartedColliding; - - [SerializeField] - [FormerlySerializedAs("SaberStartColliding")] - private UnityEvent _rightSaberStartedColliding; - - [SerializeField] - [FormerlySerializedAs("SaberStopColliding")] - private UnityEvent _leftSaberStoppedColliding; - - [SerializeField] - [FormerlySerializedAs("SaberStopColliding")] - private UnityEvent _rightSaberStoppedColliding; - - [SerializeField] - [FormerlySerializedAs("OnComboChanged")] - private IntUnityEvent _comboIncreased; - - [SerializeField] - [FormerlySerializedAs("OnComboBreak")] - private UnityEvent _comboBroken; - - [SerializeField] - [FormerlySerializedAs("MultiplierUp")] - private IntUnityEvent _multiplierIncreased; - - [SerializeField] - private IntUnityEvent _multiplierDecreased; - - [SerializeField] - [FormerlySerializedAs("OnLevelStart")] - private UnityEvent _levelStarted; - - [SerializeField] - [FormerlySerializedAs("OnLevelFinish")] - private UnityEvent _levelFinished; - - [SerializeField] - [FormerlySerializedAs("OnLevelFail")] - private UnityEvent _levelFailed; - - [SerializeField] - [FormerlySerializedAs("OnMenuEnter")] - private UnityEvent _menuEntered; - - [SerializeField] - private UnityEvent _multiplayerLobbyEntered; -#pragma warning restore CS0169 -#else - private static readonly FieldInfo kPersistentCallsField = typeof(UnityEventBase).GetField("m_PersistentCalls", BindingFlags.NonPublic | BindingFlags.Instance); - - #region Legacy -#pragma warning disable IDE1006 - - // these are only present because FormerlySerializedAs does not work in the game - - [SerializeField] - private UnityEvent OnSlice; - - [SerializeField] - private UnityEvent OnComboBreak; - - [SerializeField] - private UnityEvent MultiplierUp; - - [SerializeField] - private UnityEvent SaberStartColliding; - - [SerializeField] - private UnityEvent SaberStopColliding; - - [SerializeField] - private UnityEvent OnMenuEnter; - - [SerializeField] - private UnityEvent OnLevelStart; - - [SerializeField] - private UnityEvent OnLevelFail; - - [SerializeField] - private UnityEvent OnLevelFinish; - - [SerializeField] - private UnityEvent OnComboChanged; - -#pragma warning restore IDE1006 - #endregion - - [SerializeField] - private UnityEvent _leftGoodCut; - - [SerializeField] - private UnityEvent _rightGoodCut; - - [SerializeField] - private UnityEvent _leftBadCut; - - [SerializeField] - private UnityEvent _rightBadCut; - - [SerializeField] - private UnityEvent _leftNoteMissed; - - [SerializeField] - private UnityEvent _rightNoteMissed; - - [SerializeField] - private UnityEvent _leftSaberStartedColliding; - - [SerializeField] - private UnityEvent _rightSaberStartedColliding; - - [SerializeField] - private UnityEvent _leftSaberStoppedColliding; - - [SerializeField] - private UnityEvent _rightSaberStoppedColliding; - - [SerializeField] - private UnityEvent _comboIncreased; - - [SerializeField] - private UnityEvent _comboBroken; - - [SerializeField] - private UnityEvent _multiplierIncreased; - - [SerializeField] - private UnityEvent _multiplierDecreased; - - [SerializeField] - private UnityEvent _levelStarted; - - [SerializeField] - private UnityEvent _levelFinished; - - [SerializeField] - private UnityEvent _levelFailed; - - [SerializeField] - private UnityEvent _menuEntered; - - [SerializeField] - private UnityEvent _multiplayerLobbyEntered; - - public void OnBeforeSerialize() - { - } - - public void OnAfterDeserialize() - { - // find first event with serialized persistent calls since FormerlySerializedAs doesn't work - // can't do ?? since events are never deserialized as null - _leftGoodCut = FirstWithPersistentCalls(_leftGoodCut, OnSlice); - _rightGoodCut = FirstWithPersistentCalls(_rightGoodCut, OnSlice); - _comboBroken = FirstWithPersistentCalls(_comboBroken, OnComboBreak); - _multiplierIncreased = FirstWithPersistentCalls(_multiplierIncreased, MultiplierUp); - _leftSaberStartedColliding = FirstWithPersistentCalls(_leftSaberStartedColliding, SaberStartColliding); - _rightSaberStartedColliding = FirstWithPersistentCalls(_rightSaberStartedColliding, SaberStartColliding); - _leftSaberStoppedColliding = FirstWithPersistentCalls(_leftSaberStoppedColliding, SaberStopColliding); - _rightSaberStoppedColliding = FirstWithPersistentCalls(_rightSaberStoppedColliding, SaberStopColliding); - _menuEntered = FirstWithPersistentCalls(_menuEntered, OnMenuEnter); - _levelStarted = FirstWithPersistentCalls(_levelStarted, OnLevelStart); - _levelFailed = FirstWithPersistentCalls(_levelFailed, OnLevelFail); - _levelFinished = FirstWithPersistentCalls(_levelFinished, OnLevelFinish); - _comboIncreased = FirstWithPersistentCalls(_comboIncreased, OnComboChanged); - - comboIncreased = DeserializeGenericEvent(_comboIncreased); - multiplierIncreased = DeserializeGenericEvent(_multiplierIncreased); - multiplierDecreased = DeserializeGenericEvent(_multiplierDecreased); - } - - // The game won't deserialize generic events since they require a custom serializable class and Unity can't see those if they're outside the game's main assemblies. - // However, no matter the number of type parameters all UnityEvents inherit from UnityEventBase which contains all the serialized fields. - // Unity will deserialize any event into a UnityEvent so we can simply extract the calls from the UnityEvent and assign them to the proper class with type parameters. - private static T DeserializeGenericEvent(UnityEvent evt) where T : UnityEventBase, new() - { - var newEvent = new T(); - kPersistentCallsField.SetValue(newEvent, kPersistentCallsField.GetValue(evt)); - ((ISerializationCallbackReceiver)newEvent).OnAfterDeserialize(); - return newEvent; - } - - private static UnityEvent FirstWithPersistentCalls(params UnityEvent[] events) - { - foreach (UnityEvent evt in events) - { - if (evt.GetPersistentEventCount() > 0) - { - return evt; - } - } - - return events[0]; - } - -#if DEBUG - [Inject] - [UsedImplicitly] - private void Construct(ILoggerFactory loggerProvider, SpawnedAvatar avatar) - { - ILogger logger = loggerProvider.CreateLogger(avatar.prefab.descriptor.name); - leftGoodCut.AddListener(() => logger.LogTrace($"{nameof(leftGoodCut)} invoked")); - rightGoodCut.AddListener(() => logger.LogTrace($"{nameof(rightGoodCut)} invoked")); - leftBadCut.AddListener(() => logger.LogTrace($"{nameof(leftBadCut)} invoked")); - rightBadCut.AddListener(() => logger.LogTrace($"{nameof(rightBadCut)} invoked")); - leftNoteMissed.AddListener(() => logger.LogTrace($"{nameof(leftNoteMissed)} invoked")); - rightNoteMissed.AddListener(() => logger.LogTrace($"{nameof(rightNoteMissed)} invoked")); - leftSaberStartedColliding.AddListener(() => logger.LogTrace($"{nameof(leftSaberStartedColliding)} invoked")); - rightSaberStartedColliding.AddListener(() => logger.LogTrace($"{nameof(rightSaberStartedColliding)} invoked")); - leftSaberStoppedColliding.AddListener(() => logger.LogTrace($"{nameof(leftSaberStoppedColliding)} invoked")); - rightSaberStoppedColliding.AddListener(() => logger.LogTrace($"{nameof(rightSaberStoppedColliding)} invoked")); - comboIncreased.AddListener((_) => logger.LogTrace($"{nameof(comboIncreased)} invoked")); - comboBroken.AddListener(() => logger.LogTrace($"{nameof(comboBroken)} invoked")); - multiplierIncreased.AddListener((_) => logger.LogTrace($"{nameof(multiplierIncreased)} invoked")); - multiplierDecreased.AddListener((_) => logger.LogTrace($"{nameof(multiplierDecreased)} invoked")); - levelStarted.AddListener(() => logger.LogTrace($"{nameof(levelStarted)} invoked")); - levelFinished.AddListener(() => logger.LogTrace($"{nameof(levelFinished)} invoked")); - levelFailed.AddListener(() => logger.LogTrace($"{nameof(levelFailed)} invoked")); - menuEntered.AddListener(() => logger.LogTrace($"{nameof(menuEntered)} invoked")); - multiplayerLobbyEntered.AddListener(() => logger.LogTrace($"{nameof(multiplayerLobbyEntered)} invoked")); - } -#endif // DEBUG -#endif // UNITY_EDITOR - [Serializable] public class IntUnityEvent : UnityEvent { } } diff --git a/Source/CustomAvatar/Scripts/VRIKManager.cs b/Source/CustomAvatar/Scripts/VRIKManager.cs index 895ae2a9..ea0836bc 100644 --- a/Source/CustomAvatar/Scripts/VRIKManager.cs +++ b/Source/CustomAvatar/Scripts/VRIKManager.cs @@ -15,7 +15,6 @@ // along with this program. If not, see . extern alias BeatSaberFinalIK; - using System; using System.Diagnostics.CodeAnalysis; using BeatSaberFinalIK::RootMotion; @@ -24,17 +23,16 @@ using UnityEngine.Events; using static BeatSaberFinalIK::RootMotion.FinalIK.IKSolverVR.Arm; -#if UNITY_EDITOR -using UnityEditor; -#else +#if !UNITY_EDITOR using Zenject; #endif + // keeping root namespace for compatibility namespace CustomAvatar { [Serializable] - public class VRIKManager : MonoBehaviour + public partial class VRIKManager : MonoBehaviour { [Tooltip("If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance. Not recommended for CCD and FABRIK solvers.")] public bool fixTransforms = true; @@ -427,78 +425,5 @@ protected void Reset() { AutoDetectReferences(); } - -#if UNITY_EDITOR - private GUIStyle _redLabelStyle; - private GUIStyle _greenLabelStyle; - private GUIStyle _blueLabelStyle; - - protected void OnDrawGizmosSelected() - { - if (_redLabelStyle == null) - { - _redLabelStyle = new GUIStyle(EditorStyles.label); - _redLabelStyle.normal.textColor = Color.red; - } - - if (_greenLabelStyle == null) - { - _greenLabelStyle = new GUIStyle(EditorStyles.label); - _greenLabelStyle.normal.textColor = Color.green; - } - - if (_blueLabelStyle == null) - { - _blueLabelStyle = new GUIStyle(EditorStyles.label); - _blueLabelStyle.normal.textColor = Color.blue; - } - - DrawHandAxes(references_leftHand, solver_leftArm_wristToPalmAxis, solver_leftArm_palmToThumbAxis, true); - DrawHandAxes(references_rightHand, solver_rightArm_wristToPalmAxis, solver_rightArm_palmToThumbAxis, false); - } - - private void DrawHandAxes(Transform reference, Vector3 wristToPalmAxis, Vector3 palmToThumbAxis, bool invertNormal) - { - if (!reference) - { - return; - } - - Vector3 wristToPalmVector = default; - Vector3 palmToThumbVector = default; - - if (wristToPalmAxis.sqrMagnitude > 0) - { - wristToPalmVector = reference.rotation * wristToPalmAxis.normalized; - - Handles.color = Color.green; - Handles.ArrowHandleCap(0, reference.position, Quaternion.LookRotation(wristToPalmVector), 0.1f, EventType.Repaint); - Handles.Label(reference.position + wristToPalmVector * 0.12f, "Wrist to Palm Axis", _greenLabelStyle); - } - - if (palmToThumbAxis.sqrMagnitude > 0) - { - palmToThumbVector = reference.rotation * palmToThumbAxis.normalized; - - Handles.color = Color.red; - Handles.ArrowHandleCap(0, reference.position, Quaternion.LookRotation(palmToThumbVector), 0.1f, EventType.Repaint); - Handles.Label(reference.position + palmToThumbVector * 0.12f, "Palm to Thumb Axis", _redLabelStyle); - } - - if (wristToPalmAxis.sqrMagnitude > 0 && palmToThumbAxis.sqrMagnitude > 0) - { - Vector3 planeNormal = new Plane(reference.position, reference.position + wristToPalmVector, reference.position + palmToThumbVector).normal; - - if (invertNormal) - { - planeNormal = -planeNormal; - } - - Handles.color = Color.blue; - Handles.ArrowHandleCap(0, reference.position, Quaternion.LookRotation(planeNormal), 0.1f, EventType.Repaint); - Handles.Label(reference.position + planeNormal * 0.12f, "Palm Inside Axis", _blueLabelStyle); - } - } -#endif } }