Decompiled source of Chainbound v0.2.16

plugins\patchnote.Chainbound.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak.Afflictions;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Chainbound
{
	public static class ChainboundAPI
	{
		public static bool HostHasChainbound => ChainboundPlugin.Instance?.ApiHostHasChainbound ?? false;

		public static bool Enabled => ChainboundPlugin.Instance?.ApiEnabled ?? false;

		public static event Action<IReadOnlyList<IReadOnlyList<ChainboundGroupMember>>>? GroupsChanged;

		public static IReadOnlyList<IReadOnlyList<ChainboundGroupMember>> GetGroups()
		{
			return ChainboundPlugin.Instance?.GetApiGroupsSnapshot() ?? Array.Empty<IReadOnlyList<ChainboundGroupMember>>();
		}

		public static bool TryGetGroupForActor(int actorNumber, out IReadOnlyList<ChainboundGroupMember> group)
		{
			foreach (IReadOnlyList<ChainboundGroupMember> group2 in GetGroups())
			{
				if (group2.Any((ChainboundGroupMember member) => member.ActorNumber == actorNumber))
				{
					group = group2;
					return true;
				}
			}
			group = Array.Empty<ChainboundGroupMember>();
			return false;
		}

		internal static void NotifyGroupsChanged(IReadOnlyList<IReadOnlyList<ChainboundGroupMember>> groups)
		{
			Action<IReadOnlyList<IReadOnlyList<ChainboundGroupMember>>> groupsChanged = ChainboundAPI.GroupsChanged;
			if (groupsChanged == null)
			{
				return;
			}
			Delegate[] invocationList = groupsChanged.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<IReadOnlyList<IReadOnlyList<ChainboundGroupMember>>> action = (Action<IReadOnlyList<IReadOnlyList<ChainboundGroupMember>>>)invocationList[i];
				try
				{
					action(groups);
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"ChainboundAPI.GroupsChanged subscriber failed: {arg}");
				}
			}
		}
	}
	public sealed class ChainboundGroupMember
	{
		public int ActorNumber { get; }

		public string DisplayName { get; }

		public string StableKey { get; }

		public bool IsLocal { get; }

		public bool IsAlive { get; }

		public Character? Character { get; }

		internal ChainboundGroupMember(int actorNumber, string displayName, string stableKey, bool isLocal, bool isAlive, Character? character)
		{
			ActorNumber = actorNumber;
			DisplayName = displayName;
			StableKey = stableKey;
			IsLocal = isLocal;
			IsAlive = isAlive;
			Character = character;
		}
	}
	[BepInPlugin("patchnote.chainbound", "Chainbound", "0.2.16")]
	public sealed class ChainboundPlugin : BaseUnityPlugin
	{
		private sealed class ChainState
		{
			internal readonly List<ChainLink> Links = new List<ChainLink>();

			internal readonly List<ChainLink> LocalLinks = new List<ChainLink>();

			internal readonly HashSet<Character> ObservedCharacters = new HashSet<Character>();

			internal readonly List<Player> MissingMod = new List<Player>();

			internal readonly List<Player> VersionMismatches = new List<Player>();

			internal List<Character> LocalLivingChunk = new List<Character>();

			internal List<ChainMember> LocalMembers = new List<ChainMember>();

			internal List<ChainMember?> LocalChunkSlots = new List<ChainMember>();

			internal int LocalSlotIndex = -1;

			internal bool LocalHasStrongAnchor;
		}

		private sealed class FallVelocitySample
		{
			private const int SampleCount = 8;

			private readonly float[] _downSpeeds = new float[8];

			private int _nextIndex;

			internal Vector3 LastCenter { get; set; }

			internal float LastTime { get; set; }

			internal int Count { get; private set; }

			internal FallVelocitySample(Vector3 center, float time)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				LastCenter = center;
				LastTime = time;
			}

			internal void AddDownSpeed(float downSpeed)
			{
				_downSpeeds[_nextIndex] = downSpeed;
				_nextIndex = (_nextIndex + 1) % _downSpeeds.Length;
				Count = Mathf.Min(Count + 1, _downSpeeds.Length);
			}

			internal float[] GetSortedSpeeds()
			{
				float[] array = new float[Count];
				Array.Copy(_downSpeeds, array, Count);
				Array.Sort(array);
				return array;
			}
		}

		private sealed class ProxyBody
		{
			internal GameObject GameObject { get; }

			internal Rigidbody Body { get; }

			internal int WarmupSteps { get; set; }

			internal ProxyBody(GameObject gameObject, Rigidbody body)
			{
				GameObject = gameObject;
				Body = body;
			}
		}

		private readonly struct ProxyCorrectionResult
		{
			internal Vector3 Acceleration { get; }

			internal int LocalProxyCount { get; }

			internal bool HasUpperAnchorTension { get; }

			internal ProxyCorrectionResult(Vector3 acceleration, int localProxyCount, bool hasUpperAnchorTension)
			{
				//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)
				Acceleration = acceleration;
				LocalProxyCount = localProxyCount;
				HasUpperAnchorTension = hasUpperAnchorTension;
			}
		}

		private sealed class ChainMember
		{
			internal Player Player { get; }

			internal string StableKey { get; }

			internal Character? Character { get; }

			internal Character? ForceTarget { get; }

			internal int ActorNumber => Player.ActorNumber;

			internal ChainMember(Player player, string stableKey, Character? character, Character? forceTarget)
			{
				Player = player;
				StableKey = stableKey;
				Character = character;
				ForceTarget = forceTarget;
			}
		}

		private readonly struct ChainLink
		{
			internal ChainMember Left { get; }

			internal ChainMember Right { get; }

			internal string Key
			{
				get
				{
					if (Left.ActorNumber >= Right.ActorNumber)
					{
						return $"{Right.ActorNumber}:{Left.ActorNumber}";
					}
					return $"{Left.ActorNumber}:{Right.ActorNumber}";
				}
			}

			internal ChainLink(ChainMember left, ChainMember right)
			{
				Left = left;
				Right = right;
			}
		}

		[HarmonyPatch(typeof(Character), "AddForce", new Type[]
		{
			typeof(Vector3),
			typeof(float),
			typeof(float)
		})]
		private static class CharacterAddForcePatch
		{
			private static void Prefix(Character __instance, Vector3 move)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				RecordExternalAcceleration(__instance, move);
			}
		}

		[HarmonyPatch(typeof(Character), "RPCA_AddForceAtPosition")]
		private static class CharacterAddForceAtPositionPatch
		{
			private static void Prefix(Character __instance, ref Vector3 force)
			{
				//IL_0003: 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_0014: Unknown result type (might be due to invalid IL or missing references)
				force = ScaleExternalImpulse(__instance, force);
				RecordExternalAcceleration(__instance, force);
			}
		}

		[HarmonyPatch(typeof(CharacterGrabbing), "RPCA_Kick")]
		private static class CharacterGrabbingKickPatch
		{
			private static bool Prefix(CharacterGrabbing __instance)
			{
				ChainboundPlugin instance = _instance;
				if (!((Object)(object)instance == (Object)null))
				{
					return !instance.TryPunishKick(__instance);
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Action_LaunchPlayer), "RunAction")]
		private static class ActionLaunchPlayerPatch
		{
			private static bool Prefix(Action_LaunchPlayer __instance)
			{
				ChainboundPlugin instance = _instance;
				if (!((Object)(object)instance == (Object)null))
				{
					return !instance.TryPunishCookedLaunch(__instance);
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(CookingBehavior_RunActions), "TriggerBehaviour")]
		private static class CookingBehaviorRunActionsPatch
		{
			private static bool Prefix(CookingBehavior_RunActions __instance)
			{
				ChainboundPlugin instance = _instance;
				if (!((Object)(object)instance == (Object)null))
				{
					return !instance.TryPunishCookedRunActions(__instance);
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Action_RandomMushroomEffect), "RunAction")]
		private static class ActionRandomMushroomEffectPatch
		{
			private static bool Prefix(Action_RandomMushroomEffect __instance)
			{
				ChainboundPlugin instance = _instance;
				if (!((Object)(object)instance == (Object)null))
				{
					return !instance.TryBlockFartShroom(__instance);
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(CharacterAfflictions), "AddStatus", new Type[]
		{
			typeof(STATUSTYPE),
			typeof(float),
			typeof(bool),
			typeof(bool),
			typeof(bool)
		})]
		private static class CharacterAfflictionsAddStatusPatch
		{
			private static void Prefix(CharacterAfflictions __instance, STATUSTYPE statusType, out DamageLogState? __state)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				__state = null;
				ChainboundPlugin instance = _instance;
				if (!((Object)(object)instance == (Object)null) && (int)statusType == 0)
				{
					Character component = ((Component)__instance).GetComponent<Character>();
					if (instance.ShouldLogDamageFor(component))
					{
						__state = new DamageLogState
						{
							InjuryBefore = __instance.GetCurrentStatus((STATUSTYPE)0)
						};
					}
				}
			}

			private static void Postfix(CharacterAfflictions __instance, STATUSTYPE statusType, float amount, bool fromRPC, bool playEffects, bool notify, bool __result, DamageLogState? __state)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				ChainboundPlugin instance = _instance;
				if (!((Object)(object)instance == (Object)null) && (int)statusType == 0)
				{
					instance.LogInjuryDamageApplied(__instance, amount, fromRPC, playEffects, notify, __result, __state);
				}
			}
		}

		[HarmonyPatch(typeof(CharacterMovement), "CheckFallDamage")]
		private static class CharacterMovementCheckFallDamagePatch
		{
			private static bool Prefix(CharacterMovement __instance)
			{
				ChainboundPlugin instance = _instance;
				if ((Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null)
				{
					return true;
				}
				Character component = ((Component)__instance).GetComponent<Character>();
				if (instance.ShouldSuppressChainLandingDamage(component))
				{
					return false;
				}
				if (!instance.ShouldUseSpeedBasedFallDamage(component))
				{
					return true;
				}
				instance.ApplySpeedBasedFallDamage(component, 0f, "landing");
				return false;
			}
		}

		[HarmonyPatch(typeof(CharacterMovement), "UpdateVariables")]
		private static class CharacterMovementUpdateVariablesPatch
		{
			private static void Postfix(CharacterMovement __instance)
			{
				ChainboundPlugin instance = _instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)__instance == (Object)null))
				{
					instance.RecordFallVelocitySample(((Component)__instance).GetComponent<Character>());
				}
			}
		}

		[HarmonyPatch(typeof(CharacterClimbing), "CheckFallDamage")]
		private static class CharacterClimbingCheckFallDamagePatch
		{
			private static bool Prefix(CharacterClimbing __instance, RaycastHit hit)
			{
				//IL_008b: 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_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: 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)
				ChainboundPlugin instance = _instance;
				if ((Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null)
				{
					return true;
				}
				Character component = ((Component)__instance).GetComponent<Character>();
				if ((Object)(object)component == (Object)null)
				{
					return true;
				}
				if (instance.ShouldSuppressClimbFallDamage(component))
				{
					return false;
				}
				if (!instance.ShouldUseSpeedBasedFallDamage(component))
				{
					return true;
				}
				float extraImpactSpeed = 0f;
				if ((Object)(object)component.data != (Object)null)
				{
					Vector3 val = ((((Vector3)(ref component.data.avarageLastFrameVelocity)).sqrMagnitude > ((Vector3)(ref component.data.avarageVelocity)).sqrMagnitude) ? component.data.avarageLastFrameVelocity : component.data.avarageVelocity);
					extraImpactSpeed = Mathf.Max(0f, Vector3.Dot(val, -((RaycastHit)(ref hit)).normal));
				}
				instance.ApplySpeedBasedFallDamage(component, extraImpactSpeed, "climb");
				return false;
			}
		}

		[HarmonyPatch(typeof(Campfire), "Light_Rpc")]
		private static class CampfireLightRpcPatch
		{
			private static void Postfix(object[] __args)
			{
				bool flag = default(bool);
				int num;
				if (__args.Length != 0)
				{
					object obj = __args[0];
					if (obj is bool)
					{
						flag = (bool)obj;
						num = 1;
					}
					else
					{
						num = 0;
					}
				}
				else
				{
					num = 0;
				}
				if (((uint)num & (flag ? 1u : 0u)) != 0)
				{
					_instance?.HandleCampfireSegmentAdvanced();
				}
			}
		}

		private sealed class DamageLogState
		{
			internal float InjuryBefore;
		}

		private sealed class ChainboundCallbacks : MonoBehaviourPunCallbacks
		{
			private ChainboundPlugin? _plugin;

			internal void Init(ChainboundPlugin plugin)
			{
				_plugin = plugin;
			}

			public override void OnJoinedRoom()
			{
				_plugin?.HandleJoinedRoom();
			}

			public override void OnLeftRoom()
			{
				_plugin?.HandleLeftRoom();
			}

			public override void OnPlayerEnteredRoom(Player newPlayer)
			{
				_plugin?.HandlePlayerListOrPropertiesChanged();
			}

			public override void OnPlayerLeftRoom(Player otherPlayer)
			{
				_plugin?.HandlePlayerListOrPropertiesChanged();
			}

			public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
			{
				_plugin?.HandlePlayerListOrPropertiesChanged();
			}

			public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
			{
				_plugin?.HandleRoomPropertiesChanged();
			}

			public override void OnMasterClientSwitched(Player newMasterClient)
			{
				if ((Object)(object)_plugin != (Object)null)
				{
					_plugin._settingsDirty = true;
					_plugin._chainOrderDirty = true;
					_plugin._nextRoomPropertyPublish = 0f;
				}
			}
		}

		internal const string PluginGuid = "patchnote.chainbound";

		internal const string PluginName = "Chainbound";

		internal const string PluginVersion = "0.2.16";

		private const string PlayerVersionKey = "pn.cb.ver";

		private const string PlayerEnabledKey = "pn.cb.on";

		private const string PlayerPullInKey = "pn.cb.pull";

		private const string PlayerPullTargetKey = "pn.cb.ptgt";

		private const string RoomEnabledKey = "pn.cb.r.on";

		private const string RoomMaxGroupSizeKey = "pn.cb.r.max";

		private const string RoomLinkLengthKey = "pn.cb.r.len";

		private const string RoomMaxPullAccelerationKey = "pn.cb.r.acc";

		private const string RoomFallClampKey = "pn.cb.r.fall";

		private const string RoomBreakDistanceKey = "pn.cb.r.brk";

		private const string RoomChainGravityKey = "pn.cb.r.grv";

		private const string RoomAirbornePullKey = "pn.cb.r.air";

		private const string RoomBalloonPullKey = "pn.cb.r.bal";

		private const string RoomDownedAnchorKey = "pn.cb.r.down";

		private const string RoomExternalPropagationKey = "pn.cb.r.ext";

		private const string RoomExternalThresholdKey = "pn.cb.r.exth";

		private const string RoomExternalMaxKey = "pn.cb.r.extm";

		private const string RoomStuckBreakKey = "pn.cb.r.stuk";

		private const string RoomProxyTrackKey = "pn.cb.r.ptrk";

		private const string RoomProxyCorrectionKey = "pn.cb.r.pcor";

		private const string RoomProxyDampingKey = "pn.cb.r.pdmp";

		private const string RoomPullInAccelKey = "pn.cb.r.pacc";

		private const string RoomPullInTargetKey = "pn.cb.r.ptrg";

		private const string RoomPullInStaminaKey = "pn.cb.r.psta";

		private const string RoomDanglingStaminaKey = "pn.cb.r.dsta";

		private const string RoomClimberLoadKey = "pn.cb.r.clmb";

		private const string RoomGroundAnchorDownKey = "pn.cb.r.ganc";

		private const string RoomBalloonExternalKey = "pn.cb.r.bext";

		private const string RoomSwingGravityKey = "pn.cb.r.swng";

		private const string RoomHangingStaminaKey = "pn.cb.r.hstm";

		private const string RoomSpeedDamageKey = "pn.cb.r.sbd";

		private const string RoomSpeedDamageMinKey = "pn.cb.r.sdmi";

		private const string RoomSpeedDamageMaxKey = "pn.cb.r.sdma";

		private const string RoomSpeedDamageScaleKey = "pn.cb.r.sdsc";

		private const string RoomPunishTKKey = "pn.cb.r.ptk";

		private const string RoomChainOrderKey = "pn.cb.r.order";

		private const string EmptyChainSlotPrefix = "empty:";

		private const float OpenParasolAnchorStrength = 0.9f;

		private const float OpenParasolProxyMass = 7f;

		private const float OpenParasolProxyDrive = 2.35f;

		private const float OpenParasolLiftBase = 14f;

		private const float OpenParasolLiftPerDownSpeed = 8f;

		private static ChainboundPlugin? _instance;

		private readonly Dictionary<string, LineRenderer> _chainLines = new Dictionary<string, LineRenderer>(StringComparer.Ordinal);

		private readonly Dictionary<int, Vector3> _lastObservedVelocities = new Dictionary<int, Vector3>();

		private readonly Dictionary<int, Vector3> _recordedExternalAccelerations = new Dictionary<int, Vector3>();

		private readonly Dictionary<int, FallVelocitySample> _fallVelocitySamples = new Dictionary<int, FallVelocitySample>();

		private readonly Dictionary<int, ProxyBody> _proxyBodies = new Dictionary<int, ProxyBody>();

		private readonly Dictionary<string, ConfigurableJoint> _proxyJoints = new Dictionary<string, ConfigurableJoint>(StringComparer.Ordinal);

		private readonly List<string> _roomChainOrder = new List<string>();

		private Material? _lineMaterial;

		private GUIStyle? _lobbyBoxStyle;

		private GUIStyle? _lobbyHeaderStyle;

		private GUIStyle? _lobbyTextStyle;

		private Texture2D? _lobbyBoxTexture;

		private IReadOnlyList<IReadOnlyList<ChainboundGroupMember>> _apiGroups = Array.Empty<IReadOnlyList<ChainboundGroupMember>>();

		private string _apiGroupSignature = string.Empty;

		private ChainboundCallbacks? _callbacks;

		private float _nextPlayerPropertyPublish;

		private float _nextRoomPropertyPublish;

		private float _nextPullInPropertyPublish;

		private bool _lastPublishedEnabled;

		private bool _localPullInHeld;

		private int _localPullInTargetActor;

		private bool _localPullPreviewActive;

		private int _localPullPreviewTargetActor;

		private bool _lastPublishedPullIn;

		private int _lastPublishedPullInTargetActor;

		private bool _settingsDirty = true;

		private bool _chainOrderDirty = true;

		private bool _shuffleKeyWasDown;

		private float _lastCampfireShuffleTime = float.NegativeInfinity;

		private bool _roomHasChainboundHost;

		private bool _roomEnabled;

		private int _roomMaxGroupSize;

		private float _roomLinkLength;

		private float _roomMaxPullAcceleration;

		private float _roomFallClampSeconds;

		private float _roomLinkBreakDistance;

		private float _roomChainGravity;

		private float _roomAirbornePullMultiplier;

		private float _roomBalloonPullMultiplier;

		private float _roomDownedAnchorMultiplier;

		private float _roomExternalForcePropagation;

		private float _roomExternalForceThreshold;

		private float _roomExternalForceMaxAcceleration;

		private float _roomStuckBreakAcceleration;

		private float _roomProxyTrackStrength;

		private float _roomProxyCorrectionStrength;

		private float _roomProxyCorrectionDamping;

		private float _roomPullInAcceleration;

		private float _roomPullInTargetLengthMultiplier;

		private float _roomPullInStaminaPerSecond;

		private float _roomDanglingStaminaPerPlayer;

		private float _roomClimberLoadMultiplier;

		private float _roomGroundAnchorMaxDownAcceleration;

		private float _roomBalloonExternalForceMultiplier;

		private float _roomSwingGravityMultiplier;

		private float _roomHangingStaminaRegenMultiplier;

		private bool _roomSpeedBasedFallDamage;

		private float _roomFallDamageMinSpeed;

		private float _roomFallDamageMaxSpeed;

		private float _roomFallDamageMultiplier;

		private bool _roomPunishTK;

		private int _localCharacterViewId;

		private float _localCharacterSpawnTime;

		private float _chainFallProtectedUntil;

		private float _chainClimbDamageProtectedUntil;

		private float _lastCatchUpTime = float.NegativeInfinity;

		private int _catchUpAttemptsForCharacter;

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<int> _maxGroupSize;

		private ConfigEntry<bool> _drawChain;

		private ConfigEntry<bool> _showLobbyStatus;

		private ConfigEntry<bool> _showInGameStatus;

		private ConfigEntry<bool> _showLobbyStatusToEveryone;

		private ConfigEntry<bool> _requireExactVersion;

		private ConfigEntry<float> _linkLength;

		private ConfigEntry<float> _maxPullAcceleration;

		private ConfigEntry<float> _maxTotalAccelerationMultiplier;

		private ConfigEntry<float> _anchorMaxDownAcceleration;

		private ConfigEntry<float> _fallClampSeconds;

		private ConfigEntry<float> _fallProtectionAfterPullSeconds;

		private ConfigEntry<float> _spawnGraceSeconds;

		private ConfigEntry<float> _linkBreakDistance;

		private ConfigEntry<float> _chainGravity;

		private ConfigEntry<float> _airbornePullMultiplier;

		private ConfigEntry<float> _balloonPullMultiplier;

		private ConfigEntry<float> _downedAnchorMultiplier;

		private ConfigEntry<float> _externalForcePropagation;

		private ConfigEntry<float> _externalForceThreshold;

		private ConfigEntry<float> _externalForceMaxAcceleration;

		private ConfigEntry<float> _stuckBreakAcceleration;

		private ConfigEntry<float> _proxyTrackStrength;

		private ConfigEntry<float> _proxyCorrectionStrength;

		private ConfigEntry<float> _proxyCorrectionDamping;

		private ConfigEntry<float> _pullInAcceleration;

		private ConfigEntry<float> _pullInTargetLengthMultiplier;

		private ConfigEntry<float> _pullInStaminaPerSecond;

		private ConfigEntry<float> _danglingStaminaPerPlayer;

		private ConfigEntry<float> _climberLoadMultiplier;

		private ConfigEntry<float> _groundAnchorMaxDownAcceleration;

		private ConfigEntry<float> _balloonExternalForceMultiplier;

		private ConfigEntry<float> _swingGravityMultiplier;

		private ConfigEntry<float> _hangingStaminaRegenMultiplier;

		private ConfigEntry<bool> _speedBasedFallDamage;

		private ConfigEntry<float> _fallDamageMinSpeed;

		private ConfigEntry<float> _fallDamageMaxSpeed;

		private ConfigEntry<float> _fallDamageMultiplier;

		private ConfigEntry<bool> _autoCatchUpEnabled;

		private ConfigEntry<float> _autoCatchUpDistance;

		private ConfigEntry<float> _autoCatchUpWindowSeconds;

		private ConfigEntry<float> _autoCatchUpCooldownSeconds;

		private ConfigEntry<KeyCode> _pullInKeyboardKey;

		private ConfigEntry<KeyCode> _pullInGamepadButton;

		private ConfigEntry<float> _pullInAimAngleDegrees;

		private ConfigEntry<bool> _shuffleAtCampfires;

		private ConfigEntry<KeyCode> _shuffleKeyboardKey;

		private ConfigEntry<bool> _punishTK;

		private ConfigEntry<bool> _debugLogging;

		private ConfigEntry<bool> _damageLogging;

		private Harmony? _harmony;

		internal static ChainboundPlugin? Instance => _instance;

		internal bool ApiHostHasChainbound => _roomHasChainboundHost;

		internal bool ApiEnabled => ShouldRunHostEnabledGameplay();

		private void Awake()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			_instance = this;
			BindConfig();
			RefreshRoomSettingsFromLocalConfig();
			_harmony = new Harmony("patchnote.chainbound");
			_harmony.PatchAll(typeof(ChainboundPlugin).Assembly);
			_callbacks = ((Component)this).gameObject.AddComponent<ChainboundCallbacks>();
			_callbacks.Init(this);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded Chainbound.");
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
			ClearChainLines();
			ClearProxyChain();
			ClearApiGroups();
			if ((Object)(object)_callbacks != (Object)null)
			{
				Object.Destroy((Object)(object)_callbacks);
				_callbacks = null;
			}
			if ((Object)(object)_lineMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_lineMaterial);
				_lineMaterial = null;
			}
			if ((Object)(object)_lobbyBoxTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_lobbyBoxTexture);
				_lobbyBoxTexture = null;
			}
			if (_instance == this)
			{
				_instance = null;
			}
		}

		private void BindConfig()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Expected O, but got Unknown
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Expected O, but got Unknown
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Expected O, but got Unknown
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Expected O, but got Unknown
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Expected O, but got Unknown
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Expected O, but got Unknown
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Expected O, but got Unknown
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Expected O, but got Unknown
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Expected O, but got Unknown
			//IL_0430: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Expected O, but got Unknown
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0478: Expected O, but got Unknown
			//IL_04ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b6: Expected O, but got Unknown
			//IL_04ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f4: Expected O, but got Unknown
			//IL_0528: Unknown result type (might be due to invalid IL or missing references)
			//IL_0532: Expected O, but got Unknown
			//IL_0566: Unknown result type (might be due to invalid IL or missing references)
			//IL_0570: Expected O, but got Unknown
			//IL_05a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ae: Expected O, but got Unknown
			//IL_05e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ec: Expected O, but got Unknown
			//IL_0620: Unknown result type (might be due to invalid IL or missing references)
			//IL_062a: Expected O, but got Unknown
			//IL_065e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0668: Expected O, but got Unknown
			//IL_069c: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a6: Expected O, but got Unknown
			//IL_06da: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e4: Expected O, but got Unknown
			//IL_0718: Unknown result type (might be due to invalid IL or missing references)
			//IL_0722: Expected O, but got Unknown
			//IL_0756: Unknown result type (might be due to invalid IL or missing references)
			//IL_0760: Expected O, but got Unknown
			//IL_0794: Unknown result type (might be due to invalid IL or missing references)
			//IL_079e: Expected O, but got Unknown
			//IL_07d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07dc: Expected O, but got Unknown
			//IL_0831: Unknown result type (might be due to invalid IL or missing references)
			//IL_083b: Expected O, but got Unknown
			//IL_086f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0879: Expected O, but got Unknown
			//IL_08ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b7: Expected O, but got Unknown
			//IL_090c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0916: Expected O, but got Unknown
			//IL_094a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0954: Expected O, but got Unknown
			//IL_0988: Unknown result type (might be due to invalid IL or missing references)
			//IL_0992: Expected O, but got Unknown
			//IL_0a0d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a17: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the chain mod. The host's value is synced to the room.");
			_maxGroupSize = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxGroupSize", 0, new ConfigDescription("Host setting. 0 chains everyone together; 2 creates pairs; 3 creates trios.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 8), Array.Empty<object>()));
			_drawChain = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DrawChain", true, "Draw local chain links between living players.");
			_shuffleAtCampfires = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShuffleAtCampfires", true, "Host setting. Shuffle the chain order automatically when a campfire advances to the next segment.");
			_showLobbyStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("Lobby", "ShowLobbyStatus", true, "Show an airport lobby overlay listing players who are missing or using a different version of the mod.");
			_showInGameStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("Lobby", "ShowInGameStatus", true, "Show an in-run overlay when players are missing Chainbound or using a different version.");
			_showLobbyStatusToEveryone = ((BaseUnityPlugin)this).Config.Bind<bool>("Lobby", "ShowLobbyStatusToEveryone", false, "Show Chainbound status overlays on non-host clients too.");
			_requireExactVersion = ((BaseUnityPlugin)this).Config.Bind<bool>("Lobby", "RequireExactVersion", true, "Treat players with a different Chainbound version as not ready in the lobby status overlay.");
			_linkLength = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "LinkLength", 7f, new ConfigDescription("Host setting. Maximum distance between proxy bodies before a joint limit becomes taut.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), Array.Empty<object>()));
			_maxPullAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "MaxPullAcceleration", 85f, new ConfigDescription("Host setting. Maximum acceleration the solved proxy chain can apply to a real local player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 250f), Array.Empty<object>()));
			_maxTotalAccelerationMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "MaxTotalAccelerationMultiplier", 1.6f, new ConfigDescription("Multiplier for the local acceleration cap when one body is affected by multiple proxy links.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 4f), Array.Empty<object>()));
			_anchorMaxDownAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "AnchorMaxDownAcceleration", 14f, new ConfigDescription("Local safety cap for downward acceleration on grounded/climbing anchors.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 80f), Array.Empty<object>()));
			_fallClampSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "FallClampSeconds", 0.45f, new ConfigDescription("Host setting. Maximum since-grounded/since-jump timer while chain protection is active, reducing chain-caused fall damage.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1.5f), Array.Empty<object>()));
			_fallProtectionAfterPullSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "FallProtectionAfterPullSeconds", 0.8f, new ConfigDescription("Local extra fall-damage protection after a chain pull stops.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			_spawnGraceSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "SpawnGraceSeconds", 5f, new ConfigDescription("Seconds after spawning/warping before normal chain forces start.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			_linkBreakDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "LinkBreakDistance", 80f, new ConfigDescription("Host setting. Links farther than this are treated as disconnected until players get close again. Prevents checkpoint and revive warps from pulling across the map.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 300f), Array.Empty<object>()));
			_chainGravity = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "ChainGravity", 18f, new ConfigDescription("Host setting. Extra pendulum gravity along taut or nearly-taut chain links so dangling players sag and swing instead of walking sideways at the same height.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			_airbornePullMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "AirbornePullMultiplier", 0.35f, new ConfigDescription("Host setting. How strongly an unsupported airborne player anchors the chain compared to a grounded/climbing player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_balloonPullMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "BalloonPullMultiplier", 0.2f, new ConfigDescription("Host setting. How strongly a balloon-floating player anchors the chain compared to a grounded/climbing player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_downedAnchorMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "DownedAnchorMultiplier", 0.12f, new ConfigDescription("Host setting. How strongly a passed-out player anchors and resists the chain. Lower values make downed players easier to drag.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_externalForcePropagation = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "ExternalForcePropagation", 0.65f, new ConfigDescription("Host setting. Portion of sudden neighbor acceleration that propagates through taut links, helping roots wind and similar forces move the chain together.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1.5f), Array.Empty<object>()));
			_externalForceThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "ExternalForceThreshold", 10f, new ConfigDescription("Host setting. Sudden acceleration below this is ignored by force propagation.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 80f), Array.Empty<object>()));
			_externalForceMaxAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "ExternalForceMaxAcceleration", 70f, new ConfigDescription("Host setting. Maximum acceleration added by external force propagation per link.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
			_stuckBreakAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "StuckBreakAcceleration", 55f, new ConfigDescription("Host setting. Chain acceleration needed to pull the local player out of cactus/sticky joints.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
			_proxyTrackStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "ProxyTrackStrength", 45f, new ConfigDescription("Host setting. Acceleration per meter used to keep proxy bodies near the real players they represent. Strong anchors are tracked harder; airborne players are tracked softer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 160f), Array.Empty<object>()));
			_proxyCorrectionStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "ProxyCorrectionStrength", 28f, new ConfigDescription("Host setting. Acceleration per meter used to pull the local real ragdoll toward its solved proxy body.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 120f), Array.Empty<object>()));
			_proxyCorrectionDamping = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "ProxyCorrectionDamping", 5f, new ConfigDescription("Host setting. Velocity damping used when pulling the local real ragdoll toward its solved proxy body.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), Array.Empty<object>()));
			_pullInAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "PullInAcceleration", 100f, new ConfigDescription("Host setting. Acceleration used when a player holds the pull-in key to winch the looked-at chain link shorter.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 250f), Array.Empty<object>()));
			_pullInTargetLengthMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "PullInTargetLengthMultiplier", 0.25f, new ConfigDescription("Host setting. Target chain-link length while pulling, as a multiplier of LinkLength.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.15f, 1f), Array.Empty<object>()));
			_pullInStaminaPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "PullInStaminaPerSecond", 0.15f, new ConfigDescription("Host setting. Stamina drained per second from the player actively winching a chain link.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_danglingStaminaPerPlayer = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "DanglingStaminaPerPlayer", 0.05f, new ConfigDescription("Host setting. Extra stamina drained per second for each unsupported player tautly hanging from you while you are on a rope, vine, or climb chain. Load is split between supports.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.3f), Array.Empty<object>()));
			_climberLoadMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "ClimberLoadMultiplier", 0.1f, new ConfigDescription("Host setting. Multiplier for chain load fed into PEAK's climbing drag hook. Lower values let climbers resist the chain more.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			_groundAnchorMaxDownAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "GroundAnchorMaxDownAcceleration", 3.5f, new ConfigDescription("Host setting. Downward acceleration cap for grounded anchors holding a lower unsupported player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 80f), Array.Empty<object>()));
			_balloonExternalForceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "BalloonExternalForceMultiplier", 0.25f, new ConfigDescription("Host setting. Multiplier for external impulse forces, such as roots wind, on balloon-floating chained players.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_swingGravityMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "SwingGravityMultiplier", 2.8f, new ConfigDescription("Host setting. Multiplier for tangential gravity when dangling from an upper anchor. Higher values make ledge swings feel faster.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 6f), Array.Empty<object>()));
			_hangingStaminaRegenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Physics", "HangingStaminaRegenMultiplier", 1f, new ConfigDescription("Host setting. Multiplier for normal stamina regen while the chain is holding an unsupported player from above. 1 is PEAK's grounded regen rate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			_speedBasedFallDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("Damage", "SpeedBasedFallDamage", false, "Host setting. Replace PEAK's airtime-based landing and wall-grab damage with speed-based damage.");
			_fallDamageMinSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "FallDamageMinSpeed", 11f, new ConfigDescription("Host setting. Downward impact speed in m/s where speed-based fall damage starts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 40f), Array.Empty<object>()));
			_fallDamageMaxSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "FallDamageMaxSpeed", 23f, new ConfigDescription("Host setting. Downward impact speed in m/s that reaches full speed-based fall damage.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>()));
			_fallDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "FallDamageMultiplier", 1f, new ConfigDescription("Host setting. Multiplier applied to speed-based fall damage after speed is converted to injury.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			_autoCatchUpEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("CatchUp", "AutoCatchUpEnabled", true, "Warp a newly spawned local player near their chain group if they spawned far away after joining late.");
			_autoCatchUpDistance = ((BaseUnityPlugin)this).Config.Bind<float>("CatchUp", "AutoCatchUpDistance", 55f, new ConfigDescription("Distance from the nearest living group member before a fresh local spawn is caught up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 300f), Array.Empty<object>()));
			_autoCatchUpWindowSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("CatchUp", "AutoCatchUpWindowSeconds", 35f, new ConfigDescription("Only auto catch-up during this many seconds after the local character spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 180f), Array.Empty<object>()));
			_autoCatchUpCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("CatchUp", "AutoCatchUpCooldownSeconds", 20f, new ConfigDescription("Minimum time between automatic catch-up warps.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 180f), Array.Empty<object>()));
			_pullInKeyboardKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "PullInKeyboardKey", (KeyCode)121, "Keyboard key used to pull in the chain link the local player is looking toward. Set to None to disable.");
			_pullInGamepadButton = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "PullInGamepadButton", (KeyCode)335, "Gamepad button used to pull in the chain link the local player is looking toward. Xbox RB / PlayStation R1 is usually JoystickButton5. Set to None to disable.");
			_pullInAimAngleDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("Input", "PullInAimAngleDegrees", 20f, new ConfigDescription("Maximum angle from your look direction for choosing an adjacent chain link to pull. Lower values require more precise aim.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 75f), Array.Empty<object>()));
			_shuffleKeyboardKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "ShuffleKeyboardKey", (KeyCode)289, "Host-only keyboard key used to shuffle the chain order immediately. Set to None to disable.");
			_punishTK = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PunishTK", true, "When chained, punish dangerous team-kill actions. Kicking or drinking cooked launch items kills the user; fart shroom launch is blocked.");
			_debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Write Chainbound debug messages to the BepInEx log.");
			_damageLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DamageLogging", true, "Write a BepInEx log line whenever the local player actually gains injury damage.");
			RefreshPullInTuningDefaults();
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				_settingsDirty = true;
				_chainOrderDirty = true;
				_nextPlayerPropertyPublish = 0f;
				_nextRoomPropertyPublish = 0f;
			};
		}

		private void RefreshPullInTuningDefaults()
		{
			if (Mathf.Approximately(_pullInAcceleration.Value, 85f))
			{
				_pullInAcceleration.Value = 165f;
			}
			if (Mathf.Approximately(_pullInTargetLengthMultiplier.Value, 0.45f))
			{
				_pullInTargetLengthMultiplier.Value = 0.25f;
			}
		}

		private void Update()
		{
			if (_settingsDirty)
			{
				RefreshRoomSettings();
				_settingsDirty = false;
			}
			UpdatePullInInputState();
			if (PhotonNetwork.InRoom)
			{
				PublishPlayerPropertiesIfNeeded(force: false);
				MaintainHostChainOrderIfNeeded(force: false);
				UpdateHostShuffleInput();
				PublishPullInPropertiesIfNeeded(force: false);
				PublishRoomPropertiesIfNeeded(force: false);
				RefreshApiGroups();
			}
			else
			{
				_shuffleKeyWasDown = false;
				ClearApiGroups();
			}
			TrackLocalCharacterSpawn();
			UpdateChainVisuals();
		}

		private void UpdateHostShuffleInput()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			bool flag = PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && (int)_shuffleKeyboardKey.Value != 0 && !IsInputBlocked() && IsKeyboardKeyPressed(_shuffleKeyboardKey.Value);
			if (flag && !_shuffleKeyWasDown)
			{
				ShuffleChainOrder("host key");
			}
			_shuffleKeyWasDown = flag;
		}

		private void UpdatePullInInputState()
		{
			_localPullInHeld = false;
			_localPullInTargetActor = 0;
			_localPullPreviewActive = false;
			_localPullPreviewTargetActor = 0;
			if (ShouldApplyChainPhysics(out Character localCharacter) && !((Object)(object)localCharacter == (Object)null) && IsPlayerOptedIntoChain(PhotonNetwork.LocalPlayer) && CanUseChainPull(localCharacter) && IsVanillaPullUpInputActive(localCharacter) && TryFindPullInTargetActor(localCharacter, out var targetActor))
			{
				_localPullPreviewActive = true;
				_localPullPreviewTargetActor = targetActor;
				if (IsPullInInputPressed(localCharacter) && TrySpendPullInStamina(localCharacter))
				{
					_localPullInHeld = true;
					_localPullInTargetActor = targetActor;
				}
			}
		}

		private static bool CanUseChainPull(Character character)
		{
			CharacterData data = character.data;
			if ((Object)(object)data == (Object)null || !data.fullyConscious)
			{
				return false;
			}
			if ((Object)(object)data.currentItem != (Object)null)
			{
				return false;
			}
			if (Time.time - data.lastConsumedItem < 0.5f)
			{
				return false;
			}
			if (data.isClimbing || data.isRopeClimbing || data.isVineClimbing || (Object)(object)data.currentClimbHandle != (Object)null)
			{
				return false;
			}
			return true;
		}

		private static bool IsVanillaPullUpInputActive(Character localCharacter)
		{
			if ((Object)(object)localCharacter.input != (Object)null)
			{
				return localCharacter.input.useSecondaryIsPressed;
			}
			return false;
		}

		private bool TrySpendPullInStamina(Character localCharacter)
		{
			float num = _roomPullInStaminaPerSecond * Time.deltaTime;
			if (num <= 0f)
			{
				return true;
			}
			CharacterData data = localCharacter.data;
			if ((Object)(object)data == (Object)null)
			{
				return false;
			}
			num *= Ascents.climbStaminaMultiplier;
			if (num <= 0f)
			{
				return true;
			}
			float totalStamina = localCharacter.GetTotalStamina();
			if (totalStamina <= num || totalStamina <= 0.005f)
			{
				return false;
			}
			if (data.currentStamina <= 0f)
			{
				if (data.extraStamina <= 0f)
				{
					return false;
				}
				data.extraStamina = Mathf.Clamp(data.extraStamina - num, 0f, 1f);
				data.sinceUseStamina = 0f;
				GUIManager.instance.bar.ChangeBar();
				return data.extraStamina > 0f;
			}
			data.currentStamina -= num;
			data.sinceUseStamina = 0f;
			GUIManager.instance.bar.ChangeBar();
			if (data.currentStamina <= 0f)
			{
				localCharacter.ClampStamina();
				return data.extraStamina > 0f;
			}
			return true;
		}

		private bool IsPullInInputPressed(Character localCharacter)
		{
			//IL_001d: 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_003d: 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)
			if ((Object)(object)localCharacter.data == (Object)null || IsInputBlocked())
			{
				return false;
			}
			bool num = (int)_pullInKeyboardKey.Value != 0 && IsKeyboardKeyPressed(_pullInKeyboardKey.Value);
			bool flag = (int)_pullInGamepadButton.Value != 0 && IsGamepadButtonPressed(_pullInGamepadButton.Value);
			return num || flag;
		}

		private static bool IsKeyboardKeyPressed(KeyCode key)
		{
			//IL_003c: 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_000c: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			Keyboard current = Keyboard.current;
			if (current != null)
			{
				if ((int)key == 103)
				{
					return ((ButtonControl)current.gKey).isPressed;
				}
				if ((int)key == 116)
				{
					return ((ButtonControl)current.tKey).isPressed;
				}
				if ((int)key == 121)
				{
					return ((ButtonControl)current.yKey).isPressed;
				}
			}
			return TryGetLegacyKey(key);
		}

		private static bool IsGamepadButtonPressed(KeyCode key)
		{
			//IL_00ba: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected I4, but got Unknown
			Gamepad current = Gamepad.current;
			if (current != null)
			{
				switch (key - 330)
				{
				case 0:
					return current.buttonSouth.isPressed;
				case 1:
					return current.buttonEast.isPressed;
				case 2:
					return current.buttonWest.isPressed;
				case 3:
					return current.buttonNorth.isPressed;
				case 4:
					return current.leftShoulder.isPressed;
				case 5:
					return current.rightShoulder.isPressed;
				case 6:
					return current.selectButton.isPressed;
				case 7:
					return current.startButton.isPressed;
				case 8:
					return current.leftStickButton.isPressed;
				case 9:
					return current.rightStickButton.isPressed;
				}
			}
			return TryGetLegacyKey(key);
		}

		private static bool TryGetLegacyKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return Input.GetKey(key);
			}
			catch
			{
				return false;
			}
		}

		private static bool IsInputBlocked()
		{
			try
			{
				return (Object)(object)GUIManager.instance != (Object)null && (GUIManager.instance.windowBlockingInput || GUIManager.instance.wheelActive);
			}
			catch
			{
				return false;
			}
		}

		private bool TryFindPullInTargetActor(Character localCharacter, out int targetActor)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_005d: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			targetActor = 0;
			if (PhotonNetwork.LocalPlayer == null || (Object)(object)localCharacter.data == (Object)null)
			{
				return false;
			}
			ChainState chainState = BuildChainState();
			if (chainState.LocalLinks.Count == 0)
			{
				return false;
			}
			Vector3 val = localCharacter.data.lookDirection;
			if (!IsFinite(val) || ((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = localCharacter.data.lookDirection_Flat;
			}
			if (!IsFinite(val) || ((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return false;
			}
			((Vector3)(ref val)).Normalize();
			int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
			float num = Mathf.Cos(Mathf.Clamp(_pullInAimAngleDegrees.Value, 10f, 75f) * ((float)Math.PI / 180f));
			ChainMember chainMember = null;
			foreach (ChainLink localLink in chainState.LocalLinks)
			{
				ChainMember chainMember2 = null;
				if (localLink.Left.ActorNumber == actorNumber)
				{
					chainMember2 = localLink.Right;
				}
				else if (localLink.Right.ActorNumber == actorNumber)
				{
					chainMember2 = localLink.Left;
				}
				if ((Object)(object)chainMember2?.Character == (Object)null)
				{
					continue;
				}
				Vector3 vector = GetProxyTargetPosition(chainMember2) - localCharacter.Center;
				if (IsFinite(vector) && !(((Vector3)(ref vector)).sqrMagnitude < 0.01f))
				{
					float num2 = Vector3.Dot(val, ((Vector3)(ref vector)).normalized);
					if (num2 > num)
					{
						num = num2;
						chainMember = chainMember2;
					}
				}
			}
			if (chainMember == null)
			{
				return false;
			}
			targetActor = chainMember.ActorNumber;
			return true;
		}

		private void FixedUpdate()
		{
			if (!ShouldApplyChainPhysics(out Character localCharacter) || (Object)(object)localCharacter == (Object)null)
			{
				ClearProxyChain();
				return;
			}
			ChainState chainState = BuildChainState();
			if (IsPlayerOptedIntoChain(PhotonNetwork.LocalPlayer) && TryAutoCatchUp(localCharacter, chainState))
			{
				UpdateObservedVelocities(chainState.ObservedCharacters);
				return;
			}
			if (chainState.LocalLinks.Count == 0)
			{
				ClearProxyChain();
				UpdateObservedVelocities(chainState.ObservedCharacters);
				return;
			}
			if (IsRecentlyWarped(localCharacter))
			{
				ClearProxyChain();
				UpdateObservedVelocities(chainState.ObservedCharacters);
				return;
			}
			if (Time.realtimeSinceStartup - _localCharacterSpawnTime < _spawnGraceSeconds.Value)
			{
				ClearProxyChain();
				UpdateObservedVelocities(chainState.ObservedCharacters);
				return;
			}
			if (!RunProxyChainSimulation(localCharacter, chainState))
			{
				ClearProxyChain();
			}
			UpdateObservedVelocities(chainState.ObservedCharacters);
		}

		private bool ShouldApplyChainPhysics(out Character? localCharacter)
		{
			localCharacter = null;
			if (!ShouldRunHostEnabledGameplay() || IsLobbyScene())
			{
				return false;
			}
			localCharacter = Character.localCharacter;
			if (!IsChainAlive(localCharacter) || (Object)(object)((MonoBehaviourPun)localCharacter).photonView == (Object)null || !((MonoBehaviourPun)localCharacter).photonView.IsMine)
			{
				return false;
			}
			if (localCharacter.warping || localCharacter.data.isCarried || (Object)(object)localCharacter.data.carrier != (Object)null)
			{
				return false;
			}
			return true;
		}

		private bool ShouldRunHostEnabledGameplay()
		{
			if (PhotonNetwork.InRoom && _roomHasChainboundHost)
			{
				return _roomEnabled;
			}
			return false;
		}

		private void TryBreakStuckJoint(Character character, Vector3 acceleration)
		{
			if (!(_roomStuckBreakAcceleration <= 0f) && !(((Vector3)(ref acceleration)).sqrMagnitude < _roomStuckBreakAcceleration * _roomStuckBreakAcceleration))
			{
				bool flag;
				try
				{
					flag = character.IsStuck();
				}
				catch
				{
					return;
				}
				if (flag && !((Object)(object)character.refs?.view == (Object)null) && character.refs.view.IsMine)
				{
					DebugLog($"Breaking stuck joint with chain acceleration={((Vector3)(ref acceleration)).magnitude:0.0}");
					character.refs.view.RPC("RPCA_Unstick", (RpcTarget)0, Array.Empty<object>());
				}
			}
		}

		private void ApplyAcceleration(Character character, Vector3 acceleration)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFinite(acceleration) || ((Vector3)(ref acceleration)).sqrMagnitude < 0.0001f || character.refs?.ragdoll?.partList == null)
			{
				return;
			}
			foreach (Bodypart part in character.refs.ragdoll.partList)
			{
				Rigidbody val = (((Object)(object)part != (Object)null) ? part.Rig : null);
				if ((Object)(object)val != (Object)null && !val.isKinematic)
				{
					val.AddForce(acceleration, (ForceMode)5);
				}
			}
		}

		private void ApplyClimberLoad(Character character, Vector3 acceleration)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			CharacterData data = character.data;
			if ((Object)(object)data == (Object)null || ((Vector3)(ref acceleration)).sqrMagnitude < 9f || (!data.isClimbing && !data.isRopeClimbing && !data.isVineClimbing && (Object)(object)data.currentClimbHandle == (Object)null))
			{
				return;
			}
			float magnitude = ((Vector3)(ref acceleration)).magnitude;
			float num = magnitude * _roomClimberLoadMultiplier;
			if (num < 3f)
			{
				return;
			}
			Vector3 val = acceleration / Mathf.Max(magnitude, 0.001f);
			try
			{
				character.dragTowardsAction?.Invoke(character.Center + val, Mathf.Min(num, _roomMaxPullAcceleration));
				if ((Object)(object)character.refs?.climbing != (Object)null)
				{
					character.refs.climbing.climbingStamMinimumMultiplier = Mathf.Max(character.refs.climbing.climbingStamMinimumMultiplier, 1f + Mathf.Clamp01(num / 80f) * 0.7f);
				}
			}
			catch (Exception ex)
			{
				DebugLog("ApplyClimberLoad failed: " + ex.Message);
			}
			ProtectFromChainFall(character);
			_chainClimbDamageProtectedUntil = Time.time + _fallProtectionAfterPullSeconds.Value;
		}

		private bool RunProxyChainSimulation(Character localCharacter, ChainState state)
		{
			//IL_0047: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (state.LocalMembers.Count <= 1 || state.LocalLinks.Count == 0)
			{
				ClearProxyChain();
				return false;
			}
			EnsureProxyChain(state);
			ProxyCorrectionResult proxyCorrectionResult = ComputeLocalProxyCorrection(localCharacter, state);
			PrepareProxyStep(state);
			if (proxyCorrectionResult.LocalProxyCount == 0)
			{
				return false;
			}
			Vector3 acceleration = proxyCorrectionResult.Acceleration;
			if (((Vector3)(ref acceleration)).sqrMagnitude > 0.0001f)
			{
				TryBreakStuckJoint(localCharacter, proxyCorrectionResult.Acceleration);
				ApplyAcceleration(localCharacter, proxyCorrectionResult.Acceleration);
				ApplyClimberLoad(localCharacter, proxyCorrectionResult.Acceleration);
			}
			if (proxyCorrectionResult.HasUpperAnchorTension || HasUpperChainSupportForStamina(localCharacter, state))
			{
				ProtectFromChainFall(localCharacter);
				ApplyHangingStaminaRegen(localCharacter);
				_chainFallProtectedUntil = Time.time + _fallProtectionAfterPullSeconds.Value;
				_chainClimbDamageProtectedUntil = Time.time + _fallProtectionAfterPullSeconds.Value;
			}
			ApplyDanglingSupportStaminaDrain(localCharacter, state);
			return true;
		}

		private void ApplyDanglingSupportStaminaDrain(Character localCharacter, ChainState state)
		{
			float danglingSupportLoad = GetDanglingSupportLoad(localCharacter, state);
			if (!(danglingSupportLoad <= 0f))
			{
				float num = danglingSupportLoad * _roomDanglingStaminaPerPlayer * Time.fixedDeltaTime;
				if (!(num <= 0f))
				{
					DrainLocalStamina(localCharacter, num);
				}
			}
		}

		private static void DrainLocalStamina(Character character, float cost)
		{
			CharacterData data = character.data;
			if ((Object)(object)data == (Object)null || cost <= 0f)
			{
				return;
			}
			cost *= Ascents.climbStaminaMultiplier;
			if (cost <= 0f)
			{
				return;
			}
			if (data.currentStamina <= 0f)
			{
				if (!(data.extraStamina <= 0f))
				{
					data.extraStamina = Mathf.Clamp(data.extraStamina - cost, 0f, 1f);
					data.sinceUseStamina = 0f;
					GUIManager.instance.bar.ChangeBar();
				}
			}
			else
			{
				data.currentStamina -= cost;
				data.sinceUseStamina = 0f;
				character.ClampStamina();
				GUIManager.instance.bar.ChangeBar();
			}
		}

		private float GetDanglingSupportLoad(Character localCharacter, ChainState state)
		{
			Character localCharacter2 = localCharacter;
			if (_roomDanglingStaminaPerPlayer <= 0f || !IsRopeVineOrChainSupported(localCharacter2) || state.LocalMembers.Count <= 1)
			{
				return 0f;
			}
			int num = state.LocalMembers.FindIndex((ChainMember member) => (Object)(object)member.ForceTarget == (Object)(object)localCharacter2 || (Object)(object)member.Character == (Object)(object)localCharacter2);
			if (num < 0)
			{
				return 0f;
			}
			float num2 = 0f;
			for (int i = 0; i < state.LocalMembers.Count; i++)
			{
				if (i == num)
				{
					continue;
				}
				Character val = state.LocalMembers[i].ForceTarget ?? state.LocalMembers[i].Character;
				if (!((Object)(object)val == (Object)null) && IsUnsupported(val))
				{
					List<int> list = new List<int>();
					int num3 = FindNearestTautSupportIndex(state, i, -1);
					int num4 = FindNearestTautSupportIndex(state, i, 1);
					if (num3 >= 0)
					{
						list.Add(num3);
					}
					if (num4 >= 0 && num4 != num3)
					{
						list.Add(num4);
					}
					if (list.Count > 0 && list.Contains(num))
					{
						num2 += 1f / (float)list.Count;
					}
				}
			}
			return num2;
		}

		private int FindNearestTautSupportIndex(ChainState state, int startIndex, int step)
		{
			for (int i = startIndex + step; i >= 0 && i < state.LocalMembers.Count; i += step)
			{
				if (!AreAdjacentMembersTautForLoad(state.LocalMembers[i - ((step > 0) ? 1 : 0)], state.LocalMembers[i + ((step < 0) ? 1 : 0)]))
				{
					return -1;
				}
				Character val = state.LocalMembers[i].ForceTarget ?? state.LocalMembers[i].Character;
				if ((Object)(object)val == (Object)null)
				{
					return -1;
				}
				if (IsLoadStoppingSupport(val))
				{
					return i;
				}
			}
			return -1;
		}

		private bool AreAdjacentMembersTautForLoad(ChainMember left, ChainMember right)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			Character val = left.ForceTarget ?? left.Character;
			Character val2 = right.ForceTarget ?? right.Character;
			if ((Object)(object)left.Character == (Object)null || (Object)(object)right.Character == (Object)null || (Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return false;
			}
			if (!CanLinkConnect(left.Character, right.Character))
			{
				return false;
			}
			return Vector3.Distance(val.Center, val2.Center) >= _roomLinkLength * 0.88f;
		}

		private static bool IsRopeVineOrChainSupported(Character character)
		{
			CharacterData data = character.data;
			if ((Object)(object)data != (Object)null)
			{
				if (!data.isRopeClimbing && !data.isVineClimbing)
				{
					return (Object)(object)data.currentClimbHandle != (Object)null;
				}
				return true;
			}
			return false;
		}

		private bool IsLoadStoppingSupport(Character character)
		{
			return IsSupported(character);
		}

		private void ApplyHangingStaminaRegen(Character character)
		{
			CharacterData data = character.data;
			if (!(_roomHangingStaminaRegenMultiplier <= 0f) && !((Object)(object)data == (Object)null) && ((MonoBehaviourPun)character).photonView.IsMine && data.fullyConscious && !data.isGrounded && !data.isClimbing && !data.isRopeClimbing && !data.isVineClimbing && !((Object)(object)data.currentClimbHandle != (Object)null))
			{
				float num = ((data.currentStamina > 0f) ? 1f : 2f);
				if (!(data.sinceUseStamina < num) && !(character.GetTotalStamina() >= character.GetMaxStamina()))
				{
					character.AddStamina(Time.fixedDeltaTime * 0.2f * _roomHangingStaminaRegenMultiplier);
				}
			}
		}

		private bool HasUpperChainSupportForStamina(Character localCharacter, ChainState state)
		{
			//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_00d9: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)localCharacter.data == (Object)null || !IsUnsupported(localCharacter))
			{
				return false;
			}
			int num = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1));
			Vector3 center = localCharacter.Center;
			foreach (ChainLink localLink in state.LocalLinks)
			{
				ChainMember chainMember = null;
				if (localLink.Left.ActorNumber == num || (Object)(object)localLink.Left.ForceTarget == (Object)(object)localCharacter)
				{
					chainMember = localLink.Right;
				}
				else if (localLink.Right.ActorNumber == num || (Object)(object)localLink.Right.ForceTarget == (Object)(object)localCharacter)
				{
					chainMember = localLink.Left;
				}
				if (chainMember == null)
				{
					continue;
				}
				Character val = chainMember.ForceTarget ?? chainMember.Character;
				if (!((Object)(object)val == (Object)null) && IsChainAlive(val))
				{
					Vector3 proxyTargetPosition = GetProxyTargetPosition(chainMember);
					if (proxyTargetPosition.y > center.y + 0.75f && Vector3.Distance(center, proxyTargetPosition) > _roomLinkLength * 0.55f && Vector3.Distance(center, proxyTargetPosition) <= _roomLinkBreakDistance)
					{
						return true;
					}
				}
			}
			return false;
		}

		private ProxyCorrectionResult ComputeLocalProxyCorrection(Character localCharacter, ChainState state)
		{
			//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_05be: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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_00d6: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0625: Unknown result type (might be due to invalid IL or missing references)
			//IL_0628: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: 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_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_049a: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04be: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			//IL_0455: Unknown result type (might be due to invalid IL or missing references)
			//IL_046a: Unknown result type (might be due to invalid IL or missing references)
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0501: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_056f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0573: Unknown result type (might be due to invalid IL or missing references)
			//IL_0578: Unknown result type (might be due to invalid IL or missing references)
			//IL_057d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			int num = 0;
			int num2 = 0;
			bool hasUpperAnchorTension = false;
			bool flag = false;
			bool flag2 = false;
			foreach (ChainMember localMember in state.LocalMembers)
			{
				if ((Object)(object)localMember.ForceTarget != (Object)(object)localCharacter || !_proxyBodies.TryGetValue(localMember.ActorNumber, out ProxyBody value))
				{
					continue;
				}
				num++;
				if (value.WarmupSteps > 0)
				{
					continue;
				}
				Vector3 proxyTargetPosition = GetProxyTargetPosition(localMember);
				if (!IsFinite(proxyTargetPosition) || !IsFinite(value.Body.position) || Vector3.Distance(value.Body.position, proxyTargetPosition) > _roomLinkBreakDistance * 0.5f)
				{
					ResetProxyBody(value, localMember, 2);
					continue;
				}
				Vector3 proxyTargetVelocity = GetProxyTargetVelocity(localMember);
				Vector3 val2 = (value.Body.position - proxyTargetPosition) * _roomProxyCorrectionStrength + (value.Body.linearVelocity - proxyTargetVelocity) * _roomProxyCorrectionDamping;
				foreach (ChainLink localLink in state.LocalLinks)
				{
					if (!TryGetOtherMember(localLink, localMember, out ChainMember other) || other == null || !_proxyBodies.TryGetValue(other.ActorNumber, out ProxyBody value2))
					{
						continue;
					}
					Vector3 proxyTargetPosition2 = GetProxyTargetPosition(other);
					Vector3 val3 = proxyTargetPosition2 - proxyTargetPosition;
					float magnitude = ((Vector3)(ref val3)).magnitude;
					if (magnitude <= 0.001f || magnitude > _roomLinkBreakDistance)
					{
						continue;
					}
					Vector3 val4 = val3 / magnitude;
					float num3 = magnitude - _roomLinkLength;
					float num4 = Vector3.Distance(value.Body.position, value2.Body.position);
					bool flag3 = num3 > 0f || num4 > _roomLinkLength * 0.92f;
					bool flag4 = HasStrongAnchor(other) && proxyTargetPosition2.y > proxyTargetPosition.y + 0.75f;
					bool flag5 = HasOpenParasol(other.ForceTarget ?? other.Character) && proxyTargetPosition2.y > proxyTargetPosition.y + 0.75f;
					bool flag6 = IsPlayerPullingLink(localMember, other);
					bool flag7 = IsPlayerPullingLink(other, localMember);
					float pullInTargetLength = GetPullInTargetLength();
					bool flag8 = (flag6 || flag7) && magnitude > pullInTargetLength;
					if (!flag3 && !flag4 && !flag5 && !flag8)
					{
						continue;
					}
					Vector3 val5 = Vector3.zero;
					Vector3 proxyTargetVelocity2 = GetProxyTargetVelocity(other);
					if (flag8)
					{
						float num5 = magnitude - pullInTargetLength;
						float num6 = Mathf.Min(_roomPullInAcceleration, num5 * _roomProxyTrackStrength * 2.4f + _roomPullInAcceleration * 0.55f);
						float anchorStrength = GetAnchorStrength(localCharacter);
						float num7 = 0f;
						if (flag7)
						{
							num7 += Mathf.Lerp(1f, GetPullInAnchorScale(localCharacter), anchorStrength);
						}
						if (flag6)
						{
							num7 += Mathf.Lerp(1f, GetPullInAnchorScale(localCharacter) * 0.5f, anchorStrength);
						}
						if (num7 > 0f)
						{
							val5 += val4 * num6 * Mathf.Clamp01(num7);
							flag = true;
						}
					}
					if (flag3)
					{
						float num8 = Mathf.Max(0f, Vector3.Dot(val2, val4));
						float num9 = Mathf.Max(0f, Vector3.Dot(proxyTargetVelocity2 - proxyTargetVelocity, val4));
						float num10 = Mathf.Max(0f, num3) * _roomProxyTrackStrength * 1.6f + num9 * _roomProxyCorrectionDamping * 1.35f;
						val5 += val4 * Mathf.Max(num8, num10);
					}
					if (flag5 && magnitude > _roomLinkLength * 0.82f && IsUnsupported(localCharacter))
					{
						float num11 = Mathf.Max(0f, 0f - proxyTargetVelocity.y);
						float num12 = Mathf.Max(0f, 0f - proxyTargetVelocity2.y);
						float num13 = Mathf.Max(0f, num11 - num12);
						float num14 = Mathf.Max(0f, magnitude - _roomLinkLength * 0.82f);
						float num15 = num13 * _roomProxyCorrectionDamping * 2.5f + num14 * _roomProxyTrackStrength * 2f;
						if (num15 > 0f)
						{
							val5 += val4 * Mathf.Min(num15, _roomMaxPullAcceleration * 2.4f);
							hasUpperAnchorTension = true;
							flag2 = true;
						}
					}
					if (flag4 && magnitude > _roomLinkLength * 0.55f && IsUnsupported(localCharacter))
					{
						hasUpperAnchorTension = true;
						Vector3 val6 = Vector3.ProjectOnPlane(Vector3.down * _roomChainGravity * _roomSwingGravityMultiplier, val4);
						val5 += val6;
					}
					if (!(((Vector3)(ref val5)).sqrMagnitude <= 0.0001f))
					{
						if (IsSupported(localCharacter) && val5.y < 0f)
						{
							float supportedDownAccelerationCap = GetSupportedDownAccelerationCap(localCharacter, other, proxyTargetPosition, proxyTargetPosition2);
							val5.y = Mathf.Max(val5.y, 0f - supportedDownAccelerationCap);
						}
						float num16 = Mathf.Max(new float[4]
						{
							_roomMaxPullAcceleration,
							_roomMaxPullAcceleration * _maxTotalAccelerationMultiplier.Value,
							flag8 ? _roomPullInAcceleration : 0f,
							flag2 ? (_roomMaxPullAcceleration * 2.4f) : 0f
						});
						val += Vector3.ClampMagnitude(val5, num16);
						num2++;
					}
				}
			}
			if (num2 > 1)
			{
				val /= Mathf.Sqrt((float)num2);
			}
			float num17 = Mathf.Max(new float[4]
			{
				_roomMaxPullAcceleration,
				_roomMaxPullAcceleration * _maxTotalAccelerationMultiplier.Value,
				flag ? _roomPullInAcceleration : 0f,
				flag2 ? (_roomMaxPullAcceleration * 2.4f) : 0f
			});
			return new ProxyCorrectionResult(Vector3.ClampMagnitude(val, num17), num, hasUpperAnchorTension);
		}

		private static bool TryGetOtherMember(ChainLink link, ChainMember member, out ChainMember? other)
		{
			if (link.Left.ActorNumber == member.ActorNumber)
			{
				other = link.Right;
				return true;
			}
			if (link.Right.ActorNumber == member.ActorNumber)
			{
				other = link.Left;
				return true;
			}
			other = null;
			return false;
		}

		private bool IsPlayerPullingLink(ChainMember puller, ChainMember target)
		{
			if (PhotonNetwork.LocalPlayer != null && puller.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber)
			{
				if (_localPullInHeld)
				{
					return _localPullInTargetActor == target.ActorNumber;
				}
				return false;
			}
			if (!TryReadBool(puller.Player.CustomProperties, "pn.cb.pull", out var value) || !value)
			{
				return false;
			}
			if (TryReadInt(puller.Player.CustomProperties, "pn.cb.ptgt", out var value2))
			{
				return value2 == target.ActorNumber;
			}
			return false;
		}

		private bool IsLinkBeingPulledIn(ChainLink link)
		{
			if (!IsPlayerPullingLink(link.Left, link.Right))
			{
				return IsPlayerPullingLink(link.Right, link.Left);
			}
			return true;
		}

		private float GetPullInTargetLength()
		{
			return Mathf.Clamp(_roomLinkLength * _roomPullInTargetLengthMultiplier, 0.75f, _roomLinkLength);
		}

		private static float GetPullInAnchorScale(Character character)
		{
			CharacterData data = character.data;
			if ((Object)(object)data == (Object)null)
			{
				return 0.25f;
			}
			if (data.isGrounded && data.sinceGrounded < 0.4f)
			{
				return 0.18f;
			}
			if (data.isClimbing || data.isRopeClimbing || data.isVineClimbing || (Object)(object)data.currentClimbHandle != (Object)null)
			{
				return 0.28f;
			}
			return 0.4f;
		}

		private float GetSupportedDownAccelerationCap(Character localCharacter, ChainMember neighbor, Vector3 localPosition, Vector3 neighborPosition)
		{
			//IL_0023: 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)
			Character val = neighbor.ForceTarget ?? neighbor.Character;
			bool flag = (Object)(object)val != (Object)null && IsUnsupported(val) && neighborPosition.y < localPosition.y - 0.75f;
			if ((Object)(object)localCharacter.data != (Object)null && localCharacter.data.isGrounded && localCharacter.data.sinceGrounded < 0.4f && flag)
			{
				return Mathf.Min(_anchorMaxDownAcceleration.Value, _roomGroundAnchorMaxDownAcceleration);
			}
			if ((Object)(object)localCharacter.data != (Object)null && (localCharacter.data.isClimbing || localCharacter.data.isRopeClimbing || localCharacter.data.isVineClimbing || (Object)(object)localCharacter.data.currentClimbHandle != (Object)null))
			{
				return Mathf.Min(_anchorMaxDownAcceleration.Value, Mathf.Max(_roomGroundAnchorMaxDownAcceleration, _roomMaxPullAcceleration * _roomClimberLoadMultiplier));
			}
			return _anchorMaxDownAcceleration.Value;
		}

		private void EnsureProxyChain(ChainState state)
		{
			HashSet<int> liveBodies = new HashSet<int>();
			foreach (ChainMember localMember in state.LocalMembers)
			{
				liveBodies.Add(localMember.ActorNumber);
				EnsureProxyBody(localMember);
			}
			foreach (int item in _proxyBodies.Keys.Where((int key) => !liveBodies.Contains(key)).ToList())
			{
				DestroyProxyBody(item);
			}
			HashSet<string> liveLinks = new HashSet<string>(StringComparer.Ordinal);
			foreach (ChainLink localLink in state.LocalLinks)
			{
				liveLinks.Add(localLink.Key);
				EnsureProxyJoint(localLink);
				if (_proxyJoints.TryGetValue(localLink.Key, out ConfigurableJoint value) && (Object)(object)value != (Object)null)
				{
					ConfigureProxyJoint(value, IsLinkBeingPulledIn(localLink));
				}
			}
			foreach (string item2 in _proxyJoints.Keys.Where((string key) => !liveLinks.Contains(key)).ToList())
			{
				if ((Object)(object)_proxyJoints[item2] != (Object)null)
				{
					Object.Destroy((Object)(object)_proxyJoints[item2]);
				}
				_proxyJoints.Remove(item2);
			}
		}

		private void EnsureProxyBody(ChainMember member)
		{
			//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_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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0062: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 proxyTargetPosition = GetProxyTargetPosition(member);
			Vector3 proxyTargetVelocity = GetProxyTargetVelocity(member);
			if (!_proxyBodies.TryGetValue(member.ActorNumber, out ProxyBody value) || (Object)(object)value.Body == (Object)null)
			{
				GameObject val = new GameObject("Chainbound Proxy " + member.ActorNumber)
				{
					hideFlags = (HideFlags)61
				};
				Object.DontDestroyOnLoad((Object)val);
				Rigidbody val2 = val.AddComponent<Rigidbody>();
				val2.useGravity = true;
				val2.detectCollisions = false;
				val2.isKinematic = false;
				val2.interpolation = (RigidbodyInterpolation)0;
				val2.collisionDetectionMode = (CollisionDetectionMode)0;
				val2.linearDamping = 0f;
				val2.angularDamping = 2f;
				val2.maxLinearVelocity = 80f;
				val2.position = proxyTargetPosition;
				val2.rotation = Quaternion.identity;
				val2.linearVelocity = proxyTargetVelocity;
				value = new ProxyBody(val, val2)
				{
					WarmupSteps = 2
				};
				_proxyBodies[member.ActorNumber] = value;
			}
			else if ((Object)(object)member.Character != (Object)null && IsRecentlyWarped(member.Character))
			{
				ResetProxyBody(value, member, 2);
			}
			else if (!IsFinite(value.Body.position) || Vector3.Distance(value.Body.position, proxyTargetPosition) > _roomLinkBreakDistance * 0.75f)
			{
				ResetProxyBody(value, member, 2);
			}
		}

		private void EnsureProxyJoint(ChainLink link)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (_proxyBodies.TryGetValue(link.Left.ActorNumber, out ProxyBody value) && _proxyBodies.TryGetValue(link.Right.ActorNumber, out ProxyBody value2))
			{
				if (!_proxyJoints.TryGetValue(link.Key, out ConfigurableJoint value3) || (Object)(object)value3 == (Object)null)
				{
					value3 = ((Component)value.Body).gameObject.AddComponent<ConfigurableJoint>();
					((Joint)value3).connectedBody = value2.Body;
					((Joint)value3).autoConfigureConnectedAnchor = false;
					((Joint)value3).anchor = Vector3.zero;
					((Joint)value3).connectedAnchor = Vector3.zero;
					_proxyJoints[link.Key] = value3;
				}
				ConfigureProxyJoint(value3, pullInActive: false);
			}
		}

		private void ConfigureProxyJoint(ConfigurableJoint joint, bool pullInActive)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			joint.xMotion = (ConfigurableJointMotion)1;
			joint.yMotion = (ConfigurableJointMotion)1;
			joint.zMotion = (ConfigurableJointMotion)1;
			joint.angularXMotion = (ConfigurableJointMotion)2;
			joint.angularYMotion = (ConfigurableJointMotion)2;
			joint.angularZMotion = (ConfigurableJointMotion)2;
			((Joint)joint).enableCollision = false;
			((Joint)joint).enablePreprocessing = false;
			((Joint)joint).breakForce = float.PositiveInfinity;
			((Joint)joint).breakTorque = float.PositiveInfinity;
			joint.projectionMode = (JointProjectionMode)1;
			joint.projectionDistance = 0.75f;
			joint.projectionAngle = 180f;
			SoftJointLimit linearLimit = joint.linearLimit;
			((SoftJointLimit)(ref linearLimit)).limit = Mathf.Max(0.1f, pullInActive ? GetPullInTargetLength() : _roomLinkLength);
			((SoftJointLimit)(ref linearLimit)).bounciness = 0f;
			((SoftJointLimit)(ref linearLimit)).contactDistance = 0.15f;
			joint.linearLimit = linearLimit;
			SoftJointLimitSpring linearLimitSpring = joint.linearLimitSpring;
			((SoftJointLimitSpring)(ref linearLimitSpring)).spring = (pullInActive ? Mathf.Max(0f, _roomPullInAcceleration * 0.35f) : 0f);
			((SoftJointLimitSpring)(ref linearLimitSpring)).damper = (pullInActive ? Mathf.Max(0f, _roomProxyCorrectionDamping * 2f) : 0f);
			joint.linearLimitSpring = linearLimitSpring;
		}

		private void PrepareProxyStep(ChainState state)
		{
			//IL_00c7: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: 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_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			foreach (ChainMember localMember in state.LocalMembers)
			{
				if (!_proxyBodies.TryGetValue(localMember.ActorNumber, out ProxyBody value) || (Object)(object)value.Body == (Object)null)
				{
					continue;
				}
				Character val = localMember.ForceTarget ?? localMember.Character;
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.data == (Object)null))
				{
					float anchorStrength = GetAnchorStrength(val);
					value.Body.mass = GetProxyMass(val, anchorStrength);
					value.Body.useGravity = true;
					value.Body.linearDamping = Mathf.Lerp(0f, 0.25f, anchorStrength);
					value.Body.angularDamping = 2f;
					Vector3 proxyTargetPosition = GetProxyTargetPosition(localMember);
					Vector3 proxyTargetVelocity = GetProxyTargetVelocity(localMember);
					Vector3 val2 = proxyTargetPosition - value.Body.position;
					Vector3 val3 = proxyTargetVelocity - value.Body.linearVelocity;
					float proxyDriveMultiplier = GetProxyDriveMultiplier(val, anchorStrength);
					float num = _roomProxyCorrectionDamping * Mathf.Lerp(0.02f, 1f, anchorStrength);
					Vector3 val4 = val2 * _roomProxyTrackStrength * proxyDriveMultiplier + val3 * num * proxyDriveMultiplier;
					float num2 = Mathf.Max(_roomMaxPullAcceleration, _roomProxyTrackStrength * 2f);
					value.Body.AddForce(Vector3.ClampMagnitude(val4, num2), (ForceMode)5);
					if (state.LocalHasStrongAnchor && IsUnsupported(val))
					{
						float num3 = Mathf.Lerp(1f, 0.2f, anchorStrength);
						float num4 = Mathf.Max(0f, _roomChainGravity - Mathf.Abs(Physics.gravity.y));
						value.Body.AddForce(Vector3.down * num4 * num3, (ForceMode)5);
					}
					Vector3 proxyExternalAcceleration = GetProxyExternalAcceleration(localMember);
					if (((Vector3)(ref proxyExternalAcceleration)).sqrMagnitude > _roomExternalForceThreshold * _roomExternalForceThreshold)
					{
						Vector3 val5 = Vector3.ClampMagnitude(proxyExternalAcceleration, _roomExternalForceMaxAcceleration);
						value.Body.AddForce(val5 * _roomExternalForcePropagation, (ForceMode)5);
					}
					if (value.WarmupSteps > 0)
					{
						value.WarmupSteps--;
					}
				}
			}
		}

		private float GetProxyMass(Character target, float anchorStrength)
		{
			if (IsDowned(target))
			{
				return 0.8f;
			}
			if (HasOpenParasol(target))
			{
				return 7f;
			}
			if ((Object)(object)target.data != (Object)null && (target.data.isClimbing || target.data.isRopeClimbing || target.data.isVineClimbing || (Object)(object)target.data.currentClimbHandle != (Object)null))
			{
				return 12f;
			}
			try
			{
				if (target.IsStuck())
				{
					return 10f;
				}
			}
			catch
			{
			}
			if ((Object)(object)target.data != (Object)null && target.data.isGrounded && target.data.sinceGrounded < 0.4f)
			{
				return 6f;
			}
			return Mathf.Lerp(0.75f, 4f, anchorStrength);
		}

		private float GetProxyDriveMultiplier(Character target, float anchorStrength)
		{
			if (IsDowned(target))
			{
				return 0.05f;
			}
			if (HasOpenParasol(target))
			{
				return 2.35f;
			}
			if ((Object)(object)target.data != (Object)null && (target.data.isClimbing || target.data.isRopeClimbing || target.data.isVineClimbing || (Object)(object)target.data.currentClimbHandle != (Object)null))
			{
				return 2.4f;
			}
			try
			{
				if (target.IsStuck())
				{
					return 2f;
				}
			}
			catch
			{
			}
			if ((Object)(object)target.data != (Object)null && target.data.isGrounded && target.data.sinceGrounded < 0.4f)
			{
				return 1.55f;
			}
			if (GetBalloonCount(target) > 0)
			{
				return 0.04f;
			}
			return Mathf.Lerp(0.08f, 1.2f, anchorStrength);
		}

		private Vector3 GetProxyTargetPosition(ChainMember member)
		{
			//IL_0021: 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)
			Character val = member.ForceTarget ?? member.Character;
			if (!((Object)(object)val != (Object)null))
			{
				return Vector3.zero;
			}
			return val.Center;
		}

		private Vector3 GetProxyTargetVelocity(ChainMember member)
		{
			//IL_0031: 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)
			Character val = member.ForceTarget ?? member.Character;
			if (!((Object)(object)val?.data != (Object)null))
			{
				return Vector3.zero;
			}
			return val.data.avarageVelocity;
		}

		private Vector3 GetProxyExternalAcceleration(ChainMember member)
		{
			//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_0014: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_005a: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			if ((Object)(object)member.Character != (Object)null)
			{
				val += GetRecordedExternalAcceleration(mem