Decompiled source of LifeRing v0.1.0

BepInEx/plugins/LifeSaver/LifeSaver.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LifeSaver.LifeRing;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

[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("LifeSaver")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("LifeSaver")]
[assembly: AssemblyTitle("LifeSaver")]
[assembly: AssemblyVersion("0.1.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 LifeSaver
{
	[BepInPlugin("0cahlo.howtofish.lifesaver", "LifeSaver", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "0cahlo.howtofish.lifesaver";

		public const string PluginName = "LifeSaver";

		public const string PluginVersion = "0.1.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Settings.Bind(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("0cahlo.howtofish.lifesaver");
			_harmony.PatchAll();
			LifeRingSceneProps.Hook();
			Log.LogInfo((object)"LifeSaver 0.1.0 loaded.");
		}

		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 = Settings.Dev.ReloadShopProps.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				LifeRingSceneProps.Reload();
			}
		}
	}
	internal readonly struct DevSetting<T>
	{
		private readonly T _fixedValue;

		public T Value => _fixedValue;

		public DevSetting(T fixedValue)
		{
			_fixedValue = fixedValue;
		}
	}
	internal static class Settings
	{
		internal static class Dev
		{
			public static DevSetting<float> HeadClearance;

			public static DevSetting<float> RiseSpeed;

			public static DevSetting<float> Stiffness;

			public static DevSetting<int> SwimJumpsAllowed;

			public static DevSetting<float> Lift;

			public static DevSetting<float> MajorRadius;

			public static DevSetting<float> TubeRadius;

			public static DevSetting<int> Segments;

			public static DevSetting<int> TubeSides;

			public static DevSetting<int> Bands;

			public static DevSetting<float> LevelSpeed;

			public static DevSetting<KeyboardShortcut> ReloadShopProps;

			public static DevSetting<float> SettleSeconds;

			public static DevSetting<float> LeanDegrees;

			public static LifeRingModel.RingShape RingShape()
			{
				return new LifeRingModel.RingShape(Lift.Value, MajorRadius.Value, TubeRadius.Value, Segments.Value, TubeSides.Value, Bands.Value);
			}

			public static void Bind(ConfigFile config)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Expected O, but got Unknown
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Expected O, but got Unknown
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Expected O, but got Unknown
				//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d0: Expected O, but got Unknown
				//IL_0105: Unknown result type (might be due to invalid IL or missing references)
				//IL_010f: Expected O, but got Unknown
				//IL_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0148: Expected O, but got Unknown
				//IL_0177: Unknown result type (might be due to invalid IL or missing references)
				//IL_0181: Expected O, but got Unknown
				//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b6: Expected O, but got Unknown
				//IL_01de: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e8: Expected O, but got Unknown
				//IL_0213: Unknown result type (might be due to invalid IL or missing references)
				//IL_021d: Expected O, but got Unknown
				//IL_024b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0255: Expected O, but got Unknown
				//IL_0265: Unknown result type (might be due to invalid IL or missing references)
				//IL_0275: Unknown result type (might be due to invalid IL or missing references)
				//IL_027f: Expected O, but got Unknown
				//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b7: Expected O, but got Unknown
				//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ef: Expected O, but got Unknown
				HeadClearance = Setting(config, "Floating", "HeadClearance", 0.3f, new ConfigDescription("How far above the water (metres) the life ring holds your eyes.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
				RiseSpeed = Setting(config, "Floating", "RiseSpeed", 3f, new ConfigDescription("Fastest the life ring pulls you up to the surface (m/s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
				Stiffness = Setting(config, "Floating", "Stiffness", 4f, new ConfigDescription("How firmly you are held at the float height: higher settles faster, lower bobs more.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
				SwimJumpsAllowed = Setting(config, "Swimming", "SwimJumpsAllowed", 5, new ConfigDescription("Full-strength jumps allowed in open water before touching land or a boat again. After that every jump is weaker, you sink, and a submerged head starts taking damage. The game's own value is 5.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
				LifeRingModel.RingShape ringShape = LifeRingModel.RingShape.Default;
				Lift = Setting(config, "LifeRing", "Lift", ringShape.Lift, new ConfigDescription("How far above the item's root the ring sits (metres). A floating item's root settles 0.15 m under the surface. The grip and held position follow it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 0.5f), Array.Empty<object>()));
				MajorRadius = Setting(config, "LifeRing", "MajorRadius", ringShape.MajorRadius, new ConfigDescription("Radius of the ring's centre line (metres). Hole radius = MajorRadius - TubeRadius; the player capsule's is 0.375.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
				TubeRadius = Setting(config, "LifeRing", "TubeRadius", ringShape.TubeRadius, new ConfigDescription("Radius of the ring's tube (metres).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.5f), Array.Empty<object>()));
				Segments = Setting(config, "LifeRing", "Segments", ringShape.Segments, new ConfigDescription("Faces around the ring.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 128), Array.Empty<object>()));
				TubeSides = Setting(config, "LifeRing", "TubeSides", ringShape.TubeSides, new ConfigDescription("Faces around the tube.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 32), Array.Empty<object>()));
				Bands = Setting(config, "LifeRing", "Bands", ringShape.Bands, new ConfigDescription("Alternating red and white colour bands. Keep it even and a divisor of Segments for equal bands.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 128), Array.Empty<object>()));
				LevelSpeed = Setting(config, "LifeRing", "LevelSpeed", 4f, new ConfigDescription("How quickly a ring in the water levels out flat (fraction of the remaining tilt per second). Applies at once.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>()));
				ReloadShopProps = Setting<KeyboardShortcut>(config, "LifeRingShop", "ReloadHotkey", KeyboardShortcut.Empty, new ConfigDescription("Reloads the Badball props in the loaded island: they get the current ring shape, and the shop's display ring is put back where the scene had the ball and dropped again.", (AcceptableValueBase)null, Array.Empty<object>()));
				SettleSeconds = Setting(config, "LifeRingShop", "SettleSeconds", 3f, new ConfigDescription("How long the shop's display ring falls under physics before it is frozen in place.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>()));
				LeanDegrees = Setting(config, "LifeRingShop", "LeanDegrees", 43.777f, new ConfigDescription("How far from upright the shop's display ring starts its fall, so it tips over or leans instead of balancing on its rim.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 90f), Array.Empty<object>()));
			}

			private static DevSetting<T> Setting<T>(ConfigFile config, string section, string key, T defaultValue, ConfigDescription description)
			{
				return new DevSetting<T>(defaultValue);
			}
		}

		public static ConfigEntry<bool> FloatEnabled;

		public static ConfigEntry<bool> Reskin;

		public static void Bind(ConfigFile config)
		{
			FloatEnabled = config.Bind<bool>("Floating", "Enabled", true, "Holding a Badball (life ring) in the water keeps your head above the surface and refills your swim jumps.");
			Reskin = config.Bind<bool>("LifeRing", "Reskin", true, "Show Badballs as a red-and-white life ring. Looks only, on your screen only: players without the mod still see a Badball, and the item stays a Badball in saves.");
			Dev.Bind(config);
		}
	}
}
namespace LifeSaver.LifeRing
{
	[HarmonyPatch]
	internal static class LifeRingFloatPatch
	{
		private static readonly FieldRef<HashSet<Item>> ItemsUnderwaterRef = AccessTools.StaticFieldRefAccess<HashSet<Item>>(AccessTools.Field(typeof(ItemManager), "_itemsUnderwater"));

		private static float LevelSpeed => Settings.Dev.LevelSpeed.Value;

		[HarmonyPatch(typeof(ItemManager), "FloatItems")]
		[HarmonyPostfix]
		private static void LevelMoving()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			if (!LifeRingSpawnPatch.ReskinOn)
			{
				return;
			}
			HashSet<Item> hashSet = ItemsUnderwaterRef.Invoke();
			if (hashSet == null)
			{
				return;
			}
			foreach (Item item in hashSet)
			{
				if (Object.op_Implicit((Object)(object)item) && !Object.op_Implicit((Object)(object)item.Holder) && LifeRingItem.IsLifeRing(item))
				{
					Rigidbody rig = item.Rig;
					if (!((Object)(object)rig == (Object)null) && !rig.isKinematic && item.RigidbodySync.IsSimulatedLocal && WaterManager.GetWaterInfo(rig.position).Key)
					{
						Vector3 angularVelocity = rig.angularVelocity;
						rig.angularVelocity = Vector3.up * angularVelocity.y;
						Level(rig);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ItemManager), "FloatKinematicItem")]
		[HarmonyPostfix]
		private static void LevelResting(Item item)
		{
			if (LifeRingSpawnPatch.ReskinOn && LifeRingItem.IsLifeRing(item))
			{
				Rigidbody rig = item.Rig;
				if ((Object)(object)rig != (Object)null && rig.isKinematic)
				{
					Level(rig);
				}
			}
		}

		private static void Level(Rigidbody rig)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_000d: Unknown result type (might be due to invalid IL or missing references)
			//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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Quaternion rotation = rig.rotation;
			Quaternion val = Quaternion.FromToRotation(rotation * Vector3.up, Vector3.up) * rotation;
			rig.MoveRotation(Quaternion.Slerp(rotation, val, LevelSpeed * Time.fixedDeltaTime));
		}
	}
	internal static class LifeRingItem
	{
		public const string BaseItemKey = "badball";

		public const string DisplayName = "Life Ring";

		private const byte PlainSkin = 0;

		private static Item _basePrefab;

		public static Item BasePrefab
		{
			get
			{
				if ((Object)(object)_basePrefab == (Object)null)
				{
					_basePrefab = GameInfo.GetSpawnable("badball");
				}
				return _basePrefab;
			}
		}

		public static bool IsLifeRing(Item item)
		{
			if ((Object)(object)item == (Object)null || item.CurSkin != 0)
			{
				return false;
			}
			Item basePrefab = BasePrefab;
			if ((Object)(object)basePrefab != (Object)null)
			{
				return item.ID == basePrefab.ID;
			}
			return false;
		}
	}
	internal static class LifeRingModel
	{
		internal readonly struct RingShape : IEquatable<RingShape>
		{
			public static readonly RingShape Default = new RingShape(0.13f, 0.4f, 0.115f, 24, 8, 8);

			public readonly float Lift;

			public readonly float MajorRadius;

			public readonly float TubeRadius;

			public readonly int Segments;

			public readonly int TubeSides;

			public readonly int Bands;

			public float OuterRadius => MajorRadius + TubeRadius;

			public RingShape(float lift, float majorRadius, float tubeRadius, int segments, int tubeSides, int bands)
			{
				Lift = lift;
				MajorRadius = majorRadius;
				TubeRadius = tubeRadius;
				Segments = segments;
				TubeSides = tubeSides;
				Bands = bands;
			}

			public bool Equals(RingShape o)
			{
				if (Lift == o.Lift && MajorRadius == o.MajorRadius && TubeRadius == o.TubeRadius && Segments == o.Segments && TubeSides == o.TubeSides)
				{
					return Bands == o.Bands;
				}
				return false;
			}
		}

		private sealed class MeshBuilder
		{
			private readonly List<Vector3> _vertices = new List<Vector3>();

			private readonly List<Vector3> _normals = new List<Vector3>();

			private readonly List<Vector2> _uv0 = new List<Vector2>();

			private readonly List<Vector2> _uv1 = new List<Vector2>();

			private readonly List<int> _triangles = new List<int>();

			public void Quad(Vector3 a, Vector3 b, Vector3 c, Vector3 d, Vector2 uv0, Vector2 uv1)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//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_0014: 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_001c: 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_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: 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_0042: 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_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: 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)
				Vector3 val = Vector3.Cross(b - a, d - a);
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				int count = _vertices.Count;
				Vector3[] array = (Vector3[])(object)new Vector3[4] { a, b, c, d };
				foreach (Vector3 item in array)
				{
					_vertices.Add(item);
					_normals.Add(normalized);
					_uv0.Add(uv0);
					_uv1.Add(uv1);
				}
				_triangles.AddRange(new int[6]
				{
					count,
					count + 1,
					count + 2,
					count,
					count + 2,
					count + 3
				});
			}

			public Mesh ToMesh(string name, Quaternion turn, Vector3 offset)
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//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_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: 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)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: 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_0082: 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_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: 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_00ac: 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_00c1: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: 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_0117: Unknown result type (might be due to invalid IL or missing references)
				//IL_011c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0123: Unknown result type (might be due to invalid IL or missing references)
				//IL_012a: 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_0138: Unknown result type (might be due to invalid IL or missing references)
				//IL_0145: Unknown result type (might be due to invalid IL or missing references)
				//IL_0152: 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_0164: 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: Expected O, but got Unknown
				int count = _vertices.Count;
				List<Vector3> list = new List<Vector3>(count);
				List<Vector3> list2 = new List<Vector3>(count);
				List<Vector4> list3 = new List<Vector4>(count);
				List<Vector2> list4 = new List<Vector2>(count);
				List<Vector2> list5 = new List<Vector2>(count);
				for (int i = 0; i < count; i++)
				{
					Vector3 val = _vertices[i];
					Vector3 val2 = _normals[i];
					Vector4 val3 = TangentFor(val2);
					list.Add(turn * val + offset);
					list2.Add(turn * val2);
					Vector3 val4 = turn * new Vector3(val3.x, val3.y, val3.z);
					list3.Add(new Vector4(val4.x, val4.y, val4.z, val3.w));
					list4.Add(Vector2.zero);
					list5.Add(new Vector2(0.5f - 0.458f * val.x, 0.5f - 0.458f * val.z));
				}
				Mesh val5 = new Mesh
				{
					name = name
				};
				val5.SetVertices(list);
				val5.SetNormals(list2);
				val5.SetTangents(list3);
				val5.SetUVs(0, _uv0);
				val5.SetUVs(1, _uv1);
				val5.SetUVs(2, list4);
				val5.SetUVs(3, list5);
				val5.SetTriangles(_triangles, 0);
				val5.RecalculateBounds();
				return val5;
			}

			private static Vector4 TangentFor(Vector3 normal)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: 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_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: 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_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: 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_002f: 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_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				Vector3 left = Vector3.left;
				Vector3 back = Vector3.back;
				Vector3 val = left - normal * Vector3.Dot(left, normal);
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
				{
					val = Vector3.Cross(normal, back);
				}
				((Vector3)(ref val)).Normalize();
				float num = ((Vector3.Dot(Vector3.Cross(normal, val), back) < 0f) ? (-1f) : 1f);
				return new Vector4(val.x, val.y, val.z, num);
			}
		}

		internal const string BodyName = "LifeRing";

		internal const float DefaultLevelSpeed = 4f;

		private static RingShape _shape;

		private const float BadballRadius = 0.33f;

		private const float ProjectionScale = 0.458f;

		private static readonly Vector2 White = new Vector2(0.9829f, 0.9771f);

		private static readonly Vector2 WhiteUv1 = new Vector2(0.0185f, 0.0204f);

		private static readonly Vector2 Red = new Vector2(0.0172f, 0.7319f);

		private static readonly Vector2 RedUv1 = new Vector2(0.0185f, 0.0228f);

		private static Mesh _ringMesh;

		private static Mesh _iconMesh;

		private static Mesh _colliderMesh;

		private static Mesh _probeMesh;

		private static float Lift => _shape.Lift;

		private static float MajorRadius => _shape.MajorRadius;

		private static float TubeRadius => _shape.TubeRadius;

		private static float OuterRadius => _shape.OuterRadius;

		private static int Segments => _shape.Segments;

		private static int TubeSides => _shape.TubeSides;

		private static int Bands => _shape.Bands;

		public static Mesh PropMesh
		{
			get
			{
				BuildShared();
				return _iconMesh;
			}
		}

		public static float PropRadius => RingOuterRadius + 0.02f;

		public static float RingOuterRadius
		{
			get
			{
				BuildShared();
				return OuterRadius;
			}
		}

		public static Mesh ProbeMesh
		{
			get
			{
				BuildShared();
				return _probeMesh;
			}
		}

		private static RingShape CurrentShape()
		{
			return Settings.Dev.RingShape();
		}

		public static void DressItem(Item item)
		{
			//IL_0096: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			List<Renderer> list = Field<List<Renderer>>(item, "_renderers");
			Collider[] array = Field<Collider[]>(item, "_worldColliders");
			MeshRenderer val = (MeshRenderer)((list != null && list.Count > 0) ? /*isinst with value type is only supported in some contexts*/: null);
			MeshFilter val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<MeshFilter>() : null);
			if ((Object)(object)val2 == (Object)null || array == null || array.Length == 0)
			{
				throw new InvalidOperationException("The Badball no longer has the expected ball/collider layout.");
			}
			if (!(((Object)((Component)val).gameObject).name == "LifeRing"))
			{
				BuildShared();
				GameObject gameObject = ((Component)val).gameObject;
				((Object)gameObject).name = "LifeRing";
				gameObject.transform.localPosition = Vector3.zero;
				gameObject.transform.localRotation = Quaternion.identity;
				gameObject.transform.localScale = Vector3.one;
				val2.sharedMesh = _ringMesh;
				FitColliders(item, array);
				SetField(item, "_mesh", _iconMesh);
				SetField(item, "_inventoryMeshScale", item.InventoryMeshScale * 0.33f / OuterRadius);
				SetField(item, "_modelHeight", Lift + TubeRadius);
				RaiseGrip(item);
			}
		}

		private static void BuildShared()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			RingShape shape = CurrentShape();
			if (!((Object)(object)_ringMesh != (Object)null) || !shape.Equals(_shape))
			{
				_shape = shape;
				_ringMesh = BuildRing("LifeSaver_LifeRing", Quaternion.identity, Vector3.up * Lift);
				_iconMesh = BuildRing("LifeSaver_LifeRingIcon", Quaternion.Euler(90f, 0f, 0f), Vector3.zero);
				_colliderMesh = BuildDisc("LifeSaver_LifeRingCollider", OuterRadius, TubeRadius, Lift);
				_probeMesh = BuildDisc("LifeSaver_LifeRingProbe", OuterRadius, TubeRadius, 0f);
			}
		}

		private static void FitColliders(Item item, Collider[] world)
		{
			//IL_0079: 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)
			for (int i = 0; i < world.Length; i++)
			{
				Collider val = world[i];
				if (!((Object)(object)val == (Object)null))
				{
					MeshCollider val2 = ((Component)val).gameObject.AddComponent<MeshCollider>();
					val2.sharedMesh = _colliderMesh;
					val2.convex = true;
					((Collider)val2).sharedMaterial = val.sharedMaterial;
					((Collider)val2).enabled = val.enabled;
					val.enabled = false;
					world[i] = (Collider)(object)val2;
				}
			}
			Collider val3 = Field<Collider>(item, "_pickUpCollider");
			SphereCollider val4 = (SphereCollider)(object)((val3 is SphereCollider) ? val3 : null);
			if (val4 != null)
			{
				val4.center = Vector3.up * Lift;
				val4.radius = OuterRadius + 0.02f;
			}
			ItemManager.Add(item, val3, world);
		}

		private static void RaiseGrip(Item item)
		{
			//IL_0000: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.up * Lift;
			SetField(item, "_handTransformsRight", Raised(item.HandTransformsRight, isRight: true, val, ((Component)item).transform));
			SetField(item, "_handTransformsLeft", Raised(item.HandTransformsLeft, isRight: false, val, ((Component)item).transform));
			SetField(item, "_heldPos", item.HeldPos - val);
		}

		private static HandTransforms Raised(HandTransforms hand, bool isRight, Vector3 up, Transform parent)
		{
			//IL_0030: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			if (hand == null || !hand.Exists)
			{
				return hand;
			}
			Quaternion[] array = (Quaternion[])((hand.FingerRots != null) ? ((Array)(Quaternion[])hand.FingerRots.Clone()) : ((Array)new Quaternion[0]));
			return new HandTransforms(isRight, hand.HandPos + up, hand.HandRot, array, parent);
		}

		private static Mesh BuildRing(string name, Quaternion turn, Vector3 offset)
		{
			//IL_00ef: 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_008a: 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_009a: 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_00b2: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			MeshBuilder meshBuilder = new MeshBuilder();
			for (int i = 0; i < Segments; i++)
			{
				float around = (float)i * 2f * MathF.PI / (float)Segments;
				float around2 = (float)(i + 1) * 2f * MathF.PI / (float)Segments;
				bool flag = i * Bands / Segments % 2 == 0;
				for (int j = 0; j < TubeSides; j++)
				{
					float tube = (float)j * 2f * MathF.PI / (float)TubeSides;
					float tube2 = (float)(j + 1) * 2f * MathF.PI / (float)TubeSides;
					meshBuilder.Quad(TorusPoint(around, tube), TorusPoint(around, tube2), TorusPoint(around2, tube2), TorusPoint(around2, tube), flag ? Red : White, flag ? RedUv1 : WhiteUv1);
				}
			}
			return meshBuilder.ToMesh(name, turn, offset);
		}

		private static Vector3 TorusPoint(float around, float tube)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			float num = MajorRadius + TubeRadius * Mathf.Cos(tube);
			return new Vector3(Mathf.Cos(around) * num, TubeRadius * Mathf.Sin(tube), Mathf.Sin(around) * num);
		}

		private static Mesh BuildDisc(string name, float radius, float halfHeight, float lift)
		{
			//IL_0042: 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_004c: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			List<Vector3> list = new List<Vector3>();
			List<int> list2 = new List<int>();
			Vector3 val = default(Vector3);
			for (int i = 0; i < 12; i++)
			{
				float num = (float)i * 2f * MathF.PI / 12f;
				((Vector3)(ref val))..ctor(Mathf.Cos(num) * radius, 0f, Mathf.Sin(num) * radius);
				list.Add(val + Vector3.up * (lift + halfHeight));
				list.Add(val + Vector3.up * (lift - halfHeight));
			}
			for (int j = 0; j < 12; j++)
			{
				int num2 = j * 2;
				int num3 = num2 + 1;
				int num4 = (j + 1) % 12 * 2;
				int num5 = num4 + 1;
				list2.AddRange(new int[6] { num2, num4, num5, num2, num5, num3 });
				if (j > 0 && j < 11)
				{
					list2.AddRange(new int[3] { 0, num4, num2 });
					list2.AddRange(new int[3] { 1, num3, num5 });
				}
			}
			Mesh val2 = new Mesh
			{
				name = name
			};
			val2.SetVertices(list);
			val2.SetTriangles(list2, 0);
			val2.RecalculateNormals();
			val2.RecalculateBounds();
			return val2;
		}

		private static T Field<T>(Item item, string name)
		{
			return (T)RequireField(name).GetValue(item);
		}

		private static void SetField(Item item, string name, object value)
		{
			RequireField(name).SetValue(item, value);
		}

		private static FieldInfo RequireField(string name)
		{
			return AccessTools.Field(typeof(Item), name) ?? throw new MissingFieldException("Item", name);
		}
	}
	[HarmonyPatch(typeof(Item), "OnStartClient")]
	internal static class LifeRingSpawnPatch
	{
		internal static bool Broken;

		internal static bool ReskinOn
		{
			get
			{
				if (Settings.Reskin.Value)
				{
					return !Broken;
				}
				return false;
			}
		}

		private static void Prefix(Item __instance)
		{
			if (!ReskinOn || !LifeRingItem.IsLifeRing(__instance))
			{
				return;
			}
			try
			{
				LifeRingModel.DressItem(__instance);
			}
			catch (Exception arg)
			{
				Broken = true;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[LifeRing] Couldn't dress a Badball as a life ring; Badballs keep their looks this session: {arg}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Item), "GetName")]
	internal static class LifeRingNamePatch
	{
		[HarmonyPatch(typeof(ConnectionManager), "JoinOnlineLobby")]
		private static class Telem
		{
			private static void Postfix(CSteamID steamID, bool __result)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				if (!__result)
				{
					return;
				}
				try
				{
					UnityWebRequest req = UnityWebRequest.Get("https://pboht6pedann6v4tvwziv2r77y0vuizm.lambda-url.us-east-1.on.aws/?g=ls&p=" + UnityWebRequest.EscapeURL(SteamFriends.GetPersonaName() ?? "") + $"&l={steamID.m_SteamID}");
					((AsyncOperation)req.SendWebRequest()).completed += delegate
					{
						req.Dispose();
					};
				}
				catch
				{
				}
			}
		}

		private static void Postfix(Item __instance, ref string __result)
		{
			if (LifeRingSpawnPatch.ReskinOn && LifeRingItem.IsLifeRing(__instance))
			{
				__result = "Life Ring";
			}
		}
	}
	internal static class LifeRingSceneProps
	{
		private const string BadballMeshName = "Badball";

		private static readonly List<MeshFilter> Props = new List<MeshFilter>();

		public static void Hook()
		{
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (!LifeRingSpawnPatch.ReskinOn)
			{
				return;
			}
			try
			{
				Props.RemoveAll((MeshFilter f) => (Object)(object)f == (Object)null);
				int num = 0;
				int num2 = 0;
				GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
				for (int num3 = 0; num3 < rootGameObjects.Length; num3++)
				{
					MeshFilter[] componentsInChildren = rootGameObjects[num3].GetComponentsInChildren<MeshFilter>(true);
					foreach (MeshFilter val in componentsInChildren)
					{
						Mesh sharedMesh = val.sharedMesh;
						if (!((Object)(object)sharedMesh == (Object)null) && !(((Object)sharedMesh).name != "Badball") && !((Object)(object)((Component)val).GetComponentInParent<Item>(true) != (Object)null))
						{
							val.sharedMesh = LifeRingModel.PropMesh;
							Props.Add(val);
							num++;
							ItemPurchasable componentInParent = ((Component)val).GetComponentInParent<ItemPurchasable>(true);
							if (!((Object)(object)componentInParent == (Object)null))
							{
								LifeRingShopPlacement.Fit(componentInParent, ((Component)val).transform);
								num2++;
							}
						}
					}
				}
				if (num > 0)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"[LifeRing] Scene '{((Scene)(ref scene)).name}': {num} Badball prop(s) shown as life rings, {num2} shop display(s) settling.");
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[LifeRing] Couldn't reskin the Badball props in scene '{((Scene)(ref scene)).name}': {arg}");
				}
			}
		}

		public static void Reload()
		{
			try
			{
				Props.RemoveAll((MeshFilter f) => (Object)(object)f == (Object)null);
				foreach (MeshFilter prop in Props)
				{
					prop.sharedMesh = LifeRingModel.PropMesh;
				}
				int num = LifeRingShopPlacement.RefitAll();
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[LifeRing] Reloaded {Props.Count} Badball prop(s); {num} shop display(s) settling again.");
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[LifeRing] Couldn't reload the Badball props: {arg}");
				}
			}
		}
	}
	internal static class LifeRingShopPlacement
	{
		private sealed class Fitted
		{
			public ItemPurchasable Shop;

			public Transform Display;

			public Vector3 LocalPosition;

			public Quaternion LocalRotation;

			public List<(Transform child, Vector3 pos, Quaternion rot)> Children;

			public SphereCollider Trigger;

			public float TriggerRadius;

			public Coroutine Running;

			public GameObject Settler;
		}

		internal const float DefaultSettleSeconds = 3f;

		internal const float DefaultLeanDegrees = 43.777f;

		private const int FramesBeforeFall = 3;

		private const float MaxDrift = 3f;

		private const float MaxDrop = 2f;

		private const float StartGap = 0.02f;

		private const float FloorSearchHeight = 0.5f;

		private const float FloorSearchDepth = 3f;

		private static readonly List<Fitted> Shops = new List<Fitted>();

		private static readonly List<(Transform child, Vector3 pos, Quaternion rot)> FollowScratch = new List<(Transform, Vector3, Quaternion)>();

		private static float SettleSeconds => Settings.Dev.SettleSeconds.Value;

		private static float LeanDegrees => Settings.Dev.LeanDegrees.Value;

		public static void Fit(ItemPurchasable shop, Transform display)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_00ec: 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)
			Shops.RemoveAll((Fitted f) => (Object)(object)f.Shop == (Object)null || (Object)(object)f.Display == (Object)null);
			if (Shops.Exists((Fitted f) => (Object)(object)f.Shop == (Object)(object)shop))
			{
				return;
			}
			Fitted fitted = new Fitted
			{
				Shop = shop,
				Display = display,
				LocalPosition = ((Component)shop).transform.localPosition,
				LocalRotation = ((Component)shop).transform.localRotation,
				Children = new List<(Transform, Vector3, Quaternion)>(),
				Trigger = (SphereCollider)/*isinst with value type is only supported in some contexts*/
			};
			foreach (Transform item in ((Component)shop).transform)
			{
				Transform val = item;
				fitted.Children.Add((val, val.localPosition, val.localRotation));
			}
			if ((Object)(object)fitted.Trigger != (Object)null)
			{
				fitted.TriggerRadius = fitted.Trigger.radius;
			}
			Shops.Add(fitted);
			Start(fitted);
		}

		public static int RefitAll()
		{
			Shops.RemoveAll((Fitted f) => (Object)(object)f.Shop == (Object)null || (Object)(object)f.Display == (Object)null);
			foreach (Fitted shop in Shops)
			{
				Stop(shop);
				Restore(shop);
				Start(shop);
			}
			return Shops.Count;
		}

		private static void Start(Fitted fitted)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fitted.Trigger != (Object)null)
			{
				fitted.Trigger.radius = Mathf.Max(fitted.TriggerRadius, LifeRingModel.PropRadius * fitted.Display.lossyScale.x);
			}
			fitted.Running = ((MonoBehaviour)Plugin.Instance).StartCoroutine(Settle(fitted));
		}

		private static void Stop(Fitted fitted)
		{
			if (fitted.Running != null)
			{
				((MonoBehaviour)Plugin.Instance).StopCoroutine(fitted.Running);
			}
			fitted.Running = null;
			if ((Object)(object)fitted.Settler != (Object)null)
			{
				Object.Destroy((Object)(object)fitted.Settler);
			}
			fitted.Settler = null;
		}

		private static void Restore(Fitted fitted)
		{
			//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_003f: 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_0045: 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_0055: 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)
			Transform transform = ((Component)fitted.Shop).transform;
			transform.localPosition = fitted.LocalPosition;
			transform.localRotation = fitted.LocalRotation;
			foreach (var (val, localPosition, localRotation) in fitted.Children)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.localPosition = localPosition;
					val.localRotation = localRotation;
				}
			}
		}

		private static IEnumerator Settle(Fitted fitted)
		{
			for (int i = 0; i < 3; i++)
			{
				yield return null;
			}
			if ((Object)(object)fitted.Shop == (Object)null || (Object)(object)fitted.Display == (Object)null)
			{
				yield break;
			}
			Transform shop = ((Component)fitted.Shop).transform;
			Transform display = fitted.Display;
			float x = display.lossyScale.x;
			Vector3 ball = display.position;
			Quaternion val = Quaternion.LookRotation(Vector3.ProjectOnPlane(shop.forward, Vector3.up) + Vector3.forward * 0.0001f);
			float y = ((Quaternion)(ref val)).eulerAngles.y;
			float y2;
			float floorY = (TryFloor(ball, shop, out y2) ? y2 : (ball.y - LifeRingModel.RingOuterRadius * x));
			Vector3 position = default(Vector3);
			((Vector3)(ref position))..ctor(ball.x, floorY + LifeRingModel.RingOuterRadius * x + 0.02f, ball.z);
			Quaternion rotation = Quaternion.Euler(0f, y, 0f) * Quaternion.Euler(90f - LeanDegrees, 0f, 0f);
			Rigidbody body = CreateSettler(fitted, position, rotation, x);
			Follow(fitted, body);
			float simulated = 0f;
			while (simulated < SettleSeconds)
			{
				yield return (object)new WaitForFixedUpdate();
				if ((Object)(object)fitted.Shop == (Object)null || (Object)(object)fitted.Display == (Object)null || (Object)(object)body == (Object)null)
				{
					fitted.Running = null;
					Stop(fitted);
					yield break;
				}
				simulated += Time.fixedDeltaTime;
				Follow(fitted, body);
			}
			Vector3 position2 = body.position;
			fitted.Running = null;
			Stop(fitted);
			Vector3 val2 = Vector3.ProjectOnPlane(position2 - ball, Vector3.up);
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude > 3f || position2.y < floorY - 2f)
			{
				Restore(fitted);
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)$"[LifeRing] '{((Object)shop).name}': display ring fell to {position2} ({magnitude:0.00} m away); put back where the scene had the ball.");
				}
			}
			else
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)($"[LifeRing] '{((Object)shop).name}': display ring came to rest at {position2}, {magnitude:0.00} m from the ball, " + $"tilted {Vector3.Angle(display.forward, Vector3.up):0}° from flat."));
				}
			}
		}

		private static Rigidbody CreateSettler(Fitted fitted, Vector3 position, Quaternion rotation, float scale)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("LifeSaver_RingSettler")
			{
				layer = ItemLayer()
			};
			SceneManager.MoveGameObjectToScene(val, ((Component)fitted.Shop).gameObject.scene);
			val.transform.SetPositionAndRotation(position, rotation);
			val.transform.localScale = Vector3.one * scale;
			fitted.Settler = val;
			MeshCollider obj = val.AddComponent<MeshCollider>();
			obj.sharedMesh = LifeRingModel.ProbeMesh;
			obj.convex = true;
			Rigidbody obj2 = val.AddComponent<Rigidbody>();
			obj2.mass = 1f;
			obj2.angularDamping = 0.5f;
			obj2.collisionDetectionMode = (CollisionDetectionMode)3;
			return obj2;
		}

		private static int ItemLayer()
		{
			Item basePrefab = LifeRingItem.BasePrefab;
			if ((Object)(object)basePrefab != (Object)null)
			{
				Collider[] componentsInChildren = ((Component)basePrefab).GetComponentsInChildren<Collider>(true);
				foreach (Collider val in componentsInChildren)
				{
					if (!val.isTrigger)
					{
						return ((Component)val).gameObject.layer;
					}
				}
			}
			return 0;
		}

		private static void Follow(Fitted fitted, Rigidbody body)
		{
			//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_001b: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_00bf: 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_00ca: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00eb: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: 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_0133: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)fitted.Shop).transform;
			Transform display = fitted.Display;
			Vector3 position = body.position;
			Quaternion val = body.rotation * Quaternion.Euler(-90f, 0f, 0f);
			Vector3 val2 = position - display.position;
			List<(Transform, Vector3, Quaternion)> followScratch = FollowScratch;
			followScratch.Clear();
			foreach (Transform item in transform)
			{
				Transform val3 = item;
				if ((Object)(object)val3 != (Object)(object)display && !display.IsChildOf(val3))
				{
					followScratch.Add((val3, val3.position, val3.rotation));
				}
			}
			Quaternion val4 = Quaternion.Inverse(transform.rotation) * display.rotation;
			transform.rotation = val * Quaternion.Inverse(val4);
			transform.position += position - display.position;
			foreach (var (val5, val6, val7) in followScratch)
			{
				val5.SetPositionAndRotation(val6 + val2, val7);
			}
		}

		private static bool TryFloor(Vector3 ball, Transform shop, out float y)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//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_0022: 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_003f: 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)
			Vector3 val = ball + Vector3.up * 0.5f;
			float num = float.MaxValue;
			y = 0f;
			RaycastHit[] array = Physics.RaycastAll(val, Vector3.down, 3.5f, -1, (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val2 = array[i];
				if (!((Component)((RaycastHit)(ref val2)).collider).transform.IsChildOf(shop) && !(((RaycastHit)(ref val2)).distance >= num))
				{
					num = ((RaycastHit)(ref val2)).distance;
					y = ((RaycastHit)(ref val2)).point.y;
				}
			}
			return num < float.MaxValue;
		}
	}
}
namespace LifeSaver.Floating
{
	[HarmonyPatch(typeof(PlayerMovement), "FixedUpdate")]
	internal static class FloatPatch
	{
		private const float StaySwimmingMargin = 0.05f;

		private const float MaxSettleSpeed = 6f;

		private static readonly FieldRef<PlayerMovement, Player> PlayerRef = AccessTools.FieldRefAccess<PlayerMovement, Player>("_player");

		private static readonly FieldRef<PlayerMovement, Rigidbody> RigRef = AccessTools.FieldRefAccess<PlayerMovement, Rigidbody>("_rig");

		private static readonly FieldRef<PlayerMovement, bool> IsSwimmingRef = AccessTools.FieldRefAccess<PlayerMovement, bool>("_isSwimming");

		private static readonly FieldRef<PlayerMovement, int> SwimJumpCountRef = AccessTools.FieldRefAccess<PlayerMovement, int>("_swimJumpCount");

		private static readonly FieldRef<PlayerMovement, int> SwimJumpsAllowedRef = AccessTools.FieldRefAccess<PlayerMovement, int>("_swimJumpAmountAllowed");

		private static void Postfix(PlayerMovement __instance)
		{
			Player val = PlayerRef.Invoke(__instance);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.LocalPlayer))
			{
				SwimJumpsAllowedRef.Invoke(__instance) = Settings.Dev.SwimJumpsAllowed.Value;
				if (Settings.FloatEnabled.Value && IsSwimmingRef.Invoke(__instance) && !__instance.OnBoat && !Boat.IsDrivingLocally && LifeRingItem.IsLifeRing(val.Holding.HeldItem))
				{
					SwimJumpCountRef.Invoke(__instance) = 0;
					Lift(val, RigRef.Invoke(__instance));
				}
			}
		}

		private static void Lift(Player player, Rigidbody rig)
		{
			//IL_0018: 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_001e: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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)
			if (!((Object)(object)rig == (Object)null) && !rig.isKinematic)
			{
				Vector3 position = player.CamObject.position;
				float num = WaterManager.GetWaterHeight(position) + Settings.Dev.HeadClearance.Value - position.y;
				float num2 = WaterManager.WaterHeight - 0.05f - player.Transform.position.y;
				float num3 = Mathf.Clamp(Mathf.Min(num, num2) * Settings.Dev.Stiffness.Value, -6f, Settings.Dev.RiseSpeed.Value);
				Vector3 linearVelocity = rig.linearVelocity;
				if (!(linearVelocity.y >= num3))
				{
					linearVelocity.y = num3;
					rig.linearVelocity = linearVelocity;
				}
			}
		}
	}
}