Decompiled source of WallPlant v2.5.7

WallPlant.dll

Decompiled a year ago
using System;
using System.Collections;
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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrewBoom;
using CrewBoomAPI;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Reptile;
using SlopCrew.API;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: IgnoresAccessChecksTo("CrewBoom")]
[assembly: IgnoresAccessChecksTo("CrewBoomMono")]
[assembly: AssemblyCompany("WallPlant")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("My first plugin")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("WallPlant")]
[assembly: AssemblyTitle("WallPlant")]
[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 WallPlant
{
	public class Decal : MonoBehaviour
	{
		public Action OnDestroyCallback;

		private static int ProgressProperty = Shader.PropertyToID("_Progress");

		private float _progress;

		private bool _animating;

		private Material _material;

		private List<GameObject> _decals = new List<GameObject>();

		private void Awake()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			Core.OnUpdate += new OnUpdateHandler(OnUpdate);
		}

		private void OnUpdate()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_material == (Object)null)
			{
				return;
			}
			float num = ((Component)this).transform.lossyScale.x * 0.5f;
			float num2 = ((Component)this).transform.lossyScale.y * 0.5f;
			float num3 = ((Component)this).transform.lossyScale.z * 0.5f;
			Vector3 val = ((Component)this).transform.forward * num3 + ((Component)this).transform.right * num + ((Component)this).transform.up * num2;
			Matrix4x4 val2 = ((Component)this).transform.worldToLocalMatrix * Matrix4x4.Translate(val);
			_material.SetMatrix("_Projection", val2);
			_material.SetVector("_Origin", Vector4.op_Implicit(((Component)this).transform.position));
			_material.SetVector("_Bounds", Vector4.op_Implicit(((Component)this).transform.lossyScale * 2f));
			_material.SetVector("_Normal", Vector4.op_Implicit(((Component)this).transform.forward));
			if (_animating)
			{
				_progress += WallPlantSettings.GraffitiPaintSpeed * Core.dt;
				if (_progress >= 1f)
				{
					_progress = 1f;
					_animating = false;
				}
				_material.SetFloat(ProgressProperty, _progress);
			}
		}

		public static Decal Create(Vector3 point, Vector3 normal, float size, LayerMask affectedLayers)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Decal");
			val.transform.position = point;
			val.transform.rotation = Quaternion.LookRotation(normal);
			val.transform.localScale = new Vector3(size, size, size);
			Decal decal = val.AddComponent<Decal>();
			decal.Build(affectedLayers);
			DecalManager.Instance.PushDecal(decal);
			return decal;
		}

		public void SetSize(float size)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.localScale = new Vector3(size, size, size);
		}

		public void SetTexture(Texture texture)
		{
			_material.mainTexture = texture;
		}

		private void MakeDecalMesh(Transform originalTransform, Mesh mesh)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Decal Mesh");
			_decals.Add(val);
			val.transform.SetParent(originalTransform);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one;
			MeshFilter val2 = val.AddComponent<MeshFilter>();
			MeshRenderer obj = val.AddComponent<MeshRenderer>();
			((Renderer)obj).sortingOrder = 1;
			val2.sharedMesh = mesh;
			((Renderer)obj).sharedMaterial = _material;
		}

		public void Build(LayerMask affectedLayers)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Plugin.GraffitiMaterial == (Object)null || (Object)(object)DecalManager.Instance == (Object)null)
			{
				return;
			}
			_material = new Material(Plugin.GraffitiMaterial);
			Bounds bounds = default(Bounds);
			((Bounds)(ref bounds))..ctor(((Component)this).transform.position, ((Component)this).transform.localScale);
			foreach (LevelMesh levelMeshesIntersectingBound in DecalManager.Instance.GetLevelMeshesIntersectingBounds(bounds, affectedLayers))
			{
				MakeDecalMesh(((Component)levelMeshesIntersectingBound.Renderer).transform, levelMeshesIntersectingBound.Mesh);
			}
		}

		public void AnimateSpray()
		{
			_material.SetFloat(ProgressProperty, 0f);
			_progress = 0f;
			_animating = true;
		}

		public void SetCompleted()
		{
			_material.SetFloat(ProgressProperty, 1f);
			_progress = 1f;
			_animating = false;
		}

		private void OnDestroy()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			OnDestroyCallback?.Invoke();
			Core.OnUpdate -= new OnUpdateHandler(OnUpdate);
			foreach (GameObject decal in _decals)
			{
				if (!((Object)(object)decal == (Object)null))
				{
					Object.Destroy((Object)(object)decal);
				}
			}
			Object.Destroy((Object)(object)_material);
		}
	}
	public class DecalManager : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static OnStageInitializedDelegate <0>__StageManager_OnStagePostInitialization;
		}

		private List<LevelMesh> _levelMeshes = new List<LevelMesh>();

		private Queue<Decal> _decals = new Queue<Decal>();

		public static DecalManager Instance;

		private void Awake()
		{
			Instance = this;
			CacheLevelMeshes();
		}

		public List<LevelMesh> GetLevelMeshesIntersectingBounds(Bounds bounds, LayerMask layermask)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			List<LevelMesh> list = new List<LevelMesh>();
			foreach (LevelMesh levelMesh in _levelMeshes)
			{
				if (!((Object)(object)levelMesh.Renderer == (Object)null) && !((Object)(object)levelMesh.Mesh == (Object)null) && ((1 << ((Component)levelMesh.Renderer).gameObject.layer) & LayerMask.op_Implicit(layermask)) != 0 && ((Bounds)(ref bounds)).Intersects(((Renderer)levelMesh.Renderer).bounds))
				{
					list.Add(levelMesh);
				}
			}
			return list;
		}

		private void CacheLevelMeshes()
		{
			_levelMeshes.Clear();
			MeshRenderer[] array = Object.FindObjectsOfType<MeshRenderer>(true);
			foreach (MeshRenderer val in array)
			{
				MeshRenderer renderer = val;
				MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null) && !Object.op_Implicit((Object)(object)((Component)val).GetComponent<Rigidbody>()))
				{
					LevelMesh levelMesh = default(LevelMesh);
					levelMesh.Mesh = component.sharedMesh;
					levelMesh.Renderer = renderer;
					LevelMesh item = levelMesh;
					_levelMeshes.Add(item);
				}
			}
		}

		private void OnDestroy()
		{
			Instance = null;
		}

		internal static void Initialize()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__StageManager_OnStagePostInitialization;
			if (obj == null)
			{
				OnStageInitializedDelegate val = StageManager_OnStagePostInitialization;
				<>O.<0>__StageManager_OnStagePostInitialization = val;
				obj = (object)val;
			}
			StageManager.OnStagePostInitialization += (OnStageInitializedDelegate)obj;
		}

		private static void StageManager_OnStagePostInitialization()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new GameObject("Decal Manager").AddComponent<DecalManager>();
		}

		public void PushDecal(Decal decal)
		{
			if (_decals.Count > 0)
			{
				while (_decals.Count >= WallPlantSettings.MaxGraffiti)
				{
					Decal decal2 = _decals.Dequeue();
					if ((Object)(object)decal2 != (Object)null)
					{
						Object.Destroy((Object)(object)decal2);
					}
				}
			}
			_decals.Enqueue(decal);
		}
	}
	internal static class GraffitiDatabase
	{
		private static Dictionary<string, List<Texture2D>> CustomGraffiti = new Dictionary<string, List<Texture2D>>();

		public static void Initialize()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			string text = Path.Combine(Paths.ConfigPath, "Wall Plant", "Graffiti");
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
				Directory.CreateDirectory(Path.Combine(text, "Global"));
				WriteReadme(Path.Combine(text, "Readme.txt"));
			}
			string[] directories = Directory.GetDirectories(text);
			foreach (string path in directories)
			{
				string text2 = Path.GetFileName(path).ToLowerInvariant();
				string[] files = Directory.GetFiles(path, "*.png");
				foreach (string path2 in files)
				{
					try
					{
						byte[] array = File.ReadAllBytes(path2);
						Texture2D val = new Texture2D(2, 2);
						ImageConversion.LoadImage(val, array);
						((Texture)val).wrapMode = (TextureWrapMode)1;
						if (!CustomGraffiti.TryGetValue(text2, out var value))
						{
							value = new List<Texture2D>();
						}
						value.Add(val);
						CustomGraffiti[text2] = value;
						Plugin.Instance.GetLogger().LogInfo((object)("Loaded custom graffiti " + Path.GetFileName(path2) + " for character " + text2));
					}
					catch (Exception arg)
					{
						Plugin.Instance.GetLogger().LogError((object)$"Problem loading graffiti {Path.GetFileName(path2)}: {arg}");
					}
				}
			}
		}

		private static void WriteReadme(string filename)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Invalid comparison between Unknown and I4
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Invalid comparison between Unknown and I4
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Create subfolders here and put PNG images inside them to replace the Graffiti Plant graffiti for each character, using their internal names. For CrewBoom characters, create a folder with their filename as the name (minus the .cbb extension).");
			stringBuilder.AppendLine($"For instance, if you create a folder named \"{(object)(Characters)1}\" and add 2 PNG images with any filename inside, when you Graffiti plant as {(object)(Characters)1} a random image will be picked from that folder to place.");
			stringBuilder.AppendLine("A \"Global\" folder was automatically created for you. PNG images placed in this folder will override the graffiti for every character, unless they have their own subfolder here.");
			stringBuilder.AppendLine("Possible character internal names are as follows:");
			foreach (Characters value in Enum.GetValues(typeof(Characters)))
			{
				Characters val = value;
				if ((int)val != 26 && (int)val != -1)
				{
					stringBuilder.AppendLine(((object)(Characters)(ref val)).ToString());
				}
			}
			File.WriteAllText(filename, stringBuilder.ToString());
		}

		private static void GetinternalNameAndCharacterForCrewBoomCharacter(ref Characters character, ref string text)
		{
			Guid key = default(Guid);
			if (CrewBoomAPIDatabase.IsInitialized && CrewBoomAPIDatabase.GetUserGuidForCharacter((int)character, ref key))
			{
				string path = CharacterDatabase._characterBundlePaths[key];
				text = Path.GetFileNameWithoutExtension(path).ToLowerInvariant();
			}
			else
			{
				character = (Characters)3;
				text = "metalhead";
			}
		}

		public static Texture GetGraffitiTexture(Characters character)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			string text = ((object)(Characters)(ref character)).ToString().ToLowerInvariant();
			if (Plugin.CrewBoomInstalled && (int)character >= 26)
			{
				GetinternalNameAndCharacterForCrewBoomCharacter(ref character, ref text);
			}
			if (!CustomGraffiti.TryGetValue(text, out var value) && !CustomGraffiti.TryGetValue("global", out value))
			{
				value = null;
			}
			if (value == null)
			{
				return Plugin.GetGraffitiArtInfo().FindByCharacter(character).graffitiMaterial.mainTexture;
			}
			return (Texture)(object)value[Random.Range(0, value.Count)];
		}

		public static Texture GetGraffitiTexture(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return GetGraffitiTexture(player.character);
		}
	}
	public struct LevelMesh
	{
		public MeshRenderer Renderer;

		public Mesh Mesh;
	}
	internal class NetDecalList
	{
		public int DecalLimit;

		public List<NetDecal> Decals = new List<NetDecal>();

		public static NetDecalList MakeFromCurrentDecals()
		{
			return new NetDecalList
			{
				Decals = new List<NetDecal>(Net.CurrentDecals),
				DecalLimit = WallPlantSettings.MaxGraffiti
			};
		}

		public static NetDecalList Read(BinaryReader reader)
		{
			NetDecalList netDecalList = new NetDecalList();
			if (netDecalList.Deserialize(reader))
			{
				return netDecalList;
			}
			return null;
		}

		public void Serialize(BinaryWriter writer)
		{
			writer.Write((byte)0);
			writer.Write(DecalLimit);
			writer.Write(Decals.Count);
			foreach (NetDecal decal in Decals)
			{
				decal.Serialize(writer);
			}
		}

		public bool Deserialize(BinaryReader reader)
		{
			if (reader.ReadByte() > 0)
			{
				Debug.Log((object)"Got Decal list from the future, ignoring.");
				return false;
			}
			DecalLimit = reader.ReadInt32();
			int num = Mathf.Clamp(reader.ReadInt32(), 0, WallPlantSettings.MaxGraffiti);
			for (int i = 0; i < num; i++)
			{
				NetDecal netDecal = NetDecal.Read(reader);
				if (netDecal != null)
				{
					Decals.Add(netDecal);
					continue;
				}
				return false;
			}
			return true;
		}

		public void ApplyToWorld()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			for (int num = Decals.Count - 1; num >= 0; num--)
			{
				NetDecal netDecal = Decals[num];
				Decal decal = Decal.Create(netDecal.Point, netDecal.Normal, netDecal.Size, WallPlantAbility.WallPlantLayerMask);
				Net.BindNetDecal(netDecal, decal);
				decal.SetTexture(GraffitiDatabase.GetGraffitiTexture(netDecal.Character));
				decal.SetCompleted();
			}
		}
	}
	internal class NetDecal
	{
		public bool UsingCustomCharacter;

		public Characters VanillaCharacter = (Characters)3;

		public Guid CrewBoomGUID;

		public Vector3 Point;

		public Vector3 Normal;

		public float Size = 1.5f;

		public Characters Character
		{
			get
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				if (!UsingCustomCharacter)
				{
					return VanillaCharacter;
				}
				if (!Plugin.CrewBoomInstalled)
				{
					return (Characters)3;
				}
				return ReturnCrewBoomCharacter();
				Characters ReturnCrewBoomCharacter()
				{
					//IL_001a: Unknown result type (might be due to invalid IL or missing references)
					if (!CrewBoomAPIDatabase.IsInitialized)
					{
						return (Characters)3;
					}
					Characters result = default(Characters);
					if (!CharacterDatabase.GetCharacterValueFromGuid(CrewBoomGUID, ref result))
					{
						return (Characters)3;
					}
					return result;
				}
			}
		}

		public NetDecal(Characters character, Vector3 point, Vector3 normal, float size)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			//IL_005c: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Characters character2 = character;
			base..ctor();
			NetDecal netDecal = this;
			UsingCustomCharacter = false;
			VanillaCharacter = character2;
			if ((int)character2 > 26)
			{
				VanillaCharacter = (Characters)3;
				if (Plugin.CrewBoomInstalled)
				{
					CrewBoomStuff();
				}
			}
			Point = point;
			Normal = normal;
			Size = Mathf.Clamp(size, 0.1f, 15f);
			void CrewBoomStuff()
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Expected I4, but got Unknown
				Guid crewBoomGUID = default(Guid);
				if (CrewBoomAPIDatabase.IsInitialized && CrewBoomAPIDatabase.GetUserGuidForCharacter((int)character2, ref crewBoomGUID))
				{
					UsingCustomCharacter = true;
					CrewBoomGUID = crewBoomGUID;
				}
			}
		}

		private NetDecal()
		{
		}//IL_0002: Unknown result type (might be due to invalid IL or missing references)


		public static NetDecal Read(BinaryReader reader)
		{
			NetDecal netDecal = new NetDecal();
			if (netDecal.Deserialize(reader))
			{
				return netDecal;
			}
			return null;
		}

		public bool Deserialize(BinaryReader reader)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (reader.ReadByte() > 0)
			{
				Debug.LogError((object)"Got a wallplant decal from a future version, ignoring.");
				return false;
			}
			UsingCustomCharacter = !reader.ReadBoolean();
			if (!UsingCustomCharacter)
			{
				VanillaCharacter = (Characters)reader.ReadInt32();
			}
			else
			{
				CrewBoomGUID = Guid.Parse(reader.ReadString());
			}
			LayerMask.op_Implicit(reader.ReadInt32());
			Size = Mathf.Clamp(reader.ReadSingle(), 0.1f, 15f);
			Point = ReadVector3(reader);
			Normal = Vector3.Normalize(ReadVector3(reader));
			return true;
		}

		private static Vector3 ReadVector3(BinaryReader reader)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			float num = reader.ReadSingle();
			float num2 = reader.ReadSingle();
			float num3 = reader.ReadSingle();
			return new Vector3(num, num2, num3);
		}

		public void Serialize(BinaryWriter writer)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected I4, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			writer.Write((byte)0);
			writer.Write(!UsingCustomCharacter);
			if (!UsingCustomCharacter)
			{
				writer.Write((int)VanillaCharacter);
			}
			else
			{
				writer.Write(CrewBoomGUID.ToString());
			}
			writer.Write(LayerMask.op_Implicit(WallPlantAbility.WallPlantLayerMask));
			writer.Write(Size);
			WriteVector3(writer, Point);
			WriteVector3(writer, Normal);
		}

		private static void WriteVector3(BinaryWriter writer, Vector3 vector)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			writer.Write(vector.x);
			writer.Write(vector.y);
			writer.Write(vector.z);
		}
	}
	internal static class Net
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action<uint, string, byte[]> <0>__OnDecalReceived;

			public static Action<uint, string, byte[]> <1>__OnDecalListReceived;

			public static Action<uint, string, byte[]> <2>__OnDecalListRequestReceived;

			public static OnStageInitializedDelegate <3>__OnStagePostInitialization;
		}

		public static List<NetDecal> CurrentDecals = new List<NetDecal>();

		public static List<NetDecalList> ReceivedDecalLists = new List<NetDecalList>();

		public static bool ReceivedDecalList = true;

		public static bool DecalRequestSent = false;

		public static float CurrentDecalListWaitTime = 0f;

		public static int DecalRequestCurrentAttempt = 1;

		public const int DecalRequestAttempts = 3;

		public const float DecalListWaitTime = 1f;

		public const float DecalListWaitTimeReceivedPackets = 1f;

		public static void Initialize()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			if (Plugin.SlopCrewInstalled)
			{
				APIManager.API.OnCustomPacketReceived += OnDecalReceived;
				APIManager.API.OnCustomPacketReceived += OnDecalListReceived;
				APIManager.API.OnCustomPacketReceived += OnDecalListRequestReceived;
				object obj = <>O.<3>__OnStagePostInitialization;
				if (obj == null)
				{
					OnStageInitializedDelegate val = OnStagePostInitialization;
					<>O.<3>__OnStagePostInitialization = val;
					obj = (object)val;
				}
				StageManager.OnStagePostInitialization += (OnStageInitializedDelegate)obj;
			}
		}

		private static void OnStagePostInitialization()
		{
			CurrentDecals.Clear();
			ReceivedDecalLists.Clear();
			ReceivedDecalList = false;
			CurrentDecalListWaitTime = 0f;
			DecalRequestSent = false;
			DecalRequestCurrentAttempt = 1;
			((MonoBehaviour)Plugin.Instance).StopAllCoroutines();
			((MonoBehaviour)Plugin.Instance).StartCoroutine(OnJoinNewStage());
		}

		private static IEnumerator OnJoinNewStage()
		{
			yield return (object)new WaitForSecondsRealtime(0.5f);
			if (!APIManager.API.Connected)
			{
				yield return null;
			}
			if (APIManager.API.PlayerCount <= 1)
			{
				Log("We're alone in this stage, not requesting decals.");
				ReceivedDecalList = true;
			}
			else
			{
				Log($"Requesting decals for this stage. There are {APIManager.API.PlayerCount} players including ourselves.");
				RequestDecalList();
				DecalRequestSent = true;
			}
		}

		private static void Log(string message)
		{
			if (WallPlantSettings.DebugNetworking)
			{
				Debug.Log((object)("[WALLPLANT NETWORKING] " + message));
			}
		}

		public static void Update()
		{
			if (ReceivedDecalList || !DecalRequestSent)
			{
				return;
			}
			CurrentDecalListWaitTime += Core.dt;
			float num = 1f;
			if (ReceivedDecalLists.Count > 0)
			{
				num = 1f;
			}
			if (!(CurrentDecalListWaitTime >= num))
			{
				return;
			}
			if (DecalRequestCurrentAttempt < 3 && APIManager.API.Connected)
			{
				Log("Wait for decal list expired. Trying again.");
				CurrentDecalListWaitTime = 0f;
				DecalRequestCurrentAttempt++;
				RequestDecalList();
				return;
			}
			Log($"Wait for decal list expired after {DecalRequestCurrentAttempt} attempts");
			ReceivedDecalList = true;
			NetDecalList netDecalList = null;
			int num2 = 0;
			foreach (NetDecalList receivedDecalList in ReceivedDecalLists)
			{
				if (netDecalList == null)
				{
					netDecalList = receivedDecalList;
					num2 = receivedDecalList.Decals.Count;
				}
				else if (receivedDecalList.Decals.Count > num2)
				{
					netDecalList = receivedDecalList;
					num2 = receivedDecalList.Decals.Count;
				}
			}
			if (netDecalList != null)
			{
				Log($"Applying a decal list! Contains {num2} decals.");
				netDecalList.ApplyToWorld();
			}
			Log("Didn't receive any decal list.");
			ReceivedDecalLists.Clear();
		}

		public static void RequestDecalList()
		{
			if (Plugin.SlopCrewInstalled)
			{
				Log("Sending request decal list packet.");
				MemoryStream memoryStream = new MemoryStream();
				BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
				binaryWriter.Write(WallPlantSettings.MaxGraffiti);
				binaryWriter.Flush();
				byte[] array = memoryStream.ToArray();
				APIManager.API.SendCustomPacket("WallPlant-DecalRequest", array);
				binaryWriter.Close();
			}
		}

		public static void SendDecalList(NetDecalList decalList)
		{
			if (Plugin.SlopCrewInstalled)
			{
				Log("Sending a decal list packet");
				MemoryStream memoryStream = new MemoryStream();
				BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
				decalList.Serialize(binaryWriter);
				binaryWriter.Flush();
				byte[] array = memoryStream.ToArray();
				APIManager.API.SendCustomPacket("WallPlant-DecalList", array);
				binaryWriter.Close();
			}
		}

		public static NetDecal SendDecal(Characters character, Vector3 point, Vector3 normal, float size, LayerMask affectedLayers)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.SlopCrewInstalled)
			{
				return null;
			}
			Log($"Sending a decal. Currently have {CurrentDecals.Count} decals.");
			MemoryStream memoryStream = new MemoryStream();
			BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			NetDecal netDecal = new NetDecal(character, point, normal, size);
			netDecal.Serialize(binaryWriter);
			binaryWriter.Flush();
			byte[] array = memoryStream.ToArray();
			APIManager.API.SendCustomPacket("WallPlant-Decal", array);
			binaryWriter.Close();
			return netDecal;
		}

		public static void OnDecalListReceived(uint player, string packetId, byte[] data)
		{
			if ((Object)(object)DecalManager.Instance == (Object)null || ReceivedDecalList || packetId != "WallPlant-DecalList")
			{
				return;
			}
			Log("Received a decal list packet.");
			BinaryReader binaryReader = new BinaryReader(new MemoryStream(data));
			NetDecalList netDecalList = NetDecalList.Read(binaryReader);
			if (netDecalList == null)
			{
				binaryReader.Close();
				return;
			}
			Log($"Decal list contains {netDecalList.Decals.Count} decals.");
			if (netDecalList.DecalLimit >= WallPlantSettings.MaxGraffiti || netDecalList.Decals.Count < netDecalList.DecalLimit)
			{
				Log($"Applying the decal list we just received! Contains {netDecalList.Decals.Count} decals.");
				ReceivedDecalList = true;
				netDecalList.ApplyToWorld();
				binaryReader.Close();
				ReceivedDecalLists.Clear();
			}
			else
			{
				Log("Adding the decal list we just received to our candidates.");
				ReceivedDecalLists.Add(netDecalList);
				binaryReader.Close();
			}
		}

		public static void OnDecalListRequestReceived(uint player, string packetId, byte[] data)
		{
			if (!((Object)(object)DecalManager.Instance == (Object)null) && ReceivedDecalList && !(packetId != "WallPlant-DecalRequest"))
			{
				Log($"Player {player} is requesting a decal list. Sending.");
				SendDecalList(NetDecalList.MakeFromCurrentDecals());
			}
		}

		public static void OnDecalReceived(uint player, string packetId, byte[] data)
		{
			//IL_0061: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (WallPlantSettings.MaxGraffiti > 0 && !((Object)(object)DecalManager.Instance == (Object)null) && !(packetId != "WallPlant-Decal"))
			{
				Log($"Got a decal. Currently at {CurrentDecals.Count} decals.");
				BinaryReader binaryReader = new BinaryReader(new MemoryStream(data));
				NetDecal netDecal = NetDecal.Read(binaryReader);
				if (netDecal == null)
				{
					binaryReader.Close();
					return;
				}
				Decal decal = Decal.Create(netDecal.Point, netDecal.Normal, netDecal.Size, WallPlantAbility.WallPlantLayerMask);
				BindNetDecal(netDecal, decal);
				decal.SetTexture(GraffitiDatabase.GetGraffitiTexture(netDecal.Character));
				decal.AnimateSpray();
				binaryReader.Close();
			}
		}

		public static void BindNetDecal(NetDecal netDecal, Decal decal)
		{
			CurrentDecals.Insert(0, netDecal);
			decal.OnDestroyCallback = (Action)Delegate.Combine(decal.OnDestroyCallback, (Action)delegate
			{
				CurrentDecals.Remove(netDecal);
			});
		}
	}
	[BepInPlugin("com.LazyDuchess.BRC.WallPlant", "Wall Plant", "2.5.7")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class Plugin : BaseUnityPlugin
	{
		private const string CrewBoomGUID = "CrewBoom";

		private const string SlopCrewGUID = "SlopCrew.Plugin";

		public static Material GraffitiMaterial;

		public static Plugin Instance;

		public const string GUID = "com.LazyDuchess.BRC.WallPlant";

		public const string Name = "Wall Plant";

		public const string Version = "2.5.7";

		public static bool SlopCrewInstalled { get; private set; }

		public static bool CrewBoomInstalled { get; private set; }

		private void Awake()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			try
			{
				SlopCrewInstalled = IsSlopCrewInstalled();
				CrewBoomInstalled = IsCrewBoomInstalled();
				if (SlopCrewInstalled)
				{
					try
					{
						Net.Initialize();
					}
					catch (Exception arg)
					{
						Debug.LogError((object)$"Failed to initialize networking support for Wallplant even though SlopCrew is installed. You might have an outdated mod or an older version of the SlopCrew API for some reason.{Environment.NewLine}{arg}");
						SlopCrewInstalled = false;
					}
				}
				GraffitiDatabase.Initialize();
				DecalManager.Initialize();
				GraffitiMaterial = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "wallplant")).LoadAsset<Material>("GraffitiMaterial");
				WallPlantSettings.Initialize(((BaseUnityPlugin)this).Config);
				new Harmony("com.LazyDuchess.BRC.WallPlant").PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Wall Plant 2.5.7 loaded!");
			}
			catch (Exception arg2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0} {1} failed to load! {2}", "Wall Plant", "2.5.7", arg2));
			}
		}

		private void Update()
		{
			if (SlopCrewInstalled)
			{
				Net.Update();
			}
		}

		public ManualLogSource GetLogger()
		{
			return ((BaseUnityPlugin)this).Logger;
		}

		public static GraffitiArtInfo GetGraffitiArtInfo()
		{
			return Core.Instance.Assets.LoadAssetFromBundle<GraffitiArtInfo>("graffiti", "GraffitiArtInfo");
		}

		private static bool IsCrewBoomInstalled()
		{
			return Chainloader.PluginInfos.Keys.Contains("CrewBoom");
		}

		private static bool IsSlopCrewInstalled()
		{
			return Chainloader.PluginInfos.Keys.Contains("SlopCrew.Plugin");
		}
	}
	public class WallPlantAbility : Ability
	{
		private enum State
		{
			Planting,
			PlantedOut
		}

		public static LayerMask WallPlantLayerMask = LayerMask.op_Implicit(1041);

		public int TimesPlanted;

		private static float HitpauseDuration = 0.2f;

		private float _speedIntoWall;

		private float _timeSinceReachedMinSpeed = 1000f;

		private int _parkourHash = Animator.StringToHash("hitBounce");

		private int _footPlantHash = Animator.StringToHash("grindRetour");

		private int _footPlantOutHash = Animator.StringToHash("airTrick0");

		private int _grindDirectionHash = Animator.StringToHash("grindDirection");

		private State _state;

		private bool _didTrick;

		private Vector3 _wallNormal;

		private Vector3 _wallPoint;

		private bool _hasWall;

		private bool _graffiti;

		private bool _graffitiPlaced;

		public WallPlantAbility(Player player)
			: base(player)
		{
			base.p.abilities.Remove((Ability)(object)this);
			base.p.abilities.Insert(0, (Ability)(object)this);
		}

		public static WallPlantAbility Get(Player player)
		{
			foreach (Ability ability in player.abilities)
			{
				if (ability is WallPlantAbility)
				{
					return ability as WallPlantAbility;
				}
			}
			return null;
		}

		public override void Init()
		{
			base.normalMovement = true;
			base.decc = base.p.stats.airDecc;
			base.customGravity = 0f;
			base.treatPlayerAsSortaGrounded = true;
		}

		public void Trigger(Vector3 wallPoint, Vector3 wallNormal)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			_wallPoint = wallPoint;
			_wallNormal = wallNormal;
			base.p.ActivateAbility((Ability)(object)this);
		}

		public override void OnStartAbility()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			float num = WallPlantSettings.MoveStyleWallOffset;
			if ((int)base.p.moveStyle == 0)
			{
				num = WallPlantSettings.ParkourWallOffset;
			}
			base.p.SetPosAndRotHard(_wallPoint + _wallNormal * num, Quaternion.LookRotation(-_wallNormal, Vector3.up));
			TimesPlanted++;
			base.acc = 0f;
			base.targetSpeed = 0f;
			base.normalRotation = false;
			base.canStartGrind = false;
			base.canStartWallrun = false;
			_didTrick = false;
			_graffitiPlaced = false;
			_graffiti = WallPlantSettings.GraffitiPlantDefault;
			if (WallPlantSettings.RegainAirMobility)
			{
				base.p.RegainAirMobility();
			}
			SetState(State.Planting);
		}

		public void PassiveUpdate()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			_hasWall = false;
			if ((int)Core.Instance.SaveManager.CurrentSaveSlot.CurrentStoryObjective == 0)
			{
				base.locked = ((Ability)base.p.airDashAbility).locked;
			}
			if (base.p.ability != this)
			{
				if (base.p.IsGrounded() || base.p.IsGrinding() || base.p.ability is HandplantAbility || base.p.ability is HeadspinAbility || base.p.ability is WallrunLineAbility)
				{
					TimesPlanted = 0;
				}
				if (GetWallForPlant(out var point, out var normal) && Vector3.Angle(base.p.motor.dir, -normal) <= WallPlantSettings.MaxWallAngle)
				{
					_hasWall = true;
					_wallNormal = normal;
					_wallPoint = point;
					float num = Vector3.Dot(base.p.motor.velocity, -normal);
					if (num >= WallPlantSettings.MinimumSpeed)
					{
						if (WallPlantSettings.AbsoluteSpeed)
						{
							Vector3 velocity = base.p.motor.velocity;
							float magnitude = ((Vector3)(ref velocity)).magnitude;
							if (magnitude > _speedIntoWall)
							{
								_speedIntoWall = magnitude;
							}
						}
						else if (num > _speedIntoWall)
						{
							_speedIntoWall = num;
						}
						_timeSinceReachedMinSpeed = 0f;
						return;
					}
				}
				if (_timeSinceReachedMinSpeed > WallPlantSettings.GracePeriod)
				{
					_speedIntoWall = 0f;
				}
			}
			_timeSinceReachedMinSpeed += Core.dt;
			if (_timeSinceReachedMinSpeed > 1000f)
			{
				_timeSinceReachedMinSpeed = 1000f;
			}
		}

		private bool ValidSurface(GameObject obj)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (((1 << obj.layer) & LayerMask.op_Implicit(WallPlantLayerMask)) == 0)
			{
				return false;
			}
			if (!obj.CompareTag("Untagged"))
			{
				return false;
			}
			return true;
		}

		private bool DoGraffiti()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00db: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			_graffitiPlaced = true;
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(new Ray(((Component)base.p).transform.position + Vector3.up * 0.5f, ((Component)base.p).transform.forward), ref val, 2f, LayerMask.op_Implicit(WallPlantLayerMask), (QueryTriggerInteraction)1))
			{
				return false;
			}
			if ((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody != (Object)null)
			{
				return false;
			}
			base.p.SetSpraycanState((SpraycanState)3);
			base.p.AudioManager.PlaySfxGameplay((SfxCollectionID)13, (AudioClipID)387, 0f);
			if (WallPlantSettings.MaxGraffiti > 0)
			{
				Decal decal = Decal.Create(((RaycastHit)(ref val)).point, -((RaycastHit)(ref val)).normal, WallPlantSettings.GraffitiSize, WallPlantLayerMask);
				if (Plugin.SlopCrewInstalled)
				{
					Net.BindNetDecal(Net.SendDecal(base.p.character, ((RaycastHit)(ref val)).point, -((RaycastHit)(ref val)).normal, WallPlantSettings.GraffitiSize, WallPlantLayerMask), decal);
				}
				decal.SetTexture(GraffitiDatabase.GetGraffitiTexture(base.p));
				((Component)decal).transform.SetParent(((Component)((RaycastHit)(ref val)).collider).transform);
				decal.AnimateSpray();
			}
			return true;
		}

		public override void FixedUpdateAbility()
		{
			base.p.SetVisualRotLocal0();
			base.p.anim.SetFloat(_grindDirectionHash, 0f);
			if (_state == State.PlantedOut)
			{
				if (base.p.IsGrounded())
				{
					base.p.StopCurrentAbility();
					return;
				}
				if (base.p.abilityTimer > 0.4f)
				{
					base.p.SetBoostpackAndFrictionEffects((BoostpackEffectMode)0, (FrictionEffectMode)0);
				}
				if (base.p.abilityTimer > 0.25f && !_didTrick)
				{
					WallPlantTrickHolder wallPlantTrickHolder = WallPlantTrickHolder.Get(base.p);
					string trickName = "Wall Plant";
					if (_graffiti)
					{
						trickName = "Graffiti Plant";
					}
					wallPlantTrickHolder.Use(trickName);
					_didTrick = true;
				}
				base.acc = base.p.stats.airAcc + 10f;
				base.targetSpeed = base.p.stats.walkSpeed + 5f;
				base.normalRotation = true;
				if (base.p.abilityTimer > 0.5f)
				{
					base.p.StopCurrentAbility();
				}
				return;
			}
			if (WallPlantSettings.EnableAlternativePlant)
			{
				if (WallPlantSettings.GraffitiPlantDefault)
				{
					if (!_graffitiPlaced && _graffiti)
					{
						if (base.p.sprayButtonHeld && !WallPlantSettings.GraffitiPlantSlideButton)
						{
							_graffiti = false;
						}
						else if ((base.p.slideButtonHeld || base.p.slideButtonNew) && WallPlantSettings.GraffitiPlantSlideButton)
						{
							_graffiti = false;
						}
					}
				}
				else if (base.p.abilityTimer <= HitpauseDuration && !_graffiti && !_graffitiPlaced)
				{
					if (base.p.sprayButtonHeld && !WallPlantSettings.GraffitiPlantSlideButton)
					{
						_graffiti = true;
					}
					else if ((base.p.slideButtonHeld || base.p.slideButtonNew) && WallPlantSettings.GraffitiPlantSlideButton)
					{
						_graffiti = true;
					}
				}
			}
			if (_graffiti && !_graffitiPlaced && base.p.abilityTimer > 0.1f)
			{
				_graffiti = DoGraffiti();
			}
			if (base.p.abilityTimer > HitpauseDuration)
			{
				SetState(State.PlantedOut);
			}
		}

		private void SetState(State state)
		{
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: 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_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			_state = state;
			if (_state == State.Planting)
			{
				base.p.AudioManager.PlaySfxGameplay((SfxCollectionID)18, (AudioClipID)352, base.p.playerOneShotAudioSource, 0f);
				base.p.SetVelocity(Vector3.zero);
				if ((int)base.p.moveStyle == 0)
				{
					base.p.PlayAnim(_parkourHash, true, true, -1f);
				}
				else
				{
					base.p.PlayAnim(_footPlantHash, true, true, -1f);
				}
				return;
			}
			base.canStartGrind = true;
			base.canStartWallrun = true;
			base.p.PlayAnim(_footPlantOutHash, true, true, -1f);
			base.p.PlayVoice((AudioClipID)489, (VoicePriority)0, true);
			base.p.AudioManager.PlaySfxGameplay(base.p.moveStyle, (AudioClipID)14, base.p.playerOneShotAudioSource, 0f);
			base.p.SetBoostpackAndFrictionEffects((BoostpackEffectMode)1, (FrictionEffectMode)0);
			base.p.ringParticles.Emit(1);
			Vector3 moveInput = base.p.moveInput;
			Quaternion val = Quaternion.LookRotation(_wallNormal, Vector3.up);
			Vector3 eulerAngles = ((Quaternion)(ref val)).eulerAngles;
			if (moveInput != Vector3.zero)
			{
				moveInput.y = 0f;
				val = Quaternion.LookRotation(moveInput, Vector3.up);
				float num = Mathf.DeltaAngle(((Quaternion)(ref val)).eulerAngles.y, eulerAngles.y);
				num = Mathf.Clamp(num, 0f - WallPlantSettings.MaxJumpOffWallAngle, WallPlantSettings.MaxJumpOffWallAngle);
				eulerAngles.y -= num;
			}
			eulerAngles.x = 0f;
			Quaternion val2 = Quaternion.Euler(eulerAngles);
			base.p.SetPosAndRotHard(_wallPoint + _wallNormal * WallPlantSettings.JumpOffWallOffset, val2);
			base.p.SetVisualRot(val2, false);
			float num2 = _speedIntoWall * WallPlantSettings.SpeedMultiplier;
			float jumpForce = WallPlantSettings.JumpForce;
			float num3 = WallPlantSettings.WallPlantsUntilMaxPenalty - 1f;
			float num4 = (0f - ((float)TimesPlanted - 1f - num3)) / num3;
			if (WallPlantSettings.WallPlantsUntilMaxPenalty <= 0f)
			{
				num4 = 1f;
			}
			num2 *= num4;
			jumpForce *= num4;
			base.p.SetVelocity(_wallNormal * num2 + Vector3.up * jumpForce);
			if (base.p.IsGrounded())
			{
				base.p.isJumping = true;
				base.p.maintainSpeedJump = false;
				base.p.jumpConsumed = true;
				base.p.jumpRequested = false;
				base.p.jumpedThisFrame = true;
				base.p.timeSinceLastJump = 0f;
				base.p.ForceUnground(true);
			}
		}

		private bool GetWallForPlant(out Vector3 point, out Vector3 normal)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			point = Vector3.zero;
			normal = Vector3.zero;
			float num = 0.33f;
			float num2 = 0.5f;
			int num3 = 0;
			bool flag = false;
			float num4 = 0f;
			Vector3 val = Vector3.zero;
			Vector3 val2 = Vector3.zero;
			RaycastHit val3 = default(RaycastHit);
			for (float num5 = 0f - num2; num5 <= num2; num5 += num)
			{
				num3++;
				if (!Physics.Raycast(new Ray(((Component)base.p).transform.position + Vector3.up * num5 + Vector3.up * 0.5f, base.p.motor.dir), ref val3, WallPlantSettings.RaycastDistance, -1, (QueryTriggerInteraction)1))
				{
					return false;
				}
				if (!ValidSurface(((Component)((RaycastHit)(ref val3)).collider).gameObject))
				{
					return false;
				}
				float num6 = Vector3.Dot(((RaycastHit)(ref val3)).point - ((Component)base.p).transform.position, base.p.motor.dir);
				Vector3 point2 = ((RaycastHit)(ref val3)).point;
				point2.y = ((Component)base.p).transform.position.y;
				if (!flag)
				{
					num4 = num6;
					val = point2;
					flag = true;
				}
				else if (num6 < num4)
				{
					num4 = num6;
					val = point2;
				}
				val2 += ((RaycastHit)(ref val3)).normal;
			}
			point = val;
			Vector3 val4 = val2 / (float)num3;
			normal = ((Vector3)(ref val4)).normalized;
			return true;
		}

		public override bool CheckActivation()
		{
			//IL_006e: 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)
			if (!_hasWall)
			{
				return false;
			}
			if (TimesPlanted >= WallPlantSettings.MaximumWallPlants && WallPlantSettings.MaximumWallPlants > 0)
			{
				return false;
			}
			if (base.p.jumpButtonNew && !base.p.IsGrounded() && (!base.p.jumpRequested || !base.p.JumpIsAllowed()) && !base.locked)
			{
				if (_timeSinceReachedMinSpeed > WallPlantSettings.GracePeriod)
				{
					return false;
				}
				Trigger(_wallPoint, _wallNormal);
				return true;
			}
			return false;
		}
	}
	public static class WallPlantSettings
	{
		private static ConfigEntry<bool> _graffitiPlantDefault;

		private static ConfigEntry<bool> _graffitiPlantSlideButton;

		private static ConfigEntry<float> _graffitiPaintSpeed;

		private static ConfigEntry<float> _graffitiSize;

		private static ConfigEntry<int> _maxGraffiti;

		private static ConfigEntry<bool> _enableAlternativePlant;

		private static ConfigEntry<bool> _absoluteSpeed;

		private static ConfigEntry<float> _raycastDistance;

		private static ConfigEntry<bool> _regainAirMobility;

		private static ConfigEntry<float> _maxWallAngle;

		private static ConfigEntry<float> _maxJumpOffWallAngle;

		private static ConfigEntry<float> _jumpForce;

		private static ConfigEntry<float> _speedMultiplier;

		private static ConfigEntry<float> _jumpOffWallOffset;

		private static ConfigEntry<float> _gracePeriod;

		private static ConfigEntry<float> _minimumSpeed;

		private static ConfigEntry<float> _wallPlantsUntilMaxPenalty;

		private static ConfigEntry<int> _maximumWallPlants;

		public static bool DebugNetworking => false;

		public static bool GraffitiPlantDefault => _graffitiPlantDefault.Value;

		public static bool GraffitiPlantSlideButton => _graffitiPlantSlideButton.Value;

		public static float GraffitiPaintSpeed => _graffitiPaintSpeed.Value;

		public static float GraffitiSize => _graffitiSize.Value;

		public static int MaxGraffiti => _maxGraffiti.Value;

		public static bool EnableAlternativePlant => _enableAlternativePlant.Value;

		public static bool AbsoluteSpeed => _absoluteSpeed.Value;

		public static float RaycastDistance => _raycastDistance.Value;

		public static bool RegainAirMobility => _regainAirMobility.Value;

		public static float MaxWallAngle => _maxWallAngle.Value;

		public static float MaxJumpOffWallAngle => _maxJumpOffWallAngle.Value;

		public static float JumpForce => _jumpForce.Value;

		public static float SpeedMultiplier => _speedMultiplier.Value;

		public static float JumpOffWallOffset => _jumpOffWallOffset.Value;

		public static float ParkourWallOffset => 0.8f;

		public static float MoveStyleWallOffset => 0.25f;

		public static float GracePeriod => _gracePeriod.Value;

		public static float MinimumSpeed => _minimumSpeed.Value;

		public static float WallPlantsUntilMaxPenalty => _wallPlantsUntilMaxPenalty.Value;

		public static int MaximumWallPlants => _maximumWallPlants.Value;

		public static void Initialize(ConfigFile config)
		{
			_graffitiPlantDefault = config.Bind<bool>("GraffitiPlant", "GraffitiPlantByDefault", false, "Whether to Graffiti Plant by default, and have to press the graf plant button to do a regular Wall Plant instead.");
			_graffitiPlantSlideButton = config.Bind<bool>("GraffitiPlant", "GraffitiPlantSlideButton", false, "Whether to use the slide button instead of the spray button to do a graffiti plant.");
			_graffitiPaintSpeed = config.Bind<float>("GraffitiPlant", "GraffitiPaintSpeed", 3f, "Speed at which the graffiti gets sprayed.");
			_graffitiSize = config.Bind<float>("GraffitiPlant", "GraffitiSize", 1.5f, "Size of each graffiti.");
			_maxGraffiti = config.Bind<int>("GraffitiPlant", "MaxGraffiti", 10, "Maximum amount of graffiti in a level, before they will start getting cleaned up.");
			_enableAlternativePlant = config.Bind<bool>("GraffitiPlant", "EnableAlternativePlant", true, "Whether to enable the alt plant. If Graffitti Plants are default, then Wall Plants will be disabled, and vice versa.");
			_absoluteSpeed = config.Bind<bool>("WallPlant", "Absolute Speed", false, "If this is true, then your absolute speed will be used for wall jumping regardless of direction rather than just your speed directly into the wall surface.");
			_raycastDistance = config.Bind<float>("WallPlant", "RayCastDistance", 2f, "Distance to look for walls. The higher this number is the further away you can be from walls and still be able to wallplant.");
			_gracePeriod = config.Bind<float>("WallPlant", "GracePeriod", 0.15f, "Window of time after hitting a wall at high speed that you'll be able to wall plant off of it.");
			_maximumWallPlants = config.Bind<int>("WallPlant", "MaxWallPlants", 4, "Maximum amount of wall plants you can do in a row, before you have to grind/wallrun/land/etc. to reset the counter. Set this to 0 to allow unlimited wall plants in a row.");
			_wallPlantsUntilMaxPenalty = config.Bind<float>("WallPlant", "WallPlantsUntilMaxPenalty", 5f, "Amount of wall plants in a row until your strength drops to zero. This should probably be higher than the maximum amount of wall plants you can do so that you don't drop to zero strength at the last one. This number can have a fractional part. Set this to 0 to disable the penalty completely.");
			_regainAirMobility = config.Bind<bool>("WallPlant", "RegainAirMobility", true, "Whether you should be allowed to boost or dash again after doing a wall plant.");
			_speedMultiplier = config.Bind<float>("WallPlant", "SpeedMultiplier", 0.75f, "How much of your velocity into the wall will be transferred when you jump off the wall.");
			_jumpForce = config.Bind<float>("WallPlant", "JumpForce", 9f, "Upwards velocity applied when jumping off a wall.");
			_minimumSpeed = config.Bind<float>("WallPlant", "MinimumSpeed", 1f, "Minimum speed into a wall to be able to wall plant off of it.");
			_maxWallAngle = config.Bind<float>("WallPlant", "MaxWallAngle", 60f, "Maximum angle difference between the player direction and the wall angle.");
			_maxJumpOffWallAngle = config.Bind<float>("WallPlant", "MaxJumpOffWallAngle", 40f, "Maximum angle relative to the wall angle that you're allowed to jump off the wall.");
			_jumpOffWallOffset = config.Bind<float>("WallPlant", "JumpOffWallOffset", 0.9f, "How far away from the wall you'll be teleported when you jump off.");
		}
	}
	public class WallPlantTrickHolder : MonoBehaviour
	{
		public Player Player;

		public Trick WallPlantTrick = new Trick(80, 20, 10);

		private void Awake()
		{
			Player = ((Component)this).GetComponent<Player>();
		}

		public void Refresh()
		{
			bool flag = false;
			WallPlantTrick.Refresh(ref flag);
		}

		public void Use(string trickName = "", int trickNum = 0)
		{
			Trick handplantTrick = Player.handplantTrick;
			Player.handplantTrick = WallPlantTrick;
			Player.DoTrick((TrickType)13, trickName, trickNum);
			Player.handplantTrick = handplantTrick;
		}

		public static WallPlantTrickHolder Get(Player player)
		{
			return ((Component)player).GetComponent<WallPlantTrickHolder>();
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "WallPlant";

		public const string PLUGIN_NAME = "WallPlant";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace WallPlant.Patches
{
	[HarmonyPatch(typeof(AirTrickAbility), "FixedUpdateAbility")]
	internal static class AirTrickAbilityPatch
	{
		private static bool Prefix(Ability __instance)
		{
			return AbilityPatches.Prefix(__instance);
		}
	}
	[HarmonyPatch(typeof(BoostAbility), "FixedUpdateAbility")]
	internal static class BoostAbilityPatch
	{
		private static bool Prefix(Ability __instance)
		{
			return AbilityPatches.Prefix(__instance);
		}
	}
	[HarmonyPatch(typeof(FlipOutJumpAbility), "FixedUpdateAbility")]
	internal static class FlipOutJumpAbilityPatch
	{
		private static bool Prefix(Ability __instance)
		{
			return AbilityPatches.Prefix(__instance);
		}
	}
	[HarmonyPatch(typeof(HitBounceAbility), "FixedUpdateAbility")]
	internal static class HitBounceAbilityPatch
	{
		private static bool Prefix(Ability __instance)
		{
			return AbilityPatches.Prefix(__instance);
		}
	}
	[HarmonyPatch(typeof(SpecialAirAbility), "FixedUpdateAbility")]
	internal static class SpecialAirAbilityPatch
	{
		private static bool Prefix(Ability __instance)
		{
			return AbilityPatches.Prefix(__instance);
		}
	}
	[HarmonyPatch(typeof(AirDashAbility), "FixedUpdateAbility")]
	internal static class AirDashAbilityPatch
	{
		private static bool Prefix(Ability __instance)
		{
			return AbilityPatches.Prefix(__instance);
		}
	}
	internal static class AbilityPatches
	{
		internal static bool Prefix(Ability __instance)
		{
			WallPlantAbility wallPlantAbility = WallPlantAbility.Get(__instance.p);
			if (wallPlantAbility == null)
			{
				return true;
			}
			float num = 0f;
			if (__instance is FlipOutJumpAbility)
			{
				num = 0.25f;
			}
			else if (__instance is HitBounceAbility)
			{
				num = 0.5f;
			}
			else if (__instance is SpecialAirAbility)
			{
				SpecialAirAbility val = (SpecialAirAbility)(object)((__instance is SpecialAirAbility) ? __instance : null);
				num = val.duration - (val.hitEnemy ? 1.2f : 0.35f);
			}
			else if (__instance is VertAbility)
			{
				num = 0.1f;
			}
			else if (__instance is AirDashAbility)
			{
				num = 0.1f;
			}
			if (num != 0f && __instance.p.abilityTimer <= num)
			{
				return true;
			}
			if (((Ability)wallPlantAbility).CheckActivation())
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player))]
	internal static class PlayerPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("InitAbilities")]
		private static void InitAbilities_Postfix(Player __instance)
		{
			if (!__instance.isAI)
			{
				new WallPlantAbility(__instance);
				((Component)__instance).gameObject.AddComponent<WallPlantTrickHolder>();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("FixedUpdateAbilities")]
		private static void FixedUpdateAbilities_Prefix(Player __instance)
		{
			if (!__instance.isAI && !(__instance.ability is WallPlantAbility))
			{
				WallPlantAbility.Get(__instance)?.PassiveUpdate();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("RefreshAllDegrade")]
		private static void RefreshAllDegrade_Prefix(Player __instance)
		{
			if (!__instance.isAI)
			{
				WallPlantTrickHolder wallPlantTrickHolder = WallPlantTrickHolder.Get(__instance);
				if (!((Object)(object)wallPlantTrickHolder == (Object)null))
				{
					wallPlantTrickHolder.Refresh();
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("RefreshAirTricks")]
		private static void RefreshAirTricks_Prefix(Player __instance)
		{
			if (!__instance.isAI)
			{
				WallPlantTrickHolder wallPlantTrickHolder = WallPlantTrickHolder.Get(__instance);
				if (!((Object)(object)wallPlantTrickHolder == (Object)null))
				{
					wallPlantTrickHolder.Refresh();
				}
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}