Decompiled source of ValhATYLSS v0.1.1

plugins/ValhATYLSS.dll

Decompiled 11 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ValhATYLSS")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ValhATYLSS")]
[assembly: AssemblyTitle("ValhATYLSS")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 Atlyss.Uncap.StatLogics
{
	[BepInPlugin("com.cconx.valhatylss", "ValhATYLSS", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private enum RepeatMode
		{
			Constant,
			PatternEveryN
		}

		[CompilerGenerated]
		private sealed class <ApplyTweaksWhenReady>d__7 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			private float <deadline>5__2;

			private Assembly <asm>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ApplyTweaksWhenReady>d__7(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<asm>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Expected O, but got Unknown
				int num = <>1__state;
				Plugin plugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<deadline>5__2 = Time.realtimeSinceStartup + 15f;
					<asm>5__3 = null;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (Time.realtimeSinceStartup < <deadline>5__2)
				{
					<asm>5__3 = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp");
					if (!(<asm>5__3 != null))
					{
						<>2__current = (object)new WaitForSeconds(0.25f);
						<>1__state = 1;
						return true;
					}
				}
				if (<asm>5__3 == null)
				{
					Logger.LogError((object)"[ValhATYLSS] Assembly-CSharp not found; aborting.");
					return false;
				}
				Type type = <asm>5__3.GetTypes().FirstOrDefault((Type t) => t.Name == "StatLogics") ?? <asm>5__3.GetTypes().FirstOrDefault((Type t) => t.Name.EndsWith("StatLogics", StringComparison.OrdinalIgnoreCase));
				if (type == null)
				{
					Logger.LogError((object)"[ValhATYLSS] StatLogics type not found; aborting.");
					return false;
				}
				object obj = FindSingletonInstance(type) ?? FindAnyStaticReferenceTo(type) ?? FindUnityObjectOfType(type);
				if (obj != null)
				{
					Logger.LogInfo((object)("[ValhATYLSS] StatLogics instance acquired via " + ((obj is Object) ? "UnityObject" : "reflection") + "."));
				}
				else
				{
					Logger.LogWarning((object)"[ValhATYLSS] StatLogics instance not found (will patch static fields only).");
				}
				plugin.TrySetIntField(type, obj, "_maxMainLevel", NewLevelCap);
				plugin.TryExtendCurve(type, obj, "_experienceCurve");
				plugin.TryExtendRewardTables(<asm>5__3);
				Logger.LogInfo((object)"[ValhATYLSS] reflection tweaks applied");
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static ManualLogSource Logger;

		public static int NewLevelCap = 64;

		public static int AnchorWindow = 4;

		public static int AttributePerLevel = 3;

		public static int SkillEveryNLevels = 2;

		public static int SkillPointsGrant = 4;

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"[ValhATYLSS] boot (reflection-only mode, instance-safe)");
			((MonoBehaviour)this).StartCoroutine(ApplyTweaksWhenReady());
		}

		[IteratorStateMachine(typeof(<ApplyTweaksWhenReady>d__7))]
		private IEnumerator ApplyTweaksWhenReady()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ApplyTweaksWhenReady>d__7(0)
			{
				<>4__this = this
			};
		}

		private void TryExtendCurve(Type owner, object ownerInstance, string fieldName)
		{
			FieldInfo field = GetField(owner, fieldName);
			if (field == null)
			{
				Logger.LogWarning((object)("[ValhATYLSS] Field '" + fieldName + "' not found on " + owner.Name + "."));
				return;
			}
			object obj = null;
			try
			{
				obj = field.GetValue(field.IsStatic ? null : ownerInstance);
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("[ValhATYLSS] Failed reading " + owner.Name + "." + fieldName + ": " + ex.Message));
				return;
			}
			if (obj == null)
			{
				Logger.LogWarning((object)("[ValhATYLSS] " + owner.Name + "." + fieldName + " is null at patch time."));
				return;
			}
			try
			{
				if (obj is int[] array)
				{
					double r;
					int[] array2 = ExtendCurveArray(array, NewLevelCap, AnchorWindow, out r);
					if (array != array2)
					{
						field.SetValue(field.IsStatic ? null : ownerInstance, array2);
						Logger.LogInfo((object)$"[ValhATYLSS] Extended int[] {fieldName} {array.Length} -> {array2.Length} (r≈{r:F4})");
					}
				}
				else if (obj is float[] array3)
				{
					double r2;
					float[] array4 = ExtendCurveArray(array3, NewLevelCap, AnchorWindow, out r2);
					if (array3 != array4)
					{
						field.SetValue(field.IsStatic ? null : ownerInstance, array4);
						Logger.LogInfo((object)$"[ValhATYLSS] Extended float[] {fieldName} {array3.Length} -> {array4.Length} (r≈{r2:F4})");
					}
				}
				else if (obj is IList list)
				{
					int count = list.Count;
					ExtendCurveList(list, NewLevelCap, AnchorWindow, out var r3);
					if (list.Count != count)
					{
						Logger.LogInfo((object)$"[ValhATYLSS] Extended List {fieldName} {count} -> {list.Count} (r≈{r3:F4})");
					}
				}
				else
				{
					Logger.LogWarning((object)("[ValhATYLSS] " + fieldName + " type " + obj.GetType().FullName + " not handled."));
				}
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"[ValhATYLSS] Failed extending {owner.Name}.{fieldName}: {arg}");
			}
		}

		private static int[] ExtendCurveArray(int[] src, int targetLevelCap, int anchor, out double r)
		{
			int num = Math.Max(src.Length, targetLevelCap + 1);
			r = EstimateGeometricRatio(src, Math.Max(1, src.Length - anchor));
			if (src.Length >= num)
			{
				return src;
			}
			int[] array = new int[num];
			Array.Copy(src, array, src.Length);
			int num2 = src[^1];
			for (int i = src.Length; i < num; i++)
			{
				num2 = (int)Math.Round((double)num2 * r);
				if (i > 0 && num2 <= array[i - 1])
				{
					num2 = array[i - 1] + 1;
				}
				array[i] = num2;
			}
			return array;
		}

		private static float[] ExtendCurveArray(float[] src, int targetLevelCap, int anchor, out double r)
		{
			int num = Math.Max(src.Length, targetLevelCap + 1);
			r = EstimateGeometricRatio(src, Math.Max(1, src.Length - anchor));
			if (src.Length >= num)
			{
				return src;
			}
			float[] array = new float[num];
			Array.Copy(src, array, src.Length);
			double num2 = src[^1];
			for (int i = src.Length; i < num; i++)
			{
				num2 *= r;
				array[i] = (float)num2;
			}
			return array;
		}

		private static void ExtendCurveList(IList list, int targetLevelCap, int anchor, out double r)
		{
			int count = list.Count;
			int num = Math.Max(1, count - anchor);
			List<double> list2 = new List<double>();
			for (int i = num; i < count - 1; i++)
			{
				double num2 = ToDouble(list[i]);
				double num3 = ToDouble(list[i + 1]);
				if (num2 > 0.0 && num3 > 0.0)
				{
					double num4 = num3 / num2;
					if (num4 > 0.1 && num4 < 10.0)
					{
						list2.Add(num4);
					}
				}
			}
			r = ((list2.Count == 0) ? 1.15 : Math.Pow(list2.Aggregate(1.0, (double p, double x) => p * x), 1.0 / (double)list2.Count));
			int num5 = Math.Max(count, targetLevelCap + 1);
			if (count >= num5)
			{
				return;
			}
			double num6 = ToDouble(list[count - 1]);
			while (list.Count < num5)
			{
				num6 = Math.Max(1.0, num6 * r);
				if (list[0] is int)
				{
					list.Add((int)Math.Round(num6));
				}
				else
				{
					list.Add((float)num6);
				}
			}
		}

		private static double ToDouble(object o)
		{
			try
			{
				return Convert.ToDouble(o);
			}
			catch
			{
				return 0.0;
			}
		}

		private static double EstimateGeometricRatio(int[] arr, int startIdx)
		{
			double num = 1.0;
			int num2 = 0;
			for (int i = startIdx; i < arr.Length - 1; i++)
			{
				if (arr[i] > 0)
				{
					double num3 = (double)arr[i + 1] / (double)arr[i];
					if (num3 > 0.1 && num3 < 10.0)
					{
						num *= num3;
						num2++;
					}
				}
			}
			if (num2 != 0)
			{
				return Math.Pow(num, 1.0 / (double)num2);
			}
			return 1.15;
		}

		private static double EstimateGeometricRatio(float[] arr, int startIdx)
		{
			double num = 1.0;
			int num2 = 0;
			for (int i = startIdx; i < arr.Length - 1; i++)
			{
				if (!(arr[i] <= 0f))
				{
					double num3 = (double)arr[i + 1] / (double)arr[i];
					if (num3 > 0.1 && num3 < 10.0)
					{
						num *= num3;
						num2++;
					}
				}
			}
			if (num2 != 0)
			{
				return Math.Pow(num, 1.0 / (double)num2);
			}
			return 1.15;
		}

		private void TryExtendRewardTables(Assembly asm)
		{
			int num = 0;
			Type[] types = asm.GetTypes();
			foreach (Type type in types)
			{
				string text = type.FullName ?? "";
				if (!text.StartsWith("System") && !text.Contains("Unity"))
				{
					num += TryExtendIntArrayField(type, null, "_attributePointsEachLevel", NewLevelCap, AttributePerLevel, RepeatMode.Constant);
					num += TryExtendIntArrayField(type, null, "_skillPointsEachLevel", NewLevelCap, 0, RepeatMode.PatternEveryN, SkillEveryNLevels, SkillPointsGrant);
				}
			}
			if (num == 0)
			{
				Logger.LogInfo((object)"[ValhATYLSS] No obvious reward arrays found. (If points past 32 don’t grant, we’ll hook the LevelUp method next.)");
			}
		}

		private int TryExtendIntArrayField(Type owner, object instance, string fieldName, int targetLen, int constant, RepeatMode mode, int n = 2, int grant = 4)
		{
			try
			{
				FieldInfo field = GetField(owner, fieldName);
				if (field == null)
				{
					return 0;
				}
				if (!field.IsStatic && instance == null)
				{
					instance = FindSingletonInstance(owner) ?? FindAnyStaticReferenceTo(owner) ?? FindUnityObjectOfType(owner);
				}
				if (!(field.GetValue(field.IsStatic ? null : instance) is int[] array))
				{
					return 0;
				}
				if (array.Length >= targetLen)
				{
					return 0;
				}
				int[] array2 = new int[targetLen];
				Array.Copy(array, array2, array.Length);
				if (mode == RepeatMode.Constant)
				{
					for (int i = array.Length; i < targetLen; i++)
					{
						array2[i] = constant;
					}
				}
				else
				{
					for (int j = array.Length; j < targetLen; j++)
					{
						int num = j + 1;
						array2[j] = ((num % n == 0) ? grant : 0);
					}
				}
				field.SetValue(field.IsStatic ? null : instance, array2);
				Logger.LogInfo((object)$"[ValhATYLSS] Extended {owner.Name}.{fieldName} {array.Length} -> {array2.Length}");
				return 1;
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("[ValhATYLSS] Failed to extend " + owner.Name + "." + fieldName + ": " + ex.Message));
				return 0;
			}
		}

		private static FieldInfo GetField(Type t, string name)
		{
			return t.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		}

		private void TrySetIntField(Type owner, object instance, string fieldName, int value)
		{
			FieldInfo field = GetField(owner, fieldName);
			if (field == null || field.FieldType != typeof(int))
			{
				return;
			}
			try
			{
				object obj = (field.IsStatic ? null : (instance ?? FindSingletonInstance(owner) ?? FindAnyStaticReferenceTo(owner) ?? FindUnityObjectOfType(owner)));
				if (!field.IsStatic && obj == null)
				{
					Logger.LogWarning((object)("[ValhATYLSS] " + owner.Name + "." + fieldName + " is instance but no instance was found."));
				}
				else
				{
					int num = (int)field.GetValue(obj);
					field.SetValue(obj, value);
					Logger.LogInfo((object)$"[ValhATYLSS] {owner.Name}.{fieldName}: {num} -> {value}");
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("[ValhATYLSS] Failed to set " + owner.Name + "." + fieldName + ": " + ex.Message));
			}
		}

		private static object FindSingletonInstance(Type t)
		{
			string[] array = new string[8] { "Instance", "instance", "_instance", "s_instance", "Singleton", "singleton", "Inst", "inst" };
			foreach (string name in array)
			{
				FieldInfo field = t.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && field.FieldType == t)
				{
					object value = field.GetValue(null);
					if (value != null)
					{
						return value;
					}
				}
				PropertyInfo property = t.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == t)
				{
					object value2 = property.GetValue(null, null);
					if (value2 != null)
					{
						return value2;
					}
				}
			}
			return null;
		}

		private static object FindAnyStaticReferenceTo(Type targetType)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type[] types;
				try
				{
					types = assembly.GetTypes();
				}
				catch
				{
					continue;
				}
				Type[] array = types;
				foreach (Type type in array)
				{
					FieldInfo[] fields;
					try
					{
						fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					}
					catch
					{
						continue;
					}
					FieldInfo[] array2 = fields;
					foreach (FieldInfo fieldInfo in array2)
					{
						try
						{
							if (targetType.IsAssignableFrom(fieldInfo.FieldType))
							{
								object value = fieldInfo.GetValue(null);
								if (value != null)
								{
									return value;
								}
							}
						}
						catch
						{
						}
					}
				}
			}
			return null;
		}

		private static object FindUnityObjectOfType(Type t)
		{
			try
			{
				if (typeof(Object).IsAssignableFrom(t))
				{
					MethodInfo methodInfo = typeof(Resources).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "FindObjectsOfTypeAll" && m.IsGenericMethodDefinition && m.GetParameters().Length == 0);
					if (methodInfo != null && methodInfo.MakeGenericMethod(t).Invoke(null, null) is Array array && array.Length > 0)
					{
						return array.GetValue(0);
					}
				}
			}
			catch
			{
			}
			return null;
		}
	}
}