Decompiled source of BlirUBoat v1.0.0

BepInEx/plugins/Stendari-BlirUBoat/BlirUBoat.dll

Decompiled a day 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.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Broadcast;
using FishNet.Connection;
using FishNet.Serializing;
using FishNet.Transporting;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BlirUBoat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+faaaf265c0d7028c431d7cc2f1491e5751925c20")]
[assembly: AssemblyProduct("BlirUBoat")]
[assembly: AssemblyTitle("BlirUBoat")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BlirUBoat
{
	internal static class BoatProps
	{
		private struct Placement
		{
			public Vector3 Position;

			public Quaternion Rotation;
		}

		private const string RootName = "BlirUBoat_Props";

		private const float PlankThickness = 0.09f;

		private static Mesh _cubeTemplate;

		private static Shader _cachedShader;

		public static float PlankThicknessMetres => 0.09f;

		private static float PlankTopY => 0.09f;

		public static void Attach(Boat boat)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00a8: 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_00e1: 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_0132: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)boat == (Object)null)
			{
				return;
			}
			Transform val = ResolveVisualRoot(boat);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Could not resolve the boat's visual root; props not attached.");
				return;
			}
			Transform val2 = val.Find("BlirUBoat_Props");
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val2).gameObject);
			}
			Placement? placement = FindBowPlacement(boat, val);
			if (!placement.HasValue)
			{
				Plugin.Log.LogWarning((object)"Could not locate the bow; props not attached.");
				return;
			}
			float scale = Mathf.Max(0.1f, ModConfig.PropScale.Value);
			GameObject val3 = new GameObject("BlirUBoat_Props");
			val3.transform.SetParent(val, false);
			val3.transform.localPosition = placement.Value.Position;
			val3.transform.localRotation = placement.Value.Rotation;
			float num = ResolvePlankWidth(val);
			Material material = MakeMaterial(new Color(0.4f, 0.26f, 0.15f));
			Material white = MakeMaterial(new Color(0.93f, 0.92f, 0.89f));
			Material red = MakeMaterial(new Color(0.7f, 0.08f, 0.1f));
			Material tobacco = MakeMaterial(new Color(0.85f, 0.68f, 0.36f));
			Material plateMat = MakeMaterial(new Color(0.16f, 0.16f, 0.18f));
			Material capMat = MakeMaterial(new Color(0.78f, 0.09f, 0.09f));
			BuildPlank(val3.transform, num, material);
			Transform buttonCap = BuildButton(val3.transform, num, scale, plateMat, capMat);
			BuildPack(val3.transform, num, scale, white, red, tobacco, buttonCap);
			BuildLighter(val3.transform, num, scale);
			Plugin.Log.LogInfo((object)($"Bow props attached under '{((Object)val).name}' at local {val3.transform.localPosition}, " + $"plank width {num:F2}m."));
		}

		private static float ResolvePlankWidth(Transform visualRoot)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			float value = ModConfig.PlankWidthOverride.Value;
			if (value > 0.01f)
			{
				return value;
			}
			Bounds? val = ComputeLocalBounds(visualRoot);
			float num;
			if (!val.HasValue)
			{
				num = 3f;
			}
			else
			{
				Bounds valueOrDefault = val.GetValueOrDefault();
				num = ((Bounds)(ref valueOrDefault)).size.z;
			}
			return num * 0.34f;
		}

		private static Transform ResolveVisualRoot(Boat boat)
		{
			if ((Object)(object)boat.VisualBoat != (Object)null)
			{
				return boat.VisualBoat;
			}
			if ((Object)(object)boat.VisualPhysicsRig != (Object)null)
			{
				return ((Component)boat.VisualPhysicsRig).transform;
			}
			return ((Component)boat).transform;
		}

		private static Placement? FindBowPlacement(Boat boat, Transform visualRoot)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0031: 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_0044: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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_00d9: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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)
			//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_0109: 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_0125: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: 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_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_018d: 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_01af: 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_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			Bounds? val = ComputeLocalBounds(visualRoot);
			if (!val.HasValue)
			{
				return null;
			}
			Bounds value = val.Value;
			bool flag = ((Bounds)(ref value)).size.x >= ((Bounds)(ref value)).size.z;
			Vector3 val2 = (flag ? Vector3.right : Vector3.forward);
			float num = (flag ? ((Bounds)(ref value)).size.x : ((Bounds)(ref value)).size.z) * 0.5f;
			Transform val3 = FindPropeller(boat) ?? boat.DriverPos;
			if ((Object)(object)val3 != (Object)null)
			{
				if (Vector3.Dot(visualRoot.InverseTransformPoint(val3.position) - ((Bounds)(ref value)).center, val2) > 0f)
				{
					val2 = -val2;
				}
			}
			else
			{
				Plugin.Log.LogWarning((object)"No propeller or driver position found; bow direction is a guess.");
			}
			Vector3 up = Vector3.up;
			Vector3 val4 = Vector3.Cross(up, val2);
			Vector3 normalized = ((Vector3)(ref val4)).normalized;
			Vector3 val5 = ((Bounds)(ref value)).center + val2 * (num + ModConfig.OffsetForward.Value) + normalized * ModConfig.OffsetSide.Value;
			val5.y = ((Bounds)(ref value)).min.y + ((Bounds)(ref value)).size.y * ModConfig.PlankHeightFraction.Value;
			Plugin.Log.LogInfo((object)($"Boat bounds center={((Bounds)(ref value)).center} size={((Bounds)(ref value)).size}; forward={val2} " + string.Format("(long axis {0}); props at {1}.", flag ? "X" : "Z", val5)));
			return new Placement
			{
				Position = val5,
				Rotation = Quaternion.LookRotation(val2, up)
			};
		}

		private static Transform FindPropeller(Boat boat)
		{
			if (!(AccessTools.Field(typeof(Boat), "_motors")?.GetValue(boat) is IEnumerable enumerable))
			{
				return null;
			}
			foreach (object item in enumerable)
			{
				BoatMotor val = (BoatMotor)((item is BoatMotor) ? item : null);
				if (val != null && (Object)(object)val.Propeller != (Object)null)
				{
					return val.Propeller;
				}
			}
			return null;
		}

		private static Bounds? ComputeLocalBounds(Transform visualRoot)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00ba: 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_00fa: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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_0116: 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)
			MeshRenderer[] array = (from r in ((Component)visualRoot).GetComponentsInChildren<MeshRenderer>()
				where (Object)(object)r != (Object)null && ((Renderer)r).enabled
				select r).ToArray();
			if (array.Length == 0)
			{
				return null;
			}
			bool flag = false;
			Bounds value = default(Bounds);
			MeshRenderer[] array2 = array;
			foreach (MeshRenderer val in array2)
			{
				MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
				if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null)
				{
					continue;
				}
				Matrix4x4 val2 = visualRoot.worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
				Bounds bounds = component.sharedMesh.bounds;
				for (int num2 = 0; num2 < 8; num2++)
				{
					Vector3 val3 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3(((num2 & 1) == 0) ? (-1f) : 1f, ((num2 & 2) == 0) ? (-1f) : 1f, ((num2 & 4) == 0) ? (-1f) : 1f));
					Vector3 val4 = ((Matrix4x4)(ref val2)).MultiplyPoint3x4(val3);
					if (!flag)
					{
						((Bounds)(ref value))..ctor(val4, Vector3.zero);
						flag = true;
					}
					else
					{
						((Bounds)(ref value)).Encapsulate(val4);
					}
				}
			}
			if (!flag)
			{
				return null;
			}
			return value;
		}

		private static void BuildPlank(Transform parent, float width, Material material)
		{
			//IL_0003: 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)
			GameObject obj = MakePrimitive((PrimitiveType)3, parent, material, Vector3.one, new Vector3(0f, 0.045f, 0f));
			((Object)obj).name = "Plank";
			ShapePlank(obj, width, width, ModConfig.PlankLength.Value);
			obj.AddComponent<PlankFitter>();
		}

		public static void ShapePlank(GameObject plank, float widthAft, float widthFore, float depth)
		{
			//IL_005c: 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_0063: 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_008f: 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_00a5: 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)
			MeshFilter component = plank.GetComponent<MeshFilter>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null))
			{
				if ((Object)(object)_cubeTemplate == (Object)null)
				{
					_cubeTemplate = component.sharedMesh;
				}
				Mesh val = Object.Instantiate<Mesh>(_cubeTemplate);
				((Object)val).name = "BlirUBoat_Thwart";
				Vector3[] vertices = val.vertices;
				for (int i = 0; i < vertices.Length; i++)
				{
					Vector3 val2 = vertices[i];
					float num = Mathf.Clamp01(val2.z + 0.5f);
					float num2 = Mathf.Lerp(widthAft, widthFore, num);
					vertices[i] = new Vector3(val2.x * num2, val2.y * 0.09f, val2.z * depth);
				}
				val.vertices = vertices;
				val.RecalculateNormals();
				val.RecalculateBounds();
				Mesh sharedMesh = component.sharedMesh;
				component.sharedMesh = val;
				if ((Object)(object)sharedMesh != (Object)null && ((Object)sharedMesh).name == "BlirUBoat_Thwart")
				{
					Object.Destroy((Object)(object)sharedMesh);
				}
			}
		}

		private static Transform BuildButton(Transform parent, float plankWidth, float scale, Material plateMat, Material capMat)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002f: 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_0056: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			GameObject val = new GameObject("Button");
			val.transform.SetParent(parent, false);
			val.transform.localPosition = new Vector3(plankWidth * 0.28f, 0f, 0f);
			((Object)MakePrimitive((PrimitiveType)3, val.transform, plateMat, new Vector3(0.095f, 0.018f, 0.095f) * scale, new Vector3(0f, PlankTopY + 0.009f * scale, 0f))).name = "ButtonBase";
			GameObject obj = MakePrimitive((PrimitiveType)2, val.transform, capMat, new Vector3(0.055f, 0.006f, 0.055f) * scale, new Vector3(0f, PlankTopY + 0.024f * scale, 0f));
			((Object)obj).name = "ButtonCap";
			return obj.transform;
		}

		private static void BuildPack(Transform parent, float plankWidth, float scale, Material white, Material red, Material tobacco, Transform buttonCap)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0051: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Expected O, but got Unknown
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("CigarettePack");
			val.SetActive(false);
			val.transform.SetParent(parent, false);
			val.layer = LayerMask.NameToLayer("Interactable");
			val.tag = "Interactable";
			val.transform.localPosition = new Vector3(plankWidth * -0.26f, PlankTopY, 0f);
			val.transform.localRotation = Quaternion.Euler(0f, ModConfig.PackYaw.Value, 0f);
			float num = 0.049300004f;
			float num2 = 0.0357f;
			GameObject val2 = MakePrimitive((PrimitiveType)3, val.transform, white, new Vector3(0.055f, num, 0.024f) * scale, new Vector3(0f, num * 0.5f * scale, 0f));
			((Object)val2).name = "PackBody";
			GameObject val3 = MakePrimitive((PrimitiveType)3, val.transform, red, new Vector3(0.055549998f, num2, 0.02424f) * scale, new Vector3(0f, (num + num2 * 0.5f) * scale, 0f));
			((Object)val3).name = "PackLid";
			GameObject val4 = MakePrimitive((PrimitiveType)3, val.transform, red, new Vector3(0.055f, 0.024f, 0.004f) * scale, new Vector3(0f, 0.09508f * scale, -0.01056f * scale));
			((Object)val4).name = "PackFlap";
			val4.transform.localRotation = Quaternion.Euler(-32f, 0f, 0f);
			List<GameObject> list = new List<GameObject> { val2, val3, val4 };
			for (int i = 0; i < 3; i++)
			{
				float num3 = (float)(i - 1) * 0.0135f;
				GameObject val5 = MakePrimitive((PrimitiveType)2, val.transform, (i == 1) ? tobacco : white, new Vector3(0.0072f, 0.006f, 0.0072f) * scale, new Vector3(num3 * scale, 0.089f * scale, 0f));
				((Object)val5).name = $"Cigarette{i}";
				val5.transform.localRotation = Quaternion.Euler(5f * (float)(i - 1), 0f, 4f * (float)(i - 1));
				list.Add(val5);
			}
			BoxCollider val6 = val.AddComponent<BoxCollider>();
			((Collider)val6).isTrigger = true;
			val6.size = new Vector3(0.16f, 0.16f, 0.16f) * scale;
			val6.center = new Vector3(0f, 0.0425f * scale, 0f);
			GameObject val7 = new GameObject("HoverTextAnchor");
			val7.transform.SetParent(parent, false);
			val7.transform.localPosition = val.transform.localPosition + new Vector3(ModConfig.HoverTextSide.Value, ModConfig.HoverTextUp.Value, 0f);
			val.AddComponent<CigarettePackInteractable>().Configure((Collider)(object)val6, list.ToArray(), val7.transform, buttonCap);
			val.SetActive(true);
		}

		private static void BuildLighter(Transform parent, float plankWidth, float scale)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			Transform val = VanillaAssets.FindLighter();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogInfo((object)"No lighter found inside the Dynamite prefab; skipping it.");
				return;
			}
			GameObject val2 = VanillaAssets.CloneVisual(val, parent, "Lighter");
			if (!((Object)(object)val2 == (Object)null))
			{
				val2.transform.localScale = Vector3.one * scale;
				val2.transform.localPosition = new Vector3(plankWidth * -0.09f, PlankTopY, 0.03f * scale);
				val2.transform.localRotation = Quaternion.Euler(0f, 68f, 0f);
				SeatOnParentSurface(val2);
			}
		}

		private static void SeatOnParentSurface(GameObject go)
		{
			//IL_000f: 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_0026: 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_004f: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>();
			if (componentsInChildren.Length != 0)
			{
				Bounds bounds = componentsInChildren[0].bounds;
				Renderer[] array = componentsInChildren;
				foreach (Renderer val in array)
				{
					((Bounds)(ref bounds)).Encapsulate(val.bounds);
				}
				float num = go.transform.position.y - ((Bounds)(ref bounds)).min.y;
				Transform transform = go.transform;
				transform.localPosition += new Vector3(0f, num, 0f);
			}
		}

		private static GameObject MakePrimitive(PrimitiveType type, Transform parent, Material material, Vector3 scale, Vector3 localPosition)
		{
			//IL_0000: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive(type);
			obj.transform.SetParent(parent, false);
			obj.transform.localPosition = localPosition;
			obj.transform.localScale = scale;
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Renderer component2 = obj.GetComponent<Renderer>();
			if ((Object)(object)component2 != (Object)null && (Object)(object)material != (Object)null)
			{
				component2.material = material;
			}
			return obj;
		}

		private static Material MakeMaterial(Color tint)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_002f: 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)
			Shader val = ResolveShader();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No usable shader found; props will render with the fallback material.");
				return null;
			}
			Material val2 = new Material(val);
			int num = 0;
			for (int i = 0; i < val.GetPropertyCount(); i++)
			{
				if ((int)val.GetPropertyType(i) == 0)
				{
					val2.SetColor(val.GetPropertyNameId(i), tint);
					num++;
				}
			}
			if (num == 0)
			{
				Plugin.Log.LogWarning((object)("Shader '" + ((Object)val).name + "' exposes no colour property; props will render untinted. Try a different Props.ShaderName — F9 lists the candidates."));
			}
			if (val2.HasProperty("_Smoothness"))
			{
				val2.SetFloat("_Smoothness", 0.15f);
			}
			if (val2.HasProperty("_Glossiness"))
			{
				val2.SetFloat("_Glossiness", 0.15f);
			}
			if (val2.HasProperty("_Metallic"))
			{
				val2.SetFloat("_Metallic", 0f);
			}
			return val2;
		}

		private static Shader ResolveShader()
		{
			if ((Object)(object)_cachedShader != (Object)null)
			{
				return _cachedShader;
			}
			string[] array = new string[5]
			{
				ModConfig.ShaderName.Value,
				"Universal Render Pipeline/Lit",
				"Universal Render Pipeline/Simple Lit",
				"Universal Render Pipeline/Unlit",
				"Sprites/Default"
			};
			foreach (string text in array)
			{
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				Shader val = Shader.Find(text);
				if (!((Object)(object)val == (Object)null))
				{
					if (HasBaseColour(val))
					{
						Plugin.Log.LogInfo((object)("Prop shader: '" + text + "'."));
						_cachedShader = val;
						return val;
					}
					Plugin.Log.LogInfo((object)("Shader '" + text + "' has no base colour property; trying the next candidate."));
				}
			}
			return null;
		}

		private static bool HasBaseColour(Shader shader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < shader.GetPropertyCount(); i++)
			{
				if ((int)shader.GetPropertyType(i) == 0)
				{
					string propertyName = shader.GetPropertyName(i);
					if (propertyName == "_BaseColor" || propertyName == "_Color")
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	internal class CigarettePackInteractable : Interactable
	{
		private Transform _buttonCap;

		private Vector3 _capRestPosition;

		private string _lastHoverText;

		private bool _pressing;

		public override bool InteractableWhenHoldingItem => false;

		private static bool CanUse
		{
			get
			{
				if (DiveController.CanTrigger && (Object)(object)BoatManager.Boat != (Object)null)
				{
					return BoatManager.Boat.BoatUnlocked;
				}
				return false;
			}
		}

		public void Configure(Collider interactCollider, GameObject[] outlineTargets, Transform textAnchor, Transform buttonCap)
		{
			//IL_007f: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			AccessTools.Field(typeof(Interactable), "_interactCol")?.SetValue(this, interactCollider);
			AccessTools.Field(typeof(Interactable), "_modelsToOutline")?.SetValue(this, outlineTargets);
			AccessTools.Field(typeof(Interactable), "_textTarget")?.SetValue(this, textAnchor);
			_buttonCap = buttonCap;
			_capRestPosition = (((Object)(object)buttonCap != (Object)null) ? buttonCap.localPosition : Vector3.zero);
		}

		public override void Hover()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			string text = BuildHoverText();
			if (!base._isHovering)
			{
				PlayerUI.SetLookAtText(text, ((Interactable)this).TextTarget, default(Vector3), false);
				PlayerUI.SetLookAtColor(CanUse ? Color.white : GameInfo.RedColor);
			}
			else if (text != _lastHoverText)
			{
				PlayerUI.UpdateLookAtText(text);
			}
			_lastHoverText = text;
			((Interactable)this).Hover();
		}

		public override void UnHover()
		{
			PlayerUI.HideLookAtText(_lastHoverText);
			((Interactable)this).UnHover();
		}

		public override void Interact(Player player)
		{
			if (CanUse)
			{
				((Interactable)this).Interact(player);
				if (!_pressing)
				{
					((MonoBehaviour)this).StartCoroutine(PressAnimation());
				}
				DiveNet.RequestDive();
			}
		}

		private string BuildHoverText()
		{
			if ((Object)(object)BoatManager.Boat == (Object)null || !BoatManager.Boat.BoatUnlocked)
			{
				return "Not your boat yet";
			}
			if (!DiveController.CanTrigger)
			{
				if (DiveController.Phase != DivePhase.Cooldown)
				{
					return "Too late";
				}
				return "Maybe don't";
			}
			return "Röökille\n" + SpriteManager.GetPickUpInput();
		}

		private IEnumerator PressAnimation()
		{
			_pressing = true;
			if ((Object)(object)_buttonCap != (Object)null)
			{
				for (float t = 0f; t < 0.06f; t += Time.deltaTime)
				{
					float num = Mathf.Clamp01(t / 0.06f);
					_buttonCap.localPosition = _capRestPosition - new Vector3(0f, 0.02f * num, 0f);
					yield return null;
				}
				_buttonCap.localPosition = _capRestPosition - new Vector3(0f, 0.02f, 0f);
				yield return (object)new WaitForSeconds(0.5f);
				for (float t = 0f; t < 0.25f; t += Time.deltaTime)
				{
					float num2 = Mathf.Clamp01(t / 0.25f);
					_buttonCap.localPosition = _capRestPosition - new Vector3(0f, 0.02f * (1f - num2), 0f);
					yield return null;
				}
				_buttonCap.localPosition = _capRestPosition;
			}
			_pressing = false;
		}
	}
	internal static class Diagnostics
	{
		public static void Dump()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("BlirUBoat diagnostics — " + Application.productName + " / Unity " + Application.unityVersion);
			stringBuilder.AppendLine();
			Section(stringBuilder, "AUDIO CLIPS (AudioManager._realClips)", DumpAudioClips);
			Section(stringBuilder, "ITEM PREFABS (Resources.LoadAll<Item>(\"Items\"))", DumpItems);
			Section(stringBuilder, "BOAT GEOMETRY + BOW/TRIGGER CHECK", DumpBoat);
			Section(stringBuilder, "SHADER AVAILABILITY", DumpShaders);
			Section(stringBuilder, "BOAT MATERIALS + TEXTURES", DumpBoatMaterials);
			string text = Path.Combine(Paths.ConfigPath, "BlirUBoat-diagnostics.txt");
			File.WriteAllText(text, stringBuilder.ToString());
			Plugin.Log.LogInfo((object)("Diagnostics written to " + text));
		}

		private static void Section(StringBuilder sb, string title, Action<StringBuilder> body)
		{
			sb.AppendLine(new string('=', 78));
			sb.AppendLine(title);
			sb.AppendLine(new string('=', 78));
			try
			{
				body(sb);
			}
			catch (Exception ex)
			{
				sb.AppendLine($"  FAILED: {ex}");
				Plugin.Log.LogWarning((object)("Diagnostics section '" + title + "' failed: " + ex.Message));
			}
			sb.AppendLine();
		}

		private static void DumpAudioClips(StringBuilder sb)
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(AudioManager), "_realClips");
			if (fieldInfo == null)
			{
				sb.AppendLine("  AudioManager._realClips not found — field renamed?");
				return;
			}
			if (!(fieldInfo.GetValue(null) is IDictionary dictionary))
			{
				sb.AppendLine("  _realClips was null or not a dictionary.");
				return;
			}
			IOrderedEnumerable<string> orderedEnumerable = (from object k in dictionary.Keys
				select k?.ToString() ?? "<null>").OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase);
			sb.AppendLine($"  {dictionary.Count} clips:");
			foreach (string item in orderedEnumerable)
			{
				sb.AppendLine("    " + item);
			}
		}

		private static void DumpItems(StringBuilder sb)
		{
			Item[] array = Resources.LoadAll<Item>("Items");
			sb.AppendLine($"  {array.Length} item prefabs:");
			foreach (string item in array.Select((Item i) => ((Object)i).name).OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase))
			{
				sb.AppendLine("    " + item);
			}
		}

		private static void DumpBoat(StringBuilder sb)
		{
			//IL_00fd: 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_0107: 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_0128: 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_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: 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_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			Boat boat = BoatManager.Boat;
			if ((Object)(object)boat == (Object)null)
			{
				sb.AppendLine("  No boat spawned yet — load into a save with the boat present and press the key again.");
				return;
			}
			sb.AppendLine($"  Boat: {((Object)boat).name}   BoatUnlocked={boat.BoatUnlocked}");
			sb.AppendLine("  VisualBoat: " + Describe(boat.VisualBoat));
			sb.AppendLine("  DriverPos:  " + Describe(boat.DriverPos));
			sb.AppendLine();
			if (!(AccessTools.Field(typeof(Boat), "_forcePoints")?.GetValue(boat) is Transform[] array) || array.Length == 0)
			{
				sb.AppendLine("  _forcePoints missing or empty — bow anchoring strategy needs rethinking.");
				return;
			}
			Transform transform = ((Component)boat).transform;
			sb.AppendLine($"  {array.Length} force points (boat-local space, +Z assumed forward):");
			Transform val = null;
			float num = float.NegativeInfinity;
			Transform[] array2 = array;
			foreach (Transform val2 in array2)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					Vector3 val3 = transform.InverseTransformPoint(val2.position);
					sb.AppendLine($"    {((Object)val2).name,-24} local={Fmt(val3)}");
					if (val3.z > num)
					{
						num = val3.z;
						val = val2;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				sb.AppendLine("  No usable force point found.");
				return;
			}
			sb.AppendLine();
			sb.AppendLine($"  Bow candidate (max local Z): {((Object)val).name} at local Z {num:F3}");
			BoatTrigger boatTrigger = boat.BoatTrigger;
			if ((Object)(object)boatTrigger == (Object)null)
			{
				sb.AppendLine("  BoatTrigger is null — cannot evaluate coverage.");
				return;
			}
			Collider[] componentsInChildren = ((Component)boatTrigger).GetComponentsInChildren<Collider>();
			sb.AppendLine($"  BoatTrigger '{((Object)boatTrigger).name}' has {componentsInChildren.Length} collider(s):");
			bool flag = false;
			Collider[] array3 = componentsInChildren;
			foreach (Collider val4 in array3)
			{
				Bounds bounds = val4.bounds;
				bool flag2 = ((Bounds)(ref bounds)).Contains(val.position);
				flag = flag || flag2;
				sb.AppendLine($"    {((object)val4).GetType().Name,-18} isTrigger={val4.isTrigger,-5} " + $"center={Fmt(((Bounds)(ref bounds)).center)} extents={Fmt(((Bounds)(ref bounds)).extents)} containsBow={flag2}");
			}
			sb.AppendLine();
			sb.AppendLine(flag ? "  RESULT: bow IS inside the boat trigger — vanilla OnBoat covers the button position." : "  RESULT: bow is OUTSIDE the boat trigger — drown immunity needs its own occupancy test at the bow (see RESEARCH.md §6.7).");
			sb.AppendLine("  NOTE: bounds are axis-aligned approximations; confirm by standing on the bow and checking PlayerMovement.OnBoat.");
		}

		private static void DumpShaders(StringBuilder sb)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			foreach (string item in new string[8]
			{
				ModConfig.ShaderName.Value,
				"Shader Graphs/DefaultShader",
				"Shader Graphs/LevelShader",
				"Shader Graphs/CharacterShader",
				"Universal Render Pipeline/Lit",
				"Universal Render Pipeline/Simple Lit",
				"Universal Render Pipeline/Unlit",
				"Sprites/Default"
			}.Distinct())
			{
				if (string.IsNullOrEmpty(item))
				{
					continue;
				}
				Shader val = Shader.Find(item);
				if ((Object)(object)val == (Object)null)
				{
					sb.AppendLine("  MISSING  " + item);
					continue;
				}
				List<string> list = new List<string>();
				for (int i = 0; i < val.GetPropertyCount(); i++)
				{
					if ((int)val.GetPropertyType(i) == 0)
					{
						list.Add(val.GetPropertyName(i));
					}
				}
				sb.AppendLine("  OK       " + item + "   colour properties: " + ((list.Count > 0) ? string.Join(", ", list.ToArray()) : "<none>"));
			}
		}

		private static void DumpBoatMaterials(StringBuilder sb)
		{
			//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_00be: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Invalid comparison between Unknown and I4
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			Boat boat = BoatManager.Boat;
			if ((Object)(object)boat == (Object)null)
			{
				sb.AppendLine("  No boat spawned yet.");
				return;
			}
			Transform val = (((Object)(object)boat.VisualBoat != (Object)null) ? boat.VisualBoat : ((Component)boat).transform);
			MeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<MeshRenderer>();
			sb.AppendLine($"  {componentsInChildren.Length} renderer(s) under '{((Object)val).name}':");
			MeshRenderer[] array = componentsInChildren;
			foreach (MeshRenderer val2 in array)
			{
				Material sharedMaterial = ((Renderer)val2).sharedMaterial;
				if ((Object)(object)sharedMaterial == (Object)null)
				{
					continue;
				}
				MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
				float num;
				if (!((Object)(object)component != (Object)null) || !((Object)(object)component.sharedMesh != (Object)null))
				{
					num = 0f;
				}
				else
				{
					Bounds bounds = component.sharedMesh.bounds;
					Vector3 size = ((Bounds)(ref bounds)).size;
					num = ((Vector3)(ref size)).magnitude;
				}
				float num2 = num;
				sb.AppendLine($"    {((Object)val2).name,-22} mat='{((Object)sharedMaterial).name}' shader='{((Object)sharedMaterial.shader).name}' meshSize={num2:F2}");
				Shader shader = sharedMaterial.shader;
				for (int j = 0; j < shader.GetPropertyCount(); j++)
				{
					int propertyNameId = shader.GetPropertyNameId(j);
					ShaderPropertyType propertyType = shader.GetPropertyType(j);
					if ((int)propertyType == 4)
					{
						Texture texture = sharedMaterial.GetTexture(propertyNameId);
						if ((Object)(object)texture != (Object)null)
						{
							sb.AppendLine("        tex  " + shader.GetPropertyName(j) + " = '" + ((Object)texture).name + "' " + $"({texture.width}x{texture.height})");
						}
					}
					else if ((int)propertyType == 0)
					{
						sb.AppendLine($"        col  {shader.GetPropertyName(j)} = {sharedMaterial.GetColor(propertyNameId)}");
					}
				}
			}
		}

		private static string Describe(Transform t)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)t == (Object)null))
			{
				return ((Object)t).name + " world=" + Fmt(t.position);
			}
			return "<null>";
		}

		private static string Fmt(Vector3 v)
		{
			//IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			return $"({v.x:F2}, {v.y:F2}, {v.z:F2})";
		}
	}
	internal enum DivePhase
	{
		Idle,
		Descending,
		Submerged,
		Ascending,
		Cooldown
	}
	internal static class DiveController
	{
		private const float ProportionalGain = 9f;

		private const float DerivativeGain = 5f;

		private const float MaxAcceleration = 28f;

		private static float _phaseStart;

		private static float _submergedDuration;

		private static float _currentTargetDepth;

		public static DivePhase Phase { get; private set; }

		private static float PhaseElapsed => Time.time - _phaseStart;

		public static bool Diving
		{
			get
			{
				if (Phase != DivePhase.Descending && Phase != DivePhase.Submerged)
				{
					return Phase == DivePhase.Ascending;
				}
				return true;
			}
		}

		public static bool CanTrigger => Phase == DivePhase.Idle;

		public static void ServerBeginDive()
		{
			if (!CanTrigger)
			{
				Plugin.Log.LogInfo((object)$"Dive requested but phase is {Phase}; ignoring.");
				return;
			}
			_submergedDuration = Random.Range(ModConfig.SubmergedSecondsMin.Value, Mathf.Max(ModConfig.SubmergedSecondsMin.Value, ModConfig.SubmergedSecondsMax.Value));
			EnterPhase(DivePhase.Descending);
			Plugin.Log.LogInfo((object)($"Dive started — descending over {ModConfig.DescentSeconds.Value:F1}s, " + $"holding {_submergedDuration:F1}s."));
			DiveNet.ServerAnnounceDiveStarted();
		}

		public static void Abort(string reason)
		{
			if (Phase != DivePhase.Idle)
			{
				Plugin.Log.LogInfo((object)("Dive aborted: " + reason));
				Phase = DivePhase.Idle;
				_currentTargetDepth = 0f;
				Klaxon.Stop();
			}
		}

		private static void EnterPhase(DivePhase phase)
		{
			Phase = phase;
			_phaseStart = Time.time;
		}

		public static bool ServerTick(Boat boat)
		{
			AdvancePhase();
			if (!Diving)
			{
				return false;
			}
			if ((Object)(object)boat == (Object)null)
			{
				return false;
			}
			Rigidbody hiddenPhysicsRig = boat.HiddenPhysicsRig;
			if ((Object)(object)hiddenPhysicsRig == (Object)null)
			{
				return false;
			}
			ApplyDepthControl(boat, hiddenPhysicsRig);
			KeepUpright(boat, hiddenPhysicsRig);
			ApplyUnderwaterDamping(boat, hiddenPhysicsRig);
			return true;
		}

		private static void AdvancePhase()
		{
			switch (Phase)
			{
			case DivePhase.Descending:
				if (PhaseElapsed >= ModConfig.DescentSeconds.Value)
				{
					EnterPhase(DivePhase.Submerged);
					Klaxon.Stop();
				}
				break;
			case DivePhase.Submerged:
				if (PhaseElapsed >= _submergedDuration)
				{
					EnterPhase(DivePhase.Ascending);
					Plugin.Log.LogInfo((object)"Surfacing.");
				}
				break;
			case DivePhase.Ascending:
				if (PhaseElapsed >= ModConfig.AscentSeconds.Value)
				{
					EnterPhase(DivePhase.Cooldown);
				}
				break;
			case DivePhase.Cooldown:
				if (PhaseElapsed >= ModConfig.CooldownSeconds.Value)
				{
					Phase = DivePhase.Idle;
					Plugin.Log.LogInfo((object)"Boat ready to dive again.");
				}
				break;
			}
		}

		private static float TargetDepth()
		{
			float value = ModConfig.DiveDepth.Value;
			return Phase switch
			{
				DivePhase.Descending => value * Smooth(Mathf.Clamp01(PhaseElapsed / Mathf.Max(0.01f, ModConfig.DescentSeconds.Value))), 
				DivePhase.Submerged => value, 
				DivePhase.Ascending => value * (1f - Smooth(Mathf.Clamp01(PhaseElapsed / Mathf.Max(0.01f, ModConfig.AscentSeconds.Value)))), 
				_ => 0f, 
			};
		}

		private static float Smooth(float t)
		{
			return t * t * (3f - 2f * t);
		}

		private static void ApplyDepthControl(Boat boat, Rigidbody rig)
		{
			//IL_000b: 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_0011: 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_0025: 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)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			_currentTargetDepth = TargetDepth();
			Vector3 position = rig.position;
			float num = WaterManager.GetWaterHeight(position) - _currentTargetDepth - position.y;
			float y = rig.linearVelocity.y;
			float num2 = Mathf.Clamp(num * 9f - y * 5f, -28f, 28f);
			rig.AddForce(Vector3.up * num2, (ForceMode)5);
		}

		private static void KeepUpright(Boat boat, Rigidbody rig)
		{
			//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_0053: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//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_0062: 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)
			if (AccessTools.Field(typeof(Boat), "_antiRollOverForce")?.GetValue(boat) is float num)
			{
				Quaternion val = Quaternion.Euler(0f, ((Component)rig).transform.eulerAngles.y, 0f);
				Vector3 angularVelocityToTarget = DazedUtils.GetAngularVelocityToTarget(rig.rotation, val);
				rig.AddTorque(angularVelocityToTarget * num);
			}
		}

		private static void ApplyUnderwaterDamping(Boat boat, Rigidbody rig)
		{
			object obj = AccessTools.Field(typeof(Boat), "_underwaterLinearDamp")?.GetValue(boat);
			object obj2 = AccessTools.Field(typeof(Boat), "_underwaterAngularDamp")?.GetValue(boat);
			if (obj is float linearDamping)
			{
				rig.linearDamping = linearDamping;
			}
			if (obj2 is float angularDamping)
			{
				rig.angularDamping = angularDamping;
			}
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	internal struct DiveRequestBroadcast : IBroadcast
	{
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	internal struct DiveStartedBroadcast : IBroadcast
	{
	}
	internal static class DiveNet
	{
		private static bool _serializersInstalled;

		private static bool _serverRegistered;

		private static bool _clientRegistered;

		public static bool Available { get; private set; }

		public static void RequestDive()
		{
			if (InstanceFinder.IsServerStarted)
			{
				DiveController.ServerBeginDive();
				return;
			}
			if (!Available)
			{
				Plugin.Log.LogWarning((object)"Dive requested but this client cannot reach the host (broadcast unavailable). The host must have the mod installed.");
				return;
			}
			try
			{
				InstanceFinder.ClientManager.Broadcast<DiveRequestBroadcast>(default(DiveRequestBroadcast), (Channel)0);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to send dive request: " + ex.Message));
			}
		}

		public static void ServerAnnounceDiveStarted()
		{
			if (!InstanceFinder.IsServerStarted)
			{
				return;
			}
			Klaxon.Play(((Object)(object)BoatManager.Boat != (Object)null) ? BoatManager.Boat.VisualBoat : null);
			if (!Available)
			{
				return;
			}
			try
			{
				InstanceFinder.ServerManager.Broadcast<DiveStartedBroadcast>(default(DiveStartedBroadcast), true, (Channel)0);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to announce dive to clients: " + ex.Message));
			}
		}

		public static void EnsureRegistered(bool asServer)
		{
			InstallSerializers();
			try
			{
				if (asServer && !_serverRegistered && (Object)(object)InstanceFinder.ServerManager != (Object)null)
				{
					InstanceFinder.ServerManager.RegisterBroadcast<DiveRequestBroadcast>((Action<NetworkConnection, DiveRequestBroadcast, Channel>)OnServerDiveRequest, true);
					_serverRegistered = true;
					Plugin.Log.LogInfo((object)"Registered server broadcast handler.");
				}
				if (!asServer && !_clientRegistered && (Object)(object)InstanceFinder.ClientManager != (Object)null)
				{
					InstanceFinder.ClientManager.RegisterBroadcast<DiveStartedBroadcast>((Action<DiveStartedBroadcast, Channel>)OnClientDiveStarted);
					_clientRegistered = true;
					Plugin.Log.LogInfo((object)"Registered client broadcast handler.");
				}
			}
			catch (Exception ex)
			{
				Available = false;
				Plugin.Log.LogWarning((object)("Broadcast registration failed (" + ex.Message + "). Falling back to host-only triggering."));
			}
		}

		public static void Reset()
		{
			_serverRegistered = false;
			_clientRegistered = false;
		}

		private static void InstallSerializers()
		{
			if (_serializersInstalled)
			{
				return;
			}
			try
			{
				InstallSerializer<DiveRequestBroadcast>();
				InstallSerializer<DiveStartedBroadcast>();
				_serializersInstalled = true;
				Available = true;
				Plugin.Log.LogInfo((object)"Installed FishNet broadcast serializers.");
			}
			catch (Exception ex)
			{
				Available = false;
				Plugin.Log.LogWarning((object)("Could not install broadcast serializers (" + ex.Message + "). Host-only triggering will still work."));
			}
		}

		private static void InstallSerializer<T>() where T : struct, IBroadcast
		{
			Action<Writer, T> value = delegate
			{
			};
			Func<Reader, T> value2 = (Reader reader) => default(T);
			SetStaticMember(typeof(GenericWriter<T>), "<Write>k__BackingField", value);
			SetStaticMember(typeof(GenericReader<T>), "<Read>k__BackingField", value2);
			SetStaticMember(typeof(GenericWriter<T>), "HasCustomSerializer", true, optional: true);
			SetStaticMember(typeof(GenericReader<T>), "HasCustomSerializer", true, optional: true);
		}

		private static void SetStaticMember(Type type, string name, object value, bool optional = false)
		{
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(null, value);
				return;
			}
			PropertyInfo propertyInfo = AccessTools.Property(type, name);
			if (propertyInfo != null && propertyInfo.CanWrite)
			{
				propertyInfo.SetValue(null, value, null);
			}
			else if (!optional)
			{
				throw new MissingFieldException(type.FullName, name);
			}
		}

		private static void OnServerDiveRequest(NetworkConnection sender, DiveRequestBroadcast msg, Channel channel)
		{
			Plugin.Log.LogInfo((object)$"Dive requested by client {sender?.ClientId}.");
			DiveController.ServerBeginDive();
		}

		private static void OnClientDiveStarted(DiveStartedBroadcast msg, Channel channel)
		{
			if (!InstanceFinder.IsServerStarted)
			{
				Klaxon.Play(((Object)(object)BoatManager.Boat != (Object)null) ? BoatManager.Boat.VisualBoat : null);
			}
		}
	}
	internal static class Klaxon
	{
		private const int SampleRate = 44100;

		private const float ToneSeconds = 0.45f;

		private static readonly float[] Tones = new float[2] { 620f, 440f };

		private static AudioClip _clip;

		private static AudioSource _source;

		public static void Play(Transform parent)
		{
			if (!ModConfig.AlarmEnabled.Value)
			{
				return;
			}
			try
			{
				EnsureSource(parent);
				if (!((Object)(object)_source == (Object)null))
				{
					_source.volume = ModConfig.AlarmVolume.Value;
					if (!_source.isPlaying)
					{
						_source.Play();
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not start alarm: " + ex.Message));
			}
		}

		public static void Stop()
		{
			if ((Object)(object)_source != (Object)null && _source.isPlaying)
			{
				_source.Stop();
			}
		}

		private static void EnsureSource(Transform parent)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_clip == (Object)null)
			{
				_clip = Generate();
			}
			if ((Object)(object)_source == (Object)null || (Object)(object)((Component)_source).gameObject == (Object)null)
			{
				_source = new GameObject("BlirUBoat_Alarm").AddComponent<AudioSource>();
				_source.clip = _clip;
				_source.loop = true;
				_source.playOnAwake = false;
				_source.spatialBlend = 1f;
				_source.rolloffMode = (AudioRolloffMode)1;
				_source.minDistance = 4f;
				_source.maxDistance = 90f;
				_source.outputAudioMixerGroup = ResolveFxMixerGroup();
			}
			if ((Object)(object)parent != (Object)null)
			{
				((Component)_source).transform.SetParent(parent, false);
				((Component)_source).transform.localPosition = Vector3.zero;
			}
		}

		private static AudioMixerGroup ResolveFxMixerGroup()
		{
			object obj = AccessTools.Field(typeof(AudioManager), "_instance")?.GetValue(null);
			if (obj == null)
			{
				Plugin.Log.LogWarning((object)"AudioManager instance not found; alarm will bypass the FX mixer.");
				return null;
			}
			object? obj2 = AccessTools.Field(typeof(AudioManager), "_fxGroup")?.GetValue(obj);
			return (AudioMixerGroup)((obj2 is AudioMixerGroup) ? obj2 : null);
		}

		private static AudioClip Generate()
		{
			int num = Mathf.RoundToInt(19845f);
			float[] array = new float[num * Tones.Length];
			for (int i = 0; i < Tones.Length; i++)
			{
				float num2 = Tones[i];
				for (int j = 0; j < num; j++)
				{
					float num3 = (float)j / 44100f;
					float num4 = MathF.PI * 2f * num2 * num3;
					float num5 = Mathf.Sin(num4) + 0.45f * Mathf.Sin(2f * num4) + 0.22f * Mathf.Sin(3f * num4);
					num5 /= 1.67f;
					array[i * num + j] = num5 * Envelope((float)j / (float)num) * 0.8f;
				}
			}
			AudioClip obj = AudioClip.Create("BlirUBoat_Klaxon", array.Length, 1, 44100, false);
			obj.SetData(array, 0);
			return obj;
		}

		private static float Envelope(float t)
		{
			if (t < 0.03f)
			{
				return t / 0.03f;
			}
			if (t > 0.9f)
			{
				return (1f - t) / 0.1f;
			}
			return 1f;
		}
	}
	internal static class ModConfig
	{
		public static ConfigEntry<float> DiveDepth;

		public static ConfigEntry<float> DescentSeconds;

		public static ConfigEntry<float> SubmergedSecondsMin;

		public static ConfigEntry<float> SubmergedSecondsMax;

		public static ConfigEntry<float> AscentSeconds;

		public static ConfigEntry<float> CooldownSeconds;

		public static ConfigEntry<bool> AlarmEnabled;

		public static ConfigEntry<float> AlarmVolume;

		public static ConfigEntry<float> PropScale;

		public static ConfigEntry<float> PlankWidthOverride;

		public static ConfigEntry<float> PlankInset;

		public static ConfigEntry<float> PlankLength;

		public static ConfigEntry<float> OffsetForward;

		public static ConfigEntry<float> OffsetSide;

		public static ConfigEntry<float> PlankHeightFraction;

		public static ConfigEntry<float> PackYaw;

		public static ConfigEntry<float> HoverTextSide;

		public static ConfigEntry<float> HoverTextUp;

		public static ConfigEntry<string> ShaderName;

		public static ConfigEntry<KeyboardShortcut> DiagnosticsKey;

		public static void Bind(ConfigFile cfg)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Expected O, but got Unknown
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Expected O, but got Unknown
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			DiveDepth = cfg.Bind<float>("Dive", "Depth", 4f, "How far below the water surface the boat settles, in metres.");
			DescentSeconds = cfg.Bind<float>("Dive", "DescentSeconds", 7f, new ConfigDescription("How long the boat takes to go under.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			SubmergedSecondsMin = cfg.Bind<float>("Dive", "SubmergedSecondsMin", 15f, "Minimum time held underwater before surfacing.");
			SubmergedSecondsMax = cfg.Bind<float>("Dive", "SubmergedSecondsMax", 25f, "Maximum time held underwater before surfacing.");
			AscentSeconds = cfg.Bind<float>("Dive", "AscentSeconds", 4f, new ConfigDescription("How long the boat takes to come back up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			CooldownSeconds = cfg.Bind<float>("Dive", "CooldownSeconds", 10f, "Delay after surfacing before the button can be used again.");
			AlarmEnabled = cfg.Bind<bool>("Audio", "AlarmEnabled", true, "Play the alarm while the boat is going under.");
			AlarmVolume = cfg.Bind<float>("Audio", "AlarmVolume", 0.55f, new ConfigDescription("Alarm loudness. Still scaled by the game's own FX volume slider.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			PropScale = cfg.Bind<float>("Props", "Scale", 1f, "Size multiplier for the cigarette pack and button.");
			PlankWidthOverride = cfg.Bind<float>("Props", "PlankWidthOverride", 0f, "Fixed plank width across the boat, in metres. Leave at 0 to measure the hull and fit the plank automatically — the hull tapers, so a fixed width punches through the sides near the bow.");
			PlankInset = cfg.Bind<float>("Props", "PlankInset", -0.22f, new ConfigDescription("How far short of the measured hull each end of the plank stops, in metres. Small values fit snugly; negative values push the ends into the hull sides.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 0.5f), Array.Empty<object>()));
			PlankLength = cfg.Bind<float>("Props", "PlankDepth", 0.5f, "Plank depth along the boat, in metres.");
			OffsetForward = cfg.Bind<float>("Props", "OffsetForward", -1f, "Distance from the very tip of the bow, in metres. Negative moves inboard.");
			OffsetSide = cfg.Bind<float>("Props", "OffsetSide", 0f, "Sideways offset across the boat, in metres.");
			PackYaw = cfg.Bind<float>("Props", "PackYaw", 204f, new ConfigDescription("Which way the cigarette pack faces, in degrees around the vertical axis.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 360f), Array.Empty<object>()));
			HoverTextSide = cfg.Bind<float>("Props", "HoverTextSide", 0.32f, "How far to the side the 'Röökille' prompt sits from the pack, in metres, so the label doesn't cover the model.");
			HoverTextUp = cfg.Bind<float>("Props", "HoverTextUp", 0.06f, "How far above the plank the prompt sits, in metres.");
			PlankHeightFraction = cfg.Bind<float>("Props", "HeightFraction", 0.5f, new ConfigDescription("How far up the hull the plank sits, as a fraction of the boat's height. 0 is the keel, 1 is the gunwale, 0.5 is halfway up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1.2f), Array.Empty<object>()));
			ShaderName = cfg.Bind<string>("Props", "ShaderName", "Universal Render Pipeline/Lit", "Shader used for the props. URP/Lit by default: it is the only candidate confirmed to expose _BaseColor. \"Shader Graphs/DefaultShader\" matches the game art style more closely but exposes no standard colour property. Never use the boat shader.");
			DiagnosticsKey = cfg.Bind<KeyboardShortcut>("Diagnostics", "DumpKey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Writes a report of audio clips, item prefabs and boat geometry to the config folder.");
		}
	}
	[HarmonyPatch(typeof(Boat), "ApplyWaterForce")]
	internal static class BoatApplyWaterForcePatch
	{
		private static bool Prefix(Boat __instance)
		{
			return !DiveController.ServerTick(__instance);
		}
	}
	[HarmonyPatch(typeof(Boat), "OnStartClient")]
	internal static class BoatOnStartClientPatch
	{
		private static void Postfix(Boat __instance)
		{
			try
			{
				DiveNet.EnsureRegistered(asServer: false);
				BoatProps.Attach(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to set up boat props: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(Boat), "OnStartServer")]
	internal static class BoatOnStartServerPatch
	{
		private static void Postfix()
		{
			DiveNet.EnsureRegistered(asServer: true);
		}
	}
	[HarmonyPatch(typeof(Boat), "OnStopClient")]
	internal static class BoatOnStopClientPatch
	{
		private static void Postfix()
		{
			DiveController.Abort("boat despawned");
			DiveNet.Reset();
		}
	}
	[HarmonyPatch(typeof(BoatManager), "TryMoveBoat")]
	internal static class BoatManagerTryMoveBoatPatch
	{
		private static void Prefix()
		{
			DiveController.Abort("boat relocated");
		}
	}
	[HarmonyPatch(typeof(BoatManager), "RemoveBoat")]
	internal static class BoatManagerRemoveBoatPatch
	{
		private static void Prefix()
		{
			DiveController.Abort("boat removed");
		}
	}
	[HarmonyPatch(typeof(PlayerMovement), "UnderWaterCheck")]
	internal static class PlayerMovementUnderWaterCheckPatch
	{
		private static readonly FieldRef<PlayerMovement, float> TimeWentUnderWater = AccessTools.FieldRefAccess<PlayerMovement, float>("_timeWentUnderWater");

		private static void Prefix(PlayerMovement __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && __instance.OnBoat && BoatIsSubmerged())
			{
				TimeWentUnderWater.Invoke(__instance) = Time.time;
			}
		}

		private static bool BoatIsSubmerged()
		{
			//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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Boat boat = BoatManager.Boat;
			if ((Object)(object)boat == (Object)null)
			{
				return false;
			}
			Vector3 val = BoatVisualPosition(boat);
			return val.y < WaterManager.GetWaterHeight(val) - 0.15f;
		}

		private static Vector3 BoatVisualPosition(Boat boat)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)boat.VisualPhysicsRig != (Object)null)
			{
				return boat.VisualPhysicsRig.position;
			}
			if ((Object)(object)boat.VisualBoat != (Object)null)
			{
				return boat.VisualBoat.position;
			}
			return ((Component)boat).transform.position;
		}
	}
	internal class PlankFitter : MonoBehaviour
	{
		private const float MaxReach = 3f;

		private const float GiveUpAfterSeconds = 5f;

		private float _elapsed;

		private bool _done;

		private void FixedUpdate()
		{
			if (!_done)
			{
				_elapsed += Time.fixedDeltaTime;
				if (TryFit())
				{
					_done = true;
					Object.Destroy((Object)(object)this);
				}
				else if (_elapsed >= 5f)
				{
					Plugin.Log.LogInfo((object)"Could not probe the hull for the plank's shape; leaving it rectangular. Set Props.PlankWidthOverride if it doesn't fit.");
					_done = true;
					Object.Destroy((Object)(object)this);
				}
			}
		}

		private bool TryFit()
		{
			float value = ModConfig.PlankLength.Value;
			float value2 = ModConfig.PlankInset.Value;
			if (!TryMeasureAt(value * 0.45f, out var width))
			{
				return false;
			}
			if (!TryMeasureAt((0f - value) * 0.45f, out var width2))
			{
				return false;
			}
			float num = Mathf.Max(0.15f, width - value2 * 2f);
			float num2 = Mathf.Max(0.15f, width2 - value2 * 2f);
			BoatProps.ShapePlank(((Component)this).gameObject, num2, num, value);
			Plugin.Log.LogInfo((object)($"Plank fitted to hull: {num2:F2}m aft, {num:F2}m fore " + $"(hull spans {width2:F2}m / {width:F2}m)."));
			return true;
		}

		private bool TryMeasureAt(float alongBoat, out float width)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0062: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			width = 0f;
			Vector3 origin = ((Component)this).transform.position + ((Component)this).transform.forward * alongBoat + ((Component)this).transform.up * (BoatProps.PlankThicknessMetres * 0.5f);
			if (!TryCast(origin, ((Component)this).transform.right, out var distance))
			{
				return false;
			}
			if (!TryCast(origin, -((Component)this).transform.right, out var distance2))
			{
				return false;
			}
			width = distance + distance2;
			return width > 0.05f;
		}

		private bool TryCast(Vector3 origin, Vector3 direction, out float distance)
		{
			//IL_0007: 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_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)
			distance = 0f;
			RaycastHit[] array = Physics.RaycastAll(origin, direction, 3f, -1, (QueryTriggerInteraction)1);
			if (array.Length == 0)
			{
				return false;
			}
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit[] array2 = array;
			for (int num = 0; num < array2.Length; num++)
			{
				RaycastHit val = array2[num];
				if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && BoatManager.ColToBoat.ContainsKey(((RaycastHit)(ref val)).collider))
				{
					distance = ((RaycastHit)(ref val)).distance;
					return true;
				}
			}
			return false;
		}
	}
	[BepInPlugin("Stendari.BlirUBoat", "BlirUBoat", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Stendari.BlirUBoat";

		public const string PluginName = "BlirUBoat";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("Stendari.BlirUBoat");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"BlirUBoat 1.0.0 loaded. Press the button.");
		}

		private void Update()
		{
			//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)
			KeyboardShortcut value = ModConfig.DiagnosticsKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				Diagnostics.Dump();
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class VanillaAssets
	{
		private static Item[] _items;

		private static Item[] Items => _items ?? (_items = Resources.LoadAll<Item>("Items"));

		private static Item FindItem(string nameFragment)
		{
			return ((IEnumerable<Item>)Items).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((Object)i).name.IndexOf(nameFragment, StringComparison.OrdinalIgnoreCase) >= 0));
		}

		public static Transform FindLighter()
		{
			Item val = FindItem("Dynamite");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Explosive val2 = ((Component)val).GetComponent<Explosive>() ?? ((Component)val).GetComponentInChildren<Explosive>(true);
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			object? obj = AccessTools.Field(typeof(Explosive), "_lighter")?.GetValue(val2);
			return (Transform)((obj is Transform) ? obj : null);
		}

		public static GameObject CloneVisual(Transform source, Transform parent, string name)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			MeshRenderer[] array = ((Component)source).GetComponentsInChildren<MeshRenderer>(true).Where(delegate(MeshRenderer r)
			{
				if ((Object)(object)r != (Object)null)
				{
					MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
					return (Object)(object)((component != null) ? component.sharedMesh : null) != (Object)null;
				}
				return false;
			}).ToArray();
			if (array.Length == 0)
			{
				Plugin.Log.LogWarning((object)("'" + ((Object)source).name + "' has no mesh renderers to clone."));
				return null;
			}
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			MeshRenderer[] array2 = array;
			foreach (MeshRenderer val2 in array2)
			{
				GameObject val3 = new GameObject(((Object)val2).name);
				val3.transform.SetParent(val.transform, false);
				val3.transform.localPosition = source.InverseTransformPoint(((Component)val2).transform.position);
				val3.transform.localRotation = Quaternion.Inverse(source.rotation) * ((Component)val2).transform.rotation;
				val3.transform.localScale = ((Component)val2).transform.lossyScale;
				val3.AddComponent<MeshFilter>().sharedMesh = ((Component)val2).GetComponent<MeshFilter>().sharedMesh;
				((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)val2).sharedMaterials;
			}
			Plugin.Log.LogInfo((object)$"Cloned visual from '{((Object)source).name}' ({array.Length} renderer(s)).");
			return val;
		}
	}
}