[BadAnimatorFix] Speculative fix for loading Login, Init, and HQ scenes.

Exterrata said it kept erroring but I could not reproduce. This should solve it.
This commit is contained in:
NotAKidoS 2023-06-14 17:51:28 -05:00
parent 13927f1d67
commit a902cd250f
6 changed files with 49 additions and 50 deletions

View file

@ -6,20 +6,20 @@ namespace NAK.BadAnimatorFix;
public static class BadAnimatorFixManager public static class BadAnimatorFixManager
{ {
private static List<BadAnimatorFixer> badAnimatorFixes = new List<BadAnimatorFixer>(); static List<BadAnimatorFixer> _animatorFixers = new List<BadAnimatorFixer>();
private static int currentIndex = 0; static int _currentIndex = 0;
private static float checkInterval = 5f; static float _checkInterval = 5f;
public static void Add(BadAnimatorFixer bad) public static void Add(BadAnimatorFixer bad)
{ {
if (!badAnimatorFixes.Contains(bad)) if (!_animatorFixers.Contains(bad))
badAnimatorFixes.Add(bad); _animatorFixers.Add(bad);
} }
public static void Remove(BadAnimatorFixer bad) public static void Remove(BadAnimatorFixer bad)
{ {
if (badAnimatorFixes.Contains(bad)) if (_animatorFixers.Contains(bad))
badAnimatorFixes.Remove(bad); _animatorFixers.Remove(bad);
} }
public static void OnPlayerLoaded() public static void OnPlayerLoaded()
@ -43,25 +43,25 @@ public static class BadAnimatorFixManager
} }
} }
private static void CheckNextAnimator()
{
if (badAnimatorFixes.Count == 0) return;
currentIndex = (currentIndex + 1) % badAnimatorFixes.Count;
BadAnimatorFixer currentAnimatorFix = badAnimatorFixes[currentIndex];
currentAnimatorFix.AttemptRewindAnimator();
}
public static void ToggleJob(bool enable) public static void ToggleJob(bool enable)
{ {
var job = SchedulerSystem.Instance.activeJobs.FirstOrDefault(pair => pair.Job.Method.Name == "CheckNextAnimator").Job; var job = SchedulerSystem.Instance.activeJobs.FirstOrDefault(pair => pair.Job.Method.Name == nameof(CheckNextAnimator)).Job;
if (enable && job == null) if (enable && job == null)
{ {
SchedulerSystem.AddJob(new SchedulerSystem.Job(CheckNextAnimator), 0f, checkInterval, -1); SchedulerSystem.AddJob(new SchedulerSystem.Job(CheckNextAnimator), 0f, _checkInterval, -1);
} }
else if (!enable && job != null) else if (!enable && job != null)
{ {
SchedulerSystem.RemoveJob(job); SchedulerSystem.RemoveJob(job);
} }
} }
static void CheckNextAnimator()
{
if (_animatorFixers.Count == 0) return;
_currentIndex = (_currentIndex + 1) % _animatorFixers.Count;
BadAnimatorFixer currentAnimatorFix = _animatorFixers[_currentIndex];
currentAnimatorFix.AttemptRewindAnimator();
}
} }

View file

@ -9,18 +9,17 @@ public class BadAnimatorFixer : MonoBehaviour
private Animator animator; private Animator animator;
private void Start() void Start()
{ {
animator = GetComponent<Animator>(); animator = GetComponent<Animator>();
} }
private void OnEnable() => BadAnimatorFixManager.Add(this); void OnEnable() => BadAnimatorFixManager.Add(this);
private void OnDisable() => BadAnimatorFixManager.Remove(this); void OnDisable() => BadAnimatorFixManager.Remove(this);
public void AttemptRewindAnimator() public void AttemptRewindAnimator()
{ {
bool rewound = false; bool rewound = false;
if (animator != null && animator.isActiveAndEnabled) if (animator != null && animator.isActiveAndEnabled)
{ {
for (int layerIndex = 0; layerIndex < animator.layerCount; layerIndex++) for (int layerIndex = 0; layerIndex < animator.layerCount; layerIndex++)
@ -38,9 +37,7 @@ public class BadAnimatorFixer : MonoBehaviour
} }
if (rewound) if (rewound)
{
PlayableExtensions.SetTime<Playable>(animator.playableGraph.GetRootPlayable(0), 0); PlayableExtensions.SetTime<Playable>(animator.playableGraph.GetRootPlayable(0), 0);
}
} }
if (BadAnimatorFix.EntryLogging.Value) if (BadAnimatorFix.EntryLogging.Value)

View file

