Decompiled source of KikisLateJoin v1.0.1

plugins/KikisLateJoin.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using Zorro.Core;

[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("KikisLateJoin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("KikisLateJoin")]
[assembly: AssemblyTitle("KikisLateJoin")]
[assembly: AssemblyVersion("1.0.1.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 KLJ
{
	internal static class Anchor
	{
		internal const float LEAD = 15f;

		private const float FOG_MARGIN = 5f;

		private const float VOID_Y = 4000f;

		private const float GROUND_HOLD = 1f;

		private const float REVIVE_HEIGHT = 2.5f;

		private const float GROUND_RAY = 8f;

		private const float SILENT = 3f;

		private const float GROUND_GRACE = 0.35f;

		private static readonly float[] SpotRadii = new float[3] { 1.1f, 1.6f, 2.2f };

		private const int SPOT_DIRECTIONS = 12;

		private const float SPOT_CHEST_UP = 0.2f;

		private const float SPOT_PROBE_RADIUS = 0.3f;

		private const float SPOT_BODY_RADIUS = 0.35f;

		private const float SPOT_EDGE = 0.7f;

		private const float SPOT_MAX_STEP = 0.6f;

		private const float SPOT_SLOPE_PER_UNIT = 0.4f;

		private const float SPOT_BODY_FLOOR = 0.35f;

		private const float SPOT_MIN_NORMAL_Y = 0.77f;

		private const float SPOT_HEAD_EXTRA = 0.4f;

		private const float SPOT_LIFT = 0.25f;

		private const float SPOT_PERSON_GAP = 0.9f;

		private static readonly Dictionary<int, float> _groundedSince = new Dictionary<int, float>();

		private static readonly List<Vector3> _recentSpots = new List<Vector3>();

		private static float _spreadResetAt;

		private static int _spreadIndex;

		private static int _spotAngleIndex;

		private static FogSphere _sphere;

		private static OrbFogHandler _sphereOwner;

		private static readonly Dictionary<int, float> _lastPacket = new Dictionary<int, float>();

		private static readonly Dictionary<int, float> _lastGroundPacket = new Dictionary<int, float>();

		private static float _notesSince;

		private static bool _hooked;

		private static readonly Dictionary<LavaRising, StatusFieldGloom[]> _gloomFields = new Dictionary<LavaRising, StatusFieldGloom[]>();

		internal static void Reset()
		{
			_groundedSince.Clear();
			_recentSpots.Clear();
			_sphere = null;
			_sphereOwner = null;
			_lastPacket.Clear();
			_lastGroundPacket.Clear();
			_notesSince = Time.time;
		}

		internal static bool Hook(Harmony h)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(CharacterSyncer), "OnDataReceived", new Type[1] { typeof(CharacterSyncData) }, (Type[])null);
				if (methodInfo == null)
				{
					return false;
				}
				h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Anchor), "PacketPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_hooked = true;
				return true;
			}
			catch (Exception e)
			{
				Plugin.Error("packet hook", e);
				return false;
			}
		}

		internal static void PacketPostfix(CharacterSyncer __instance, CharacterSyncData data)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!PhotonNetwork.IsMasterClient)
				{
					return;
				}
				PhotonView photonView = ((MonoBehaviourPun)__instance).photonView;
				if (!((Object)(object)photonView == (Object)null))
				{
					float time = Time.time;
					_lastPacket[photonView.ViewID] = time;
					if (data.isGrounded)
					{
						_lastGroundPacket[photonView.ViewID] = time;
					}
				}
			}
			catch
			{
			}
		}

		private static float SilentFor(Character a, float now)
		{
			if (!_hooked || (Object)(object)a == (Object)null || a.IsLocal || (Object)(object)((MonoBehaviourPun)a).photonView == (Object)null)
			{
				return 0f;
			}
			if (!_lastPacket.TryGetValue(((MonoBehaviourPun)a).photonView.ViewID, out var value))
			{
				value = _notesSince;
			}
			return now - value;
		}

		internal static string SilentPlayers(Character joiner, float now)
		{
			string text = "";
			List<Character> allCharacters = Character.AllCharacters;
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				try
				{
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)joiner) && !val.isBot && !((Object)(object)val.data == (Object)null) && !val.data.dead && val.IsPlayerControlled)
					{
						float num = SilentFor(val, now);
						if (num > 3f)
						{
							text = text + ((text.Length > 0) ? ", '" : "'") + Plugin.Name(val) + "' " + num.ToString("0") + "s";
						}
					}
				}
				catch
				{
				}
			}
			return text;
		}

		internal static void TrackGround(float now)
		{
			List<Character> allCharacters = Character.AllCharacters;
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if ((Object)(object)val == (Object)null || (Object)(object)((MonoBehaviourPun)val).photonView == (Object)null || (Object)(object)val.data == (Object)null)
				{
					continue;
				}
				int viewID = ((MonoBehaviourPun)val).photonView.ViewID;
				if (!val.data.dead && OnSolidGround(val, now))
				{
					if (!_groundedSince.ContainsKey(viewID))
					{
						_groundedSince[viewID] = now;
					}
				}
				else
				{
					_groundedSince.Remove(viewID);
				}
			}
		}

		internal static Character Rearmost(Character joiner, HashSet<Character> skip, out string how)
		{
			return Rearmost(joiner, skip, mustStand: false, 0f, out how);
		}

		internal static Character Rearmost(Character joiner, HashSet<Character> skip, bool mustStand, float now, out string how)
		{
			//IL_007d: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			OrbFogHandler fog = null;
			try
			{
				fog = Singleton<OrbFogHandler>.Instance;
			}
			catch
			{
			}
			LavaRising riser = CurrentRiser();
			Vector3 pos;
			bool flag = CampfireAhead(out pos);
			Character val = null;
			float num = float.MinValue;
			List<Character> allCharacters = Character.AllCharacters;
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val2 = allCharacters[i];
				if (!((Object)(object)val2 == (Object)(object)joiner) && (skip == null || !skip.Contains(val2)) && IsCandidate(val2, fog, riser) && (!mustStand || Stable(val2, now)))
				{
					float num2 = (flag ? Vector3.Distance(pos, val2.Center) : (0f - val2.Center.y));
					if (!((Object)(object)val != (Object)null) || !(num2 <= num))
					{
						val = val2;
						num = num2;
					}
				}
			}
			how = (flag ? ("the scout furthest from the campfire, " + (num * CharacterStats.unitsToMeters).ToString("0") + " m") : "the lowest scout, no campfire ahead");
			return val;
		}

		private static bool CampfireAhead(out Vector3 pos)
		{
			//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_0020: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected I4, but got Unknown
			//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)
			pos = Vector3.zero;
			try
			{
				MapHandler instance = Singleton<MapHandler>.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return false;
				}
				Segment currentSegment = instance.GetCurrentSegment();
				if ((int)currentSegment == 6)
				{
					return false;
				}
				GameObject campfireRoot = MapHandler.GetCampfireRoot((int)currentSegment);
				Campfire val = (((Object)(object)campfireRoot != (Object)null) ? campfireRoot.GetComponentInChildren<Campfire>(true) : null);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				pos = ((Component)val).transform.position;
				return true;
			}
			catch
			{
				return false;
			}
		}

		internal static bool Stable(Character a, float now)
		{
			//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_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_0058: 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)
			if ((Object)(object)a == (Object)null || (Object)(object)((MonoBehaviourPun)a).photonView == (Object)null)
			{
				return false;
			}
			if (!_groundedSince.TryGetValue(((MonoBehaviourPun)a).photonView.ViewID, out var value) || now - value < 1f)
			{
				return false;
			}
			return Physics.Raycast(a.Center + Vector3.up * 2.5f, Vector3.down, 8f, LayerMask.op_Implicit(HelperFunctions.AllPhysicalExceptCharacter));
		}

		private static bool IsCandidate(Character a, OrbFogHandler fog, LavaRising riser)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			try
			{
				if ((Object)(object)a == (Object)null || a.isBot || (Object)(object)a.data == (Object)null || !a.IsPlayerControlled || (Object)(object)((MonoBehaviourPun)a).photonView == (Object)null)
				{
					return false;
				}
				if (a.data.dead || a.data.passedOut || a.data.fullyPassedOut || (Object)(object)a.Ghost != (Object)null)
				{
					return false;
				}
				if (a.warping || a.data.isCarried || a.Center.y > 4000f)
				{
					return false;
				}
				if (SilentFor(a, Time.time) > 3f)
				{
					return false;
				}
				if (InFog(a, fog))
				{
					return false;
				}
				if (InRisingGloom(riser, a.Head) || InRisingGloom(riser, a.Head + Vector3.up * 2f))
				{
					return false;
				}
				float num = GloomRiseIn(riser, 15f);
				if (num > 0f && InRisingGloom(riser, a.Head - Vector3.up * num))
				{
					return false;
				}
				return !BelowRisingLava(riser, a);
			}
			catch
			{
				return false;
			}
		}

		private static bool OnSolidGround(Character c, float now)
		{
			CharacterData data = c.data;
			if (data.isClimbing || data.isRopeClimbing || data.isVineClimbing || data.isCarried)
			{
				return false;
			}
			if (!_hooked)
			{
				return data.isGrounded;
			}
			if (c.IsLocal)
			{
				if (!data.isGrounded)
				{
					return data.sinceGrounded <= 0.35f;
				}
				return true;
			}
			if (_lastGroundPacket.TryGetValue(((MonoBehaviourPun)c).photonView.ViewID, out var value))
			{
				return now - value <= 0.35f;
			}
			return false;
		}

		private static bool InFog(Character a, OrbFogHandler fog)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fog == (Object)null || LoadingScreenHandler.loading || !Ascents.fogEnabled)
			{
				return false;
			}
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null || (int)instance.GetCurrentSegment() >= 4)
			{
				return false;
			}
			if ((Object)(object)_sphereOwner != (Object)(object)fog || (Object)(object)_sphere == (Object)null)
			{
				_sphereOwner = fog;
				_sphere = ((Component)fog).GetComponentInChildren<FogSphere>(true);
			}
			FogSphere sphere = _sphere;
			if ((Object)(object)sphere == (Object)null || !((Component)sphere).gameObject.activeInHierarchy || sphere.ENABLE < 0.5f)
			{
				return false;
			}
			float num = 5f;
			if (fog.isMoving && fog.speed > 0f)
			{
				num = Mathf.Max(num, fog.speed * 15f);
			}
			return Vector3.Distance(sphere.fogPoint, a.Center) > sphere.currentSize - num;
		}

		private static LavaRising CurrentRiser()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			List<LavaRising> aLL_LAVA = LavaRising.ALL_LAVA;
			MapHandler instance = Singleton<MapHandler>.Instance;
			if (aLL_LAVA == null || (Object)(object)instance == (Object)null)
			{
				return null;
			}
			Segment currentSegment = instance.GetCurrentSegment();
			for (int i = 0; i < aLL_LAVA.Count; i++)
			{
				if ((Object)(object)aLL_LAVA[i] != (Object)null && aLL_LAVA[i].requiredSegment == currentSegment)
				{
					return aLL_LAVA[i];
				}
			}
			return null;
		}

		private static bool InRisingGloom(LavaRising r, Vector3 point)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)r == (Object)null || (int)r.risingFieldType != 1 || !r.started)
			{
				return false;
			}
			if (!_gloomFields.TryGetValue(r, out var value) || value == null)
			{
				value = ((Component)r).GetComponentsInChildren<StatusFieldGloom>(true);
				_gloomFields[r] = value;
			}
			for (int i = 0; i < value.Length; i++)
			{
				if ((Object)(object)value[i] != (Object)null && ((Component)value[i]).gameObject.activeInHierarchy && ((StatusFieldBounds)value[i]).PointInField(point))
				{
					return true;
				}
			}
			return false;
		}

		private static float GloomRiseIn(LavaRising r, float seconds)
		{
			//IL_004f: 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 ((Object)(object)r == (Object)null || !r.started || r.ended || (Object)(object)r.lava == (Object)null || (Object)(object)r.topTransform == (Object)null)
			{
				return 0f;
			}
			float num = r.travelTime - r.timeTraveled;
			float num2 = r.topTransform.position.y - ((Component)r.lava).transform.position.y;
			if (num <= 0.05f || num2 <= 0f)
			{
				return 0f;
			}
			return Mathf.Min(num2, num2 / num * seconds);
		}

		private static bool BelowRisingLava(LavaRising r, Character c)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)r == (Object)null || (int)r.risingFieldType != 0 || !r.started || (Object)(object)r.lava == (Object)null)
			{
				return false;
			}
			return c.Center.y < ((Component)r.lava).transform.position.y + 3f;
		}

		internal static bool FindSpot(Character anchor, Character joiner, out Vector3 pos)
		{
			//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_0027: 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_0038: 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_0053: 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_0078: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: 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)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time > _spreadResetAt)
			{
				_spreadIndex = 0;
				_recentSpots.Clear();
			}
			pos = Vector3.zero;
			int num = LayerMask.op_Implicit(HelperFunctions.AllPhysicalExceptCharacter);
			Vector3 center = anchor.Center;
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(center, Vector3.down, ref val, 8f, num, (QueryTriggerInteraction)1))
			{
				return false;
			}
			float y = ((RaycastHit)(ref val)).point.y;
			float num2 = Mathf.Clamp(center.y - y, 0.5f, 2.5f);
			float num3 = Mathf.Clamp(anchor.Head.y - y, num2 + 0.2f, 3.5f) + 0.4f;
			Vector3 val2 = center + Vector3.up * 0.2f;
			bool flag = !Physics.CheckSphere(val2, 0.3f, num, (QueryTriggerInteraction)1);
			float num4 = MathF.PI / 6f;
			float num5 = (float)_spotAngleIndex++ * 2.3999631f;
			Vector3 val3 = default(Vector3);
			RaycastHit val4 = default(RaycastHit);
			for (int i = 0; i < SpotRadii.Length; i++)
			{
				float num6 = SpotRadii[i];
				for (int j = 0; j < 12; j++)
				{
					float num7 = num5 + (float)j * num4;
					((Vector3)(ref val3))..ctor(Mathf.Cos(num7), 0f, Mathf.Sin(num7));
					float num8 = num6 + 0.7f;
					if (Physics.Raycast(val2, val3, num8, num, (QueryTriggerInteraction)1) || (flag && Physics.SphereCast(val2, 0.3f, val3, ref val4, num8, num, (QueryTriggerInteraction)1)) || !GroundAt(val2 + val3 * num6, y, num2, num6, out var hit) || !GroundAt(val2 + val3 * num8, y, num2, num8, out var _))
					{
						continue;
					}
					Vector3 point = ((RaycastHit)(ref hit)).point;
					if (Physics.Raycast(point + Vector3.up * 0.1f, Vector3.up, num3, num, (QueryTriggerInteraction)1))
					{
						continue;
					}
					Vector3 val5 = point + Vector3.up * 0.7f;
					Vector3 val6 = point + Vector3.up * Mathf.Max(num3 - 0.35f, 0.8f);
					if (!Physics.CheckCapsule(val5, val6, 0.35f, num, (QueryTriggerInteraction)1))
					{
						Vector3 val7 = point + Vector3.up * (num2 + 0.25f);
						if (!Occupied(val7, joiner))
						{
							pos = val7;
							Remember(pos);
							return true;
						}
					}
				}
			}
			return false;
		}

		internal static Vector3 ForcedSpot(Character anchor)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			int num = LayerMask.op_Implicit(HelperFunctions.AllPhysicalExceptCharacter);
			Vector3 center = anchor.Center;
			float num2 = Mathf.Max(anchor.Head.y - center.y, 0.3f) + 0.4f;
			float num3 = 2.5f;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(anchor.Head, Vector3.up, ref val, 2.5f + num2, num, (QueryTriggerInteraction)1))
			{
				num3 = Mathf.Clamp(((RaycastHit)(ref val)).point.y - num2 - center.y, 0f, 2.5f);
			}
			Vector3 val2 = center + Vector3.up * num3;
			int num4 = _spreadIndex++;
			if (num4 > 0)
			{
				float num5 = (float)num4 * 2.3999631f;
				Vector3 val3 = new Vector3(Mathf.Cos(num5), 0f, Mathf.Sin(num5)) * 1.2f;
				if (!Physics.Raycast(val2, ((Vector3)(ref val3)).normalized, ((Vector3)(ref val3)).magnitude + 0.3f, num, (QueryTriggerInteraction)1))
				{
					val2 += val3;
				}
			}
			Remember(val2);
			return val2;
		}

		private static void Remember(Vector3 p)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			_spreadResetAt = Time.time + 3f;
			_recentSpots.Add(p);
		}

		private static bool GroundAt(Vector3 top, float groundY, float torsoH, float dist, out RaycastHit hit)
		{
			//IL_001e: 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_0027: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			float num = 0.6f + dist * 0.4f;
			float num2 = torsoH + 0.2f + num + 0.3f;
			if (!Physics.Raycast(top, Vector3.down, ref hit, num2, LayerMask.op_Implicit(HelperFunctions.AllPhysicalExceptCharacter), (QueryTriggerInteraction)1))
			{
				return false;
			}
			if (Mathf.Abs(((RaycastHit)(ref hit)).point.y - groundY) > num)
			{
				return false;
			}
			return ((RaycastHit)(ref hit)).normal.y >= 0.77f;
		}

		private static bool Occupied(Vector3 target, Character joiner)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			List<Character> allCharacters = Character.AllCharacters;
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				try
				{
					if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)joiner || (Object)(object)val.data == (Object)null || val.data.dead || !(Vector3.Distance(val.Center, target) < 0.9f))
					{
						continue;
					}
					return true;
				}
				catch
				{
				}
			}
			for (int j = 0; j < _recentSpots.Count; j++)
			{
				if (Vector3.Distance(_recentSpots[j], target) < 0.9f)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal class Joiners : MonoBehaviourPunCallbacks
	{
		private class Pending
		{
			public Player Player;

			public string Name;

			public float JoinedAt;

			public float SeenAt;

			public float AnchorSince;

			public float NotedAt = -999f;
		}

		private readonly Dictionary<int, Pending> _pending = new Dictionary<int, Pending>();

		private readonly HashSet<string> _runSeen = new HashSet<string>();

		private readonly HashSet<string> _arrivedBefore = new HashSet<string>();

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

		private readonly HashSet<Character> _skip = new HashSet<Character>();

		private bool _wasOnIsland;

		private float _nextTick;

		private float _nextSweep;

		private const float TICK = 0.25f;

		private const float SWEEP = 2f;

		private static bool OnIsland()
		{
			try
			{
				return GameHandler.IsOnIsland;
			}
			catch
			{
				return false;
			}
		}

		private static string Key(Player p)
		{
			if (p == null)
			{
				return "";
			}
			if (!string.IsNullOrEmpty(p.UserId))
			{
				return "id:" + p.UserId;
			}
			return "nick:" + p.NickName;
		}

		private void Update()
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				if (_pending.Count > 0 || _runSeen.Count > 0 || _arrivedBefore.Count > 0)
				{
					_pending.Clear();
					_runSeen.Clear();
					_arrivedBefore.Clear();
				}
				_wasOnIsland = false;
				return;
			}
			if (!OnIsland())
			{
				if (_wasOnIsland || _pending.Count > 0)
				{
					_pending.Clear();
					_runSeen.Clear();
					_arrivedBefore.Clear();
					Anchor.Reset();
				}
				_wasOnIsland = false;
				return;
			}
			float now = Time.time;
			if (!_wasOnIsland)
			{
				_wasOnIsland = true;
				_runSeen.Clear();
				_arrivedBefore.Clear();
				_pending.Clear();
				Anchor.Reset();
				_nextSweep = 0f;
			}
			if (now >= _nextSweep)
			{
				_nextSweep = now + 2f;
				Plugin.Safe("sweep", SweepRunSeen);
			}
			if (_pending.Count == 0 || !Plugin.Enabled.Value || now < _nextTick)
			{
				return;
			}
			_nextTick = now + 0.25f;
			Plugin.Safe("ground", delegate
			{
				Anchor.TrackGround(now);
			});
			_done.Clear();
			foreach (KeyValuePair<int, Pending> item in _pending)
			{
				int actor = item.Key;
				Pending p = item.Value;
				Plugin.Safe("process", delegate
				{
					if (Process(p, now))
					{
						_done.Add(actor);
					}
				});
			}
			for (int num = 0; num < _done.Count; num++)
			{
				if (_pending.TryGetValue(_done[num], out var value) && HasCharacter(value.Player))
				{
					_runSeen.Add(Key(value.Player));
				}
				_pending.Remove(_done[num]);
			}
		}

		private static bool HasCharacter(Player p)
		{
			if (p == null)
			{
				return false;
			}
			try
			{
				Character playerCharacter = PlayerHandler.GetPlayerCharacter(p);
				return (Object)(object)playerCharacter != (Object)null && (Object)(object)playerCharacter.data != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private void SweepRunSeen()
		{
			if (!PhotonNetwork.InRoom)
			{
				return;
			}
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				if (val != null && !_pending.ContainsKey(val.ActorNumber) && HasCharacter(val))
				{
					_runSeen.Add(Key(val));
				}
			}
		}

		public override void OnPlayerEnteredRoom(Player p)
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			Plugin.Safe("entered", delegate
			{
				if (p != null && !p.IsLocal && OnIsland())
				{
					string item = Key(p);
					bool flag = _arrivedBefore.Contains(item);
					_arrivedBefore.Add(item);
					bool flag2 = false;
					try
					{
						flag2 = RunSettings.isMiniRun;
					}
					catch
					{
					}
					if (!flag2)
					{
						bool flag3 = _runSeen.Contains(item);
						try
						{
							ReconnectData val = default(ReconnectData);
							SerializableRunBasedValues val2 = default(SerializableRunBasedValues);
							if (ReconnectHandler.TryGetReconnectData(p, ref val, ref val2))
							{
								flag3 = true;
							}
						}
						catch
						{
						}
						if (flag3)
						{
							_runSeen.Add(item);
							Plugin.L.LogInfo((object)("[KLJ] '" + Plugin.Name(p) + "' is back (had a character in this climb before) - the game handles it"));
						}
						else
						{
							_pending[p.ActorNumber] = new Pending
							{
								Player = p,
								Name = Plugin.Name(p),
								JoinedAt = Time.time
							};
							Plugin.L.LogInfo((object)("[KLJ] '" + Plugin.Name(p) + "' joined the climb in progress - waiting for them to arrive" + (flag ? " (they were in the room before, but never had a character here - so not a returning player)" : "")));
						}
					}
				}
			});
		}

		public override void OnPlayerLeftRoom(Player p)
		{
			if (p != null && _pending.ContainsKey(p.ActorNumber))
			{
				_pending.Remove(p.ActorNumber);
				if (PhotonNetwork.IsMasterClient)
				{
					Plugin.L.LogInfo((object)("[KLJ] '" + Plugin.Name(p) + "' left before they were placed"));
				}
			}
		}

		public override void OnMasterClientSwitched(Player newMaster)
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				_pending.Clear();
				_runSeen.Clear();
				_arrivedBefore.Clear();
				_wasOnIsland = false;
			}
		}

		public override void OnLeftRoom()
		{
			_pending.Clear();
			_runSeen.Clear();
			_arrivedBefore.Clear();
			_wasOnIsland = false;
		}

		private bool Process(Pending p, float now)
		{
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.CurrentRoom == null || PhotonNetwork.CurrentRoom.GetPlayer(p.Player.ActorNumber, false) == null)
			{
				return true;
			}
			Character playerCharacter = PlayerHandler.GetPlayerCharacter(p.Player);
			if ((Object)(object)playerCharacter == (Object)null || (Object)(object)playerCharacter.data == (Object)null)
			{
				if (now - p.JoinedAt <= Plugin.GiveUpSeconds.Value)
				{
					return false;
				}
				Plugin.L.LogInfo((object)("[KLJ] gave up on '" + p.Name + "' - no character after " + Plugin.GiveUpSeconds.Value.ToString("0") + "s"));
				return true;
			}
			if (p.SeenAt == 0f)
			{
				p.SeenAt = now;
				return false;
			}
			float num = Plugin.SettleSeconds.Value;
			if (playerCharacter.data.dead && !GameRevivesAtCamp())
			{
				num = Mathf.Min(num, Plugin.DeadSettleSeconds.Value);
			}
			if (now - p.SeenAt < num || playerCharacter.warping)
			{
				return false;
			}
			if (now - p.SeenAt > Plugin.GiveUpSeconds.Value)
			{
				Plugin.L.LogInfo((object)("[KLJ] gave up on '" + p.Name + "' - nobody to bring them to for " + Plugin.GiveUpSeconds.Value.ToString("0") + "s, the game decides"));
				return true;
			}
			bool flag = false;
			try
			{
				flag = VoidBiome.VoidBiomeActive && VoidBiome.SoulFreedStatus == 1;
			}
			catch
			{
			}
			if (flag)
			{
				Plugin.L.LogInfo((object)("[KLJ] '" + p.Name + "' arrived after the soul was freed - the game decides, like vanilla"));
				return true;
			}
			if (playerCharacter.data.dead)
			{
				if (HasItems(playerCharacter))
				{
					Plugin.L.LogWarning((object)("[KLJ] '" + p.Name + "' is dead but carries items - not reviving (the revive would drop them), the game decides"));
					return true;
				}
				return Place(p, playerCharacter, now, revive: true);
			}
			if (!Plugin.BringFromBaseCamp.Value)
			{
				Plugin.L.LogInfo((object)("[KLJ] '" + p.Name + "' arrived alive - left where the game put them"));
				return true;
			}
			BuildSkip(playerCharacter);
			string how;
			Character val = Anchor.Rearmost(playerCharacter, _skip, out how);
			if ((Object)(object)val == (Object)null)
			{
				return Waiting(p, now, "no teammate is alive, awake and safe from the fog right now");
			}
			float num2 = Vector3.Distance(playerCharacter.Center, val.Center) * CharacterStats.unitsToMeters;
			if (num2 <= Plugin.FarMeters.Value)
			{
				Plugin.L.LogInfo((object)("[KLJ] '" + p.Name + "' arrived alive " + num2.ToString("0") + " m from '" + Plugin.Name(val) + "' (" + how + ") - left there"));
				return true;
			}
			return Place(p, playerCharacter, now, revive: false);
		}

		private bool Place(Pending p, Character c, float now, bool revive)
		{
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: 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_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)
			BuildSkip(c);
			string how;
			Character val = Anchor.Rearmost(c, _skip, out how);
			if ((Object)(object)val == (Object)null)
			{
				return Waiting(p, now, "no teammate is alive, awake, sending data and at least " + 15f.ToString("0") + "s ahead of the fog/gloom right now");
			}
			if (p.AnchorSince == 0f)
			{
				p.AnchorSince = now;
			}
			bool flag = now - p.AnchorSince >= Plugin.AnchorWaitSeconds.Value;
			string how2;
			Character val2 = Anchor.Rearmost(c, _skip, mustStand: true, now, out how2);
			if ((Object)(object)val2 != (Object)null)
			{
				how = how2;
			}
			else
			{
				if (!flag)
				{
					return Waiting(p, now, "nobody is standing on solid ground right now (furthest back: '" + Plugin.Name(val) + "')");
				}
				val2 = val;
			}
			string text = (((Object)(object)val2 != (Object)(object)val) ? (" | '" + Plugin.Name(val) + "' is further back but not on solid ground") : "");
			string text2 = Anchor.SilentPlayers(c, now);
			if (text2.Length > 0)
			{
				text = text + " | no data from " + text2;
			}
			bool flag2 = false;
			if (!Anchor.FindSpot(val2, c, out var pos))
			{
				if (!flag)
				{
					return Waiting(p, now, "no free spot next to '" + Plugin.Name(val2) + "' yet");
				}
				pos = Anchor.ForcedSpot(val2);
				flag2 = true;
			}
			float num = now - p.JoinedAt;
			if (revive)
			{
				((MonoBehaviourPun)c).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { pos, false, -1 });
				Plugin.L.LogInfo((object)("[KLJ] '" + p.Name + "' revived next to '" + Plugin.Name(val2) + "' (" + how + ")" + (flag2 ? " - FORCED, no free spot found" : " on a free spot") + " | " + num.ToString("0") + "s after joining, " + (now - p.SeenAt).ToString("0.0") + "s after arriving" + text));
			}
			else
			{
				float num2 = Vector3.Distance(c.Center, val2.Center) * CharacterStats.unitsToMeters;
				((MonoBehaviourPun)c).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { pos, true });
				Plugin.L.LogInfo((object)("[KLJ] '" + p.Name + "' arrived alive " + num2.ToString("0") + " m behind - brought to '" + Plugin.Name(val2) + "' (" + how + ")" + (flag2 ? " - FORCED, no free spot found" : " on a free spot") + " | " + num.ToString("0") + "s after joining" + text));
			}
			return true;
		}

		private static bool GameRevivesAtCamp()
		{
			try
			{
				return MapHandler.BaseCampHasRevived && MapHandler.LastSeenCampfireIsSafe;
			}
			catch
			{
				return true;
			}
		}

		private void BuildSkip(Character self)
		{
			_skip.Clear();
			foreach (Pending value in _pending.Values)
			{
				Character val = null;
				try
				{
					val = PlayerHandler.GetPlayerCharacter(value.Player);
				}
				catch
				{
				}
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)self)
				{
					_skip.Add(val);
				}
			}
		}

		private static bool Waiting(Pending p, float now, string why)
		{
			if (now - p.NotedAt > 30f)
			{
				p.NotedAt = now;
				Plugin.L.LogInfo((object)("[KLJ] '" + p.Name + "' is waiting: " + why));
			}
			return false;
		}

		private static bool HasItems(Character c)
		{
			try
			{
				Player player = c.player;
				if ((Object)(object)player == (Object)null)
				{
					return false;
				}
				for (int i = 0; i < player.itemSlots.Length; i++)
				{
					if (player.itemSlots[i] != null && !player.itemSlots[i].IsEmpty())
					{
						return true;
					}
				}
				if (player.backpackSlot != null && !((ItemSlot)player.backpackSlot).IsEmpty())
				{
					return true;
				}
				if (player.tempFullSlot != null && !player.tempFullSlot.IsEmpty())
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}
	}
	[BepInPlugin("kikislatejoin.peak.klj", "Kikis Late Join", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		internal sealed class Fixed<T>
		{
			public readonly T Value;

			public Fixed(T v)
			{
				Value = v;
			}
		}

		public const string GUID = "kikislatejoin.peak.klj";

		public const string NAME = "Kikis Late Join";

		public const string VERSION = "1.0.1";

		internal static Plugin Instance;

		internal static ManualLogSource L;

		internal static readonly Fixed<bool> Enabled = new Fixed<bool>(v: true);

		internal static readonly Fixed<float> SettleSeconds = new Fixed<float>(3f);

		internal static readonly Fixed<float> DeadSettleSeconds = new Fixed<float>(0.5f);

		internal static readonly Fixed<float> GiveUpSeconds = new Fixed<float>(180f);

		internal static readonly Fixed<float> AnchorWaitSeconds = new Fixed<float>(20f);

		internal static readonly Fixed<bool> BringFromBaseCamp = new Fixed<bool>(v: true);

		internal static readonly Fixed<float> FarMeters = new Fixed<float>(40f);

		private static readonly HashSet<string> _errors = new HashSet<string>();

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Instance = this;
			L = ((BaseUnityPlugin)this).Logger;
			bool flag = Anchor.Hook(new Harmony("kikislatejoin.peak.klj"));
			((Component)this).gameObject.AddComponent<Joiners>();
			string text = "";
			if (Chainloader.PluginInfos.ContainsKey("com.sol.latejoinfix"))
			{
				text += " | WARNING: LateJoinFix is loaded too - turn one of them off";
			}
			if (Chainloader.PluginInfos.ContainsKey("com.iatespaghetti.waitformeak"))
			{
				text += " | WARNING: WaitForMEak is loaded too - turn one of them off";
			}
			L.LogInfo((object)("[KLJ] Kikis Late Join 1.0.1 loaded - host-locked (does nothing as a guest) | settle " + SettleSeconds.Value.ToString("0") + "s (dead " + DeadSettleSeconds.Value.ToString("0.0#") + "s), scout furthest from the campfire (else the lowest) who is standing and " + (flag ? "sending" : "PACKET HOOK MISSING") + ", " + 15f.ToString("0") + "s ahead of fog/gloom | base camp: bring to group beyond " + FarMeters.Value.ToString("0") + " m" + text));
		}

		internal static void Safe(string where, Action a)
		{
			try
			{
				a();
			}
			catch (Exception e)
			{
				Error(where, e);
			}
		}

		internal static void Error(string where, Exception e)
		{
			if (_errors.Add(where + "|" + e.GetType().Name))
			{
				L.LogWarning((object)("[KLJ] error in " + where + ": " + e));
			}
		}

		internal static string Name(Character c)
		{
			try
			{
				return ((Object)(object)c != (Object)null) ? c.characterName : "?";
			}
			catch
			{
				return "?";
			}
		}

		internal static string Name(Player p)
		{
			try
			{
				return (p != null) ? p.NickName : "?";
			}
			catch
			{
				return "?";
			}
		}
	}
}