Decompiled source of PeakPuffer v1.2.0

plugins/PeakPuffer/PeakPuffer.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PeakPuffer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("PeakPuffer")]
[assembly: AssemblyTitle("PeakPuffer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace PeakPuffer
{
	internal static class CameraRig
	{
		private static Camera? _fallback;

		internal static Camera? Current
		{
			get
			{
				MainCamera instance = MainCamera.instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance.cam != (Object)null)
				{
					return instance.cam;
				}
				if ((Object)(object)_fallback != (Object)null)
				{
					return _fallback;
				}
				return _fallback = Camera.main;
			}
		}
	}
	internal static class ItemIcons
	{
		private static bool _prefabsDone;

		internal static void ApplyToPrefabs()
		{
			if (_prefabsDone || !Plugin.Enabled || !Plugin.ReplaceIcons)
			{
				return;
			}
			try
			{
				ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance;
				if (instance?.itemLookup == null || instance.itemLookup.Count == 0)
				{
					return;
				}
				int num = 0;
				foreach (KeyValuePair<ushort, Item> item in instance.itemLookup)
				{
					Item value = item.Value;
					if ((Object)(object)value == (Object)null)
					{
						continue;
					}
					PufferTarget pufferTarget = PufferTargets.Match(((Component)value).gameObject);
					if (pufferTarget != null && pufferTarget.Kind == TargetKind.Item)
					{
						PufferSkin pufferSkin = PufferAssets.For(pufferTarget);
						if (pufferSkin != null && Apply(value, pufferSkin, pufferTarget))
						{
							num++;
						}
					}
				}
				_prefabsDone = true;
				if (num > 0)
				{
					Plugin.Log.LogInfo((object)$"Replaced {num} inventory icon(s).");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not replace inventory icons: " + ex.Message));
				_prefabsDone = true;
			}
		}

		internal static void ApplyToInstance(Item item, PufferSkin skin, PufferTarget target)
		{
			if (!Plugin.ReplaceIcons)
			{
				return;
			}
			try
			{
				Apply(item, skin, target);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not replace item icon: " + ex.Message));
			}
		}

		private static bool Apply(Item item, PufferSkin skin, PufferTarget target)
		{
			if ((Object)(object)item == (Object)null || item.UIData == null)
			{
				return false;
			}
			Texture2D val = PufferAssets.IconFor(target) ?? skin.Texture;
			item.UIData.icon = val;
			if (item.UIData.hasAltIcon || item.UIData.hasColorBlindIcon)
			{
				item.UIData.altIcon = val;
			}
			return true;
		}
	}
	[BepInProcess("PEAK.exe")]
	[BepInPlugin("PeakPuffer", "PeakPuffer", "1.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<float> _scale;

		private static ConfigEntry<float> _itemScale;

		private static ConfigEntry<float> _pushOut;

		private static ConfigEntry<bool> _hideOriginal;

		private static ConfigEntry<float> _roundness;

		private static ConfigEntry<float> _brightness;

		private static ConfigEntry<bool> _replaceIcons;

		private static ConfigEntry<bool> _itemBillboards;

		public const string Id = "PeakPuffer";

		internal static ManualLogSource Log { get; private set; }

		internal static bool Enabled => _enabled.Value;

		internal static float Scale => _scale.Value;

		internal static float ItemScale => _itemScale.Value;

		internal static float PushOut => _pushOut.Value;

		internal static bool HideOriginal => _hideOriginal.Value;

		internal static float Roundness => _roundness.Value;

		internal static float Brightness => _brightness.Value;

		internal static bool ReplaceIcons => _replaceIcons.Value;

		internal static bool ItemBillboards => _itemBillboards.Value;

		public static string Name => "PeakPuffer";

		public static string Version => "1.2.0";

		private void Awake()
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Expected O, but got Unknown
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Expected O, but got Unknown
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable or disable the mod.");
			PufferTarget[] all = PufferTargets.All;
			foreach (PufferTarget pufferTarget in all)
			{
				string text = ((pufferTarget.Kind == TargetKind.Item) ? "Items" : "Hazards");
				ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>(text, pufferTarget.Id, true, pufferTarget.Description);
				pufferTarget.Enabled = val.Value;
			}
			_replaceIcons = ((BaseUnityPlugin)this).Config.Bind<bool>("Items", "ReplaceInventoryIcons", true, "Replace item icons in the backpack and hotbar.");
			_itemBillboards = ((BaseUnityPlugin)this).Config.Bind<bool>("Items", "UseBillboards", true, "Render items as camera-facing billboards instead of crossed quads.");
			_scale = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "Scale", 0.9f, new ConfigDescription("Hazard fish scale relative to the original object.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 4f), Array.Empty<object>()));
			_itemScale = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "ItemScale", 1f, new ConfigDescription("Item fish scale relative to the original item.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 4f), Array.Empty<object>()));
			_roundness = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "Roundness", 0.6f, new ConfigDescription("Spherical normal intensity for billboard shading (0 = flat, 1 = round).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_pushOut = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "PushOut", 1.05f, new ConfigDescription("Camera-forward offset for hazard billboards to prevent clipping.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			_brightness = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "Brightness", 1f, new ConfigDescription("Brightness multiplier for fish textures.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
			_hideOriginal = ((BaseUnityPlugin)this).Config.Bind<bool>("Appearance", "HideOriginalMesh", false, "Hide original hazard mesh while keeping its shadow.");
			if (!_enabled.Value)
			{
				Log.LogInfo((object)"Disabled in config.");
				return;
			}
			Harmony harmony = new Harmony("PeakPuffer");
			bool flag = Patch(harmony, typeof(TriggerEvent), "Start", "OnTriggerEventStarted");
			bool flag2 = Patch(harmony, typeof(SwingingAxe), "Start", "OnSwingingAxeStarted");
			bool flag3 = Patch(harmony, typeof(GhostBall), "Awake", "OnGhostBallAwake");
			bool flag4 = Patch(harmony, typeof(Item), "OnEnable", "OnItemEnabled");
			if (!flag && !flag2 && !flag3 && !flag4)
			{
				Log.LogError((object)"No hooks could be installed; PeakPuffer is disabled.");
				return;
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			Log.LogInfo((object)"PeakPuffer loaded.");
		}

		private static bool Patch(Harmony harmony, Type type, string method, string postfix)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Log.LogError((object)("Could not find " + type.Name + "." + method + "; hook disabled."));
					return false;
				}
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(Plugin), postfix, (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return true;
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to patch {type.Name}.{method}: {arg}");
				return false;
			}
		}

		private static void OnTriggerEventStarted(TriggerEvent __instance)
		{
			Convert((Component)(object)__instance);
		}

		private static void OnSwingingAxeStarted(SwingingAxe __instance)
		{
			Convert((Component)(object)__instance);
		}

		private static void OnGhostBallAwake(GhostBall __instance)
		{
			Convert((Component)(object)__instance);
		}

		private static void OnItemEnabled(Item __instance)
		{
			Convert((Component)(object)__instance);
		}

		private static void Convert(Component instance)
		{
			try
			{
				if ((Object)(object)instance != (Object)null)
				{
					Replacer.Convert(instance.gameObject);
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Failed to replace object: " + ex.Message));
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			((MonoBehaviour)this).StartCoroutine(SweepNextFrame());
		}

		private static IEnumerator SweepNextFrame()
		{
			yield return null;
			Replacer.SweepLoadedScene();
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}
	}
	internal sealed class PufferSkin
	{
		internal Texture2D Texture;

		internal Material Material;

		internal Vector2 SilhouetteSize = Vector2.one;

		internal Vector2 SilhouetteOffset = Vector2.zero;
	}
	internal static class PufferAssets
	{
		private static class ShaderIds
		{
			internal static readonly int BaseMap = Shader.PropertyToID("_BaseMap");

			internal static readonly int MainTex = Shader.PropertyToID("_MainTex");

			internal static readonly int BaseColor = Shader.PropertyToID("_BaseColor");

			internal static readonly int Color = Shader.PropertyToID("_Color");

			internal static readonly int Surface = Shader.PropertyToID("_Surface");

			internal static readonly int Cutoff = Shader.PropertyToID("_Cutoff");

			internal static readonly int SrcBlend = Shader.PropertyToID("_SrcBlend");

			internal static readonly int DstBlend = Shader.PropertyToID("_DstBlend");

			internal static readonly int ZWrite = Shader.PropertyToID("_ZWrite");

			internal static readonly int AlphaClip = Shader.PropertyToID("_AlphaClip");

			internal static readonly int Cull = Shader.PropertyToID("_Cull");

			internal static readonly int Metallic = Shader.PropertyToID("_Metallic");

			internal static readonly int Smoothness = Shader.PropertyToID("_Smoothness");

			internal static readonly int WorkflowMode = Shader.PropertyToID("_WorkflowMode");

			internal static readonly int ReceiveShadows = Shader.PropertyToID("_ReceiveShadows");

			internal static readonly int EnvironmentReflections = Shader.PropertyToID("_EnvironmentReflections");

			internal static readonly int SpecularHighlights = Shader.PropertyToID("_SpecularHighlights");

			internal static readonly int EmissionMap = Shader.PropertyToID("_EmissionMap");

			internal static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor");
		}

		private const string ResourcePrefix = "PeakPuffer.";

		internal const float AlphaCutoff = 0.5f;

		private static readonly Dictionary<string, PufferSkin> Cache = new Dictionary<string, PufferSkin>(StringComparer.Ordinal);

		private static readonly Dictionary<string, Texture2D?> Icons = new Dictionary<string, Texture2D>(StringComparer.Ordinal);

		private static Shader? _shader;

		private static bool _shaderMissing;

		internal static string ShaderName { get; private set; } = "(none)";

		internal static PufferSkin? For(PufferTarget target)
		{
			if (target.Broken)
			{
				return null;
			}
			if (Cache.TryGetValue(target.Texture, out PufferSkin value))
			{
				return value;
			}
			PufferSkin pufferSkin = Build(target);
			if (pufferSkin == null)
			{
				target.Broken = true;
				Plugin.Log.LogError((object)("Could not build skin for '" + target.Id + "'."));
				return null;
			}
			Cache[target.Texture] = pufferSkin;
			return pufferSkin;
		}

		private static PufferSkin? Build(PufferTarget target)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_003a: Expected O, but got Unknown
			byte[] array = ReadEmbedded(target.Texture);
			if (array == null)
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, false)
			{
				name = "PeakPuffer_" + target.Id,
				hideFlags = (HideFlags)61
			};
			if (!ImageConversion.LoadImage(val, array, false))
			{
				Plugin.Log.LogError((object)("'" + target.Texture + "' is not a valid PNG."));
				Object.Destroy((Object)(object)val);
				return null;
			}
			PufferSkin pufferSkin = new PufferSkin
			{
				Texture = val
			};
			Measure(val, pufferSkin);
			val.Apply(false, true);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).anisoLevel = 4;
			Material val2 = BuildMaterial(val, target);
			if ((Object)(object)val2 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			pufferSkin.Material = val2;
			Plugin.Log.LogInfo((object)("Skin '" + target.Id + "' ready (" + ShaderName + ", " + $"subject {pufferSkin.SilhouetteSize.x:0.##}x{pufferSkin.SilhouetteSize.y:0.##} of image)."));
			return pufferSkin;
		}

		private static void Measure(Texture2D texture, PufferSkin skin)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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)
			try
			{
				Color32[] pixels = texture.GetPixels32();
				int width = ((Texture)texture).width;
				int height = ((Texture)texture).height;
				byte b = (byte)Mathf.RoundToInt(127.5f);
				int num = width;
				int num2 = height;
				int num3 = -1;
				int num4 = -1;
				for (int i = 0; i < height; i++)
				{
					int num5 = i * width;
					for (int j = 0; j < width; j++)
					{
						if (pixels[num5 + j].a >= b)
						{
							if (j < num)
							{
								num = j;
							}
							if (j > num3)
							{
								num3 = j;
							}
							if (i < num2)
							{
								num2 = i;
							}
							if (i > num4)
							{
								num4 = i;
							}
						}
					}
				}
				if (num3 < num || num4 < num2)
				{
					Plugin.Log.LogWarning((object)("'" + ((Object)texture).name + "' is fully transparent; using it whole."));
					return;
				}
				skin.SilhouetteSize = new Vector2((float)(num3 - num + 1) / (float)width, (float)(num4 - num2 + 1) / (float)height);
				skin.SilhouetteOffset = new Vector2((float)(num + num3 + 1) * 0.5f / (float)width - 0.5f, (float)(num2 + num4 + 1) * 0.5f / (float)height - 0.5f);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not measure '" + ((Object)texture).name + "': " + ex.Message));
			}
		}

		internal static Texture2D? IconFor(PufferTarget target)
		{
			if (Icons.TryGetValue(target.ModelFile, out Texture2D value))
			{
				return value;
			}
			Texture2D val = LoadIcon(target.ModelFile + "-icon.png") ?? LoadIcon(Path.GetFileNameWithoutExtension(target.Texture) + "-icon.png");
			Icons[target.ModelFile] = val;
			return val;
		}

		private static Texture2D? LoadIcon(string name)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0057: Expected O, but got Unknown
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				if (string.IsNullOrEmpty(directoryName))
				{
					return null;
				}
				string path = Path.Combine(directoryName, name);
				if (!File.Exists(path))
				{
					return null;
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false, false)
				{
					name = "PeakPuffer_Icon_" + name,
					hideFlags = (HideFlags)61
				};
				if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path), true))
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				Plugin.Log.LogInfo((object)("Icon override " + name + " loaded."));
				return val;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read icon override: " + ex.Message));
				return null;
			}
		}

		private static byte[]? ReadEmbedded(string fileName)
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("PeakPuffer." + fileName);
			if (stream == null)
			{
				Plugin.Log.LogError((object)("Embedded resource 'PeakPuffer." + fileName + "' is missing."));
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		private static Material? BuildMaterial(Texture2D texture, PufferTarget target)
		{
			//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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0078: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			Shader val = FindShader();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Material val2 = new Material(val)
			{
				name = "PeakPuffer_" + target.Id,
				hideFlags = (HideFlags)61
			};
			float num = Mathf.Clamp(Plugin.Brightness, 0.1f, 2f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(num, num, num, 1f);
			val2.SetTexture(ShaderIds.BaseMap, (Texture)(object)texture);
			val2.SetTexture(ShaderIds.MainTex, (Texture)(object)texture);
			val2.SetColor(ShaderIds.BaseColor, val3);
			val2.SetColor(ShaderIds.Color, val3);
			if (((Object)val).name.StartsWith("Universal Render Pipeline/", StringComparison.Ordinal))
			{
				ConfigureUrp(val2);
				if (target.Glow)
				{
					val2.EnableKeyword("_EMISSION");
					val2.SetTexture(ShaderIds.EmissionMap, (Texture)(object)texture);
					val2.SetColor(ShaderIds.EmissionColor, Color.white);
					val2.renderQueue = 3900;
				}
			}
			else
			{
				val2.SetOverrideTag("RenderType", "Transparent");
				val2.renderQueue = 3000;
			}
			return val2;
		}

		private static void ConfigureUrp(Material material)
		{
			material.SetFloat(ShaderIds.Surface, 0f);
			material.SetFloat(ShaderIds.SrcBlend, 1f);
			material.SetFloat(ShaderIds.DstBlend, 0f);
			material.SetFloat(ShaderIds.ZWrite, 1f);
			material.SetFloat(ShaderIds.AlphaClip, 1f);
			material.SetFloat(ShaderIds.Cutoff, 0.5f);
			material.EnableKeyword("_ALPHATEST_ON");
			material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT");
			material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
			material.SetFloat(ShaderIds.Cull, 0f);
			material.SetFloat(ShaderIds.Metallic, 0f);
			material.SetFloat(ShaderIds.Smoothness, 0f);
			material.SetFloat(ShaderIds.WorkflowMode, 1f);
			material.SetFloat(ShaderIds.ReceiveShadows, 1f);
			material.SetFloat(ShaderIds.EnvironmentReflections, 0f);
			material.SetFloat(ShaderIds.SpecularHighlights, 0f);
			material.DisableKeyword("_RECEIVE_SHADOWS_OFF");
			material.EnableKeyword("_ENVIRONMENTREFLECTIONS_OFF");
			material.EnableKeyword("_SPECULARHIGHLIGHTS_OFF");
			material.SetOverrideTag("RenderType", "TransparentCutout");
			material.renderQueue = 2450;
		}

		private static Shader? FindShader()
		{
			if ((Object)(object)_shader != (Object)null)
			{
				return _shader;
			}
			if (_shaderMissing)
			{
				return null;
			}
			string[] array = new string[2] { "Universal Render Pipeline/Lit", "Universal Render Pipeline/Unlit" };
			foreach (string text in array)
			{
				Shader val = Shader.Find(text) ?? FindLoaded(text);
				if ((Object)(object)val != (Object)null)
				{
					ShaderName = ((Object)val).name;
					return _shader = val;
				}
			}
			Shader val2 = Shader.Find("Sprites/Default");
			if ((Object)(object)val2 != (Object)null)
			{
				Plugin.Log.LogWarning((object)"URP shaders unavailable; falling back to Sprites/Default.");
				ShaderName = ((Object)val2).name;
				return _shader = val2;
			}
			Plugin.Log.LogError((object)"No usable shader found; PeakPuffer cannot render.");
			_shaderMissing = true;
			return null;
		}

		private static Shader? FindLoaded(string name)
		{
			Shader[] array = Resources.FindObjectsOfTypeAll<Shader>();
			foreach (Shader val in array)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}
	}
	internal sealed class PufferBillboard : MonoBehaviour
	{
		private Transform _bomb;

		private MeshRenderer _renderer;

		private Vector3 _localCentre;

		private Vector2 _offset;

		private Vector3 _halfExtents;

		private float _baseQuad;

		private float _pushOut;

		private float _cullSize;

		private float _cullThreshold;

		internal static PufferBillboard? Attach(GameObject bomb, PufferTarget target, PufferSkin skin, float scale, float pushOut)
		{
			//IL_0014: 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)
			//IL_0021: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: 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_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: 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_01c9: Unknown result type (might be due to invalid IL or missing references)
			if (!TryMeasure(bomb, target, out var bounds, out var layer))
			{
				return null;
			}
			GameObject val = new GameObject("PeakPuffer_Billboard")
			{
				layer = layer
			};
			MeshFilter val2 = val.AddComponent<MeshFilter>();
			val2.sharedMesh = PufferMesh.Quad;
			MeshRenderer val3 = val.AddComponent<MeshRenderer>();
			((Renderer)val3).sharedMaterial = skin.Material;
			((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)val3).receiveShadows = true;
			((Renderer)val3).lightProbeUsage = (LightProbeUsage)1;
			((Renderer)val3).reflectionProbeUsage = (ReflectionProbeUsage)1;
			((Renderer)val3).enabled = false;
			PufferBillboard pufferBillboard = val.AddComponent<PufferBillboard>();
			pufferBillboard._bomb = bomb.transform;
			pufferBillboard._renderer = val3;
			pufferBillboard._localCentre = ((Bounds)(ref bounds)).center;
			pufferBillboard.ReadCullSettings(bomb);
			Vector3 lossyScale = bomb.transform.lossyScale;
			Vector3 val4 = Vector3.Scale(((Bounds)(ref bounds)).size, new Vector3(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z)));
			float[] array = new float[3] { val4.x, val4.y, val4.z };
			Array.Sort(array);
			float num = (array[1] + array[2]) * 0.5f;
			Vector2 silhouetteSize = skin.SilhouetteSize;
			float num2 = Mathf.Max(0.01f, Mathf.Max(silhouetteSize.x, silhouetteSize.y));
			float num3 = num * scale / num2;
			pufferBillboard._offset = -skin.SilhouetteOffset * num3;
			pufferBillboard._halfExtents = val4 * 0.5f;
			pufferBillboard._baseQuad = num3;
			pufferBillboard._pushOut = Mathf.Max(val4.x, Mathf.Max(val4.y, val4.z)) * 0.5f * pushOut;
			val.transform.localScale = new Vector3(num3, num3, 1f);
			return pufferBillboard;
		}

		private void ReadCullSettings(GameObject bomb)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			LODGroup componentInChildren = bomb.GetComponentInChildren<LODGroup>(true);
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				LOD[] lODs = componentInChildren.GetLODs();
				if (lODs.Length != 0)
				{
					Vector3 lossyScale = ((Component)componentInChildren).transform.lossyScale;
					float num = Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Max(Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z)));
					_cullSize = componentInChildren.size * num;
					_cullThreshold = lODs[^1].screenRelativeTransitionHeight;
				}
			}
		}

		private static bool TryMeasure(GameObject bomb, PufferTarget target, out Bounds bounds, out int layer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0110: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			bounds = default(Bounds);
			layer = 0;
			bool flag = false;
			Transform val = Replacer.FindVisual(bomb, target);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Matrix4x4 worldToLocalMatrix = bomb.transform.worldToLocalMatrix;
			MeshFilter[] componentsInChildren = ((Component)val).GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val2 in componentsInChildren)
			{
				Mesh sharedMesh = val2.sharedMesh;
				if ((Object)(object)sharedMesh == (Object)null || ((Component)val2).gameObject.layer == 21)
				{
					continue;
				}
				if (!flag)
				{
					layer = ((Component)val2).gameObject.layer;
				}
				Bounds bounds2 = sharedMesh.bounds;
				Matrix4x4 val3 = worldToLocalMatrix * ((Component)val2).transform.localToWorldMatrix;
				for (int j = 0; j < 8; j++)
				{
					Vector3 val4 = ((Bounds)(ref bounds2)).center + Vector3.Scale(((Bounds)(ref bounds2)).extents, new Vector3(((j & 1) == 0) ? (-1f) : 1f, ((j & 2) == 0) ? (-1f) : 1f, ((j & 4) == 0) ? (-1f) : 1f));
					Vector3 val5 = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(val4);
					if (flag)
					{
						((Bounds)(ref bounds)).Encapsulate(val5);
						continue;
					}
					bounds = new Bounds(val5, Vector3.zero);
					flag = true;
				}
			}
			if (flag)
			{
				Vector3 size = ((Bounds)(ref bounds)).size;
				return ((Vector3)(ref size)).sqrMagnitude > 0.0001f;
			}
			return false;
		}

		private void LateUpdate()
		{
			//IL_0044: 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)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//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_0062: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_bomb == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			Camera current = CameraRig.Current;
			bool flag = false;
			if ((Object)(object)current != (Object)null && ((Component)_bomb).gameObject.activeInHierarchy)
			{
				Vector3 val = _bomb.TransformPoint(_localCentre);
				Transform transform = ((Component)current).transform;
				Vector3 toCamera = transform.position - val;
				float magnitude = ((Vector3)(ref toCamera)).magnitude;
				flag = !LodCulled(current, magnitude);
				if (flag)
				{
					Face(transform, val, toCamera, magnitude);
				}
			}
			if (((Renderer)_renderer).enabled != flag)
			{
				((Renderer)_renderer).enabled = flag;
			}
		}

		private bool LodCulled(Camera camera, float distance)
		{
			if (_cullThreshold <= 0f || camera.orthographic || distance < 0.001f)
			{
				return false;
			}
			float num = _cullSize * QualitySettings.lodBias / (2f * distance * Mathf.Tan(camera.fieldOfView * 0.5f * (MathF.PI / 180f)));
			return num < _cullThreshold;
		}

		private void Face(Transform cameraTf, Vector3 centre, Vector3 toCamera, float distance)
		{
			//IL_0020: 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_002b: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_0107: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: 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_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00b6: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Min(_pushOut, distance * 0.9f);
			Vector3 val = ((distance > 0.001f) ? (centre + toCamera * (num / distance)) : centre);
			float num2 = ((distance > 0.001f) ? Mathf.Clamp((distance - num) / distance, 0.1f, 1f) : 1f);
			float num3 = _baseQuad * num2;
			((Component)this).transform.localScale = new Vector3(num3, num3, 1f);
			Quaternion val2 = cameraTf.rotation;
			if (distance > 0.001f)
			{
				Vector3 val3 = toCamera * (-1f / distance);
				float num4 = Mathf.Abs(val3.y);
				Vector3 val4 = ((num4 < 0.9f) ? Vector3.up : Vector3.Slerp(Vector3.up, cameraTf.up, Mathf.InverseLerp(0.9f, 0.995f, num4)));
				val2 = Quaternion.LookRotation(val3, val4);
			}
			val += val2 * new Vector3(_offset.x * num2, _offset.y * num2, 0f);
			Vector3 val5 = val2 * Vector3.right;
			Vector3 val6 = val2 * Vector3.up;
			float num5 = 0.5f * num3 * (Mathf.Abs(val5.y) + Mathf.Abs(val6.y));
			float num6 = centre.y - _halfExtents.y;
			float num7 = num6 + num5 - val.y;
			if (num7 > 0f)
			{
				val.y += num7;
			}
			((Component)this).transform.SetPositionAndRotation(val, val2);
		}
	}
	internal static class PufferImpostor
	{
		private const float FlatRatio = 0.5f;

		internal static bool Attach(GameObject item, PufferTarget target, PufferSkin skin, float scale)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0065: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00ce: 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_00e0: 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_0112: 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_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			Transform val = Replacer.FindVisual(item, target);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (!Measure(val, out var bounds))
			{
				return false;
			}
			GameObject val2 = new GameObject("PeakPuffer_Impostor");
			val2.transform.SetParent(((Component)val).transform, false);
			val2.transform.localPosition = ((Bounds)(ref bounds)).center;
			val2.transform.localRotation = Quaternion.identity;
			Vector3 size = ((Bounds)(ref bounds)).size;
			float num = Mathf.Max(0.01f, Mathf.Max(skin.SilhouetteSize.x, skin.SilhouetteSize.y));
			float num2 = Mathf.Max(size.x, Mathf.Max(size.y, size.z)) * scale / num;
			val2.transform.localScale = new Vector3(num2, num2, num2);
			float[] array = new float[3] { size.x, size.y, size.z };
			int num3 = 0;
			for (int i = 1; i < 3; i++)
			{
				if (array[i] < array[num3])
				{
					num3 = i;
				}
			}
			float num4 = Mathf.Max(size.x, Mathf.Max(size.y, size.z));
			bool flag = num4 > 0f && array[num3] / num4 < 0.5f;
			MeshFilter val3 = val2.AddComponent<MeshFilter>();
			val3.sharedMesh = (flag ? PufferMesh.Quad : PufferMesh.Cross);
			if (flag)
			{
				Transform transform = val2.transform;
				transform.localRotation = (Quaternion)(num3 switch
				{
					0 => Quaternion.Euler(0f, 90f, 0f), 
					1 => Quaternion.Euler(90f, 0f, 0f), 
					_ => Quaternion.identity, 
				});
			}
			MeshRenderer val4 = val2.AddComponent<MeshRenderer>();
			((Renderer)val4).sharedMaterial = skin.Material;
			((Renderer)val4).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)val4).receiveShadows = true;
			((Renderer)val4).lightProbeUsage = (LightProbeUsage)1;
			((Renderer)val4).reflectionProbeUsage = (ReflectionProbeUsage)1;
			MeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val5 in componentsInChildren)
			{
				if ((Object)(object)val5 != (Object)null && (Object)(object)val5 != (Object)(object)val4)
				{
					((Renderer)val5).forceRenderingOff = true;
				}
			}
			return true;
		}

		private static bool Measure(Transform visual, out Bounds bounds)
		{
			//IL_0001: 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_000f: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_0068: 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_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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_00d9: 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)
			bounds = default(Bounds);
			bool flag = false;
			Matrix4x4 worldToLocalMatrix = visual.worldToLocalMatrix;
			MeshFilter[] componentsInChildren = ((Component)visual).GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val in componentsInChildren)
			{
				Mesh sharedMesh = val.sharedMesh;
				if ((Object)(object)sharedMesh == (Object)null)
				{
					continue;
				}
				Bounds bounds2 = sharedMesh.bounds;
				Matrix4x4 val2 = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
				for (int j = 0; j < 8; j++)
				{
					Vector3 val3 = ((Bounds)(ref bounds2)).center + Vector3.Scale(((Bounds)(ref bounds2)).extents, new Vector3(((j & 1) == 0) ? (-1f) : 1f, ((j & 2) == 0) ? (-1f) : 1f, ((j & 4) == 0) ? (-1f) : 1f));
					Vector3 val4 = ((Matrix4x4)(ref val2)).MultiplyPoint3x4(val3);
					if (flag)
					{
						((Bounds)(ref bounds)).Encapsulate(val4);
						continue;
					}
					bounds = new Bounds(val4, Vector3.zero);
					flag = true;
				}
			}
			if (flag)
			{
				Vector3 size = ((Bounds)(ref bounds)).size;
				return ((Vector3)(ref size)).sqrMagnitude > 1E-08f;
			}
			return false;
		}
	}
	internal static class PufferMesh
	{
		private const int Segments = 12;

		private static readonly Dictionary<int, Mesh> Cache = new Dictionary<int, Mesh>();

		internal static Mesh Quad => Get(1);

		internal static Mesh Cross => Get(2);

		private static Mesh Get(int planes)
		{
			if (Cache.TryGetValue(planes, out Mesh value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Mesh val = Build(planes);
			Cache[planes] = val;
			return val;
		}

		private static Mesh Build(int planes)
		{
			//IL_005b: 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_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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_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_0155: 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)
			float num = Mathf.Clamp01(Plugin.Roundness);
			int num2 = 13;
			int num3 = num2 * num2;
			Vector3[] array = (Vector3[])(object)new Vector3[num3 * planes];
			Vector3[] array2 = (Vector3[])(object)new Vector3[num3 * planes];
			Vector2[] array3 = (Vector2[])(object)new Vector2[num3 * planes];
			int[] array4 = new int[864 * planes];
			int num4 = 0;
			for (int i = 0; i < planes; i++)
			{
				Quaternion val = Quaternion.Euler(0f, (float)i * 90f, 0f);
				int num5 = i * num3;
				for (int j = 0; j < num2; j++)
				{
					for (int k = 0; k < num2; k++)
					{
						int num6 = num5 + j * num2 + k;
						float num7 = (float)k / 12f;
						float num8 = (float)j / 12f;
						array[num6] = val * new Vector3(num7 - 0.5f, num8 - 0.5f, 0f);
						array3[num6] = new Vector2(num7, num8);
						float num9 = (num7 - 0.5f) * 2f;
						float num10 = (num8 - 0.5f) * 2f;
						float num11 = num9 * num9 + num10 * num10;
						float num12 = ((num11 < 1f) ? (0f - Mathf.Sqrt(1f - num11)) : 0f);
						Vector3 val2 = new Vector3(num9, num10, num12);
						Vector3 normalized = ((Vector3)(ref val2)).normalized;
						array2[num6] = val * Vector3.Slerp(new Vector3(0f, 0f, -1f), normalized, num);
					}
				}
				for (int l = 0; l < 12; l++)
				{
					for (int m = 0; m < 12; m++)
					{
						int num13 = num5 + l * num2 + m;
						array4[num4++] = num13;
						array4[num4++] = num13 + num2;
						array4[num4++] = num13 + 1;
						array4[num4++] = num13 + num2;
						array4[num4++] = num13 + num2 + 1;
						array4[num4++] = num13 + 1;
					}
				}
			}
			Mesh val3 = new Mesh
			{
				name = ((planes > 1) ? "PeakPuffer_Cross" : "PeakPuffer_Quad"),
				hideFlags = (HideFlags)61,
				vertices = array,
				normals = array2,
				uv = array3,
				triangles = array4
			};
			val3.RecalculateBounds();
			return val3;
		}
	}
	internal static class PufferModel
	{
		private static readonly Dictionary<string, Mesh?> Cache = new Dictionary<string, Mesh>(StringComparer.Ordinal);

		private static readonly Dictionary<string, Texture2D?> BakedTextures = new Dictionary<string, Texture2D>(StringComparer.Ordinal);

		private static readonly Dictionary<string, Material> BakedMaterials = new Dictionary<string, Material>(StringComparer.Ordinal);

		private static readonly Dictionary<string, Texture2D?> ModelTextures = new Dictionary<string, Texture2D>(StringComparer.Ordinal);

		private static readonly Dictionary<string, string[]> Groups = new Dictionary<string, string[]>(StringComparer.Ordinal);

		private static readonly Dictionary<string, Material?> NativeMaterials = new Dictionary<string, Material>(StringComparer.Ordinal);

		internal static bool TryAttach(GameObject go, PufferTarget target, PufferSkin skin)
		{
			//IL_002a: 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_0053: Expected O, but got Unknown
			//IL_006d: 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_0075: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_0107: 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)
			Mesh val = MeshFor(target);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Transform val2 = Replacer.FindVisual(go, target);
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			GameObject val3 = new GameObject("PeakPuffer_Model")
			{
				layer = ((((Component)val2).gameObject.layer != 21) ? ((Component)val2).gameObject.layer : 0)
			};
			Transform transform = val3.transform;
			transform.SetParent(go.transform, false);
			Vector3 localScale = go.transform.localScale;
			transform.localScale = new Vector3(Mathf.Approximately(localScale.x, 0f) ? 1f : (1f / localScale.x), Mathf.Approximately(localScale.y, 0f) ? 1f : (1f / localScale.y), Mathf.Approximately(localScale.z, 0f) ? 1f : (1f / localScale.z));
			transform.localRotation = Quaternion.identity;
			transform.localPosition = go.transform.InverseTransformPoint(val2.position);
			MeshFilter val4 = val3.AddComponent<MeshFilter>();
			val4.sharedMesh = val;
			MeshRenderer val5 = val3.AddComponent<MeshRenderer>();
			((Renderer)val5).sharedMaterials = MaterialsFor(target, skin, val, val2);
			((Renderer)val5).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)val5).receiveShadows = true;
			((Renderer)val5).lightProbeUsage = (LightProbeUsage)1;
			((Renderer)val5).reflectionProbeUsage = (ReflectionProbeUsage)1;
			MeshRenderer[] componentsInChildren = ((Component)val2).GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val6 in componentsInChildren)
			{
				if ((Object)(object)val6 != (Object)null && (Object)(object)val6 != (Object)(object)val5 && ((Component)val6).gameObject.layer != 21)
				{
					((Renderer)val6).forceRenderingOff = true;
				}
			}
			return true;
		}

		private static Mesh? MeshFor(PufferTarget target)
		{
			//IL_00bb: 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)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			string text = target.ModelFile + ".obj";
			if (Cache.TryGetValue(text, out Mesh value))
			{
				return value;
			}
			Mesh val = null;
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				string text2 = ((directoryName == null) ? null : Path.Combine(directoryName, text));
				if (text2 != null && File.Exists(text2))
				{
					val = Parse(File.ReadAllLines(text2), text, out Texture2D baked, out string[] groupNames);
					BakedTextures[text] = baked;
					Groups[text] = groupNames;
					if ((Object)(object)val != (Object)null)
					{
						ManualLogSource log = Plugin.Log;
						string text3 = $"Custom model {text}: {val.vertexCount} verts, ";
						object arg = val.triangles.Length / 3;
						Bounds bounds = val.bounds;
						log.LogInfo((object)(text3 + $"{arg} tris, bounds {((Bounds)(ref bounds)).size}" + (((Object)(object)baked != (Object)null) ? ", vertex colours baked to texture." : ".")));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not load " + text + ": " + ex.Message));
				val = null;
			}
			Cache[text] = val;
			return val;
		}

		private static Mesh? Parse(string[] lines, string name, out Texture2D? baked, out string[] groupNames)
		{
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_0415: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0437: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			baked = null;
			groupNames = new string[1] { "body" };
			List<Vector3> list = new List<Vector3>();
			List<Color> list2 = new List<Color>();
			List<Vector2> list3 = new List<Vector2>();
			List<Vector3> list4 = new List<Vector3>();
			List<Vector3> list5 = new List<Vector3>();
			List<Color> list6 = new List<Color>();
			List<Vector2> list7 = new List<Vector2>();
			List<Vector3> list8 = new List<Vector3>();
			List<int> list9 = new List<int>();
			List<(string, List<int>)> list10 = new List<(string, List<int>)>();
			List<int> list11 = new List<int>();
			list10.Add(("body", list11));
			bool flag = false;
			Dictionary<(int, int, int), int> corners = new Dictionary<(int, int, int), int>();
			List<int> list12 = new List<int>();
			bool allNormals = true;
			bool allUvs = true;
			Color val = default(Color);
			foreach (string text in lines)
			{
				string text2 = text;
				int num = text2.IndexOf('#');
				if (num >= 0)
				{
					text2 = text2.Substring(0, num);
				}
				string[] array = text2.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length == 0)
				{
					continue;
				}
				switch (array[0])
				{
				case "v":
					if (array.Length >= 4)
					{
						list.Add(new Vector3(0f - F(array[1]), F(array[2]), F(array[3])));
						if (array.Length >= 7)
						{
							((Color)(ref val))..ctor(F(array[4]), F(array[5]), F(array[6]), 1f);
							list2.Add(val);
							flag |= val.r < 0.98f || val.g < 0.98f || val.b < 0.98f;
						}
						else
						{
							list2.Add(Color.white);
						}
					}
					break;
				case "vt":
					if (array.Length >= 3)
					{
						list3.Add(new Vector2(F(array[1]), F(array[2])));
					}
					break;
				case "vn":
					if (array.Length >= 4)
					{
						list4.Add(new Vector3(0f - F(array[1]), F(array[2]), F(array[3])));
					}
					break;
				case "usemtl":
					if (array.Length < 2)
					{
						break;
					}
					list11 = null;
					foreach (var item in list10)
					{
						if (item.Item1 == array[1])
						{
							list11 = item.Item2;
							break;
						}
					}
					if (list11 == null)
					{
						list11 = new List<int>();
						list10.Add((array[1], list11));
					}
					break;
				case "f":
					if (array.Length >= 4)
					{
						list12.Clear();
						for (int j = 1; j < array.Length; j++)
						{
							list12.Add(Corner(array[j], list, list2, list3, list4, corners, list5, list6, list7, list8, ref allUvs, ref allNormals));
						}
						for (int k = 1; k < list12.Count - 1; k++)
						{
							list9.Add(list12[0]);
							list9.Add(list12[k + 1]);
							list9.Add(list12[k]);
							list11.Add(list12[0]);
							list11.Add(list12[k + 1]);
							list11.Add(list12[k]);
						}
					}
					break;
				}
			}
			if (list5.Count == 0 || list9.Count == 0)
			{
				Plugin.Log.LogWarning((object)(name + " contains no usable geometry."));
				return null;
			}
			if (flag && !allUvs)
			{
				ExpandToAtlas(list5, list6, list7, list8, list9, allNormals);
				allUvs = true;
				list10.Clear();
				list10.Add(("body", new List<int>(list9)));
				Plugin.Log.LogInfo((object)(name + ": no UVs, generated a triangle atlas for its vertex colours."));
			}
			Mesh val2 = new Mesh
			{
				name = "PeakPuffer_" + name,
				hideFlags = (HideFlags)61,
				indexFormat = (IndexFormat)(list5.Count > 65535)
			};
			val2.SetVertices(list5);
			if (allUvs)
			{
				val2.SetUVs(0, list7);
			}
			List<(string, List<int>)> list13 = new List<(string, List<int>)>();
			foreach (var item2 in list10)
			{
				if (item2.Item2.Count > 0)
				{
					list13.Add(item2);
				}
			}
			if (list13.Count == 0)
			{
				list13.Add(("body", list9));
			}
			val2.subMeshCount = list13.Count;
			groupNames = new string[list13.Count];
			for (int l = 0; l < list13.Count; l++)
			{
				val2.SetTriangles(list13[l].Item2, l);
				groupNames[l] = list13[l].Item1;
			}
			if (allNormals)
			{
				val2.SetNormals(list8);
			}
			else
			{
				val2.RecalculateNormals();
			}
			val2.RecalculateBounds();
			if (flag && allUvs)
			{
				baked = BakeVertexColours(list7, list6, list9, name);
			}
			return val2;
		}

		private static void ExpandToAtlas(List<Vector3> pos, List<Color> colour, List<Vector2> uv, List<Vector3> norm, List<int> triangles, bool hadNormals)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_0109: 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)
			int num = triangles.Count / 3;
			int num2 = Mathf.CeilToInt(Mathf.Sqrt((float)num));
			float num3 = 1f / (float)num2;
			float num4 = num3 * 0.15f;
			List<Vector3> list = new List<Vector3>(triangles.Count);
			List<Color> list2 = new List<Color>(triangles.Count);
			List<Vector2> list3 = new List<Vector2>(triangles.Count);
			List<Vector3> list4 = new List<Vector3>(triangles.Count);
			for (int i = 0; i < num; i++)
			{
				float num5 = (float)(i % num2) * num3 + num4;
				float num6 = (float)(i / num2) * num3 + num4;
				float num7 = (float)(i % num2 + 1) * num3 - num4;
				float num8 = (float)(i / num2 + 1) * num3 - num4;
				Vector2[] array = (Vector2[])(object)new Vector2[3]
				{
					new Vector2(num5, num6),
					new Vector2(num7, num6),
					new Vector2(num5, num8)
				};
				for (int j = 0; j < 3; j++)
				{
					int index = triangles[i * 3 + j];
					list.Add(pos[index]);
					list2.Add(colour[index]);
					list3.Add(array[j]);
					if (hadNormals)
					{
						list4.Add(norm[index]);
					}
				}
			}
			pos.Clear();
			pos.AddRange(list);
			colour.Clear();
			colour.AddRange(list2);
			uv.Clear();
			uv.AddRange(list3);
			norm.Clear();
			norm.AddRange(list4);
			triangles.Clear();
			for (int k = 0; k < list.Count; k++)
			{
				triangles.Add(k);
			}
		}

		private static Texture2D BakeVertexColours(List<Vector2> uvs, List<Color> colours, List<int> triangles, string name)
		{
			//IL_003f: 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)
			//IL_004e: 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_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_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_0078: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_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_00cb: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: 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_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Expected O, but got Unknown
			//IL_0194: 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_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			Color32[] array = (Color32[])(object)new Color32[262144];
			bool[] array2 = new bool[262144];
			for (int i = 0; i < triangles.Count; i += 3)
			{
				int index = triangles[i];
				int index2 = triangles[i + 1];
				int index3 = triangles[i + 2];
				Vector2 val = uvs[index] * 511f;
				Vector2 val2 = uvs[index2] * 511f;
				Vector2 val3 = uvs[index3] * 511f;
				float num = (val2.x - val.x) * (val3.y - val.y) - (val3.x - val.x) * (val2.y - val.y);
				if (Mathf.Abs(num) < 1E-06f)
				{
					continue;
				}
				int num2 = Mathf.Max(0, Mathf.FloorToInt(Mathf.Min(val.x, Mathf.Min(val2.x, val3.x))));
				int num3 = Mathf.Min(511, Mathf.CeilToInt(Mathf.Max(val.x, Mathf.Max(val2.x, val3.x))));
				int num4 = Mathf.Max(0, Mathf.FloorToInt(Mathf.Min(val.y, Mathf.Min(val2.y, val3.y))));
				int num5 = Mathf.Min(511, Mathf.CeilToInt(Mathf.Max(val.y, Mathf.Max(val2.y, val3.y))));
				for (int j = num4; j <= num5; j++)
				{
					for (int k = num2; k <= num3; k++)
					{
						float num6 = ((val2.x - val.x) * ((float)j - val.y) - ((float)k - val.x) * (val2.y - val.y)) / num;
						float num7 = (((float)k - val.x) * (val3.y - val.y) - (val3.x - val.x) * ((float)j - val.y)) / num;
						float num8 = 1f - num6 - num7;
						if (!(num6 < -0.001f) && !(num7 < -0.001f) && !(num8 < -0.001f))
						{
							Color val4 = colours[index3] * num6 + colours[index2] * num7 + colours[index] * num8;
							val4.a = 1f;
							int num9 = j * 512 + k;
							array[num9] = Color32.op_Implicit(val4);
							array2[num9] = true;
						}
					}
				}
			}
			for (int l = 0; l < 2; l++)
			{
				Color32[] array3 = (Color32[])array.Clone();
				bool[] array4 = (bool[])array2.Clone();
				for (int m = 0; m < 512; m++)
				{
					for (int n = 0; n < 512; n++)
					{
						int num10 = m * 512 + n;
						if (array2[num10])
						{
							continue;
						}
						for (int num11 = 0; num11 < 4; num11++)
						{
							int num12 = n + num11 switch
							{
								1 => -1, 
								0 => 1, 
								_ => 0, 
							};
							int num13 = m + num11 switch
							{
								3 => -1, 
								2 => 1, 
								_ => 0, 
							};
							if (num12 >= 0 && num13 >= 0 && num12 < 512 && num13 < 512)
							{
								int num14 = num13 * 512 + num12;
								if (array2[num14])
								{
									array3[num10] = array[num14];
									array4[num10] = true;
									break;
								}
							}
						}
					}
				}
				array = array3;
				array2 = array4;
			}
			Texture2D val5 = new Texture2D(512, 512, (TextureFormat)4, true, false)
			{
				name = "PeakPuffer_VertexBake_" + name,
				hideFlags = (HideFlags)61,
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)1,
				anisoLevel = 4
			};
			val5.SetPixels32(array);
			val5.Apply(true, true);
			return val5;
		}

		private static Texture2D? ModelTextureFor(PufferTarget target)
		{
			//IL_0055: 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_0070: 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_007f: 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)
			//IL_008e: Expected O, but got Unknown
			if (ModelTextures.TryGetValue(target.ModelFile, out Texture2D value))
			{
				return value;
			}
			Texture2D val = null;
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				string text = ((directoryName == null) ? null : Path.Combine(directoryName, target.ModelFile + ".png"));
				if (text != null && File.Exists(text))
				{
					val = new Texture2D(2, 2, (TextureFormat)4, true, false)
					{
						name = "PeakPuffer_Model_" + target.Id,
						hideFlags = (HideFlags)61,
						wrapMode = (TextureWrapMode)1,
						filterMode = (FilterMode)1,
						anisoLevel = 4
					};
					if (ImageConversion.LoadImage(val, File.ReadAllBytes(text), true))
					{
						Plugin.Log.LogInfo((object)("Model texture " + target.ModelFile + ".png loaded."));
					}
					else
					{
						Object.Destroy((Object)(object)val);
						val = null;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read " + target.ModelFile + ".png: " + ex.Message));
				val = null;
			}
			ModelTextures[target.ModelFile] = val;
			return val;
		}

		private static Material[] MaterialsFor(PufferTarget target, PufferSkin skin, Mesh mesh, Transform visual)
		{
			Material val = MaterialFor(target, skin);
			Material[] array = (Material[])(object)new Material[Mathf.Max(mesh.subMeshCount, 1)];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = val;
			}
			return array;
		}

		private static Material MaterialFor(PufferTarget target, PufferSkin skin)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0069: Expected O, but got Unknown
			//IL_00d3: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			string key = target.ModelFile + ".obj";
			Texture2D val = ModelTextureFor(target);
			if ((Object)(object)val != (Object)null)
			{
				if (BakedMaterials.TryGetValue(key, out Material value))
				{
					return value;
				}
				Material val2 = new Material(skin.Material)
				{
					name = ((Object)skin.Material).name + "_" + target.ModelFile,
					hideFlags = (HideFlags)61
				};
				val2.SetTexture(Shader.PropertyToID("_BaseMap"), (Texture)(object)val);
				val2.SetTexture(Shader.PropertyToID("_MainTex"), (Texture)(object)val);
				BakedMaterials[key] = val2;
				return val2;
			}
			if (!BakedTextures.TryGetValue(key, out Texture2D value2) || (Object)(object)value2 == (Object)null)
			{
				return skin.Material;
			}
			if (BakedMaterials.TryGetValue(key, out Material value3))
			{
				return value3;
			}
			Material val3 = new Material(skin.Material)
			{
				name = ((Object)skin.Material).name + "_VertexBake",
				hideFlags = (HideFlags)61
			};
			val3.SetTexture(Shader.PropertyToID("_BaseMap"), (Texture)(object)value2);
			val3.SetTexture(Shader.PropertyToID("_MainTex"), (Texture)(object)value2);
			BakedMaterials[key] = val3;
			return val3;
		}

		private static int Corner(string token, List<Vector3> positions, List<Color> colours, List<Vector2> uvs, List<Vector3> normals, Dictionary<(int, int, int), int> corners, List<Vector3> outPos, List<Color> outColour, List<Vector2> outUv, List<Vector3> outNorm, ref bool allUvs, ref bool allNormals)
		{
			//IL_0098: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			string[] array = token.Split('/');
			int num = Resolve(array[0], positions.Count);
			int num2 = ((array.Length > 1) ? Resolve(array[1], uvs.Count) : (-1));
			int num3 = ((array.Length > 2) ? Resolve(array[2], normals.Count) : (-1));
			allUvs &= num2 >= 0;
			allNormals &= num3 >= 0;
			(int, int, int) key = (num, num2, num3);
			if (corners.TryGetValue(key, out var value))
			{
				return value;
			}
			value = (corners[key] = outPos.Count);
			outPos.Add(positions[num]);
			outColour.Add(colours[num]);
			outUv.Add((num2 >= 0) ? uvs[num2] : Vector2.zero);
			outNorm.Add((num3 >= 0) ? normals[num3] : Vector3.zero);
			return value;
		}

		private static int Resolve(string s, int count)
		{
			if (string.IsNullOrEmpty(s))
			{
				return -1;
			}
			int num = int.Parse(s, CultureInfo.InvariantCulture);
			if (num <= 0)
			{
				return count + num;
			}
			return num - 1;
		}

		private static float F(string s)
		{
			return float.Parse(s, CultureInfo.InvariantCulture);
		}
	}
	internal enum TargetKind
	{
		Hazard,
		Item
	}
	internal sealed class PufferTarget
	{
		internal string Id { get; }

		internal string ObjectName { get; }

		internal TargetKind Kind { get; }

		internal string Texture { get; }

		internal string? VisualChild { get; }

		internal string Description { get; }

		internal float SizeMultiplier { get; }

		internal bool Glow { get; }

		internal bool NoPush { get; }

		internal bool NoHide { get; }

		internal string ModelFile { get; }

		internal bool Enabled { get; set; } = true;

		internal bool Broken { get; set; }

		internal PufferTarget(string id, string objectName, TargetKind kind, string texture, string? visualChild, string description, float sizeMultiplier = 1f, bool glow = false, bool noPush = false, bool noHide = false, string? modelFile = null)
		{
			Id = id;
			ObjectName = objectName;
			Kind = kind;
			Texture = texture;
			VisualChild = visualChild;
			Description = description;
			SizeMultiplier = sizeMultiplier;
			Glow = glow;
			NoPush = noPush;
			NoHide = noHide;
			ModelFile = modelFile ?? Path.GetFileNameWithoutExtension(texture);
		}
	}
	internal static class PufferTargets
	{
		internal static readonly PufferTarget[] All = new PufferTarget[15]
		{
			new PufferTarget("ExplosiveSporeBomb", "Jungle_SporeMushroomExplo", TargetKind.Hazard, "puffer.png", null, "The exploding spore bomb in the Tropics.", 1.35f),
			new PufferTarget("PoisonSporeBomb", "Jungle_SporeMushroom", TargetKind.Hazard, "puffer-poison.png", null, "The poison spore bomb in the Tropics.", 1.35f),
			new PufferTarget("SwingingSpikeball", "SwingingAxe", TargetKind.Hazard, "puffer-spikeball.png", "Axe", "The swinging spiked ball in the Citadel."),
			new PufferTarget("BigGhost", "GhostBall", TargetKind.Hazard, "puffer-ghost.png", "BigDumbSphere", "The Big Ghost that chases you in the Citadel.", 0.45f, glow: true, noPush: false, noHide: true),
			new PufferTarget("Egg", "Egg", TargetKind.Item, "puffer-egg.png", "Egg_SunnySideUp", "The cooked egg."),
			new PufferTarget("SmallEgg", "EggRaven", TargetKind.Item, "puffer-egg.png", "Egg_SunnySideUp", "The cooked small egg.", 1f, glow: false, noPush: false, noHide: false, "puffer-egg-small"),
			new PufferTarget("RedPrickleberry", "Prickleberry_Red", TargetKind.Item, "puffer-prickleberry-red.png", "Prickleberry", "The red prickleberry."),
			new PufferTarget("GoldPrickleberry", "Prickleberry_Gold", TargetKind.Item, "puffer-prickleberry-gold.png", "Prickleberry", "The gold prickleberry."),
			new PufferTarget("OrangeWinterberry", "Winterberry Orange", TargetKind.Item, "puffer-winterberry-orange.png", "Yuzu Berry", "The orange winterberry."),
			new PufferTarget("YellowWinterberry", "Winterberry Yellow", TargetKind.Item, "puffer-winterberry-yellow.png", "Yuzu Berry", "The yellow winterberry."),
			new PufferTarget("RedCrispberry", "Apple Berry Red", TargetKind.Item, "puffer.png", "Apple Berry", "The red crispberry.", 1f, glow: false, noPush: false, noHide: false, "puffer-crispberry-red"),
			new PufferTarget("GreenCrispberry", "Apple Berry Green", TargetKind.Item, "puffer.png", "Apple Berry", "The green crispberry.", 1f, glow: false, noPush: false, noHide: false, "puffer-crispberry-green"),
			new PufferTarget("YellowCrispberry", "Apple Berry Yellow", TargetKind.Item, "puffer.png", "Apple Berry", "The yellow crispberry.", 1f, glow: false, noPush: false, noHide: false, "puffer-crispberry-yellow"),
			new PufferTarget("WarpFungus", "WarpFungus", TargetKind.Item, "puffer-warpfungus.png", "WarpShroom", "The warp fungus."),
			new PufferTarget("Coconut", "Item_Coconut", TargetKind.Item, "puffer-coconut.png", "Mesh_CoconutGreen", "The whole coconut.", 0.87f)
		};

		private static readonly Dictionary<string, PufferTarget> ByName = Build();

		private static Dictionary<string, PufferTarget> Build()
		{
			Dictionary<string, PufferTarget> dictionary = new Dictionary<string, PufferTarget>(StringComparer.Ordinal);
			PufferTarget[] all = All;
			foreach (PufferTarget pufferTarget in all)
			{
				dictionary[pufferTarget.ObjectName] = pufferTarget;
			}
			return dictionary;
		}

		internal static PufferTarget? Match(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return null;
			}
			if (!ByName.TryGetValue(BaseName(((Object)go).name), out PufferTarget value) || !value.Enabled || value.Broken)
			{
				return null;
			}
			return value;
		}

		internal static string BaseName(string name)
		{
			string text = name;
			while (text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - "(Clone)".Length).TrimEnd();
			}
			while (text.Length > 2 && text[text.Length - 1] == ')')
			{
				int num = text.LastIndexOf('(');
				if (num <= 0 || num == text.Length - 2)
				{
					break;
				}
				bool flag = true;
				for (int i = num + 1; i < text.Length - 1; i++)
				{
					if (!char.IsDigit(text[i]))
					{
						flag = false;
						break;
					}
				}
				if (!flag)
				{
					break;
				}
				text = text.Substring(0, num).TrimEnd();
			}
			return text;
		}
	}
	internal static class Replacer
	{
		internal sealed class PufferTag : MonoBehaviour
		{
		}

		internal const int MapLayer = 21;

		internal static int Converted { get; private set; }

		internal static Transform? FindVisual(GameObject root, PufferTarget target)
		{
			if (target.VisualChild == null)
			{
				return root.transform;
			}
			Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && string.Equals(PufferTargets.BaseName(((Object)val).name), target.VisualChild, StringComparison.Ordinal))
				{
					return val;
				}
			}
			return null;
		}

		internal static void Convert(GameObject go)
		{
			if (!Plugin.Enabled || (Object)(object)go == (Object)null || (Object)(object)go.GetComponent<PufferTag>() != (Object)null)
			{
				return;
			}
			PufferTarget pufferTarget = PufferTargets.Match(go);
			if (pufferTarget == null)
			{
				return;
			}
			PufferSkin pufferSkin = PufferAssets.For(pufferTarget);
			if (pufferSkin == null)
			{
				return;
			}
			bool flag = pufferTarget.Kind == TargetKind.Item;
			if (!PufferModel.TryAttach(go, pufferTarget, pufferSkin) && !((flag && !Plugin.ItemBillboards) ? PufferImpostor.Attach(go, pufferTarget, pufferSkin, Plugin.ItemScale * pufferTarget.SizeMultiplier) : AttachBillboard(go, pufferTarget, pufferSkin, flag)))
			{
				Plugin.Log.LogWarning((object)("Skipped '" + ((Object)go).name + "' (" + pufferTarget.Id + "): no measurable geometry."));
				return;
			}
			go.AddComponent<PufferTag>();
			Converted++;
			if (pufferTarget.Kind == TargetKind.Item)
			{
				Item component = go.GetComponent<Item>();
				if ((Object)(object)component != (Object)null)
				{
					ItemIcons.ApplyToInstance(component, pufferSkin, pufferTarget);
				}
			}
		}

		private static bool AttachBillboard(GameObject go, PufferTarget target, PufferSkin skin, bool isItem)
		{
			float scale = (isItem ? Plugin.ItemScale : Plugin.Scale) * target.SizeMultiplier;
			float pushOut = (target.NoPush ? 0f : Plugin.PushOut);
			if ((Object)(object)PufferBillboard.Attach(go, target, skin, scale, pushOut) == (Object)null)
			{
				return false;
			}
			if (isItem)
			{
				return true;
			}
			if (Plugin.HideOriginal && !target.NoHide)
			{
				MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val in componentsInChildren)
				{
					if ((Object)(object)val != (Object)null && ((Component)val).gameObject.layer != 21)
					{
						((Renderer)val).shadowCastingMode = (ShadowCastingMode)3;
					}
				}
			}
			return true;
		}

		internal static void SweepLoadedScene()
		{
			if (!Plugin.Enabled)
			{
				return;
			}
			ItemIcons.ApplyToPrefabs();
			int converted = Converted;
			try
			{
				TriggerEvent[] array = Object.FindObjectsByType<TriggerEvent>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				foreach (TriggerEvent val in array)
				{
					if ((Object)(object)val != (Object)null)
					{
						Convert(((Component)val).gameObject);
					}
				}
				SwingingAxe[] array2 = Object.FindObjectsByType<SwingingAxe>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				foreach (SwingingAxe val2 in array2)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						Convert(((Component)val2).gameObject);
					}
				}
				GhostBall[] array3 = Object.FindObjectsByType<GhostBall>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				foreach (GhostBall val3 in array3)
				{
					if ((Object)(object)val3 != (Object)null)
					{
						Convert(((Component)val3).gameObject);
					}
				}
				Item[] array4 = Object.FindObjectsByType<Item>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				foreach (Item val4 in array4)
				{
					if ((Object)(object)val4 != (Object)null)
					{
						Convert(((Component)val4).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Scene sweep failed: " + ex.Message));
				return;
			}
			if (Converted > converted)
			{
				Plugin.Log.LogInfo((object)$"Swept scene and replaced {Converted - converted} object(s).");
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}