Decompiled source of Classic Walk v1.0.1

BepInEx/plugins/ClassicWalk/ClassicWalk.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ClassicWalk
{
	internal sealed class AnimatorSnapshot
	{
		private readonly AnimatorControllerParameter[] parameters;

		private readonly float[] floats;

		private readonly int[] integers;

		private readonly bool[] booleans;

		private readonly AnimatorStateInfo[] states;

		private readonly bool[] transitions;

		private readonly float[] weights;

		private readonly float speed;

		internal AnimatorSnapshot(Animator animator)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected I4, but got Unknown
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			parameters = animator.parameters;
			floats = new float[parameters.Length];
			integers = new int[parameters.Length];
			booleans = new bool[parameters.Length];
			for (int i = 0; i < parameters.Length; i++)
			{
				AnimatorControllerParameter val = parameters[i];
				AnimatorControllerParameterType type = val.type;
				switch (type - 1)
				{
				case 0:
					floats[i] = animator.GetFloat(val.nameHash);
					break;
				case 2:
					integers[i] = animator.GetInteger(val.nameHash);
					break;
				case 3:
					booleans[i] = animator.GetBool(val.nameHash);
					break;
				}
			}
			states = (AnimatorStateInfo[])(object)new AnimatorStateInfo[animator.layerCount];
			transitions = new bool[states.Length];
			weights = new float[states.Length];
			for (int j = 0; j < states.Length; j++)
			{
				states[j] = animator.GetCurrentAnimatorStateInfo(j);
				transitions[j] = animator.IsInTransition(j);
				weights[j] = animator.GetLayerWeight(j);
			}
			speed = animator.speed;
		}

		internal void Restore(Animator animator)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected I4, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < parameters.Length; i++)
			{
				AnimatorControllerParameter val = parameters[i];
				AnimatorControllerParameterType type = val.type;
				switch (type - 1)
				{
				case 0:
					animator.SetFloat(val.nameHash, floats[i]);
					break;
				case 2:
					animator.SetInteger(val.nameHash, integers[i]);
					break;
				case 3:
					animator.SetBool(val.nameHash, booleans[i]);
					break;
				}
			}
			for (int j = 0; j < states.Length; j++)
			{
				animator.SetLayerWeight(j, weights[j]);
				if (!transitions[j] && ((AnimatorStateInfo)(ref states[j])).fullPathHash != 0)
				{
					AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(j);
					if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash != ((AnimatorStateInfo)(ref states[j])).fullPathHash || ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime != ((AnimatorStateInfo)(ref states[j])).normalizedTime)
					{
						animator.Play(((AnimatorStateInfo)(ref states[j])).fullPathHash, j, ((AnimatorStateInfo)(ref states[j])).normalizedTime);
					}
				}
			}
			animator.speed = speed;
		}

		internal static bool CanChange(Animator animator)
		{
			if (!animator.isInitialized)
			{
				return false;
			}
			for (int i = 0; i < animator.layerCount; i++)
			{
				if (animator.IsInTransition(i))
				{
					return false;
				}
			}
			return true;
		}
	}
	[BepInPlugin("maving.classicwalk", "Classic Walk", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private static readonly FieldInfo LeftItem = typeof(Humanoid).GetField("m_leftItem", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo RightItem = typeof(Humanoid).GetField("m_rightItem", BindingFlags.Instance | BindingFlags.NonPublic);

		private ConfigEntry<KeyCode> toggleKey;

		private bool useClassic;

		private AssetBundle bundle;

		private readonly Dictionary<string, AnimationClip> classicClips = new Dictionary<string, AnimationClip>();

		private Animator animator;

		private RuntimeAnimatorController original;

		private AnimatorOverrideController replacement;

		private List<KeyValuePair<AnimationClip, AnimationClip>> originalClips;

		private List<KeyValuePair<AnimationClip, AnimationClip>> replacementClips;

		private bool classicApplied;

		private bool ready;

		private RuntimeAnimatorController rejected;

		private void Awake()
		{
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ToggleKey", (KeyCode)287, "Toggle key (for example F6, F7 or F8). None disables the hotkey. Save and use the current key off/on to reload, or restart the game.");
			useClassic = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "StartEnabled", true, "Enable classic movement at game startup. Hotkey toggles affect only the current session. Replaces the old Enabled setting.").Value;
			try
			{
				if (LeftItem == null || RightItem == null)
				{
					throw new MissingFieldException("Humanoid hand fields unavailable.");
				}
				string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "classicwalk.bundle");
				bundle = AssetBundle.LoadFromFile(text);
				if ((Object)(object)bundle == (Object)null)
				{
					throw new InvalidOperationException("Could not load " + text);
				}
				for (int i = 0; i < MovementMap.Entries.GetLength(0); i++)
				{
					string text2 = MovementMap.Entries[i, 0];
					AnimationClip val = bundle.LoadAsset<AnimationClip>(MovementMap.Entries[i, 1]);
					if ((Object)(object)val == (Object)null || val.legacy || !((Motion)val).isHumanMotion)
					{
						throw new InvalidOperationException("Missing humanoid classic clip for " + text2);
					}
					classicClips.Add(text2, val);
				}
				ready = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded " + classicClips.Count + " classic movement replacements. Toggle key: " + ((object)toggleKey.Value/*cast due to .constrained prefix*/).ToString() + ". Two-hand variants except staffs stay modern."));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Classic Walk is inactive: " + ex));
			}
		}

		private void Update()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!ready || (int)toggleKey.Value == 0 || !Input.GetKeyDown(toggleKey.Value))
			{
				return;
			}
			string text;
			try
			{
				if (useClassic)
				{
					useClassic = false;
				}
				else
				{
					((BaseUnityPlugin)this).Config.Reload();
					useClassic = true;
				}
				text = (useClassic ? "Classic Walk" : "Disney Walk");
			}
			catch (Exception ex)
			{
				useClassic = false;
				text = "Classic Walk: config error; Disney Walk selected. See log.";
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not reload Classic Walk settings: " + ex));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)text);
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		private void LateUpdate()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Invalid comparison between Unknown and I4
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if (!ready)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Restore();
				return;
			}
			Animator componentInChildren = ((Component)localPlayer).GetComponentInChildren<Animator>();
			if ((Object)(object)componentInChildren == (Object)null)
			{
				Restore();
				return;
			}
			ItemData val = (ItemData)LeftItem.GetValue(localPlayer);
			ItemData val2 = (ItemData)RightItem.GetValue(localPlayer);
			int equipmentState = ((val == null || val.m_shared == null) ? ((val2 != null && val2.m_shared != null) ? ((int)val2.m_shared.m_animationState) : 0) : (((int)val.m_shared.m_itemType == 15) ? 6 : ((int)val.m_shared.m_animationState)));
			bool flag = useClassic && !MovementPolicy.NeedsOriginalTable(IsHammer(val) || IsHammer(val2), IsLight(val) || IsLight(val2), equipmentState);
			if ((Object)(object)animator != (Object)(object)componentInChildren || (Object)(object)replacement == (Object)null || (Object)(object)componentInChildren.runtimeAnimatorController != (Object)(object)replacement)
			{
				Restore();
				if (!flag || !AnimatorSnapshot.CanChange(componentInChildren))
				{
					return;
				}
				Install(componentInChildren);
			}
			if ((Object)(object)replacement == (Object)null || flag == classicApplied || !AnimatorSnapshot.CanChange(componentInChildren))
			{
				return;
			}
			try
			{
				AnimatorSnapshot animatorSnapshot = new AnimatorSnapshot(componentInChildren);
				try
				{
					replacement.ApplyOverrides((IList<KeyValuePair<AnimationClip, AnimationClip>>)(flag ? replacementClips : originalClips));
				}
				finally
				{
					animatorSnapshot.Restore(componentInChildren);
				}
				classicApplied = flag;
				((BaseUnityPlugin)this).Logger.LogInfo((object)(flag ? "Classic movement clips active." : "Original movement clips active (Disney/equipment exception)."));
			}
			catch (Exception ex)
			{
				rejected = original;
				Restore();
				((BaseUnityPlugin)this).Logger.LogError((object)("Movement clip switch failed: " + ex));
			}
		}

		private void Install(Animator current)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			RuntimeAnimatorController runtimeAnimatorController = current.runtimeAnimatorController;
			if ((Object)(object)runtimeAnimatorController == (Object)null || (Object)(object)runtimeAnimatorController == (Object)(object)rejected)
			{
				return;
			}
			AnimatorOverrideController val = null;
			try
			{
				val = new AnimatorOverrideController(runtimeAnimatorController);
				List<KeyValuePair<AnimationClip, AnimationClip>> list = new List<KeyValuePair<AnimationClip, AnimationClip>>(val.overridesCount);
				val.GetOverrides(list);
				List<KeyValuePair<AnimationClip, AnimationClip>> list2 = new List<KeyValuePair<AnimationClip, AnimationClip>>(list);
				HashSet<string> hashSet = new HashSet<string>();
				for (int i = 0; i < list2.Count; i++)
				{
					KeyValuePair<AnimationClip, AnimationClip> keyValuePair = list2[i];
					if ((Object)(object)keyValuePair.Key != (Object)null && classicClips.TryGetValue(((Object)keyValuePair.Key).name, out var value))
					{
						if (!hashSet.Add(((Object)keyValuePair.Key).name))
						{
							throw new InvalidOperationException("Duplicate movement clip: " + ((Object)keyValuePair.Key).name);
						}
						list2[i] = new KeyValuePair<AnimationClip, AnimationClip>(keyValuePair.Key, value);
					}
				}
				if (hashSet.Count != classicClips.Count)
				{
					throw new InvalidOperationException("Expected " + classicClips.Count + " movement clips; found " + hashSet.Count);
				}
				val.ApplyOverrides((IList<KeyValuePair<AnimationClip, AnimationClip>>)list2);
				AnimatorSnapshot animatorSnapshot = new AnimatorSnapshot(current);
				animator = current;
				original = runtimeAnimatorController;
				replacement = val;
				originalClips = list;
				replacementClips = list2;
				try
				{
					animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)replacement;
				}
				finally
				{
					animatorSnapshot.Restore(current);
				}
				classicApplied = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied " + hashSet.Count + " classic movement replacements on local player; controller retained for subsequent switches."));
			}
			catch (Exception ex)
			{
				rejected = runtimeAnimatorController;
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)replacement)
				{
					Object.Destroy((Object)(object)val);
				}
				Restore();
				((BaseUnityPlugin)this).Logger.LogError((object)("Controller was not replaced: " + ex));
			}
		}

		private static bool IsHammer(ItemData item)
		{
			if (item != null && item.m_shared != null)
			{
				return item.m_shared.m_name == "$item_hammer";
			}
			return false;
		}

		private static bool IsLight(ItemData item)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			if ((int)item.m_shared.m_itemType == 15)
			{
				return true;
			}
			string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "");
			switch (text)
			{
			default:
				return text == "Lantern_DN";
			case "Torch":
			case "TorchMist":
			case "Lantern":
			case "Lantern_hooded":
				return true;
			}
		}

		private void Restore()
		{
			if ((Object)(object)animator != (Object)null && (Object)(object)replacement != (Object)null && (Object)(object)animator.runtimeAnimatorController == (Object)(object)replacement)
			{
				AnimatorSnapshot animatorSnapshot = (animator.isInitialized ? new AnimatorSnapshot(animator) : null);
				try
				{
					animator.runtimeAnimatorController = original;
				}
				finally
				{
					animatorSnapshot?.Restore(animator);
				}
			}
			if ((Object)(object)replacement != (Object)null)
			{
				Object.Destroy((Object)(object)replacement);
			}
			animator = null;
			original = null;
			replacement = null;
			originalClips = null;
			replacementClips = null;
			classicApplied = false;
		}

		private void OnDisable()
		{
			Restore();
		}

		private void OnDestroy()
		{
			Restore();
			if ((Object)(object)bundle != (Object)null)
			{
				bundle.Unload(true);
			}
		}
	}
	internal static class MovementMap
	{
		internal static readonly string[,] Entries = new string[20, 2]
		{
			{ "Walk New", "assets/classicwalk/clip_1944381297147647327.anim" },
			{ "Walk New Sword Right", "assets/classicwalk/clip_1944381297147647327.anim" },
			{ "Walk New Dual Wield", "assets/classicwalk/clip_1944381297147647327.anim" },
			{ "Walk New Staff", "assets/classicwalk/clip_1016665440172609095.anim" },
			{ "Walk New Magic Item", "assets/classicwalk/clip_3746212880225701447.anim" },
			{ "Jog New", "assets/classicwalk/clip_-6261544233206759569.anim" },
			{ "Jog New Sword Right", "assets/classicwalk/clip_7898665904424101520.anim" },
			{ "Jog New Dual Wield", "assets/classicwalk/clip_-6261544233206759569.anim" },
			{ "Jog New Staff", "assets/classicwalk/clip_7231108857784471111.anim" },
			{ "Jog New Magic Item", "assets/classicwalk/clip_7251948349769289287.anim" },
			{ "Jog New Fast", "assets/classicwalk/clip_-6261544233206759569.anim" },
			{ "Jog New Sword Right Fast", "assets/classicwalk/clip_7898665904424101520.anim" },
			{ "Jog New Dual Wield Fast", "assets/classicwalk/clip_-6261544233206759569.anim" },
			{ "Jog New Staff Fast", "assets/classicwalk/clip_7231108857784471111.anim" },
			{ "Jog New Magic Item Fast", "assets/classicwalk/clip_7251948349769289287.anim" },
			{ "Run New", "assets/classicwalk/clip_-5902040244399135219.anim" },
			{ "Run New Sword Right", "assets/classicwalk/clip_3044506059897284109.anim" },
			{ "Run New Dual Wield", "assets/classicwalk/clip_-5902040244399135219.anim" },
			{ "Run New Staff", "assets/classicwalk/clip_-5822766223083794873.anim" },
			{ "Run New Magic Item", "assets/classicwalk/clip_2518552701507046983.anim" }
		};
	}
	internal static class MovementPolicy
	{
		internal static bool NeedsOriginalTable(bool hammerHeld, bool lightHeld, int equipmentState)
		{
			if (!hammerHeld)
			{
				if (lightHeld && equipmentState != 5)
				{
					return equipmentState != 6;
				}
				return false;
			}
			return true;
		}
	}
}