Decompiled source of SaneTranscendence v1.0.0

SaneTranscendence.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using IL.RoR2;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.Cil;
using R2API;
using RoR2;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SaneTranscendence")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SaneTranscendence")]
[assembly: AssemblyTitle("SaneTranscendence")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 SaneTranscendence
{
	internal static class Log
	{
		private static ManualLogSource _logSource;

		internal static void Init(ManualLogSource logSource)
		{
			_logSource = logSource;
		}

		private static string Format(object data, string file, int line)
		{
			string fileName = Path.GetFileName(file);
			return $"[{fileName}:{line}] {data}";
		}

		internal static void Debug(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogDebug((object)Format(data, file, line));
		}

		internal static void Error(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogError((object)Format(data, file, line));
		}

		internal static void Fatal(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogFatal((object)Format(data, file, line));
		}

		internal static void Info(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogInfo((object)Format(data, file, line));
		}

		internal static void Message(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogMessage((object)Format(data, file, line));
		}

		internal static void Warning(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogWarning((object)Format(data, file, line));
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.paimcakes.sanetranscendence", "SaneTranscendence", "1.0.0")]
	public class SaneTranscendence : BaseUnityPlugin
	{
		private const float DelayPerStack = 0.2f;

		private const float RechargeKeptPerStack = 0.8f;

		private void Awake()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			CharacterBody.RecalculateStats += new Manipulator(ChangeItemStats);
			CharacterBody.UpdateOutOfCombatAndDanger += new Manipulator(PatchDangerDelay);
			HealthComponent.ServerFixedUpdate += new Manipulator(PatchShieldRecharge);
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(UpdateDescription));
		}

		private static int Stacks(CharacterBody body)
		{
			if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.inventory))
			{
				return 0;
			}
			return body.inventory.GetItemCountEffective(Items.ShieldOnly);
		}

		private void ChangeItemStats(ILContext il)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			int num = default(int);
			if (val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[4]
			{
				(Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, 1.5f),
				(Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref num),
				(Instruction x) => ILPatternMatchingExt.MatchLdcI4(x, 1),
				(Instruction x) => ILPatternMatchingExt.MatchSub(x)
			}))
			{
				int index = val.Index;
				val.Index = index + 1;
				val.Emit(OpCodes.Ldarg_0);
				val.EmitDelegate<Func<float, CharacterBody, float>>((Func<float, CharacterBody, float>)((float vanilla, CharacterBody body) => (Stacks(body) > 0) ? 1f : vanilla));
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"SaneTranscendence: health IL match failed");
			}
		}

		private void PatchDangerDelay(ILContext il)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2]
			{
				(Instruction x) => ILPatternMatchingExt.MatchLdfld<CharacterBody>(x, "outOfDangerStopwatch") || ILPatternMatchingExt.MatchCallvirt<CharacterBody>(x, "get_outOfDangerStopwatch"),
				(Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, 7f)
			}))
			{
				val.Emit(OpCodes.Ldarg_0);
				val.EmitDelegate<Func<float, CharacterBody, float>>((Func<float, CharacterBody, float>)((float delay, CharacterBody body) => delay * (1f + 0.2f * (float)Stacks(body))));
				return;
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("SaneTranscendence: delay match failed in " + ((MemberReference)il.Method).Name + ". Instructions touching outOfDanger or 7f:"));
			Collection<Instruction> instrs = il.Instrs;
			for (int num = 0; num < instrs.Count; num++)
			{
				object operand = instrs[num].Operand;
				MemberReference val2 = (MemberReference)((operand is MemberReference) ? operand : null);
				if ((val2 != null && val2.Name.Contains("outOfDanger")) || (instrs[num].Operand is float num2 && num2 == 7f))
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"--- at instruction {num}");
					for (int num3 = Math.Max(0, num - 1); num3 <= Math.Min(instrs.Count - 1, num + 3); num3++)
					{
						((BaseUnityPlugin)this).Logger.LogError((object)("    " + Describe(instrs[num3])));
					}
				}
			}
		}

		private static string Describe(Instruction ins)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			string text;
			if (ins.Operand == null)
			{
				text = "";
			}
			else
			{
				object operand = ins.Operand;
				MemberReference val = (MemberReference)((operand is MemberReference) ? operand : null);
				text = ((val != null) ? val.FullName : ((!(ins.Operand is float) && !(ins.Operand is int)) ? ins.Operand.GetType().Name : ins.Operand.ToString()));
			}
			return ((object)ins.OpCode/*cast due to .constrained prefix*/).ToString() + " " + text;
		}

		private void PatchShieldRecharge(ILContext il)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			if (val.TryGotoNext(new Func<Instruction, bool>[1]
			{
				(Instruction x) => ILPatternMatchingExt.MatchLdstr(x, "Play_item_proc_personal_shield_end")
			}) && val.TryGotoPrev((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, 0.5f)
			}))
			{
				val.Emit(OpCodes.Ldarg_0);
				val.EmitDelegate<Func<float, HealthComponent, float>>((Func<float, HealthComponent, float>)((float rate, HealthComponent hc) => rate * Mathf.Pow(0.8f, (float)Stacks(hc.body))));
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"SaneTranscendence: shield recharge IL match failed");
			}
		}

		private void UpdateDescription()
		{
			ItemDef shieldOnly = Items.ShieldOnly;
			string text = "<style=cIsHealing>Convert all but 1 health</style> into <style=cIsHealing>regenerating shields</style>. Gain <style=cIsHealing>0% maximum health</style> <style=cStack>(+25% per stack)</style>. " + $"Increase shield recharge delay by <style=cIsDamage>{20f:0}%</style> <style=cStack>(+{20f:0}% per stack)</style>. " + $"Reduce shield recharge rate by <style=cIsDamage>{19.999998f:0}%</style> <style=cStack>(-{19.999998f:0}% per stack)</style>.";
			LanguageAPI.Add(shieldOnly.descriptionToken, text);
			LanguageAPI.Add(shieldOnly.pickupToken, "Convert all but 1 health into regenerating shields. Slower shield recharge.");
		}
	}
}