This commit is contained in:
NotAKidoS 2023-03-24 17:17:53 -05:00
parent 83c101f5ee
commit 1acf58d161
5 changed files with 88 additions and 38 deletions

View file

@ -5,34 +5,30 @@ namespace NAK.Melons.BadAnimatorFix;
public class BadAnimatorFix : MonoBehaviour public class BadAnimatorFix : MonoBehaviour
{ {
private float stateLimit = 20f; private float stateLimit = 50f;
private Animator animator; private Animator animator;
private Playable playable; private Playable playable;
private void Start() void Start()
{ {
animator = GetComponent<Animator>(); animator = GetComponent<Animator>();
playable = animator.playableGraph.GetRootPlayable(0); playable = animator.playableGraph.GetRootPlayable(0);
BadAnimatorFixManager.Add(this);
} }
private void Update() void OnDestroy()
{ {
if (!BadAnimatorFixMod.EntryEnabled.Value) return; BadAnimatorFixManager.Remove(this);
if (playable.IsValid() && GetTime() > BadAnimatorFixMod.EntryPlayableTimeLimit.Value)
{
RewindAnimator();
BadAnimatorFixMod.Logger.Msg($"Rewound animator and playable {animator}.");
}
} }
private double GetTime() public double GetTime()
{ {
return PlayableExtensions.IsValid<Playable>(playable) ? PlayableExtensions.GetTime<Playable>(playable) : -1; return PlayableExtensions.IsValid<Playable>(playable) ? PlayableExtensions.GetTime<Playable>(playable) : -1;
} }
private void RewindAnimator() public void AttemptRewindAnimator()
{ {
PlayableExtensions.SetTime<Playable>(playable, 0); bool rewound = false;
for (int i = 0; i < animator.layerCount; i++) for (int i = 0; i < animator.layerCount; i++)
{ {
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(i); AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(i);
@ -42,31 +38,14 @@ public class BadAnimatorFix : MonoBehaviour
// Skip if anim doesn't loop, or hasn't looped enough // Skip if anim doesn't loop, or hasn't looped enough
if (stateInfo.normalizedTime <= stateLimit) continue; if (stateInfo.normalizedTime <= stateLimit) continue;
// Rewind state, with 10f as buffer, to account for reasonable use of ExitTime // Rewind state, with 10f as buffer, to account for reasonable use of ExitTime
rewound = true;
float offset = 10f + (stateInfo.normalizedTime % 1f); float offset = 10f + (stateInfo.normalizedTime % 1f);
animator.Play(stateInfo.fullPathHash, i, offset); animator.Play(stateInfo.fullPathHash, i, offset);
} }
} if (rewound)
private float GetNormalizedTime()
{ {
float time = 0f; PlayableExtensions.SetTime<Playable>(playable, 0);
for (int i = 0; i < animator.layerCount; i++) BadAnimatorFixMod.Logger.Msg($"Rewound animator and playable {animator}.");
{ }
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(i);
time += stateInfo.normalizedTime;
}
return time;
}
private float GetMaxNormalizedTime()
{
float time = 0f;
for (int i = 0; i < animator.layerCount; i++)
{
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(i);
if (time < stateInfo.normalizedTime)
time = stateInfo.normalizedTime;
}
return time;
} }
} }

View file

@ -6,6 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -13,7 +14,7 @@
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath> <HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath> <HintPath>..\..\FuckCohtml\FuckMetrics\ManagedLibs\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp-firstpass"> <Reference Include="Assembly-CSharp-firstpass">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath> <HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>

View file

@ -0,0 +1,54 @@
using ABI_RC.Core.IO;
namespace NAK.Melons.BadAnimatorFix;
public static class BadAnimatorFixManager
{
public static List<BadAnimatorFix> badAnimatorFixes = new List<BadAnimatorFix>();
private static int currentIndex = 0;
public static void Add(BadAnimatorFix bad)
{
if (!badAnimatorFixes.Contains(bad))
{
badAnimatorFixes.Add(bad);
}
}
public static void Remove(BadAnimatorFix bad)
{
if (badAnimatorFixes.Contains(bad))
{
badAnimatorFixes.Remove(bad);
}
}
// Runs every 5 seconds to see if an animator has played longer than PlayableTimeLimit
public static void CheckNextAnimator()
{
if (badAnimatorFixes.Count == 0) return;
if (currentIndex >= badAnimatorFixes.Count) currentIndex = 0;
BadAnimatorFix currentAnimatorFix = badAnimatorFixes[currentIndex];
if (currentAnimatorFix.GetTime() > BadAnimatorFixMod.EntryPlayableTimeLimit.Value)
{
currentAnimatorFix.AttemptRewindAnimator();
}
currentIndex++;
}
public static void ToggleJob(bool enable)
{
var job = SchedulerSystem.Instance.activeJobs.FirstOrDefault(pair => pair.Job.Method.Name == "CheckNextAnimator").Job;
if (enable && job == null)
{
SchedulerSystem.AddJob(new SchedulerSystem.Job(BadAnimatorFixManager.CheckNextAnimator), 0f, 5f, -1);
}
else if (!enable && job != null)
{
SchedulerSystem.RemoveJob(job);
}
}
}

View file

@ -2,6 +2,7 @@
using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem;
using HarmonyLib; using HarmonyLib;
using UnityEngine; using UnityEngine;
using ABI_RC.Core.IO;
namespace NAK.Melons.BadAnimatorFix.HarmonyPatches; namespace NAK.Melons.BadAnimatorFix.HarmonyPatches;
@ -51,7 +52,7 @@ internal class AnimatorPatches
private static void AddBadAnimatorFixComponentIfAnimatorExists(GameObject gameObject) private static void AddBadAnimatorFixComponentIfAnimatorExists(GameObject gameObject)
{ {
if (!BadAnimatorFixMod.EntryEnabled.Value) return; //if (!BadAnimatorFixMod.EntryEnabled.Value) return;
Animator[] animators = gameObject.GetComponentsInChildren<Animator>(); Animator[] animators = gameObject.GetComponentsInChildren<Animator>();
foreach (Animator animator in animators.Where(a => a.gameObject.GetComponent<BadAnimatorFix>() == null)) foreach (Animator animator in animators.Where(a => a.gameObject.GetComponent<BadAnimatorFix>() == null))
{ {
@ -60,4 +61,3 @@ internal class AnimatorPatches
} }
} }
} }

View file

@ -1,4 +1,6 @@
using MelonLoader; using MelonLoader;
using System.Collections;
using ABI_RC.Core.Player;
namespace NAK.Melons.BadAnimatorFix; namespace NAK.Melons.BadAnimatorFix;
@ -29,7 +31,21 @@ public class BadAnimatorFixMod : MelonMod
public override void OnInitializeMelon() public override void OnInitializeMelon()
{ {
Logger = LoggerInstance; Logger = LoggerInstance;
EntryEnabled.OnEntryValueChangedUntyped.Subscribe(OnEnabled);
ApplyPatches(typeof(HarmonyPatches.AnimatorPatches)); ApplyPatches(typeof(HarmonyPatches.AnimatorPatches));
MelonCoroutines.Start(WaitForLocalPlayer());
}
private IEnumerator WaitForLocalPlayer()
{
while (PlayerSetup.Instance == null)
yield return null;
BadAnimatorFixManager.ToggleJob(EntryEnabled.Value);
}
private void OnEnabled(object arg1, object arg2)
{
BadAnimatorFixManager.ToggleJob(EntryEnabled.Value);
} }
private void ApplyPatches(Type type) private void ApplyPatches(Type type)