@ -6,17 +6,17 @@ using UnityEngine;
namespace NAK.BadAnimatorFix.HarmonyPatches; namespace NAK.BadAnimatorFix.HarmonyPatches;
internal static class AnimatorPatches static class AnimatorPatches
{ {
[HarmonyPostfix] [HarmonyPostfix]
[HarmonyPatch(typeof(PlayerSetup), "Start")] [HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.Start))]
private static void Postfix_PlayerSetup_Start() private static void Postfix_PlayerSetup_Start()
{ {
BadAnimatorFixManager.OnPlayerLoaded(); BadAnimatorFixManager.OnPlayerLoaded();
} }
[HarmonyPostfix] [HarmonyPostfix]
[HarmonyPatch(typeof(CVRAvatar), "Start")] [HarmonyPatch(typeof(CVRAvatar), nameof(CVRAvatar.Start))]
private static void Postfix_CVRAvatar_Start(CVRAvatar __instance) private static void Postfix_CVRAvatar_Start(CVRAvatar __instance)
{ {
if (!BadAnimatorFix.EntryCVRAvatar.Value) return; if (!BadAnimatorFix.EntryCVRAvatar.Value) return;
@ -24,7 +24,7 @@ internal static class AnimatorPatches
} }
[HarmonyPostfix] [HarmonyPostfix]
[HarmonyPatch(typeof(CVRSpawnable), "Start")] [HarmonyPatch(typeof(CVRSpawnable), nameof(CVRSpawnable.Start))]
private static void Postfix_CVRSpawnable_Start(CVRSpawnable __instance) private static void Postfix_CVRSpawnable_Start(CVRSpawnable __instance)
{ {
if (!BadAnimatorFix.EntryCVRSpawnable.Value) return; if (!BadAnimatorFix.EntryCVRSpawnable.Value) return;
@ -33,7 +33,7 @@ internal static class AnimatorPatches
// Set QM stuff // Set QM stuff
[HarmonyPostfix] [HarmonyPostfix]
[HarmonyPatch(typeof(CVR_MenuManager), "Start")] [HarmonyPatch(typeof(CVR_MenuManager), nameof(CVR_MenuManager.Start))]
private static void Postfix_CVR_MenuManager_Start(ref CVR_MenuManager __instance) private static void Postfix_CVR_MenuManager_Start(ref CVR_MenuManager __instance)
{ {
if (!BadAnimatorFix.EntryMenus.Value) return; if (!BadAnimatorFix.EntryMenus.Value) return;
@ -42,7 +42,7 @@ internal static class AnimatorPatches
// Set MM stuff // Set MM stuff
[HarmonyPostfix] [HarmonyPostfix]
[HarmonyPatch(typeof(ViewManager), "Start")] [HarmonyPatch(typeof(ViewManager), nameof(ViewManager.Start))]
private static void Postfix_ViewManager_Start(ref ViewManager __instance) private static void Postfix_ViewManager_Start(ref ViewManager __instance)
{ {
if (!BadAnimatorFix.EntryMenus.Value) return; if (!BadAnimatorFix.EntryMenus.Value) return;

View file

@ -6,46 +6,48 @@ public class BadAnimatorFix : MelonMod
{ {
internal static MelonLogger.Instance Logger; internal static MelonLogger.Instance Logger;
public static readonly MelonPreferences_Category CategoryBadAnimatorFix = public static readonly MelonPreferences_Category Category =
MelonPreferences.CreateCategory(nameof(BadAnimatorFix)); MelonPreferences.CreateCategory(nameof(BadAnimatorFix));
public static readonly MelonPreferences_Entry<bool> EntryEnabled = public static readonly MelonPreferences_Entry<bool> EntryEnabled =
CategoryBadAnimatorFix.CreateEntry("Enabled", true, description: "Toggle BadAnimatorFix entirely. Requires avatar/spawnable/world reload."); Category.CreateEntry("Enabled", true, description: "Toggle BadAnimatorFix entirely. Requires avatar/spawnable/world reload.");
public static readonly MelonPreferences_Entry<bool> EntryCVRAvatar = public static readonly MelonPreferences_Entry<bool> EntryCVRAvatar =
CategoryBadAnimatorFix.CreateEntry("Add to CVRAvatar", true, description: "Should BadAnimatorFix run for CVRAvatar? Requires avatar reload."); Category.CreateEntry("Add to CVRAvatar", true, description: "Should BadAnimatorFix run for CVRAvatar? Requires avatar reload.");
public static readonly MelonPreferences_Entry<bool> EntryCVRSpawnable = public static readonly MelonPreferences_Entry<bool> EntryCVRSpawnable =
CategoryBadAnimatorFix.CreateEntry("Add to CVRSpawnable", true, description: "Should BadAnimatorFix run for CVRSpawnable? Requires spawnable reload."); Category.CreateEntry("Add to CVRSpawnable", true, description: "Should BadAnimatorFix run for CVRSpawnable? Requires spawnable reload.");
public static readonly MelonPreferences_Entry<bool> EntryCVRWorld = public static readonly MelonPreferences_Entry<bool> EntryCVRWorld =
CategoryBadAnimatorFix.CreateEntry("Add to CVRWorld", true, description: "Should BadAnimatorFix run for CVRWorld? Requires world reload."); Category.CreateEntry("Add to CVRWorld", true, description: "Should BadAnimatorFix run for CVRWorld? Requires world reload.");
public static readonly MelonPreferences_Entry<bool> EntryMenus = public static readonly MelonPreferences_Entry<bool> EntryMenus =
CategoryBadAnimatorFix.CreateEntry("Add to Menus", true, description: "Should BadAnimatorFix run for QM & MM? Requires game restart."); Category.CreateEntry("Add to Menus", true, description: "Should BadAnimatorFix run for QM & MM? Requires game restart.");
public static readonly MelonPreferences_Entry<bool> EntryLogging = public static readonly MelonPreferences_Entry<bool> EntryLogging =
CategoryBadAnimatorFix.CreateEntry("Debugging", false, description: "Toggle to log each rewind if successful. Only needed for debugging."); Category.CreateEntry("Debugging", false, description: "Toggle to log each rewind if successful. Only needed for debugging.");
public override void OnInitializeMelon() public override void OnInitializeMelon()
{ {
Logger = LoggerInstance; Logger = LoggerInstance;
EntryEnabled.OnEntryValueChangedUntyped.Subscribe(OnEnabled); EntryEnabled.OnEntryValueChanged.Subscribe(OnEntryEnabledChanged);
ApplyPatches(typeof(HarmonyPatches.AnimatorPatches)); ApplyPatches(typeof(HarmonyPatches.AnimatorPatches));
} }
public override void OnSceneWasInitialized(int buildIndex, string sceneName) public override void OnSceneWasInitialized(int buildIndex, string sceneName)
{ {
if (!EntryCVRWorld.Value) return; if (!EntryCVRWorld.Value) return;
BadAnimatorFixManager.OnSceneInitialized(sceneName);
if (buildIndex < 0) // -1 is custom world: 0 to 3 is game login, init, hq
BadAnimatorFixManager.OnSceneInitialized(sceneName);
} }
private void OnEnabled(object arg1, object arg2) void OnEntryEnabledChanged(bool newValue, bool oldValue)
{ {
BadAnimatorFixManager.ToggleJob(EntryEnabled.Value); BadAnimatorFixManager.ToggleJob(newValue);
} }
private void ApplyPatches(Type type) void ApplyPatches(Type type)
{ {
try try
{ {

View file

@ -10,7 +10,7 @@ using System.Reflection;
[assembly: AssemblyProduct(nameof(NAK.BadAnimatorFix))] [assembly: AssemblyProduct(nameof(NAK.BadAnimatorFix))]
[assembly: MelonInfo( [assembly: MelonInfo(
typeof(NAK.BadAnimatorFix.BadAnimatorFixer), typeof(NAK.BadAnimatorFix.BadAnimatorFix),
nameof(NAK.BadAnimatorFix), nameof(NAK.BadAnimatorFix),
AssemblyInfoParams.Version, AssemblyInfoParams.Version,
AssemblyInfoParams.Author, AssemblyInfoParams.Author,
@ -25,6 +25,6 @@ using System.Reflection;
namespace NAK.BadAnimatorFix.Properties; namespace NAK.BadAnimatorFix.Properties;
internal static class AssemblyInfoParams internal static class AssemblyInfoParams
{ {
public const string Version = "1.0.0"; public const string Version = "1.0.1";
public const string Author = "NotAKidoS"; public const string Author = "NotAKidoS";
} }

View file

@ -1,9 +1,9 @@
{ {
"_id": -1, "_id": 152,
"name": "BadAnimatorFix", "name": "BadAnimatorFix",
"modversion": "1.0.0", "modversion": "1.0.1",
"gameversion": "2022r170", "gameversion": "2022r170",
"loaderversion": "0.5.7", "loaderversion": "0.6.1",
"modtype": "Mod", "modtype": "Mod",
"author": "NotAKidoS", "author": "NotAKidoS",
"description": "This mod occasionally rewinds animation states that have loop enabled.\n\nUnity seems to have a weird quirk where *sometimes* animations with loop cause performance issues after running for a long time.\nYou'll only start to notice this after a few hours to a few days of idling.\n\nIf you don't happen to be AFK for long periods of time, you probably don't need this mod. This issue seems to be primarily caused by one-two frame animation clips meant for toggles with loop needlessly enabled.", "description": "This mod occasionally rewinds animation states that have loop enabled.\n\nUnity seems to have a weird quirk where *sometimes* animations with loop cause performance issues after running for a long time.\nYou'll only start to notice this after a few hours to a few days of idling.\n\nIf you don't happen to be AFK for long periods of time, you probably don't need this mod. This issue seems to be primarily caused by one-two frame animation clips meant for toggles with loop needlessly enabled.",
@ -16,8 +16,8 @@
"requirements": [ "requirements": [
"None" "None"
], ],
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r3/BadAnimatorFix.dll", "downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r10/BadAnimatorFix.dll",
"sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/BadAnimatorFix/", "sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/BadAnimatorFix/",
"changelog": "Initial Release", "changelog": "- Speculative fix for possible error while loading default cvr scenes",
"embedcolor": "7F3F99" "embedcolor": "e25352"
} }