Decompiled source of VoidStance v1.0.0

VoidStance.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using EntityStates;
using Microsoft.CodeAnalysis;
using On.RoR2;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.Skills;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("VoidStance")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+71d41ee0805864580ef5297067384fa6cd5f7753")]
[assembly: AssemblyProduct("VoidStance")]
[assembly: AssemblyTitle("VoidStance")]
[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 VoidStanceMod
{
	[BepInPlugin("com.MyName.VoidStance", "VoidStance", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public class VoidStanceToggle : BaseSkillState
		{
			public override void OnEnter()
			{
				((BaseState)this).OnEnter();
				CharacterBody characterBody = ((EntityState)this).characterBody;
				if (characterBody != null)
				{
					characterBody.SetAimTimer(0.2f);
				}
				((EntityState)this).PlayCrossfade("Gesture, Additive", "BufferEmpty", "BufferEmpty.playbackRate", 0.1f, 0.05f);
				if (!Object.op_Implicit((Object)(object)((EntityState)this).characterBody))
				{
					return;
				}
				VoidStanceController voidStanceController = ((Component)((EntityState)this).characterBody).GetComponent<VoidStanceController>();
				if (!Object.op_Implicit((Object)(object)voidStanceController))
				{
					voidStanceController = ((Component)((EntityState)this).characterBody).gameObject.AddComponent<VoidStanceController>();
				}
				if (!NetworkServer.active)
				{
					VoidStanceNet component = ((Component)((EntityState)this).characterBody).GetComponent<VoidStanceNet>();
					if ((Object)(object)component != (Object)null)
					{
						component.RequestToggle();
						return;
					}
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"[VoidStance] Net component missing on client.");
					}
				}
				else
				{
					ServerToggleNow(voidStanceController);
				}
			}

			private void ServerToggleNow(VoidStanceController ctrl)
			{
				ctrl.ResolveAndBindController();
				if (ctrl.LockedIsHigh())
				{
					ctrl.GoControlledNow();
				}
				else
				{
					ctrl.GoCorruptedNow();
				}
			}

			public override void FixedUpdate()
			{
				((EntityState)this).FixedUpdate();
				if (((EntityState)this).fixedAge >= 0.2f)
				{
					((EntityState)this).outer.SetNextStateToMain();
				}
			}

			public override InterruptPriority GetMinimumInterruptPriority()
			{
				return (InterruptPriority)1;
			}
		}

		public const string PluginGUID = "com.MyName.VoidStance";

		public const string PluginName = "VoidStance";

		public const string PluginVer = "1.0.0";

		internal static ManualLogSource Log;

		internal static SkillDef StanceSkillDef;

		private string _pluginDir;

		private Sprite _modIcon;

		private Sprite _specialIcon;

		private void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_pluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			_modIcon = LoadSprite("icon.png");
			_specialIcon = LoadSprite("icon_special.png");
			bool flag = default(bool);
			ContentAddition.AddEntityState<VoidStanceToggle>(ref flag);
			StanceSkillDef = ScriptableObject.CreateInstance<SkillDef>();
			StanceSkillDef.skillName = "VOIDSTANCE_TOGGLE";
			StanceSkillDef.skillNameToken = "VOIDSTANCE_TOGGLE_NAME";
			StanceSkillDef.skillDescriptionToken = "VOIDSTANCE_TOGGLE_DESC";
			StanceSkillDef.icon = (((Object)(object)_specialIcon != (Object)null) ? _specialIcon : _modIcon);
			StanceSkillDef.activationState = new SerializableEntityStateType(typeof(VoidStanceToggle));
			StanceSkillDef.activationStateMachineName = "Weapon";
			StanceSkillDef.baseMaxStock = 1;
			StanceSkillDef.rechargeStock = 1;
			StanceSkillDef.baseRechargeInterval = 2f;
			StanceSkillDef.beginSkillCooldownOnSkillEnd = true;
			StanceSkillDef.canceledFromSprinting = false;
			StanceSkillDef.cancelSprintingOnActivation = false;
			StanceSkillDef.fullRestockOnAssign = true;
			StanceSkillDef.isCombatSkill = true;
			StanceSkillDef.interruptPriority = (InterruptPriority)0;
			StanceSkillDef.mustKeyPress = true;
			StanceSkillDef.requiredStock = 1;
			StanceSkillDef.resetCooldownTimerOnUse = false;
			ContentAddition.AddSkillDef(StanceSkillDef);
			LanguageAPI.Add("VOIDSTANCE_TOGGLE_NAME", "Void Stance");
			LanguageAPI.Add("VOIDSTANCE_TOGGLE_DESC", "Toggle between Controlled and Corrupted at will. Prevents passive corruption drift and auto-transforms.");
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(InjectIntoVoidFiend));
			CharacterBody.onBodyStartGlobal += TryAttachControllers;
			CharacterBody.Start += new hook_Start(HookBodyStartAttach);
			Log.LogInfo((object)"[VoidStance] Loaded 1.3.3");
		}

		private Sprite LoadSprite(string fileName)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_008c: 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)
			try
			{
				if (string.IsNullOrEmpty(_pluginDir))
				{
					return null;
				}
				string path = Path.Combine(_pluginDir, fileName);
				if (!File.Exists(path))
				{
					return null;
				}
				byte[] array = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val, array))
				{
					return null;
				}
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Texture)val).filterMode = (FilterMode)1;
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[VoidStance] LoadSprite failed for '" + fileName + "': " + ex.Message));
				}
				return null;
			}
		}

		private void InjectIntoVoidFiend()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/DLC1/VoidSurvivor/VoidSurvivorBody.prefab").WaitForCompletion();
				if (!Object.op_Implicit((Object)(object)val))
				{
					Log.LogError((object)"[VoidStance] Could not load VoidSurvivorBody.");
					return;
				}
				SkillLocator component = val.GetComponent<SkillLocator>();
				if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.special) || !Object.op_Implicit((Object)(object)component.special.skillFamily))
				{
					Log.LogError((object)"[VoidStance] Void Fiend special family not found.");
					return;
				}
				SkillFamily skillFamily = component.special.skillFamily;
				if (!skillFamily.variants.Any((Variant v) => (Object)(object)v.skillDef == (Object)(object)StanceSkillDef))
				{
					Array.Resize(ref skillFamily.variants, skillFamily.variants.Length + 1);
					Variant[] variants = skillFamily.variants;
					int num = variants.Length - 1;
					Variant val2 = new Variant
					{
						skillDef = StanceSkillDef,
						unlockableDef = null
					};
					((Variant)(ref val2)).viewableNode = new Node(StanceSkillDef.skillNameToken, false, (Node)null);
					variants[num] = val2;
				}
				Log.LogInfo((object)"[VoidStance] Added 'Void Stance' to Void Fiend Special.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[VoidStance] Injection failed: " + ex));
			}
		}

		private void HookBodyStartAttach(orig_Start orig, CharacterBody self)
		{
			orig.Invoke(self);
			TryAttachControllers(self);
		}

		private void TryAttachControllers(CharacterBody body)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			if ((!Object.op_Implicit((Object)(object)((Component)body).gameObject) || ((Object)((Component)body).gameObject).name.IndexOf("VoidSurvivor", StringComparison.OrdinalIgnoreCase) < 0) && (string.IsNullOrEmpty(body.baseNameToken) || body.baseNameToken.IndexOf("VOID_SURVIVOR", StringComparison.OrdinalIgnoreCase) < 0))
			{
				string bodyName = BodyCatalog.GetBodyName(body.bodyIndex);
				if (bodyName == null || bodyName.IndexOf("VoidSurvivor", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return;
				}
			}
			if (!Object.op_Implicit((Object)(object)((Component)body).GetComponent<VoidStanceController>()))
			{
				((Component)body).gameObject.AddComponent<VoidStanceController>();
			}
			if (!Object.op_Implicit((Object)(object)((Component)body).GetComponent<VoidStanceNet>()))
			{
				((Component)body).gameObject.AddComponent<VoidStanceNet>();
			}
		}
	}
	public class VoidStanceNet : NetworkBehaviour
	{
		private CharacterBody body;

		private VoidStanceController ctrl;

		private void Awake()
		{
			body = ((Component)this).GetComponent<CharacterBody>();
			ctrl = ((Component)this).GetComponent<VoidStanceController>();
		}

		public void RequestToggle()
		{
			if (!((NetworkBehaviour)this).isServer)
			{
				CmdToggle();
			}
			else
			{
				ServerToggle();
			}
		}

		[Command]
		private void CmdToggle()
		{
			ServerToggle();
		}

		private void ServerToggle()
		{
			if (!Object.op_Implicit((Object)(object)ctrl))
			{
				ctrl = ((Component)this).GetComponent<VoidStanceController>();
			}
			if (Object.op_Implicit((Object)(object)ctrl))
			{
				ctrl.ResolveAndBindController();
				if (ctrl.LockedIsHigh())
				{
					ctrl.GoControlledNow();
				}
				else
				{
					ctrl.GoCorruptedNow();
				}
				TargetOnToggled(((NetworkBehaviour)this).connectionToClient, ctrl.LockedIsHigh());
			}
		}

		[TargetRpc]
		private void TargetOnToggled(NetworkConnection target, bool isCorrupted)
		{
		}
	}
	public class VoidStanceController : MonoBehaviour
	{
		private CharacterBody body;

		private GenericSkill special;

		private Component vfController;

		private Transform boundTransform;

		private FieldInfo fldCorruption;

		private PropertyInfo propCorruption;

		private FieldInfo fldIsCorrupted;

		private FieldInfo fldCorruptionActive;

		private FieldInfo fldMinThreshold;

		private FieldInfo fldMaxThreshold;

		private FieldInfo[] corruptionRelatedFloats;

		private MethodInfo mEnterCorruption;

		private MethodInfo mExitCorruption;

		private MethodInfo mSetCorruptionActiveBool;

		private MethodInfo mTryTransformToCorrupted;

		private MethodInfo mTryTransformToBase;

		private MethodInfo mRequestTransformationBool;

		private float lockedCorruption = float.NaN;

		private bool corruptionIsPercent = true;

		private bool userChoseStance;

		private bool overrideApplied;

		private float rebindTick;

		private bool dumped;

		private void Start()
		{
			body = ((Component)this).GetComponent<CharacterBody>();
			CharacterBody obj = body;
			special = ((obj == null) ? null : obj.skillLocator?.special);
			userChoseStance = HasVoidStanceSelected();
			ResolveAndBindController();
			SnapLockValue();
		}

		private void OnDestroy()
		{
			TryUnsetOverride();
		}

		private bool HasVoidStanceSelected()
		{
			if (!Object.op_Implicit((Object)(object)special) || (Object)(object)Plugin.StanceSkillDef == (Object)null)
			{
				return false;
			}
			return (Object)(object)special.skillDef == (Object)(object)Plugin.StanceSkillDef;
		}

		private bool FamilyContainsOurDef()
		{
			if (!Object.op_Implicit((Object)(object)special) || (Object)(object)special.skillFamily == (Object)null || (Object)(object)Plugin.StanceSkillDef == (Object)null)
			{
				return false;
			}
			SkillFamily skillFamily = special.skillFamily;
			for (int i = 0; i < skillFamily.variants.Length; i++)
			{
				if ((Object)(object)skillFamily.variants[i].skillDef == (Object)(object)Plugin.StanceSkillDef)
				{
					return true;
				}
			}
			return false;
		}

		private void TryApplyOverride()
		{
			if (!overrideApplied && Object.op_Implicit((Object)(object)special) && !((Object)(object)Plugin.StanceSkillDef == (Object)null) && FamilyContainsOurDef())
			{
				special.SetSkillOverride((object)body, Plugin.StanceSkillDef, (SkillOverridePriority)4);
				overrideApplied = true;
			}
		}

		private void TryUnsetOverride()
		{
			if (overrideApplied)
			{
				if (!Object.op_Implicit((Object)(object)special) || (Object)(object)Plugin.StanceSkillDef == (Object)null)
				{
					overrideApplied = false;
					return;
				}
				special.UnsetSkillOverride((object)body, Plugin.StanceSkillDef, (SkillOverridePriority)4);
				overrideApplied = false;
			}
		}

		public void ForceDump()
		{
			DumpAllComponents();
		}

		private void FixedUpdate()
		{
			rebindTick -= Time.fixedDeltaTime;
			if (rebindTick <= 0f)
			{
				rebindTick = 0.1f;
				if (!Object.op_Implicit((Object)(object)vfController))
				{
					ResolveAndBindController();
				}
			}
			if (HasVoidStanceSelected())
			{
				userChoseStance = true;
			}
			if (userChoseStance)
			{
				TryApplyOverride();
			}
			else
			{
				TryUnsetOverride();
			}
			if (NetworkServer.active && Object.op_Implicit((Object)(object)vfController) && userChoseStance)
			{
				StrongLockCorruption();
			}
		}

		private void Update()
		{
			if (NetworkServer.active && Object.op_Implicit((Object)(object)vfController) && userChoseStance)
			{
				StrongLockCorruption();
			}
		}

		public bool LockedIsHigh()
		{
			if (float.IsNaN(lockedCorruption))
			{
				lockedCorruption = ReadCorruption();
			}
			float num = (float.IsNaN(lockedCorruption) ? 0f : lockedCorruption);
			return num > (corruptionIsPercent ? 50f : 0.5f);
		}

		public void GoCorruptedNow()
		{
			ResolveAndBindController();
			if (HasVoidStanceSelected())
			{
				userChoseStance = true;
			}
			if (userChoseStance)
			{
				TryApplyOverride();
			}
			SafeInvoke(mSetCorruptionActiveBool, vfController, new object[1] { false });
			SafeInvoke(mEnterCorruption, vfController, null);
			SafeInvoke(mTryTransformToCorrupted, vfController, null);
			SafeInvoke(mRequestTransformationBool, vfController, new object[1] { true });
			SafeWriteBool(fldIsCorrupted, vfController, v: true);
			SafeWriteBool(fldCorruptionActive, vfController, v: false);
			lockedCorruption = (corruptionIsPercent ? 100f : 1f);
			WriteCorruption(lockedCorruption);
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[VoidStance] -> Corrupted");
			}
		}

		public void GoControlledNow()
		{
			ResolveAndBindController();
			if (HasVoidStanceSelected())
			{
				userChoseStance = true;
			}
			if (userChoseStance)
			{
				TryApplyOverride();
			}
			SafeInvoke(mSetCorruptionActiveBool, vfController, new object[1] { false });
			SafeInvoke(mExitCorruption, vfController, null);
			SafeInvoke(mTryTransformToBase, vfController, null);
			SafeInvoke(mRequestTransformationBool, vfController, new object[1] { false });
			SafeWriteBool(fldIsCorrupted, vfController, v: false);
			SafeWriteBool(fldCorruptionActive, vfController, v: false);
			lockedCorruption = 0f;
			WriteCorruption(lockedCorruption);
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[VoidStance] -> Controlled");
			}
		}

		public void ResolveAndBindController()
		{
			vfController = null;
			boundTransform = null;
			fldCorruption = null;
			propCorruption = null;
			fldIsCorrupted = null;
			fldCorruptionActive = null;
			fldMinThreshold = null;
			fldMaxThreshold = null;
			corruptionRelatedFloats = null;
			mEnterCorruption = null;
			mExitCorruption = null;
			mSetCorruptionActiveBool = null;
			mTryTransformToCorrupted = null;
			mTryTransformToBase = null;
			mRequestTransformationBool = null;
			if (!Object.op_Implicit((Object)(object)body))
			{
				return;
			}
			List<Transform> list = new List<Transform> { body.transform };
			ModelLocator modelLocator = body.modelLocator;
			if (Object.op_Implicit((Object)(object)modelLocator) && Object.op_Implicit((Object)(object)modelLocator.modelTransform))
			{
				list.Add(modelLocator.modelTransform);
			}
			if (Object.op_Implicit((Object)(object)modelLocator) && Object.op_Implicit((Object)(object)modelLocator.modelBaseTransform))
			{
				list.Add(modelLocator.modelBaseTransform);
			}
			if (Object.op_Implicit((Object)(object)body.masterObject))
			{
				list.Add(body.masterObject.transform);
			}
			foreach (Transform item in list.Where((Transform x) => Object.op_Implicit((Object)(object)x)))
			{
				Component[] componentsInChildren = ((Component)item).GetComponentsInChildren<Component>(true);
				foreach (Component val in componentsInChildren)
				{
					if (Object.op_Implicit((Object)(object)val) && ((object)val).GetType().Name.Equals("VoidSurvivorController", StringComparison.OrdinalIgnoreCase) && BindFromComponent(val))
					{
						return;
					}
				}
			}
			foreach (Transform item2 in list.Where((Transform x) => Object.op_Implicit((Object)(object)x)))
			{
				Component[] componentsInChildren2 = ((Component)item2).GetComponentsInChildren<Component>(true);
				foreach (Component val2 in componentsInChildren2)
				{
					if (Object.op_Implicit((Object)(object)val2))
					{
						Type type = ((object)val2).GetType();
						if (HasAnyMethod(type, new string[10] { "EnterCorruption", "EnterCorrupted", "StartCorruption", "ExitCorruption", "ExitCorrupted", "StopCorruption", "SetCorruptionActive", "TryTransformToCorrupted", "TryTransformToBase", "RequestTransformation" }) && BindFromComponent(val2))
						{
							return;
						}
					}
				}
			}
			foreach (Transform item3 in list.Where((Transform x) => Object.op_Implicit((Object)(object)x)))
			{
				Component[] componentsInChildren3 = ((Component)item3).GetComponentsInChildren<Component>(true);
				foreach (Component val3 in componentsInChildren3)
				{
					if (Object.op_Implicit((Object)(object)val3) && HasPlausibleCorruptionValue(val3, out var _, out var _) && BindFromComponent(val3))
					{
						return;
					}
				}
			}
			if (!dumped)
			{
				dumped = true;
				DumpAllComponents();
			}
		}

		private bool BindFromComponent(Component c)
		{
			vfController = c;
			boundTransform = c.transform;
			Type type = ((object)c).GetType();
			fldCorruption = FirstField(type, typeof(float), new string[5] { "corruption", "corruptionFrac", "corruptionFraction", "corruptionPercent", "corruptionValue" }) ?? GuessCorruptionFloatField(type, c);
			if (fldCorruption == null)
			{
				propCorruption = FirstProperty(type, typeof(float), new string[4] { "Corruption", "CorruptionFraction", "CorruptionPercent", "Value" });
			}
			fldIsCorrupted = FirstField(type, typeof(bool), new string[4] { "isCorrupted", "isCorruption", "corrupted", "isInCorruptedMode" });
			fldCorruptionActive = FirstField(type, typeof(bool), new string[3] { "corruptionActive", "isCorruptionActive", "isCorruptionOn" });
			fldMinThreshold = FirstField(type, typeof(float), new string[3] { "minCorruptionToTransform", "minCorruptionToActivate", "minCorruption" });
			fldMaxThreshold = FirstField(type, typeof(float), new string[3] { "maxCorruptionToRevert", "maxCorruptionToDeactivate", "maxCorruption" });
			FieldInfo[] array = (from f in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where f.FieldType == typeof(float)
				select f).ToArray();
			List<FieldInfo> list = new List<FieldInfo>();
			FieldInfo[] array2 = array;
			foreach (FieldInfo fieldInfo in array2)
			{
				string text = fieldInfo.Name.ToLowerInvariant();
				if (text.Contains("corrupt") && ShouldZero(fieldInfo))
				{
					list.Add(fieldInfo);
				}
			}
			corruptionRelatedFloats = list.ToArray();
			mEnterCorruption = FirstMethod(type, new string[3] { "EnterCorruption", "EnterCorrupted", "StartCorruption" }, Type.EmptyTypes);
			mExitCorruption = FirstMethod(type, new string[3] { "ExitCorruption", "ExitCorrupted", "StopCorruption" }, Type.EmptyTypes);
			mSetCorruptionActiveBool = FirstMethod(type, new string[2] { "SetCorruptionActive", "SetCorrupted" }, new Type[1] { typeof(bool) });
			mTryTransformToCorrupted = FirstMethod(type, new string[2] { "TryTransformToCorrupted", "TryEnterCorruption" }, Type.EmptyTypes);
			mTryTransformToBase = FirstMethod(type, new string[2] { "TryTransformToBase", "TryExitCorruption" }, Type.EmptyTypes);
			mRequestTransformationBool = FirstMethod(type, new string[2] { "RequestTransformation", "RequestCorruption" }, new Type[1] { typeof(bool) });
			float num = ReadCorruption();
			if (!float.IsNaN(num))
			{
				corruptionIsPercent = num > 1.0001f && num <= 100f;
			}
			else
			{
				corruptionIsPercent = false;
			}
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				object[] obj = new object[4]
				{
					type.FullName,
					PathOf(boundTransform),
					fldCorruption?.Name ?? propCorruption?.Name ?? "<?>",
					null
				};
				FieldInfo[] array3 = corruptionRelatedFloats;
				obj[3] = ((array3 != null) ? array3.Length : 0);
				log.LogInfo((object)string.Format("[VoidStance] Bound: {0} @ {1} | value={2} | floatsToZero={3}", obj));
			}
			return true;
			bool ShouldZero(FieldInfo f)
			{
				string text2 = f.Name.ToLowerInvariant();
				if (fldCorruption != null && f == fldCorruption)
				{
					return false;
				}
				if (text2.Contains("min") || text2.Contains("max") || text2.Contains("threshold") || text2.Contains("limit") || text2.Contains("bound"))
				{
					return false;
				}
				if (text2.Contains("toactivate") || text2.Contains("totransform"))
				{
					return false;
				}
				if (text2.EndsWith("percent") || text2.EndsWith("fraction") || text2.EndsWith("value"))
				{
					return false;
				}
				return text2.Contains("rate") || text2.Contains("drift") || text2.Contains("delta") || text2.Contains("speed") || text2.Contains("gain") || text2.Contains("loss") || text2.Contains("regen") || text2.Contains("persecond");
			}
		}

		private void StrongLockCorruption()
		{
			if (float.IsNaN(lockedCorruption))
			{
				lockedCorruption = ReadCorruption();
			}
			if (float.IsNaN(lockedCorruption))
			{
				lockedCorruption = 0f;
			}
			if (corruptionIsPercent)
			{
				lockedCorruption = Mathf.Clamp(lockedCorruption, 0f, 100f);
			}
			else
			{
				lockedCorruption = Mathf.Clamp01(lockedCorruption);
			}
			WriteCorruption(lockedCorruption);
			SafeInvoke(mSetCorruptionActiveBool, vfController, new object[1] { false });
			if (corruptionRelatedFloats != null)
			{
				for (int i = 0; i < corruptionRelatedFloats.Length; i++)
				{
					SafeWriteFloat(corruptionRelatedFloats[i], vfController, 0f);
				}
			}
		}

		private void DumpAllComponents()
		{
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("=== VoidStance Component Dump ===");
				CharacterBody obj = body;
				ModelLocator val = ((obj != null) ? obj.modelLocator : null);
				List<Transform> list = new List<Transform>();
				if (Object.op_Implicit((Object)(object)body))
				{
					list.Add(body.transform);
				}
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.modelTransform))
				{
					list.Add(val.modelTransform);
				}
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.modelBaseTransform))
				{
					list.Add(val.modelBaseTransform);
				}
				if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.masterObject))
				{
					list.Add(body.masterObject.transform);
				}
				foreach (Transform item in list.Where((Transform x) => Object.op_Implicit((Object)(object)x)))
				{
					stringBuilder.AppendLine("-- ROOT: " + PathOf(item));
					Component[] componentsInChildren = ((Component)item).GetComponentsInChildren<Component>(true);
					foreach (Component val2 in componentsInChildren)
					{
						if (Object.op_Implicit((Object)(object)val2))
						{
							Type type = ((object)val2).GetType();
							stringBuilder.AppendLine("  " + PathOf(val2.transform) + "  ::  " + type.FullName);
							if (HasAnyMethod(type, new string[6] { "EnterCorruption", "ExitCorruption", "SetCorruptionActive", "TryTransformToCorrupted", "TryTransformToBase", "RequestTransformation" }))
							{
								stringBuilder.AppendLine("    [*] has corruption methods");
							}
							if (HasPlausibleCorruptionValue(val2, out var fOut, out var pOut))
							{
								stringBuilder.AppendLine("    [*] has corruption value via " + ((fOut != null) ? ("field:" + fOut.Name) : ("prop:" + pOut.Name)));
							}
						}
					}
				}
				string text = Path.Combine(Paths.BepInExRootPath, "LogOutput");
				Directory.CreateDirectory(text);
				string text2 = Path.Combine(text, "VoidStance.dump.txt");
				File.WriteAllText(text2, stringBuilder.ToString());
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[VoidStance] Dump written: " + text2));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[VoidStance] Dump failed: " + ex.Message));
				}
			}
		}

		private static bool HasAnyMethod(Type t, IEnumerable<string> names)
		{
			foreach (string name in names)
			{
				if (t.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null)
				{
					return true;
				}
			}
			return false;
		}

		private static bool HasPlausibleCorruptionValue(Component c, out FieldInfo fOut, out PropertyInfo pOut)
		{
			fOut = null;
			pOut = null;
			Type type = ((object)c).GetType();
			FieldInfo fieldInfo = FirstField(type, typeof(float), new string[5] { "corruption", "corruptionFraction", "corruptionFrac", "corruptionPercent", "corruptionValue" }) ?? GuessCorruptionFloatField(type, c);
			PropertyInfo propertyInfo = null;
			if (fieldInfo == null)
			{
				propertyInfo = FirstProperty(type, typeof(float), new string[4] { "Corruption", "CorruptionFraction", "CorruptionPercent", "Value" });
			}
			float num = float.NaN;
			try
			{
				if (fieldInfo != null)
				{
					num = (float)fieldInfo.GetValue(c);
				}
				else if (propertyInfo != null)
				{
					num = (float)propertyInfo.GetValue(c, null);
				}
			}
			catch
			{
			}
			if (!float.IsNaN(num) && ((num >= 0f && num <= 1f) || (num >= 0f && num <= 100f)))
			{
				fOut = fieldInfo;
				pOut = propertyInfo;
				return true;
			}
			return false;
		}

		private static FieldInfo FirstField(Type t, Type ft, IEnumerable<string> names)
		{
			foreach (string name in names)
			{
				FieldInfo field = t.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && field.FieldType == ft)
				{
					return field;
				}
			}
			return null;
		}

		private static PropertyInfo FirstProperty(Type t, Type pt, IEnumerable<string> names)
		{
			foreach (string name in names)
			{
				PropertyInfo property = t.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == pt && property.CanRead && property.CanWrite)
				{
					return property;
				}
			}
			return null;
		}

		private static MethodInfo FirstMethod(Type t, IEnumerable<string> names, Type[] sig)
		{
			foreach (string name in names)
			{
				MethodInfo method = t.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, sig, null);
				if (method != null)
				{
					return method;
				}
			}
			return null;
		}

		private static MethodInfo FirstMethod(Type t, IEnumerable<string> names, Type emptySig)
		{
			return FirstMethod(t, names, Type.EmptyTypes);
		}

		private static FieldInfo GuessCorruptionFloatField(Type t, object inst)
		{
			try
			{
				FieldInfo[] array = (from f in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where f.FieldType == typeof(float)
					select f).ToArray();
				FieldInfo[] array2 = array.Where((FieldInfo f) => f.Name.IndexOf("corrupt", StringComparison.OrdinalIgnoreCase) >= 0).ToArray();
				FieldInfo[] array3 = ((array2.Length != 0) ? array2 : array);
				FieldInfo[] array4 = array3;
				foreach (FieldInfo fieldInfo in array4)
				{
					try
					{
						float num = (float)fieldInfo.GetValue(inst);
						if ((num >= 0f && num <= 1f) || (num >= 0f && num <= 100f))
						{
							return fieldInfo;
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private float ReadCorruption()
		{
			try
			{
				if (fldCorruption != null)
				{
					return (float)fldCorruption.GetValue(vfController);
				}
				if (propCorruption != null)
				{
					return (float)propCorruption.GetValue(vfController, null);
				}
			}
			catch
			{
			}
			return float.NaN;
		}

		private void WriteCorruption(float value)
		{
			try
			{
				if (fldCorruption != null)
				{
					fldCorruption.SetValue(vfController, value);
				}
				else if (propCorruption != null)
				{
					propCorruption.SetValue(vfController, value, null);
				}
			}
			catch
			{
			}
		}

		private void SafeWriteFloat(FieldInfo f, object o, float v)
		{
			if (f == null)
			{
				return;
			}
			try
			{
				f.SetValue(o, v);
			}
			catch
			{
			}
		}

		private void SafeWriteBool(FieldInfo f, object o, bool v)
		{
			if (f == null)
			{
				return;
			}
			try
			{
				f.SetValue(o, v);
			}
			catch
			{
			}
		}

		private bool? ReadBool(FieldInfo f, object o)
		{
			if (f == null)
			{
				return null;
			}
			try
			{
				return (bool)f.GetValue(o);
			}
			catch
			{
				return null;
			}
		}

		private bool SafeInvoke(MethodInfo m, object o, object[] args)
		{
			if (m == null)
			{
				return false;
			}
			try
			{
				m.Invoke(o, args);
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static string PathOf(Transform t)
		{
			if (!Object.op_Implicit((Object)(object)t))
			{
				return "<null>";
			}
			List<string> list = new List<string>();
			while (Object.op_Implicit((Object)(object)t))
			{
				list.Add(((Object)t).name);
				t = t.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		private void SnapLockValue()
		{
			bool? flag = ReadBool(fldIsCorrupted, vfController);
			if (flag.HasValue)
			{
				lockedCorruption = ((!flag.Value) ? 0f : (corruptionIsPercent ? 100f : 1f));
				WriteCorruption(lockedCorruption);
				return;
			}
			float num = ReadCorruption();
			if (float.IsNaN(num))
			{
				num = 0f;
			}
			if (num < 0f)
			{
				num = 0f;
			}
			if (num > 100f)
			{
				num = 100f;
			}
			if (num <= 1.0001f)
			{
				corruptionIsPercent = false;
			}
			else if (num <= 100f)
			{
				corruptionIsPercent = true;
			}
			lockedCorruption = num;
		}
	}
}
namespace VoidStance
{
	internal static class Log
	{
		private static ManualLogSource _logSource;

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

		internal static void Debug(object data)
		{
			_logSource.LogDebug(data);
		}

		internal static void Error(object data)
		{
			_logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			_logSource.LogFatal(data);
		}

		internal static void Info(object data)
		{
			_logSource.LogInfo(data);
		}

		internal static void Message(object data)
		{
			_logSource.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			_logSource.LogWarning(data);
		}
	}
}