Decompiled source of TimelineResizer v1.1.0

TimelineResizer.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BoneLib;
using BoneLib.BoneMenu;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.VRMK;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using Microsoft.CodeAnalysis;
using Timeline.WorldRecording.Recorders;
using TimelineScaleFix;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Main), "TimelineScaleFix", "1.2.0", "You", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAdditionalDependencies(new string[] { "Timeline", "BoneLib" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TimelineResizer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TimelineResizer")]
[assembly: AssemblyTitle("TimelineResizer")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[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 TimelineScaleFix
{
	internal static class AvatarResizer
	{
		public static bool Enabled = true;

		private static float _scale = 1f;

		private static float _applied = 1f;

		private static bool _applyPending;

		private static bool _forceJump;

		private static float _retryAt;

		private static float _bodyResetAt;

		private static bool _applying;

		private static float _lastOwnSwap = -10f;

		private static bool _loading;

		private static float _loadStarted;

		private static bool _inputBroken;

		private static FloatElement _slider;

		public static void Init()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			Page val = Page.Root.CreatePage("Timeline Resizer", Color.cyan, 0, true);
			val.CreateBool("Resizer Enabled", Color.green, Enabled, (Action<bool>)delegate(bool v)
			{
				Enabled = v;
				if (!v)
				{
					_applyPending = true;
				}
			});
			_slider = val.CreateFloat("Avatar Scale", Color.white, 1f, 0.1f, 0.1f, 5f, (Action<float>)delegate(float v)
			{
				_scale = Mathf.Round(v * 100f) / 100f;
			});
			val.CreateFunction("Apply", Color.green, (Action)delegate
			{
				_applyPending = true;
			});
			val.CreateFunction("Reset to 1.0 (F12)", Color.yellow, (Action)EmergencyReset);
			Hooking.OnLevelLoaded += delegate
			{
				ResetState();
			};
			Hooking.OnSwitchAvatarPostfix += delegate
			{
				if (!_applying && !(Time.realtimeSinceStartup - _lastOwnSwap < 0.5f))
				{
					ResetState();
				}
			};
			MelonLogger.Msg("Timeline Resizer menu created (v1.5)");
		}

		private static void ResetState()
		{
			_scale = 1f;
			_applied = 1f;
			_forceJump = false;
			_applyPending = false;
			_bodyResetAt = Time.realtimeSinceStartup + 0.25f;
			if (_slider != null)
			{
				_slider.Value = 1f;
			}
		}

		private static void EmergencyReset()
		{
			_scale = 1f;
			_forceJump = true;
			_applyPending = false;
			if (_slider != null)
			{
				_slider.Value = 1f;
			}
			MelonLogger.Msg("Resizer: reset requested");
		}

		private static void CheckHotkey()
		{
			if (_inputBroken)
			{
				return;
			}
			try
			{
				if (Input.GetKeyDown((KeyCode)293))
				{
					MelonLogger.Msg("Resizer: F12 pressed");
					EmergencyReset();
				}
			}
			catch (Exception ex)
			{
				_inputBroken = true;
				MelonLogger.Error("F12 hotkey unavailable: " + ex.Message);
			}
		}

		private static void ApplyBodyScale(RigManager rigManager, float s)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			PullCordDevice componentInChildren = ((Component)Player.GetPhysicsRig()).GetComponentInChildren<PullCordDevice>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((Component)componentInChildren).transform.localScale = new Vector3(s, s, s);
			}
			foreach (SlotContainer item in (Il2CppArrayBase<SlotContainer>)(object)rigManager.inventory.bodySlots)
			{
				((Component)item).transform.localScale = new Vector3(s, s, s);
				if (!((Object)item).name.Equals("BeltLf1"))
				{
					continue;
				}
				InventoryAmmoReceiver componentInChildren2 = ((Component)item).GetComponentInChildren<InventoryAmmoReceiver>();
				if (!((Object)(object)componentInChildren2 == (Object)null))
				{
					Enumerator<Magazine> enumerator2 = componentInChildren2._magazineArts.GetEnumerator();
					while (enumerator2.MoveNext())
					{
						Magazine current2 = enumerator2.Current;
						((Component)current2).transform.localScale = new Vector3(s, s, s);
					}
				}
			}
		}

		public static void Tick()
		{
			CheckHotkey();
			if (_loading)
			{
				if (Time.realtimeSinceStartup - _loadStarted < 5f)
				{
					return;
				}
				_loading = false;
			}
			if (_bodyResetAt > 0f && Time.realtimeSinceStartup >= _bodyResetAt)
			{
				RigManager rigManager = Player.RigManager;
				if ((Object)(object)rigManager == (Object)null)
				{
					_bodyResetAt = Time.realtimeSinceStartup + 0.5f;
				}
				else
				{
					_bodyResetAt = 0f;
					if (Mathf.Abs(_applied - 1f) < 0.001f)
					{
						try
						{
							ApplyBodyScale(rigManager, 1f);
						}
						catch (Exception value)
						{
							MelonLogger.Error($"Body reset failed: {value}");
						}
					}
				}
			}
			if (_forceJump)
			{
				if (ScaleTo(1f))
				{
					_forceJump = false;
				}
			}
			else if (_applyPending && !(Time.realtimeSinceStartup < _retryAt))
			{
				float num = (Enabled ? _scale : 1f);
				if (Mathf.Abs(num - _applied) < 0.001f)
				{
					_applyPending = false;
				}
				else if (ScaleTo(num))
				{
					_applyPending = false;
				}
			}
		}

		private static bool ScaleTo(float s)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			RigManager rigManager = Player.RigManager;
			if ((Object)(object)rigManager == (Object)null)
			{
				return false;
			}
			Barcode val = new Barcode(((ScannableReference)rigManager._avatarCrate).Barcode.ID);
			if (!AssetWarehouse.Instance._crateRegistry.ContainsKey(val))
			{
				return false;
			}
			AvatarCrate val2 = ((Il2CppObjectBase)AssetWarehouse.Instance._crateRegistry[val]).TryCast<AvatarCrate>();
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			_loading = true;
			_loadStarted = Time.realtimeSinceStartup;
			Action<GameObject> action = delegate(GameObject obj)
			{
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				_applying = true;
				_lastOwnSwap = Time.realtimeSinceStartup;
				try
				{
					RigManager rigManager2 = Player.RigManager;
					if (!((Object)(object)rigManager2 == (Object)null))
					{
						GameObject val3 = Object.Instantiate<GameObject>(obj);
						val3.transform.localScale = new Vector3(s, s, s);
						val3.transform.parent = ((Component)rigManager2).transform;
						val3.transform.localPosition = Vector3.zero;
						Avatar componentInChildren = val3.GetComponentInChildren<Avatar>();
						foreach (SkinnedMeshRenderer item in (Il2CppArrayBase<SkinnedMeshRenderer>)(object)componentInChildren.hairMeshes)
						{
							((Renderer)item).enabled = false;
						}
						componentInChildren.PrecomputeAvatar();
						componentInChildren.RefreshBodyMeasurements();
						rigManager2.SwitchAvatar(componentInChildren);
						PlayerRefs.Instance._bodyVitals.PROPEGATE();
						ApplyBodyScale(rigManager2, s);
						_applied = s;
						_bodyResetAt = 0f;
					}
				}
				catch (Exception value)
				{
					MelonLogger.Error($"Resize failed: {value}");
					_retryAt = Time.realtimeSinceStartup + 2f;
				}
				finally
				{
					_lastOwnSwap = Time.realtimeSinceStartup;
					_applying = false;
					_loading = false;
				}
			};
			((CrateT<GameObject>)(object)val2).LoadAsset(Action<GameObject>.op_Implicit(action));
			return true;
		}
	}
	public class Main : MelonMod
	{
		internal const string MetaKey = "avatarscale";

		internal static readonly ConditionalWeakTable<RigmanagerRecorder, ScaleTrack> Tracks = new ConditionalWeakTable<RigmanagerRecorder, ScaleTrack>();

		internal static Instance Log;

		public override void OnInitializeMelon()
		{
			Log = ((MelonBase)this).LoggerInstance;
			AvatarResizer.Init();
		}

		public override void OnUpdate()
		{
			AvatarResizer.Tick();
		}
	}
	internal class ScaleTrack
	{
		public readonly List<float> Times = new List<float>();

		public readonly List<float> Values = new List<float>();

		public bool LoadAttempted;

		public void Add(float t, float v)
		{
			if (Times.Count <= 0 || (!(t <= Times[Times.Count - 1]) && !(Mathf.Abs(Values[Values.Count - 1] - v) < 0.001f)))
			{
				Times.Add(t);
				Values.Add(v);
			}
		}

		public bool TryEvaluate(float t, out float v)
		{
			v = 1f;
			if (Times.Count == 0)
			{
				return false;
			}
			int num = Times.BinarySearch(t);
			if (num < 0)
			{
				num = ~num - 1;
			}
			if (num < 0)
			{
				num = 0;
			}
			v = Values[num];
			return true;
		}

		public string Encode()
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < Times.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(Times[i].ToString("0.000", CultureInfo.InvariantCulture)).Append(':').Append(Values[i].ToString("0.0000", CultureInfo.InvariantCulture));
			}
			return stringBuilder.ToString();
		}

		public void Decode(string s)
		{
			Times.Clear();
			Values.Clear();
			string[] array = s.Split(';');
			foreach (string text in array)
			{
				string[] array2 = text.Split(':');
				if (array2.Length == 2 && float.TryParse(array2[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
				{
					Times.Add(result);
					Values.Add(result2);
				}
			}
		}
	}
	internal static class Meta
	{
		private static readonly MethodInfo GetM = AccessTools.Method(typeof(RigmanagerRecorder), "TryGetMetadata", (Type[])null, (Type[])null);

		private static readonly MethodInfo SetM = AccessTools.Method(typeof(RigmanagerRecorder), "SetMetadata", (Type[])null, (Type[])null);

		public static bool TryGet(RigmanagerRecorder r, string key, out string value)
		{
			value = null;
			if (GetM == null)
			{
				return false;
			}
			object[] array = new object[2] { key, null };
			GetM.Invoke(r, array);
			value = array[1] as string;
			return !string.IsNullOrEmpty(value) && value != "NONE";
		}

		public static void Set(RigmanagerRecorder r, string key, string value)
		{
			if (SetM == null)
			{
				Instance log = Main.Log;
				if (log != null)
				{
					log.Error("SetMetadata not found");
				}
			}
			else
			{
				SetM.Invoke(r, new object[2] { key, value });
			}
		}
	}
	[HarmonyPatch(typeof(RigmanagerRecorder), "Capture")]
	internal static class CapturePatch
	{
		private static void Prefix(RigmanagerRecorder __instance)
		{
			try
			{
				RigManager recordingRigManager = __instance.recordingRigManager;
				if ((Object)(object)recordingRigManager == (Object)null)
				{
					return;
				}
				Avatar avatar = recordingRigManager.avatar;
				if (Object.op_Implicit((Object)(object)avatar))
				{
					Avatar currentRecordingAvatar = __instance.currentRecordingAvatar;
					IntPtr intPtr = (((Object)(object)currentRecordingAvatar != (Object)null) ? ((Il2CppObjectBase)currentRecordingAvatar).Pointer : IntPtr.Zero);
					if (!(((Il2CppObjectBase)avatar).Pointer == intPtr))
					{
						__instance.AssignAvatarBones(avatar);
						__instance.currentRecordingAvatar = avatar;
						Main.Log.Msg("Avatar instance changed mid-recording, retargeted bones");
					}
				}
			}
			catch (Exception value)
			{
				Main.Log.Error($"Retarget failed: {value}");
			}
		}

		private static void Postfix(RigmanagerRecorder __instance, float sceneTime)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			RigManager recordingRigManager = __instance.recordingRigManager;
			if ((Object)(object)recordingRigManager == (Object)null)
			{
				return;
			}
			Avatar avatar = recordingRigManager.avatar;
			if (!Object.op_Implicit((Object)(object)avatar))
			{
				return;
			}
			float x = ((Component)avatar).transform.lossyScale.x;
			if (!(x <= 0.0001f))
			{
				Main.Tracks.GetValue(__instance, (RigmanagerRecorder _) => new ScaleTrack()).Add(sceneTime, x);
			}
		}
	}
	[HarmonyPatch(typeof(RigmanagerRecorder), "OnSave")]
	internal static class SavePatch
	{
		private static void Postfix(RigmanagerRecorder __instance)
		{
			if (Main.Tracks.TryGetValue(__instance, out var value) && value.Times.Count > 0)
			{
				Meta.Set(__instance, "avatarscale", value.Encode());
			}
		}
	}
	[HarmonyPatch(typeof(RigmanagerRecorder), "Playback")]
	internal static class PlaybackPatch
	{
		private static void Prefix(RigmanagerRecorder __instance, float sceneTime)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			Avatar currentPlaybackAvatar = __instance.currentPlaybackAvatar;
			if (!Object.op_Implicit((Object)(object)currentPlaybackAvatar))
			{
				return;
			}
			ScaleTrack value = Main.Tracks.GetValue(__instance, (RigmanagerRecorder _) => new ScaleTrack());
			if (!value.LoadAttempted)
			{
				value.LoadAttempted = true;
				if (Meta.TryGet(__instance, "avatarscale", out var value2))
				{
					value.Decode(value2);
				}
			}
			if (value.TryEvaluate(sceneTime, out var v) && !(v <= 0.0001f))
			{
				Transform transform = ((Component)currentPlaybackAvatar).transform;
				float num = (Object.op_Implicit((Object)(object)transform.parent) ? transform.parent.lossyScale.x : 1f);
				if (num <= 0.0001f)
				{
					num = 1f;
				}
				transform.localScale = Vector3.one * (v / num);
			}
		}
	}
}