Decompiled source of player is v3 v1.0.0

plugins/V3PlayableRebuild/V3PlayableRebuild.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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("V3PlayableRebuild")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("V3PlayableRebuild")]
[assembly: AssemblyTitle("V3PlayableRebuild")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace V3PlayableRebuild
{
	internal static class Visuals
	{
		private sealed class ArmTemplate
		{
			public Mesh Mesh;

			public Material[] Materials;

			public string[] BoneNames;

			public string RootName;
		}

		private static readonly List<Action> Undo = new List<Action>();

		private static readonly List<Object> Created = new List<Object>();

		private static readonly HashSet<int> Seen = new HashSet<int>();

		private static readonly HashSet<int> Resized = new HashSet<int>();

		private static readonly HashSet<int> Hidden = new HashSet<int>();

		private static readonly Dictionary<TMP_Text, string> Texts = new Dictionary<TMP_Text, string>();

		private static readonly Regex V1Token = new Regex("\\bV1\\b");

		private static readonly List<ArmTemplate> Templates = new List<ArmTemplate>();

		private static string armRootName;

		private static T Own<T>(T obj) where T : Object
		{
			Created.Add((Object)(object)obj);
			return obj;
		}

		private static string Key(string name)
		{
			return name.ToLowerInvariant();
		}

		internal static void HideArm(GameObject arm)
		{
			if (!Object.op_Implicit((Object)(object)arm))
			{
				return;
			}
			Renderer[] componentsInChildren = arm.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer r in componentsInChildren)
			{
				if (!Hidden.Add(((Object)r).GetInstanceID()))
				{
					continue;
				}
				bool old = r.forceRenderingOff;
				Undo.Add(delegate
				{
					if (Object.op_Implicit((Object)(object)r))
					{
						r.forceRenderingOff = old;
					}
				});
				r.forceRenderingOff = true;
			}
		}

		internal static void ResizeHealth(HealthBar bar)
		{
			if (!Resized.Add(((Object)bar).GetInstanceID()))
			{
				return;
			}
			List<Slider> list = new List<Slider>();
			if (bar.hpSliders != null)
			{
				list.AddRange(bar.hpSliders);
			}
			if (bar.afterImageSliders != null)
			{
				list.AddRange(bar.afterImageSliders);
			}
			if (Object.op_Implicit((Object)(object)bar.antiHpSlider))
			{
				list.Add(bar.antiHpSlider);
			}
			foreach (Slider slider in list)
			{
				if (!Object.op_Implicit((Object)(object)slider))
				{
					continue;
				}
				float max = slider.maxValue;
				Undo.Add(delegate
				{
					if (Object.op_Implicit((Object)(object)slider))
					{
						slider.maxValue = max;
					}
				});
				slider.maxValue = 400f;
			}
			if (!Object.op_Implicit((Object)(object)bar.hpText))
			{
				return;
			}
			TMP_Text t = bar.hpText;
			string old = t.text;
			Undo.Add(delegate
			{
				if (Object.op_Implicit((Object)(object)t))
				{
					t.text = old;
				}
			});
		}

		internal static void Rename(TMP_Text text)
		{
			if (Object.op_Implicit((Object)(object)text) && text.text != null && V1Token.IsMatch(text.text))
			{
				if (!Texts.ContainsKey(text))
				{
					Texts.Add(text, text.text);
				}
				text.text = V1Token.Replace(text.text, "V3");
			}
		}

		internal static void Refresh()
		{
			if (!Plugin.Active)
			{
				return;
			}
			if (SceneHelper.CurrentScene == "Tutorial")
			{
				IntroTextController[] array = Object.FindObjectsOfType<IntroTextController>(true);
				for (int i = 0; i < array.Length; i++)
				{
					TMP_Text[] componentsInChildren = ((Component)array[i]).GetComponentsInChildren<TMP_Text>(true);
					for (int j = 0; j < componentsInChildren.Length; j++)
					{
						Rename(componentsInChildren[j]);
					}
				}
			}
			PlayerAnimations[] array2 = Object.FindObjectsOfType<PlayerAnimations>(true);
			for (int i = 0; i < array2.Length; i++)
			{
				SkinPlayer(array2[i]);
			}
			V2[] array3 = Object.FindObjectsOfType<V2>();
			foreach (V2 val in array3)
			{
				if (val.secondEncounter)
				{
					Feedbacker(val);
				}
			}
		}

		internal static void SkinPlayer(PlayerAnimations player)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)player) || !Seen.Add(((Object)player).GetInstanceID()))
			{
				return;
			}
			try
			{
				Transform val = (Transform)Patches.Field(typeof(PlayerAnimations), "leftArm").GetValue(player);
				if (!Object.op_Implicit((Object)(object)val))
				{
					Plugin.Warn("V3 visual: referencia leftArm ausente; modelo nao alterado.");
					return;
				}
				armRootName = Key(((Object)val).name);
				SkinnedMeshRenderer[] componentsInChildren = ((Component)player).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer smr in componentsInChildren)
				{
					Mesh original = smr.sharedMesh;
					if (!Object.op_Implicit((Object)(object)original))
					{
						continue;
					}
					Material[] oldMaterials = ((Renderer)smr).sharedMaterials;
					if (!original.isReadable)
					{
						Undo.Add(delegate
						{
							if (Object.op_Implicit((Object)(object)smr))
							{
								((Renderer)smr).sharedMaterials = oldMaterials;
							}
						});
						((Renderer)smr).sharedMaterials = oldMaterials.Select((Material m) => Recolor(m, new Color(1f, 0.65f, 0.08f))).ToArray();
						Plugin.Warn("V3 visual: skin aplicada, mas malha sem leitura CPU: " + ((Object)original).name + ". Extracao do Feedbacker requer os assets desta versao.");
						continue;
					}
					bool[] array = ArmVertices(original, smr.bones, val);
					bool num = array.Any((bool v) => v);
					if (num && Templates.Count == 0)
					{
						Mesh val2 = Filter(original, array, arm: true);
						if (val2.GetIndexCount(0) != 0 || TotalIndices(val2) != 0)
						{
							Templates.Add(new ArmTemplate
							{
								Mesh = val2,
								Materials = (Material[])oldMaterials.Clone(),
								BoneNames = smr.bones.Select((Transform b) => (!Object.op_Implicit((Object)(object)b)) ? "" : Key(((Object)b).name)).ToArray(),
								RootName = (Object.op_Implicit((Object)(object)smr.rootBone) ? Key(((Object)smr.rootBone).name) : "")
							});
						}
					}
					Material[] array2 = oldMaterials.Select((Material m) => Recolor(m, new Color(1f, 0.65f, 0.08f))).ToArray();
					Undo.Add(delegate
					{
						if (Object.op_Implicit((Object)(object)smr))
						{
							smr.sharedMesh = original;
							((Renderer)smr).sharedMaterials = oldMaterials;
						}
					});
					if (!num)
					{
						((Renderer)smr).sharedMaterials = array2;
						continue;
					}
					Mesh val3 = Own<Mesh>(Object.Instantiate<Mesh>(original));
					int subMeshCount = original.subMeshCount;
					val3.subMeshCount = subMeshCount * 2;
					for (int num2 = 0; num2 < subMeshCount; num2++)
					{
						int[] triangles = original.GetTriangles(num2);
						val3.SetTriangles(SelectTriangles(triangles, array, keepArm: false), num2);
						val3.SetTriangles(SelectTriangles(triangles, array, keepArm: true), num2 + subMeshCount);
					}
					smr.sharedMesh = val3;
					((Renderer)smr).sharedMaterials = array2.Concat(oldMaterials.Select((Material m) => Recolor(m, new Color(0.15f, 0.95f, 0.4f)))).ToArray();
				}
				Plugin.Log("V3: visual do jogador processado; modelos nativos, corpo dourado e braco verde.");
			}
			catch (Exception ex)
			{
				Plugin.Warn("V3 visual nao aplicado integralmente: " + ex.Message);
			}
		}

		private static ulong TotalIndices(Mesh m)
		{
			ulong num = 0uL;
			for (int i = 0; i < m.subMeshCount; i++)
			{
				num += m.GetIndexCount(i);
			}
			return num;
		}

		private static bool[] ArmVertices(Mesh mesh, Transform[] bones, Transform root)
		{
			//IL_005a: 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)
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < bones.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)bones[i]) && ((Object)(object)bones[i] == (Object)(object)root || bones[i].IsChildOf(root)))
				{
					hashSet.Add(i);
				}
			}
			BoneWeight[] boneWeights = mesh.boneWeights;
			bool[] array = new bool[mesh.vertexCount];
			for (int j = 0; j < boneWeights.Length; j++)
			{
				BoneWeight val = boneWeights[j];
				float num = (hashSet.Contains(((BoneWeight)(ref val)).boneIndex0) ? ((BoneWeight)(ref val)).weight0 : 0f) + (hashSet.Contains(((BoneWeight)(ref val)).boneIndex1) ? ((BoneWeight)(ref val)).weight1 : 0f) + (hashSet.Contains(((BoneWeight)(ref val)).boneIndex2) ? ((BoneWeight)(ref val)).weight2 : 0f) + (hashSet.Contains(((BoneWeight)(ref val)).boneIndex3) ? ((BoneWeight)(ref val)).weight3 : 0f);
				array[j] = num >= 0.5f;
			}
			return array;
		}

		private static int[] SelectTriangles(int[] triangles, bool[] mask, bool keepArm)
		{
			List<int> list = new List<int>();
			for (int i = 0; i + 2 < triangles.Length; i += 3)
			{
				int num = triangles[i];
				int num2 = triangles[i + 1];
				int num3 = triangles[i + 2];
				if ((mask[num] ? 1 : 0) + (mask[num2] ? 1 : 0) + (mask[num3] ? 1 : 0) >= 2 == keepArm)
				{
					list.Add(num);
					list.Add(num2);
					list.Add(num3);
				}
			}
			return list.ToArray();
		}

		private static Mesh Filter(Mesh original, bool[] mask, bool arm)
		{
			Mesh val = Own<Mesh>(Object.Instantiate<Mesh>(original));
			for (int i = 0; i < original.subMeshCount; i++)
			{
				val.SetTriangles(SelectTriangles(original.GetTriangles(i), mask, arm), i);
			}
			return val;
		}

		private static Mesh Retarget(Mesh source, Transform[] targetBones, Transform targetRenderer)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: 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_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = Own<Mesh>(Object.Instantiate<Mesh>(source));
			Matrix4x4[] bindposes = source.bindposes;
			BoneWeight[] boneWeights = source.boneWeights;
			Vector3[] vertices = source.vertices;
			Vector3[] normals = source.normals;
			Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[bindposes.Length];
			Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[bindposes.Length];
			for (int i = 0; i < bindposes.Length; i++)
			{
				array[i] = targetRenderer.worldToLocalMatrix * targetBones[i].localToWorldMatrix * bindposes[i];
				array2[i] = targetBones[i].worldToLocalMatrix * targetRenderer.localToWorldMatrix;
			}
			for (int j = 0; j < vertices.Length; j++)
			{
				BoneWeight val2 = boneWeights[j];
				Vector3 val3 = vertices[j];
				vertices[j] = ((Matrix4x4)(ref array[((BoneWeight)(ref val2)).boneIndex0])).MultiplyPoint3x4(val3) * ((BoneWeight)(ref val2)).weight0 + ((Matrix4x4)(ref array[((BoneWeight)(ref val2)).boneIndex1])).MultiplyPoint3x4(val3) * ((BoneWeight)(ref val2)).weight1 + ((Matrix4x4)(ref array[((BoneWeight)(ref val2)).boneIndex2])).MultiplyPoint3x4(val3) * ((BoneWeight)(ref val2)).weight2 + ((Matrix4x4)(ref array[((BoneWeight)(ref val2)).boneIndex3])).MultiplyPoint3x4(val3) * ((BoneWeight)(ref val2)).weight3;
				if (normals.Length == vertices.Length)
				{
					Vector3 val4 = normals[j];
					int num = j;
					Vector3 val5 = ((Matrix4x4)(ref array[((BoneWeight)(ref val2)).boneIndex0])).MultiplyVector(val4) * ((BoneWeight)(ref val2)).weight0 + ((Matrix4x4)(ref array[((BoneWeight)(ref val2)).boneIndex1])).MultiplyVector(val4) * ((BoneWeight)(ref val2)).weight1 + ((Matrix4x4)(ref array[((BoneWeight)(ref val2)).boneIndex2])).MultiplyVector(val4) * ((BoneWeight)(ref val2)).weight2 + ((Matrix4x4)(ref array[((BoneWeight)(ref val2)).boneIndex3])).MultiplyVector(val4) * ((BoneWeight)(ref val2)).weight3;
					normals[num] = ((Vector3)(ref val5)).normalized;
				}
			}
			val.vertices = vertices;
			if (normals.Length == vertices.Length)
			{
				val.normals = normals;
			}
			val.bindposes = array2;
			val.RecalculateBounds();
			return val;
		}

		private static Material Recolor(Material original, Color target)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)original))
			{
				return original;
			}
			Material val = Own<Material>(new Material(original));
			Texture mainTexture = original.mainTexture;
			if (!Object.op_Implicit((Object)(object)mainTexture))
			{
				return val;
			}
			RenderTexture active = RenderTexture.active;
			RenderTexture temporary = RenderTexture.GetTemporary(mainTexture.width, mainTexture.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			try
			{
				Graphics.Blit(mainTexture, temporary);
				RenderTexture.active = temporary;
				Texture2D val2 = Own<Texture2D>(new Texture2D(mainTexture.width, mainTexture.height, (TextureFormat)4, false));
				val2.ReadPixels(new Rect(0f, 0f, (float)mainTexture.width, (float)mainTexture.height), 0, 0);
				Color[] pixels = val2.GetPixels();
				for (int i = 0; i < pixels.Length; i++)
				{
					Color val3 = pixels[i];
					if (val3.b > val3.r * 1.25f && val3.b > val3.g * 1.12f && val3.b > 0.14f)
					{
						Color val4 = target * Mathf.Max(val3.b, 0.25f);
						val4.a = val3.a;
						pixels[i] = val4;
					}
				}
				val2.SetPixels(pixels);
				val2.Apply();
				((Texture)val2).filterMode = mainTexture.filterMode;
				((Texture)val2).wrapMode = mainTexture.wrapMode;
				val.mainTexture = (Texture)(object)val2;
				return val;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		internal static void Feedbacker(V2 enemy)
		{
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Expected O, but got Unknown
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)enemy) || !enemy.secondEncounter || Templates.Count == 0 || !Seen.Add(((Object)enemy).GetInstanceID()))
			{
				return;
			}
			SkinnedMeshRenderer originalRenderer = enemy.smr;
			GameObject val = null;
			try
			{
				if (!Object.op_Implicit((Object)(object)originalRenderer) || !Object.op_Implicit((Object)(object)originalRenderer.sharedMesh) || !originalRenderer.sharedMesh.isReadable)
				{
					throw new InvalidOperationException("malha do V2 sem leitura CPU");
				}
				Transform[] bones = originalRenderer.bones;
				Dictionary<string, Transform> dictionary = (from b in bones
					where Object.op_Implicit((Object)(object)b)
					group b by Key(((Object)b).name) into g
					where g.Count() == 1
					select g).ToDictionary((IGrouping<string, Transform> g) => g.Key, (IGrouping<string, Transform> g) => g.First());
				if (armRootName == null || !dictionary.TryGetValue(armRootName, out var value))
				{
					throw new InvalidOperationException("osso esquerdo do jogador nao possui correspondencia unica no V2");
				}
				ArmTemplate armTemplate = Templates[0];
				Transform[] array = (Transform[])(object)new Transform[armTemplate.BoneNames.Length];
				HashSet<int> hashSet = new HashSet<int>();
				BoneWeight[] boneWeights = armTemplate.Mesh.boneWeights;
				for (int num = 0; num < armTemplate.Mesh.subMeshCount; num++)
				{
					int[] triangles = armTemplate.Mesh.GetTriangles(num);
					foreach (int num3 in triangles)
					{
						BoneWeight val2 = boneWeights[num3];
						if (((BoneWeight)(ref val2)).weight0 > 0f)
						{
							hashSet.Add(((BoneWeight)(ref val2)).boneIndex0);
						}
						if (((BoneWeight)(ref val2)).weight1 > 0f)
						{
							hashSet.Add(((BoneWeight)(ref val2)).boneIndex1);
						}
						if (((BoneWeight)(ref val2)).weight2 > 0f)
						{
							hashSet.Add(((BoneWeight)(ref val2)).boneIndex2);
						}
						if (((BoneWeight)(ref val2)).weight3 > 0f)
						{
							hashSet.Add(((BoneWeight)(ref val2)).boneIndex3);
						}
					}
				}
				for (int num4 = 0; num4 < array.Length; num4++)
				{
					if (!dictionary.TryGetValue(armTemplate.BoneNames[num4], out array[num4]))
					{
						if (hashSet.Contains(num4))
						{
							throw new InvalidOperationException("osso sem correspondencia: " + armTemplate.BoneNames[num4]);
						}
						array[num4] = value;
					}
				}
				Mesh originalMesh = originalRenderer.sharedMesh;
				bool[] array2 = ArmVertices(originalMesh, bones, value);
				if (!array2.Any((bool v) => v))
				{
					throw new InvalidOperationException("nenhum vertice do braco esquerdo no V2");
				}
				Mesh sharedMesh = Filter(originalMesh, array2, arm: false);
				GameObject obj = (val = Own<GameObject>(new GameObject("V3_Rebuild_Feedbacker_Visual")));
				obj.SetActive(false);
				obj.layer = ((Component)originalRenderer).gameObject.layer;
				obj.transform.SetParent(((Component)originalRenderer).transform, false);
				SkinnedMeshRenderer obj2 = obj.AddComponent<SkinnedMeshRenderer>();
				obj2.sharedMesh = Retarget(armTemplate.Mesh, array, ((Component)originalRenderer).transform);
				((Renderer)obj2).sharedMaterials = armTemplate.Materials;
				obj2.bones = array;
				obj2.rootBone = (dictionary.TryGetValue(armTemplate.RootName, out var value2) ? value2 : originalRenderer.rootBone);
				((Renderer)obj2).localBounds = ((Renderer)originalRenderer).localBounds;
				obj2.updateWhenOffscreen = true;
				((Renderer)obj2).shadowCastingMode = ((Renderer)originalRenderer).shadowCastingMode;
				Undo.Add(delegate
				{
					if (Object.op_Implicit((Object)(object)originalRenderer))
					{
						originalRenderer.sharedMesh = originalMesh;
					}
				});
				originalRenderer.sharedMesh = sharedMesh;
				obj.SetActive(true);
				Plugin.Log("V2 segunda batalha: malha azul do braco de V1 aplicada; IA, hitboxes e progressao preservadas.");
			}
			catch (Exception ex)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(object)val);
				}
				Plugin.Warn("V2 Feedbacker NAO aplicado: " + ex.Message + ". A batalha original foi preservada. Envie o log e os bundles visuais para ajuste exato.");
			}
		}

		internal static void Restore()
		{
			for (int num = Undo.Count - 1; num >= 0; num--)
			{
				try
				{
					Undo[num]();
				}
				catch (Exception ex)
				{
					Plugin.Warn(ex.Message);
				}
			}
			foreach (KeyValuePair<TMP_Text, string> text in Texts)
			{
				if (Object.op_Implicit((Object)(object)text.Key))
				{
					text.Key.text = text.Value;
				}
			}
			foreach (Object item in Created)
			{
				if (Object.op_Implicit(item))
				{
					Object.Destroy(item);
				}
			}
			Undo.Clear();
			Created.Clear();
			Seen.Clear();
			Resized.Clear();
			Hidden.Clear();
			Texts.Clear();
			Templates.Clear();
			armRootName = null;
		}
	}
	public sealed class ShotBudget
	{
		public const int Capacity = 3;

		public const double Cooldown = 5.0;

		private double readyAt;

		public int Remaining { get; private set; } = 3;

		public void Tick(double now)
		{
			if (Remaining == 0 && now >= readyAt)
			{
				Remaining = 3;
			}
		}

		public double Wait(double now)
		{
			Tick(now);
			if (Remaining != 0)
			{
				return 0.0;
			}
			return Math.Max(0.0, readyAt - now);
		}

		public bool CanShoot(double now)
		{
			Tick(now);
			return Remaining > 0;
		}

		public bool Consume(double now)
		{
			if (!CanShoot(now))
			{
				return false;
			}
			if (--Remaining == 0)
			{
				readyAt = now + 5.0;
			}
			return true;
		}
	}
	public sealed class PullBudget
	{
		private bool paid;

		public void Begin()
		{
			paid = false;
		}

		public bool TryPay(bool enemy, bool alive, bool pulling)
		{
			if (paid || !enemy || !alive || !pulling)
			{
				return false;
			}
			paid = true;
			return true;
		}
	}
	public static class Rules
	{
		public const int MaxHealth = 400;

		public static int Heal(int hp, int amount)
		{
			return Math.Min(400, Math.Max(0, hp) + Math.Max(0, Math.Min(400, amount)));
		}
	}
	internal static class Patches
	{
		internal static readonly FieldInfo CaughtEnemy = Field(typeof(HookArm), "caughtEid");

		internal static readonly FieldInfo SpawnedArms = Field(typeof(FistControl), "spawnedArms");

		internal static readonly FieldInfo CurrentVariant = Field(typeof(FistControl), "currentVarNum");

		internal static readonly FieldInfo TotalSecrets = Field(typeof(GameProgressSaver), "lastTotalSecrets");

		internal static readonly Dictionary<int, PullBudget> Pulls = new Dictionary<int, PullBudget>();

		internal static int ResetDepth;

		internal static FieldInfo Field(Type t, string n)
		{
			return AccessTools.Field(t, n) ?? throw new MissingFieldException(t.FullName, n);
		}

		internal static MethodInfo Method(Type t, string n)
		{
			return AccessTools.Method(t, n, (Type[])null, (Type[])null) ?? throw new MissingMethodException(t.FullName, n);
		}

		internal static void Verify()
		{
			Tuple<Type, string>[] array = new Tuple<Type, string>[10]
			{
				Tuple.Create(typeof(GameProgressSaver), "get_SavePath"),
				Tuple.Create(typeof(GameProgressSaver), "PrepareFs"),
				Tuple.Create(typeof(GameProgressSaver), "CheckGear"),
				Tuple.Create(typeof(HookArm), "FixedUpdate"),
				Tuple.Create(typeof(Revolver), "Shoot"),
				Tuple.Create(typeof(Punch), "PunchStart"),
				Tuple.Create(typeof(Punch), "ActiveFrame"),
				Tuple.Create(typeof(Punch), "BlastCheck"),
				Tuple.Create(typeof(IntroText), "Start"),
				Tuple.Create(typeof(PlayerAnimations), "Start")
			};
			foreach (Tuple<Type, string> tuple in array)
			{
				Method(tuple.Item1, tuple.Item2);
			}
			Field(typeof(PlayerAnimations), "leftArm");
			if (CaughtEnemy.FieldType != typeof(EnemyIdentifier) || SpawnedArms.FieldType != typeof(List<GameObject>))
			{
				throw new NotSupportedException("Tipos de campos divergentes da DLL inspecionada.");
			}
		}

		internal static void ResetSaveCache()
		{
			TotalSecrets.SetValue(null, -1);
			BestiaryData instance = MonoSingleton<BestiaryData>.Instance;
			if (Object.op_Implicit((Object)(object)instance))
			{
				instance.CheckSave();
			}
			UnlockablesData instance2 = MonoSingleton<UnlockablesData>.Instance;
			if (Object.op_Implicit((Object)(object)instance2))
			{
				instance2.CheckSave();
			}
		}

		internal static void RestoreRuntime()
		{
			Pulls.Clear();
			ResetDepth = 0;
		}

		internal static PullBudget Pull(HookArm hook)
		{
			int instanceID = ((Object)hook).GetInstanceID();
			if (!Pulls.TryGetValue(instanceID, out var value))
			{
				value = (Pulls[instanceID] = new PullBudget());
			}
			return value;
		}

		public static void HealPull(HookArm hook)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Invalid comparison between Unknown and I4
			if (!Plugin.Active)
			{
				return;
			}
			EnemyIdentifier val = (EnemyIdentifier)CaughtEnemy.GetValue(hook);
			NewMovement instance = MonoSingleton<NewMovement>.Instance;
			if (Object.op_Implicit((Object)(object)instance) && !instance.dead && Pull(hook).TryPay(Object.op_Implicit((Object)(object)val) && val.hooked, Object.op_Implicit((Object)(object)val) && !val.dead && !val.blessed && !val.hookIgnore, (int)hook.state == 3))
			{
				instance.hp = Rules.Heal(instance.hp, 15);
				if (Object.op_Implicit((Object)(object)instance.hpFlash))
				{
					instance.hpFlash.Flash(1f);
				}
			}
		}

		public static float HealthFloat(float original)
		{
			if (!Plugin.Active)
			{
				return original;
			}
			return (original == 99f) ? 399 : 400;
		}

		public static int HealthInt(int original)
		{
			if (!Plugin.Active)
			{
				return original;
			}
			return 400;
		}
	}
	[HarmonyPatch(typeof(GameProgressSaver), "get_SavePath")]
	internal static class SavePathPatch
	{
		private static bool Prefix(ref string __result)
		{
			if (!Plugin.Active)
			{
				return true;
			}
			__result = Plugin.CampaignPath;
			return false;
		}
	}
	[HarmonyPatch(typeof(SandboxSaver), "get_SavePath")]
	internal static class SandboxPathPatch
	{
		private static bool Prefix(ref string __result)
		{
			if (!Plugin.Active)
			{
				return true;
			}
			__result = Path.Combine(Plugin.CampaignPath, "Sandbox");
			return false;
		}
	}
	[HarmonyPatch(typeof(GameProgressSaver), "PrepareFs")]
	internal static class SaveInitializationPatch
	{
		private static bool Prefix()
		{
			if (!Plugin.Active)
			{
				return true;
			}
			GameProgressSaver.CreateSaveDirs(false);
			return false;
		}
	}
	[HarmonyPatch]
	internal static class SlotProtectionPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return Patches.Method(typeof(GameProgressSaver), "SetSlot");
			yield return Patches.Method(typeof(GameProgressSaver), "WipeSlot");
			yield return Patches.Method(typeof(SaveSlotMenu), "ConfirmWipe");
			yield return Patches.Method(typeof(SaveSlotMenu), "ConfirmReload");
			yield return Patches.Method(typeof(GameProgressSaver), "MergeRootWithSlotOne");
		}

		private static bool Prefix()
		{
			if (!Plugin.Active)
			{
				return true;
			}
			Plugin.Fault = "Saia da campanha V3 pelo painel antes de gerenciar os slots normais.";
			return false;
		}
	}
	[HarmonyPatch(typeof(GameProgressSaver), "CheckGear")]
	internal static class WhiplashUnlockedPatch
	{
		private static bool Prefix(string __0, ref int __result)
		{
			if (!Plugin.Active || __0 != "arm2")
			{
				return true;
			}
			__result = 1;
			return false;
		}
	}
	[HarmonyPatch(typeof(PrefsManager), "GetInt")]
	internal static class ArmPreferencesPatch
	{
		private static bool Prefix(string __0, ref int __result)
		{
			if (!Plugin.Active)
			{
				return true;
			}
			switch (__0)
			{
			case "weapon.arm2":
				__result = 1;
				return false;
			case "weapon.arm0":
				__result = ((Patches.ResetDepth > 0) ? 1 : 0);
				return false;
			case "weapon.arm1":
			case "weapon.arm3":
				__result = 0;
				return false;
			default:
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(PrefsManager), "SetInt")]
	internal static class ProtectArmPreferencesPatch
	{
		private static bool Prefix(string __0)
		{
			if (Plugin.Active)
			{
				if (__0 != "selectedSaveSlot")
				{
					return !__0.StartsWith("weapon.arm", StringComparison.Ordinal);
				}
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(FistControl), "ResetFists")]
	internal static class FistResetPatch
	{
		private static void Prefix(FistControl __instance, out ForcedLoadout __state)
		{
			__state = __instance.forcedLoadout;
			if (Plugin.Active)
			{
				Patches.ResetDepth++;
				__instance.forcedLoadout = null;
				Patches.CurrentVariant.SetValue(__instance, 0);
			}
		}

		private static void Postfix(FistControl __instance)
		{
			if (!Plugin.Active)
			{
				return;
			}
			MonoSingleton<HookArm>.Instance.equipped = true;
			foreach (GameObject item in (List<GameObject>)Patches.SpawnedArms.GetValue(__instance))
			{
				Visuals.HideArm(item);
			}
			GameObject[] fistPanels = __instance.fistPanels;
			foreach (GameObject val in fistPanels)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					val.SetActive(false);
				}
			}
		}

		private static Exception Finalizer(Exception __exception, FistControl __instance, ForcedLoadout __state)
		{
			if (Plugin.Active)
			{
				__instance.forcedLoadout = __state;
				Patches.ResetDepth = Math.Max(0, Patches.ResetDepth - 1);
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(FistControl), "ArmChange")]
	internal static class FistChangePatch
	{
		private static bool Prefix(FistControl __instance, int __0)
		{
			if (!Plugin.Active)
			{
				return true;
			}
			if (Patches.ResetDepth == 0)
			{
				return false;
			}
			List<GameObject> list = (List<GameObject>)Patches.SpawnedArms.GetValue(__instance);
			if (__0 < 0 || __0 >= list.Count)
			{
				return false;
			}
			foreach (GameObject item in list)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					item.SetActive(false);
				}
			}
			list[__0].SetActive(true);
			Patches.Field(typeof(FistControl), "currentOrderNum").SetValue(__instance, __0);
			Patches.CurrentVariant.SetValue(__instance, 0);
			__instance.currentPunch = list[__0].GetComponent<Punch>();
			return false;
		}
	}
	[HarmonyPatch(typeof(FistControl), "ForceArm")]
	internal static class ForceArmPatch
	{
		private static bool Prefix(ref bool __result)
		{
			if (!Plugin.Active || Patches.ResetDepth > 0)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class NoArmSelectionPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return Patches.Method(typeof(FistControl), "Update");
			yield return Patches.Method(typeof(FistControl), "ScrollArm");
			yield return Patches.Method(typeof(FistControl), "TutorialCheckForArmThatCanPunch");
		}

		private static bool Prefix()
		{
			return !Plugin.Active;
		}
	}
	[HarmonyPatch(typeof(Punch), "PunchStart")]
	internal static class NoPunchPatch
	{
		private static bool Prefix(Punch __instance)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Active)
			{
				return true;
			}
			CameraController instance = MonoSingleton<CameraController>.Instance;
			FistControl instance2 = MonoSingleton<FistControl>.Instance;
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance2) || !instance2.activated || GameStateManager.Instance.PlayerInputLocked)
			{
				return false;
			}
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(((Component)instance).transform.position, ((Component)instance).transform.forward, ref val, 4f, 20971776, (QueryTriggerInteraction)2) && ((Component)((RaycastHit)(ref val)).transform).gameObject.layer == 22)
			{
				ItemPlaceZone[] components = ((Component)((RaycastHit)(ref val)).transform).GetComponents<ItemPlaceZone>();
				if (Object.op_Implicit((Object)(object)instance2.heldObject) && components.Length != 0)
				{
					__instance.PlaceHeldObject(components, ((RaycastHit)(ref val)).transform);
					return false;
				}
				ItemIdentifier component = ((Component)((RaycastHit)(ref val)).transform).GetComponent<ItemIdentifier>();
				if (!Object.op_Implicit((Object)(object)instance2.heldObject) && Object.op_Implicit((Object)(object)component))
				{
					__instance.ForceHold(component.infiniteSource ? component.CreateCopy() : component);
					return false;
				}
			}
			if (Object.op_Implicit((Object)(object)instance2.heldObject))
			{
				__instance.ForceThrow();
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class NoCombatFramesPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return Patches.Method(typeof(Punch), "ActiveFrame");
			yield return Patches.Method(typeof(Punch), "BlastCheck");
			yield return Patches.Method(typeof(Punch), "Parry");
		}

		private static bool Prefix()
		{
			return !Plugin.Active;
		}
	}
	[HarmonyPatch(typeof(HookArm), "Update")]
	internal static class HookBeginPatch
	{
		private static void Postfix(HookArm __instance)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			if (Plugin.Active && (int)__instance.state == 1)
			{
				Patches.Pull(__instance).Begin();
			}
		}
	}
	[HarmonyPatch(typeof(HookArm), "FixedUpdate")]
	internal static class HookPullPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Expected O, but got Unknown
			List<CodeInstruction> list = source.ToList();
			int num = 0;
			for (int i = 0; i + 4 < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Ldarg_0 && CodeInstructionExtensions.LoadsField(list[i + 1], Patches.Field(typeof(HookArm), "playerCollider"), false) && list[i + 2].opcode == OpCodes.Ldarg_0 && CodeInstructionExtensions.LoadsField(list[i + 3], Patches.Field(typeof(HookArm), "hookPoint"), false) && CodeInstructionExtensions.Calls(list[i + 4], AccessTools.Method(typeof(Collider), "ClosestPoint", new Type[1] { typeof(Vector3) }, (Type[])null)))
				{
					CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					val.labels.AddRange(list[i].labels);
					list[i].labels.Clear();
					val.blocks.AddRange(list[i].blocks);
					list[i].blocks.Clear();
					list.InsertRange(i, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
					{
						val,
						new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Patches), "HealPull", (Type[])null, (Type[])null))
					});
					i += 2;
					num++;
				}
			}
			if (num != 1)
			{
				throw new InvalidOperationException("Whiplash: esperado 1 ponto de cura validado, encontrados " + num);
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(Revolver), "Shoot")]
	internal static class RevolverPatch
	{
		private static bool Limited(Revolver gun)
		{
			if (Plugin.Active && gun.gunVariation == 0)
			{
				return !gun.altVersion;
			}
			return false;
		}

		private static bool Prefix(Revolver __instance, int __0, out bool __state)
		{
			__state = Limited(__instance) && (__0 == 1 || __0 == 2);
			if (__state)
			{
				return Plugin.Shots.CanShoot(Time.timeAsDouble);
			}
			return true;
		}

		private static void Postfix(bool __state, bool __runOriginal)
		{
			if (__state && __runOriginal)
			{
				Plugin.Shots.Consume(Time.timeAsDouble);
			}
		}
	}
	[HarmonyPatch]
	internal static class InitialHealthPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return Patches.Method(typeof(NewMovement), "Awake");
			yield return Patches.Method(typeof(NewMovement), "Start");
			yield return Patches.Method(typeof(NewMovement), "Respawn");
		}

		private static void Postfix(NewMovement __instance)
		{
			if (Plugin.Active)
			{
				__instance.hp = 400;
			}
		}
	}
	[HarmonyPatch(typeof(NewMovement), "GetHealth")]
	internal static class HealthGainPatch
	{
		private static void Prefix(NewMovement __instance, out int __state)
		{
			__state = __instance.hp;
		}

		private static void Postfix(NewMovement __instance, int __state)
		{
			if (Plugin.Active && !__instance.dead)
			{
				__instance.hp = Math.Min(400, Math.Max(__state, __instance.hp));
			}
		}
	}
	[HarmonyPatch]
	internal static class HealthLimitsPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return Patches.Method(typeof(NewMovement), "GetHealth");
			yield return Patches.Method(typeof(NewMovement), "ForceAntiHP");
			yield return Patches.Method(typeof(NewMovement), "GetHurt");
			yield return Patches.Method(typeof(NewMovement), "SuperCharge");
			yield return Patches.Method(typeof(NewMovement), "FullHeal");
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source, MethodBase __originalMethod)
		{
			foreach (CodeInstruction instruction in source)
			{
				yield return instruction;
				if (instruction.opcode == OpCodes.Ldc_R4 && ((float)instruction.operand == 100f || (float)instruction.operand == 99f || (__originalMethod.Name == "GetHealth" && (float)instruction.operand == 200f)))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Patches), "HealthFloat", (Type[])null, (Type[])null));
				}
				if ((__originalMethod.Name == "ForceAntiHP" && CodeInstructionExtensions.LoadsConstant(instruction, 100L)) || (__originalMethod.Name == "GetHurt" && CodeInstructionExtensions.LoadsConstant(instruction, 100L)) || ((__originalMethod.Name == "FullHeal" || __originalMethod.Name == "SuperCharge") && CodeInstructionExtensions.LoadsConstant(instruction, 200L)))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Patches), "HealthInt", (Type[])null, (Type[])null));
				}
			}
		}
	}
	[HarmonyPatch(typeof(HealthBar), "Update")]
	internal static class HudPatch
	{
		private static void Prefix(HealthBar __instance)
		{
			if (Plugin.Active)
			{
				Visuals.ResizeHealth(__instance);
			}
		}

		private static void Postfix(HealthBar __instance)
		{
			if (Plugin.Active && Object.op_Implicit((Object)(object)__instance.hpText))
			{
				NewMovement instance = MonoSingleton<NewMovement>.Instance;
				if (Object.op_Implicit((Object)(object)instance))
				{
					__instance.hpText.text = (__instance.antiHpText ? "/400" : instance.hp.ToString());
				}
			}
		}
	}
	[HarmonyPatch(typeof(IntroText), "Start")]
	internal static class IntroLabelPatch
	{
		private static void Prefix(IntroText __instance)
		{
			if (Plugin.Active)
			{
				TMP_Text component = ((Component)__instance).GetComponent<TMP_Text>();
				if (Object.op_Implicit((Object)(object)component))
				{
					Visuals.Rename(component);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAnimations), "Start")]
	internal static class PlayerSkinPatch
	{
		private static void Postfix(PlayerAnimations __instance)
		{
			if (Plugin.Active)
			{
				Visuals.SkinPlayer(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(V2), "Start")]
	internal static class V2ArmPatch
	{
		private static void Postfix(V2 __instance)
		{
			if (Plugin.Active && __instance.secondEncounter)
			{
				Visuals.Feedbacker(__instance);
			}
		}
	}
	[BepInPlugin("local.v3.playable.rebuild", "player_is_v3", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "local.v3.playable.rebuild";

		public const string Version = "1.0.0";

		internal static Plugin Instance;

		internal static bool Active;

		internal static ShotBudget Shots = new ShotBudget();

		internal static string CampaignPath;

		internal static string Fault;

		internal static bool Switching;

		internal static Harmony Harmony;

		private bool ready;

		private bool quitting;

		private bool lifecycleStarted;

		private bool menuOpen = true;

		private float nextVisual;

		private int oldSlot;

		private bool oldIntroCheck;

		internal static bool Menu => SceneHelper.CurrentScene == "Main Menu";

		private void Awake()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			Instance = this;
			CampaignPath = Path.Combine(Paths.BepInExRootPath, "V3PlayableRebuild", "the new machine");
			try
			{
				if (typeof(NewMovement).Module.ModuleVersionId != new Guid("e51acc22-4003-413a-b084-26f735246699"))
				{
					throw new NotSupportedException("Assembly-CSharp.dll diferente da versao verificada. Envie a nova DLL antes de usar este build.");
				}
				Patches.Verify();
				Harmony = new Harmony("local.v3.playable.rebuild");
				Harmony.PatchAll(typeof(Plugin).Assembly);
				ready = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("APIs verificadas; campanha inativa. Abra V3 no menu principal. Pasta: " + CampaignPath));
			}
			catch (Exception ex)
			{
				Harmony harmony = Harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
				Fault = ex.Message;
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
			SceneManager.sceneUnloaded += SceneUnloaded;
			lifecycleStarted = true;
		}

		private void OnEnable()
		{
			if (lifecycleStarted && ready && !Switching)
			{
				Harmony.PatchAll(typeof(Plugin).Assembly);
			}
		}

		internal static void Log(string text)
		{
			if (Object.op_Implicit((Object)(object)Instance))
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)text);
			}
		}

		internal static void Warn(string text)
		{
			if (Object.op_Implicit((Object)(object)Instance))
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)text);
			}
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)289))
			{
				menuOpen = !menuOpen;
			}
			if (Active && !Switching)
			{
				Shots.Tick(Time.timeAsDouble);
				FistControl instance = MonoSingleton<FistControl>.Instance;
				if (Object.op_Implicit((Object)(object)instance))
				{
					instance.fistCooldown = Mathf.MoveTowards(instance.fistCooldown, 0f, Time.deltaTime * 2f);
				}
				if (Time.unscaledTime >= nextVisual)
				{
					nextVisual = Time.unscaledTime + 1f;
					Visuals.Refresh();
				}
			}
		}

		internal void EnterCampaign()
		{
			if (!ready || Active || Switching || !Menu || SceneHelper.PendingScene != null)
			{
				return;
			}
			foreach (PluginInfo value in Chainloader.PluginInfos.Values)
			{
				if (value.Metadata.GUID != "local.v3.playable.rebuild" && value.Metadata.Name.StartsWith("V3 Playable", StringComparison.OrdinalIgnoreCase))
				{
					Fault = "Desative o mod antigo " + value.Metadata.Name + " no r2modman e reinicie o jogo.";
					return;
				}
			}
			bool flag = false;
			try
			{
				bool flag2 = Directory.Exists(CampaignPath);
				if (!flag2)
				{
					Directory.CreateDirectory(CampaignPath);
					using FileStream stream = new FileStream(Path.Combine(CampaignPath, "campaign.txt"), FileMode.CreateNew, FileAccess.Write);
					using StreamWriter streamWriter = new StreamWriter(stream);
					streamWriter.Write("the new machine\nplayer_is_v3\n");
				}
				oldSlot = GameProgressSaver.currentSlot;
				oldIntroCheck = GameStateManager.Instance.introCheckComplete;
				flag = true;
				Active = true;
				Shots = new ShotBudget();
				Patches.ResetSaveCache();
				bool flag3 = !GameProgressSaver.GetIntro();
				if (flag3)
				{
					GameStateManager.Instance.introCheckComplete = false;
				}
				string obj = ((!GameProgressSaver.GetTutorial() || flag3) ? "Tutorial" : "Main Menu");
				Fault = null;
				Log((flag2 ? "Continuando" : "Criando") + " campanha separada: the new machine");
				SceneHelper.LoadScene(obj, false);
			}
			catch (Exception ex)
			{
				Active = false;
				if (flag)
				{
					GameProgressSaver.currentSlot = oldSlot;
					GameStateManager.Instance.introCheckComplete = oldIntroCheck;
					try
					{
						Patches.ResetSaveCache();
					}
					catch (Exception ex2)
					{
						((BaseUnityPlugin)this).Logger.LogError((object)ex2);
					}
				}
				Fault = "Nao foi possivel abrir a campanha: " + ex.Message;
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		internal void LeaveCampaign(bool removeHooks)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (!Switching)
			{
				Switching = true;
				GameObject val = new GameObject("V3 cleanup");
				Object.DontDestroyOnLoad((Object)val);
				val.AddComponent<CleanupRunner>().Run(this, removeHooks);
			}
		}

		internal IEnumerator Cleanup(bool removeHooks)
		{
			while (SceneHelper.PendingScene != null)
			{
				yield return null;
			}
			if (Active)
			{
				yield return SceneHelper.LoadSceneAsync("Main Menu", false);
				Visuals.Restore();
				Active = false;
				GameProgressSaver.currentSlot = oldSlot;
				GameStateManager.Instance.introCheckComplete = oldIntroCheck;
				Patches.ResetSaveCache();
				Patches.RestoreRuntime();
				if (removeHooks)
				{
					Harmony.UnpatchSelf();
				}
				yield return SceneHelper.LoadSceneAsync("Main Menu", false);
			}
			else
			{
				Visuals.Restore();
				Patches.RestoreRuntime();
				if (removeHooks)
				{
					Harmony harmony = Harmony;
					if (harmony != null)
					{
						harmony.UnpatchSelf();
					}
				}
			}
			Switching = false;
			if (removeHooks && Object.op_Implicit((Object)(object)this) && ((Behaviour)this).enabled && ready)
			{
				Harmony.PatchAll(typeof(Plugin).Assembly);
			}
		}

		private void SceneUnloaded(Scene scene)
		{
			Visuals.Restore();
			Patches.Pulls.Clear();
		}

		private void OnDestroy()
		{
			SceneManager.sceneUnloaded -= SceneUnloaded;
		}

		private void OnApplicationQuit()
		{
			quitting = true;
		}

		private void OnDisable()
		{
			if (!lifecycleStarted || quitting)
			{
				return;
			}
			if (Active)
			{
				LeaveCampaign(removeHooks: true);
				return;
			}
			Visuals.Restore();
			Patches.RestoreRuntime();
			Harmony harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void OnGUI()
		{
			//IL_002f: 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_017e: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			if (Active && !Menu)
			{
				GUI.Box(new Rect((float)(Screen.width - 300), 12f, 288f, 78f), "V3 — the new machine");
				NewMovement instance = MonoSingleton<NewMovement>.Instance;
				GUI.Label(new Rect((float)(Screen.width - 286), 36f, 270f, 22f), "VIDA " + (Object.op_Implicit((Object)(object)instance) ? instance.hp : 400) + " / 400");
				double num = Shots.Wait(Time.timeAsDouble);
				GUI.Label(new Rect((float)(Screen.width - 286), 60f, 270f, 24f), (num > 0.0) ? ("REVOLVER: recarga " + num.ToString("0.0") + " s") : ("REVOLVER: " + Shots.Remaining + " / 3 tiros"));
			}
			if (!Menu)
			{
				return;
			}
			if (!menuOpen)
			{
				if (GUI.Button(new Rect(16f, (float)(Screen.height - 48), 210f, 32f), "player_is_v3 [F8]"))
				{
					menuOpen = true;
				}
				return;
			}
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(16f, (float)Mathf.Max(16, Screen.height - 238), 368f, 220f);
			GUI.Box(val, "player_is_v3");
			GUILayout.BeginArea(new Rect(((Rect)(ref val)).x + 12f, ((Rect)(ref val)).y + 28f, ((Rect)(ref val)).width - 24f, ((Rect)(ref val)).height - 36f));
			GUILayout.Label("the new machine", Array.Empty<GUILayoutOption>());
			if (!string.IsNullOrEmpty(Fault))
			{
				GUILayout.Label(Fault, Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Label(Active ? "Campanha V3 ativa. Use o menu do jogo para continuar ou selecionar fases." : "Campanha independente dos cinco slots normais.", Array.Empty<GUILayoutOption>());
			}
			GUI.enabled = ready && !Switching && SceneHelper.PendingScene == null;
			if (!Active)
			{
				if (GUILayout.Button(Directory.Exists(CampaignPath) ? "Continuar the new machine" : "Criar the new machine", Array.Empty<GUILayoutOption>()))
				{
					EnterCampaign();
				}
			}
			else if (GUILayout.Button("Voltar aos saves normais", Array.Empty<GUILayoutOption>()))
			{
				LeaveCampaign(removeHooks: false);
			}
			GUI.enabled = true;
			if (GUILayout.Button("Recolher painel [F8]", Array.Empty<GUILayoutOption>()))
			{
				menuOpen = false;
			}
			GUILayout.EndArea();
		}
	}
	public sealed class CleanupRunner : MonoBehaviour
	{
		internal void Run(Plugin owner, bool hooks)
		{
			((MonoBehaviour)this).StartCoroutine(Finish(owner, hooks));
		}

		private IEnumerator Finish(Plugin owner, bool hooks)
		{
			yield return owner.Cleanup(hooks);
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
}