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>>? GroupsChanged; public static IReadOnlyList> GetGroups() { return ChainboundPlugin.Instance?.GetApiGroupsSnapshot() ?? Array.Empty>(); } public static bool TryGetGroupForActor(int actorNumber, out IReadOnlyList group) { foreach (IReadOnlyList group2 in GetGroups()) { if (group2.Any((ChainboundGroupMember member) => member.ActorNumber == actorNumber)) { group = group2; return true; } } group = Array.Empty(); return false; } internal static void NotifyGroupsChanged(IReadOnlyList> groups) { Action>> groupsChanged = ChainboundAPI.GroupsChanged; if (groupsChanged == null) { return; } Delegate[] invocationList = groupsChanged.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action>> action = (Action>>)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 Links = new List(); internal readonly List LocalLinks = new List(); internal readonly HashSet ObservedCharacters = new HashSet(); internal readonly List MissingMod = new List(); internal readonly List VersionMismatches = new List(); internal List LocalLivingChunk = new List(); internal List LocalMembers = new List(); internal List LocalChunkSlots = new List(); 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(); 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(); 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()); } } } [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(); 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 _chainLines = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _lastObservedVelocities = new Dictionary(); private readonly Dictionary _recordedExternalAccelerations = new Dictionary(); private readonly Dictionary _fallVelocitySamples = new Dictionary(); private readonly Dictionary _proxyBodies = new Dictionary(); private readonly Dictionary _proxyJoints = new Dictionary(StringComparer.Ordinal); private readonly List _roomChainOrder = new List(); private Material? _lineMaterial; private GUIStyle? _lobbyBoxStyle; private GUIStyle? _lobbyHeaderStyle; private GUIStyle? _lobbyTextStyle; private Texture2D? _lobbyBoxTexture; private IReadOnlyList> _apiGroups = Array.Empty>(); 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 _enabled; private ConfigEntry _maxGroupSize; private ConfigEntry _drawChain; private ConfigEntry _showLobbyStatus; private ConfigEntry _showInGameStatus; private ConfigEntry _showLobbyStatusToEveryone; private ConfigEntry _requireExactVersion; private ConfigEntry _linkLength; private ConfigEntry _maxPullAcceleration; private ConfigEntry _maxTotalAccelerationMultiplier; private ConfigEntry _anchorMaxDownAcceleration; private ConfigEntry _fallClampSeconds; private ConfigEntry _fallProtectionAfterPullSeconds; private ConfigEntry _spawnGraceSeconds; private ConfigEntry _linkBreakDistance; private ConfigEntry _chainGravity; private ConfigEntry _airbornePullMultiplier; private ConfigEntry _balloonPullMultiplier; private ConfigEntry _downedAnchorMultiplier; private ConfigEntry _externalForcePropagation; private ConfigEntry _externalForceThreshold; private ConfigEntry _externalForceMaxAcceleration; private ConfigEntry _stuckBreakAcceleration; private ConfigEntry _proxyTrackStrength; private ConfigEntry _proxyCorrectionStrength; private ConfigEntry _proxyCorrectionDamping; private ConfigEntry _pullInAcceleration; private ConfigEntry _pullInTargetLengthMultiplier; private ConfigEntry _pullInStaminaPerSecond; private ConfigEntry _danglingStaminaPerPlayer; private ConfigEntry _climberLoadMultiplier; private ConfigEntry _groundAnchorMaxDownAcceleration; private ConfigEntry _balloonExternalForceMultiplier; private ConfigEntry _swingGravityMultiplier; private ConfigEntry _hangingStaminaRegenMultiplier; private ConfigEntry _speedBasedFallDamage; private ConfigEntry _fallDamageMinSpeed; private ConfigEntry _fallDamageMaxSpeed; private ConfigEntry _fallDamageMultiplier; private ConfigEntry _autoCatchUpEnabled; private ConfigEntry _autoCatchUpDistance; private ConfigEntry _autoCatchUpWindowSeconds; private ConfigEntry _autoCatchUpCooldownSeconds; private ConfigEntry _pullInKeyboardKey; private ConfigEntry _pullInGamepadButton; private ConfigEntry _pullInAimAngleDegrees; private ConfigEntry _shuffleAtCampfires; private ConfigEntry _shuffleKeyboardKey; private ConfigEntry _punishTK; private ConfigEntry _debugLogging; private ConfigEntry _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(); _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("General", "Enabled", true, "Enable the chain mod. The host's value is synced to the room."); _maxGroupSize = ((BaseUnityPlugin)this).Config.Bind("General", "MaxGroupSize", 0, new ConfigDescription("Host setting. 0 chains everyone together; 2 creates pairs; 3 creates trios.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 8), Array.Empty())); _drawChain = ((BaseUnityPlugin)this).Config.Bind("General", "DrawChain", true, "Draw local chain links between living players."); _shuffleAtCampfires = ((BaseUnityPlugin)this).Config.Bind("General", "ShuffleAtCampfires", true, "Host setting. Shuffle the chain order automatically when a campfire advances to the next segment."); _showLobbyStatus = ((BaseUnityPlugin)this).Config.Bind("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("Lobby", "ShowInGameStatus", true, "Show an in-run overlay when players are missing Chainbound or using a different version."); _showLobbyStatusToEveryone = ((BaseUnityPlugin)this).Config.Bind("Lobby", "ShowLobbyStatusToEveryone", false, "Show Chainbound status overlays on non-host clients too."); _requireExactVersion = ((BaseUnityPlugin)this).Config.Bind("Lobby", "RequireExactVersion", true, "Treat players with a different Chainbound version as not ready in the lobby status overlay."); _linkLength = ((BaseUnityPlugin)this).Config.Bind("Physics", "LinkLength", 7f, new ConfigDescription("Host setting. Maximum distance between proxy bodies before a joint limit becomes taut.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 30f), Array.Empty())); _maxPullAcceleration = ((BaseUnityPlugin)this).Config.Bind("Physics", "MaxPullAcceleration", 85f, new ConfigDescription("Host setting. Maximum acceleration the solved proxy chain can apply to a real local player.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 250f), Array.Empty())); _maxTotalAccelerationMultiplier = ((BaseUnityPlugin)this).Config.Bind("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(1f, 4f), Array.Empty())); _anchorMaxDownAcceleration = ((BaseUnityPlugin)this).Config.Bind("Physics", "AnchorMaxDownAcceleration", 14f, new ConfigDescription("Local safety cap for downward acceleration on grounded/climbing anchors.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 80f), Array.Empty())); _fallClampSeconds = ((BaseUnityPlugin)this).Config.Bind("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(0.05f, 1.5f), Array.Empty())); _fallProtectionAfterPullSeconds = ((BaseUnityPlugin)this).Config.Bind("Physics", "FallProtectionAfterPullSeconds", 0.8f, new ConfigDescription("Local extra fall-damage protection after a chain pull stops.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _spawnGraceSeconds = ((BaseUnityPlugin)this).Config.Bind("Physics", "SpawnGraceSeconds", 5f, new ConfigDescription("Seconds after spawning/warping before normal chain forces start.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), Array.Empty())); _linkBreakDistance = ((BaseUnityPlugin)this).Config.Bind("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(15f, 300f), Array.Empty())); _chainGravity = ((BaseUnityPlugin)this).Config.Bind("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(0f, 60f), Array.Empty())); _airbornePullMultiplier = ((BaseUnityPlugin)this).Config.Bind("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(0f, 1f), Array.Empty())); _balloonPullMultiplier = ((BaseUnityPlugin)this).Config.Bind("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(0f, 1f), Array.Empty())); _downedAnchorMultiplier = ((BaseUnityPlugin)this).Config.Bind("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(0f, 1f), Array.Empty())); _externalForcePropagation = ((BaseUnityPlugin)this).Config.Bind("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(0f, 1.5f), Array.Empty())); _externalForceThreshold = ((BaseUnityPlugin)this).Config.Bind("Physics", "ExternalForceThreshold", 10f, new ConfigDescription("Host setting. Sudden acceleration below this is ignored by force propagation.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 80f), Array.Empty())); _externalForceMaxAcceleration = ((BaseUnityPlugin)this).Config.Bind("Physics", "ExternalForceMaxAcceleration", 70f, new ConfigDescription("Host setting. Maximum acceleration added by external force propagation per link.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 200f), Array.Empty())); _stuckBreakAcceleration = ((BaseUnityPlugin)this).Config.Bind("Physics", "StuckBreakAcceleration", 55f, new ConfigDescription("Host setting. Chain acceleration needed to pull the local player out of cactus/sticky joints.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 200f), Array.Empty())); _proxyTrackStrength = ((BaseUnityPlugin)this).Config.Bind("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(5f, 160f), Array.Empty())); _proxyCorrectionStrength = ((BaseUnityPlugin)this).Config.Bind("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(2f, 120f), Array.Empty())); _proxyCorrectionDamping = ((BaseUnityPlugin)this).Config.Bind("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(0f, 40f), Array.Empty())); _pullInAcceleration = ((BaseUnityPlugin)this).Config.Bind("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(0f, 250f), Array.Empty())); _pullInTargetLengthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Physics", "PullInTargetLengthMultiplier", 0.25f, new ConfigDescription("Host setting. Target chain-link length while pulling, as a multiplier of LinkLength.", (AcceptableValueBase)(object)new AcceptableValueRange(0.15f, 1f), Array.Empty())); _pullInStaminaPerSecond = ((BaseUnityPlugin)this).Config.Bind("Physics", "PullInStaminaPerSecond", 0.15f, new ConfigDescription("Host setting. Stamina drained per second from the player actively winching a chain link.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _danglingStaminaPerPlayer = ((BaseUnityPlugin)this).Config.Bind("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(0f, 0.3f), Array.Empty())); _climberLoadMultiplier = ((BaseUnityPlugin)this).Config.Bind("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(0f, 2f), Array.Empty())); _groundAnchorMaxDownAcceleration = ((BaseUnityPlugin)this).Config.Bind("Physics", "GroundAnchorMaxDownAcceleration", 3.5f, new ConfigDescription("Host setting. Downward acceleration cap for grounded anchors holding a lower unsupported player.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 80f), Array.Empty())); _balloonExternalForceMultiplier = ((BaseUnityPlugin)this).Config.Bind("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(0f, 1f), Array.Empty())); _swingGravityMultiplier = ((BaseUnityPlugin)this).Config.Bind("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(0f, 6f), Array.Empty())); _hangingStaminaRegenMultiplier = ((BaseUnityPlugin)this).Config.Bind("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(0f, 3f), Array.Empty())); _speedBasedFallDamage = ((BaseUnityPlugin)this).Config.Bind("Damage", "SpeedBasedFallDamage", false, "Host setting. Replace PEAK's airtime-based landing and wall-grab damage with speed-based damage."); _fallDamageMinSpeed = ((BaseUnityPlugin)this).Config.Bind("Damage", "FallDamageMinSpeed", 11f, new ConfigDescription("Host setting. Downward impact speed in m/s where speed-based fall damage starts.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 40f), Array.Empty())); _fallDamageMaxSpeed = ((BaseUnityPlugin)this).Config.Bind("Damage", "FallDamageMaxSpeed", 23f, new ConfigDescription("Host setting. Downward impact speed in m/s that reaches full speed-based fall damage.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 60f), Array.Empty())); _fallDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind("Damage", "FallDamageMultiplier", 1f, new ConfigDescription("Host setting. Multiplier applied to speed-based fall damage after speed is converted to injury.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _autoCatchUpEnabled = ((BaseUnityPlugin)this).Config.Bind("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("CatchUp", "AutoCatchUpDistance", 55f, new ConfigDescription("Distance from the nearest living group member before a fresh local spawn is caught up.", (AcceptableValueBase)(object)new AcceptableValueRange(15f, 300f), Array.Empty())); _autoCatchUpWindowSeconds = ((BaseUnityPlugin)this).Config.Bind("CatchUp", "AutoCatchUpWindowSeconds", 35f, new ConfigDescription("Only auto catch-up during this many seconds after the local character spawns.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 180f), Array.Empty())); _autoCatchUpCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind("CatchUp", "AutoCatchUpCooldownSeconds", 20f, new ConfigDescription("Minimum time between automatic catch-up warps.", (AcceptableValueBase)(object)new AcceptableValueRange(3f, 180f), Array.Empty())); _pullInKeyboardKey = ((BaseUnityPlugin)this).Config.Bind("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("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("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(10f, 75f), Array.Empty())); _shuffleKeyboardKey = ((BaseUnityPlugin)this).Config.Bind("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("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("Debug", "DebugLogging", false, "Write Chainbound debug messages to the BepInEx log."); _damageLogging = ((BaseUnityPlugin)this).Config.Bind("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()); } } } 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 list = new List(); 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 liveBodies = new HashSet(); 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 liveLinks = new HashSet(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(); 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(); ((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(member.Character); } if ((Object)(object)member.ForceTarget != (Object)null && (Object)(object)member.ForceTarget != (Object)(object)member.Character) { val += GetRecordedExternalAcceleration(member.ForceTarget); } Character val2 = member.ForceTarget ?? member.Character; if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)Character.localCharacter) { val += GetObservedAcceleration(val2) * 0.25f; } if ((Object)(object)val2 != (Object)null && GetBalloonCount(val2) > 0) { val *= _roomBalloonExternalForceMultiplier; } if ((Object)(object)val2 != (Object)null) { val += GetParasolExternalAcceleration(val2); } if (!IsFinite(val)) { return Vector3.zero; } return val; } private void ResetProxyBody(ProxyBody proxy, ChainMember member, int warmupSteps) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) proxy.Body.isKinematic = false; proxy.Body.position = GetProxyTargetPosition(member); proxy.Body.rotation = Quaternion.identity; proxy.Body.linearVelocity = GetProxyTargetVelocity(member); proxy.Body.angularVelocity = Vector3.zero; proxy.WarmupSteps = Math.Max(proxy.WarmupSteps, warmupSteps); } private void DestroyProxyBody(int key) { if (!_proxyBodies.TryGetValue(key, out ProxyBody value)) { return; } foreach (string item in _proxyJoints.Keys.Where((string jointKey) => jointKey.StartsWith(key + ":", StringComparison.Ordinal) || jointKey.EndsWith(":" + key, StringComparison.Ordinal)).ToList()) { if ((Object)(object)_proxyJoints[item] != (Object)null) { Object.Destroy((Object)(object)_proxyJoints[item]); } _proxyJoints.Remove(item); } if ((Object)(object)value.GameObject != (Object)null) { Object.Destroy((Object)(object)value.GameObject); } _proxyBodies.Remove(key); } private void ClearProxyChain() { foreach (ConfigurableJoint value in _proxyJoints.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } _proxyJoints.Clear(); foreach (ProxyBody value2 in _proxyBodies.Values) { if ((Object)(object)value2.GameObject != (Object)null) { Object.Destroy((Object)(object)value2.GameObject); } } _proxyBodies.Clear(); } private void ProtectFromChainFall(Character character) { if (!((Object)(object)character.data == (Object)null)) { character.data.sinceGrounded = Mathf.Min(character.data.sinceGrounded, _roomFallClampSeconds); character.data.sinceJump = Mathf.Min(character.data.sinceJump, _roomFallClampSeconds); } } private bool ShouldSuppressClimbFallDamage(Character? character) { if ((Object)(object)character != (Object)null && (Object)(object)character == (Object)(object)Character.localCharacter) { return Time.time < _chainClimbDamageProtectedUntil; } return false; } private bool ShouldUseSpeedBasedFallDamage(Character? character) { if (_roomSpeedBasedFallDamage && ShouldRunHostEnabledGameplay() && (Object)(object)character != (Object)null && (Object)(object)((MonoBehaviourPun)character).photonView != (Object)null) { return ((MonoBehaviourPun)character).photonView.IsMine; } return false; } private bool ShouldSuppressChainLandingDamage(Character? character) { if (ShouldRunHostEnabledGameplay() && (Object)(object)character != (Object)null && (Object)(object)character == (Object)(object)Character.localCharacter && (Object)(object)((MonoBehaviourPun)character).photonView != (Object)null && ((MonoBehaviourPun)character).photonView.IsMine && (Time.time < _chainFallProtectedUntil || HasUpperParasolChainSupport(character))) { return !_roomSpeedBasedFallDamage; } return false; } private void ApplySpeedBasedFallDamage(Character character, float extraImpactSpeed, string source) { //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character.data == (Object)null || (Object)(object)character.refs?.afflictions == (Object)null) { return; } float num = Mathf.Max(0f, 0f - character.data.avarageVelocity.y); float num2 = Mathf.Max(0f, 0f - character.data.avarageLastFrameVelocity.y); float downSpeed; float num3 = (TryGetRecentCenterDownSpeed(character, out downSpeed) ? downSpeed : num); float num4 = Mathf.Max(num3, extraImpactSpeed); float num5 = Mathf.InverseLerp(Mathf.Min(_roomFallDamageMinSpeed, _roomFallDamageMaxSpeed - 0.1f), _roomFallDamageMaxSpeed, num4); if (num5 <= 0f) { DebugLog($"Speed damage skipped source={source} centerDownSpeed={num3:0.0} ragdollDownSpeed={num:0.0} ragdollLastDownSpeed={num2:0.0}"); return; } float num6 = Mathf.Pow(num5, 1.5f) * _roomFallDamageMultiplier; float num7 = Mathf.Clamp01(num6); if (num7 < 0.025f) { DebugLog($"Speed damage below threshold source={source} centerDownSpeed={num3:0.0} injury={num7:0.000} ragdollDownSpeed={num:0.0} ragdollLastDownSpeed={num2:0.0}"); return; } if (ShouldSuppressProtectedLandingDamage(character, num7, num4, source)) { DamageLog($"Speed fall damage suppressed source={source} centerDownSpeed={num3:0.00} damageSpeed={num4:0.00} rawInjury={num6:0.000} ragdollDownSpeed={num:0.00} ragdollLastDownSpeed={num2:0.00} sinceGrounded={character.data.sinceGrounded:0.00} sinceJump={character.data.sinceJump:0.00}"); return; } if (num7 > 0.3f && character.IsLocal) { character.refs.view.RPC("RPCA_Fall", (RpcTarget)0, new object[1] { num7 * 5f }); } num7 *= Ascents.fallDamageMultiplier; num7 /= Ascents.etcDamageMultiplier; DamageLog($"Speed fall damage applying source={source} centerDownSpeed={num3:0.00} damageSpeed={num4:0.00} extraImpact={extraImpactSpeed:0.00} rawInjury={num6:0.000} scaledInjury={num7:0.000} ragdollDownSpeed={num:0.00} ragdollLastDownSpeed={num2:0.00} avgVel={FormatVector(character.data.avarageVelocity)} lastVel={FormatVector(character.data.avarageLastFrameVelocity)} sinceGrounded={character.data.sinceGrounded:0.00} sinceJump={character.data.sinceJump:0.00}"); character.refs.afflictions.AddStatus((STATUSTYPE)0, num7, false, true, true); DebugLog($"Speed damage source={source} centerDownSpeed={num3:0.0} damageSpeed={num4:0.0} injury={num7:0.000}"); } private bool ShouldSuppressProtectedLandingDamage(Character character, float injury, float damageSpeed, string source) { if (!string.Equals(source, "landing", StringComparison.Ordinal) || (Object)(object)character != (Object)(object)Character.localCharacter) { return false; } if (Time.time >= _chainFallProtectedUntil && !HasUpperParasolChainSupport(character)) { return false; } float num = Mathf.Max(0.08f, Mathf.Pow(Mathf.InverseLerp(_roomFallDamageMinSpeed, _roomFallDamageMaxSpeed, _roomFallDamageMinSpeed + 2.5f), 1.5f)); if (injury <= num) { return true; } return damageSpeed <= _roomFallDamageMinSpeed + 2f; } private bool HasUpperParasolChainSupport(Character localCharacter) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_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_00bb: 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_00d0: 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) if (PhotonNetwork.LocalPlayer == null || (Object)(object)localCharacter.data == (Object)null) { return false; } ChainState chainState = BuildChainState(); int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber; Vector3 center = localCharacter.Center; foreach (ChainLink localLink in chainState.LocalLinks) { ChainMember chainMember = null; if (localLink.Left.ActorNumber == actorNumber) { chainMember = localLink.Right; } else if (localLink.Right.ActorNumber == actorNumber) { chainMember = localLink.Left; } Character val = chainMember?.ForceTarget ?? chainMember?.Character; if (!((Object)(object)val == (Object)null) && HasOpenParasol(val)) { Vector3 proxyTargetPosition = GetProxyTargetPosition(chainMember); if (proxyTargetPosition.y > center.y + 0.75f && Vector3.Distance(center, proxyTargetPosition) <= _roomLinkBreakDistance) { return true; } } } return false; } private void RecordFallVelocitySample(Character? character) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || (Object)(object)character.data == (Object)null) { return; } int viewID = ((MonoBehaviourPun)character).photonView.ViewID; if (viewID <= 0) { return; } Vector3 center = character.Center; float time = Time.time; if (!IsFinite(center) || character.warping || Time.time - character.timeLastWarped < 0.5f) { _fallVelocitySamples[viewID] = new FallVelocitySample(center, time); return; } if (!_fallVelocitySamples.TryGetValue(viewID, out FallVelocitySample value)) { _fallVelocitySamples[viewID] = new FallVelocitySample(center, time); return; } float num = time - value.LastTime; if (num > 0.001f && num < 0.25f) { float num2 = Mathf.Max(0f, (value.LastCenter.y - center.y) / num); if (!float.IsNaN(num2) && !float.IsInfinity(num2)) { value.AddDownSpeed(Mathf.Min(num2, 80f)); } } value.LastCenter = center; value.LastTime = time; } private bool TryGetRecentCenterDownSpeed(Character character, out float downSpeed) { downSpeed = 0f; if ((Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || !_fallVelocitySamples.TryGetValue(((MonoBehaviourPun)character).photonView.ViewID, out FallVelocitySample value) || value.Count <= 0) { return false; } float[] sortedSpeeds = value.GetSortedSpeeds(); if (sortedSpeeds.Length == 0) { return false; } int num = ((sortedSpeeds.Length >= 3) ? (sortedSpeeds.Length - 2) : (sortedSpeeds.Length - 1)); downSpeed = sortedSpeeds[Mathf.Clamp(num, 0, sortedSpeeds.Length - 1)]; return true; } private bool TryAutoCatchUp(Character localCharacter, ChainState state) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) if (!_autoCatchUpEnabled.Value || _catchUpAttemptsForCharacter >= 3 || state.LocalLivingChunk.Count <= 1) { return false; } float num = Time.realtimeSinceStartup - _localCharacterSpawnTime; if (num < 2f || num > _autoCatchUpWindowSeconds.Value) { return false; } float num2 = ((_catchUpAttemptsForCharacter == 0) ? _autoCatchUpCooldownSeconds.Value : 2.5f); if (Time.realtimeSinceStartup - _lastCatchUpTime < num2) { return false; } if (!TryGetCatchUpTarget(localCharacter, state, out Vector3 target, out float nearestDistance, out string anchorLabel)) { return false; } if (nearestDistance < _autoCatchUpDistance.Value) { return false; } DebugLog($"Auto catch-up warping local player near {anchorLabel}. nearestDistance={nearestDistance:0.0} target={FormatVector(target)}"); ((MonoBehaviourPun)localCharacter).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { target, true }); _lastCatchUpTime = Time.realtimeSinceStartup; _catchUpAttemptsForCharacter++; _localCharacterSpawnTime = Time.realtimeSinceStartup; Notify("Chainbound: catching you up to your group"); return true; } private bool TryGetCatchUpTarget(Character localCharacter, ChainState state, out Vector3 target, out float nearestDistance, out string anchorLabel) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: 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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) target = Vector3.zero; nearestDistance = float.MaxValue; anchorLabel = "group"; if (state.LocalSlotIndex >= 0 && state.LocalChunkSlots.Count > 0) { ChainMember chainMember = FindLivingSlotNeighbor(state.LocalChunkSlots, state.LocalSlotIndex, -1); ChainMember chainMember2 = FindLivingSlotNeighbor(state.LocalChunkSlots, state.LocalSlotIndex, 1); Character livingMemberTarget = GetLivingMemberTarget(chainMember); Character livingMemberTarget2 = GetLivingMemberTarget(chainMember2); if ((Object)(object)livingMemberTarget != (Object)null && (Object)(object)livingMemberTarget2 != (Object)null) { nearestDistance = Mathf.Min(Vector3.Distance(localCharacter.Center, livingMemberTarget.Center), Vector3.Distance(localCharacter.Center, livingMemberTarget2.Center)); target = (livingMemberTarget.Center + livingMemberTarget2.Center) * 0.5f + Vector3.up * 1.5f; anchorLabel = PlayerLabel(chainMember.Player) + " and " + PlayerLabel(chainMember2.Player); return IsFinite(target); } Character val = livingMemberTarget ?? livingMemberTarget2; ChainMember chainMember3 = (((Object)(object)livingMemberTarget != (Object)null) ? chainMember : chainMember2); if ((Object)(object)val != (Object)null && chainMember3 != null) { nearestDistance = Vector3.Distance(localCharacter.Center, val.Center); target = val.Center + GetDeterministicSpawnOffset(PhotonNetwork.LocalPlayer.ActorNumber); anchorLabel = PlayerLabel(chainMember3.Player); return IsFinite(target); } } Character val2 = null; foreach (Character item in state.LocalLivingChunk) { if (!((Object)(object)item == (Object)(object)localCharacter) && IsChainAlive(item)) { float num = Vector3.Distance(localCharacter.Center, item.Center); if (num < nearestDistance) { nearestDistance = num; } if ((Object)(object)val2 == (Object)null || item.Center.y < val2.Center.y) { val2 = item; } } } if ((Object)(object)val2 == (Object)null) { return false; } Vector3 deterministicSpawnOffset = GetDeterministicSpawnOffset(PhotonNetwork.LocalPlayer.ActorNumber); target = val2.Center + deterministicSpawnOffset; anchorLabel = val2.characterName; return IsFinite(target); } private static ChainMember? FindLivingSlotNeighbor(List slots, int startIndex, int step) { for (int i = startIndex + step; i >= 0 && i < slots.Count; i += step) { ChainMember chainMember = slots[i]; if ((Object)(object)GetLivingMemberTarget(chainMember) != (Object)null) { return chainMember; } } return null; } private static Character? GetLivingMemberTarget(ChainMember? member) { Character val = member?.ForceTarget ?? member?.Character; if (!IsChainAlive(val)) { return null; } return val; } private static Vector3 GetDeterministicSpawnOffset(int actorNumber) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) float num = (float)actorNumber * 97f * ((float)Math.PI / 180f); return new Vector3(Mathf.Cos(num) * 1.8f, 1.5f, Mathf.Sin(num) * 1.8f); } private void TrackLocalCharacterSpawn() { Character localCharacter = Character.localCharacter; int num = (((Object)(object)localCharacter != (Object)null && (Object)(object)((MonoBehaviourPun)localCharacter).photonView != (Object)null) ? ((MonoBehaviourPun)localCharacter).photonView.ViewID : 0); if (num != _localCharacterViewId) { _localCharacterViewId = num; _localCharacterSpawnTime = Time.realtimeSinceStartup; _catchUpAttemptsForCharacter = 0; _chainFallProtectedUntil = 0f; _fallVelocitySamples.Clear(); DebugLog($"Local character changed. view={num}"); } } private bool IsRecentlyWarped(Character character) { if (!character.warping) { return Time.time - character.timeLastWarped < _spawnGraceSeconds.Value; } return true; } private Vector3 GetObservedAcceleration(Character character) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || (Object)(object)character.data == (Object)null) { return Vector3.zero; } int viewID = ((MonoBehaviourPun)character).photonView.ViewID; if (viewID <= 0 || !_lastObservedVelocities.TryGetValue(viewID, out var value)) { return Vector3.zero; } return (character.data.avarageVelocity - value) / Mathf.Max(Time.fixedDeltaTime, 0.001f); } private Vector3 GetRecordedExternalAcceleration(Character character) { //IL_0017: 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_0043: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null) { return Vector3.zero; } int viewID = ((MonoBehaviourPun)character).photonView.ViewID; if (viewID <= 0 || !_recordedExternalAccelerations.TryGetValue(viewID, out var value)) { return Vector3.zero; } return value; } internal static void RecordExternalAcceleration(Character character, Vector3 acceleration) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_009c: 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) ChainboundPlugin instance = _instance; if ((Object)(object)instance == (Object)null || !instance.ShouldRunHostEnabledGameplay() || (Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || !IsFinite(acceleration)) { return; } int viewID = ((MonoBehaviourPun)character).photonView.ViewID; if (viewID > 0) { float num = Mathf.Max(instance._roomExternalForceMaxAcceleration, instance._externalForceMaxAcceleration?.Value ?? 70f) * 2f; Vector3 val = Vector3.ClampMagnitude(acceleration, Mathf.Max(1f, num)); if (instance._recordedExternalAccelerations.TryGetValue(viewID, out var value)) { instance._recordedExternalAccelerations[viewID] = Vector3.ClampMagnitude(value + val, Mathf.Max(1f, num)); } else { instance._recordedExternalAccelerations[viewID] = val; } } } internal static Vector3 ScaleExternalImpulse(Character character, Vector3 impulse) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) ChainboundPlugin instance = _instance; if ((Object)(object)instance == (Object)null || (Object)(object)character == (Object)null || !instance.ShouldScaleBalloonExternalForce(character)) { return impulse; } return impulse * instance._roomBalloonExternalForceMultiplier; } private bool ShouldScaleBalloonExternalForce(Character character) { if (!ShouldRunHostEnabledGameplay() || GetBalloonCount(character) <= 0 || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null) { return false; } Player owner = ((MonoBehaviourPun)character).photonView.Owner; if (owner != null) { return IsPlayerOptedIntoChain(owner); } return false; } private bool TryPunishKick(CharacterGrabbing grabbing) { Character actor = (((Object)(object)grabbing != (Object)null) ? ((Component)grabbing).GetComponent() : null); if (!ShouldPunishDangerousAction(actor)) { return false; } PunishDangerousAction(actor, "kicking"); return true; } private bool TryPunishCookedLaunch(Action_LaunchPlayer action) { Item val = (((Object)(object)action != (Object)null) ? ((Component)action).GetComponent() : null); Character actor = GetItemActionCharacter((ItemActionBase?)(object)action) ?? ((val != null) ? val.holderCharacter : null); if (!IsCookedLaunchItem(val) || !ShouldPunishDangerousAction(actor)) { return false; } PunishDangerousAction(actor, "cooked launch item"); return true; } private bool TryPunishCookedRunActions(CookingBehavior_RunActions behavior) { if (behavior?.actionsToRun == null || !behavior.actionsToRun.Any((ItemAction action) => action is Action_LaunchPlayer)) { return false; } Item? cookingBehaviorItem = GetCookingBehaviorItem((AdditionalCookingBehavior)(object)behavior); Character actor = ((cookingBehaviorItem != null) ? cookingBehaviorItem.holderCharacter : null); if (!IsCookedLaunchItem(cookingBehaviorItem) || !ShouldPunishDangerousAction(actor)) { return false; } PunishDangerousAction(actor, "cooked launch item"); return true; } private bool TryBlockFartShroom(Action_RandomMushroomEffect action) { Item obj = (((Object)(object)action != (Object)null) ? ((Component)action).GetComponent() : null); Character val = ((obj != null) ? obj.holderCharacter : null); if (!IsFartShroomEffect(action) || !ShouldPunishDangerousAction(val)) { return false; } if ((Object)(object)val != (Object)null && (Object)(object)((MonoBehaviourPun)val).photonView != (Object)null && ((MonoBehaviourPun)val).photonView.IsMine) { Notify("Chainbound: fart shroom launch is blocked while chained"); DebugLog("Blocked fart shroom for " + GetCharacterDebugName(val)); } return true; } private bool ShouldPunishDangerousAction(Character? actor) { if (!_roomPunishTK || !ShouldRunHostEnabledGameplay() || IsLobbyScene() || (Object)(object)actor == (Object)null || (Object)(object)((MonoBehaviourPun)actor).photonView == (Object)null) { return false; } Player owner = ((MonoBehaviourPun)actor).photonView.Owner; if (owner == null || !IsPlayerOptedIntoChain(owner)) { return false; } ChainState chainState = BuildChainState(); int actorNumber = ((MonoBehaviourPun)actor).photonView.OwnerActorNr; return chainState.Links.Any((ChainLink link) => link.Left.ActorNumber == actorNumber || link.Right.ActorNumber == actorNumber); } private void PunishDangerousAction(Character actor, string actionName) { //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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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) if (!((Object)(object)((MonoBehaviourPun)actor).photonView == (Object)null) && ((MonoBehaviourPun)actor).photonView.IsMine) { DebugLog("Punishing dangerous action=" + actionName + " character=" + GetCharacterDebugName(actor)); Notify("Chainbound: " + actionName + " is disabled while chained"); Vector3 val = actor.Center + Vector3.up * 0.2f + Vector3.forward * 0.1f; actor.refs.view.RPC("RPCA_Die", (RpcTarget)0, new object[1] { val }); } } private static Character? GetItemActionCharacter(ItemActionBase? action) { if ((Object)(object)action == (Object)null) { return null; } try { object? obj = AccessTools.PropertyGetter(typeof(ItemActionBase), "character")?.Invoke(action, Array.Empty()); return (Character?)((obj is Character) ? obj : null); } catch { return null; } } private static Item? GetCookingBehaviorItem(AdditionalCookingBehavior behavior) { try { ItemCooking value = Traverse.Create((object)behavior).Field("itemCooking").GetValue(); return ((Object)(object)value != (Object)null) ? ((Component)value).GetComponent() : null; } catch { return null; } } private static bool IsCookedLaunchItem(Item? item) { if ((Object)(object)item == (Object)null || !item.HasData((DataEntryKey)1)) { return false; } try { return item.GetData((DataEntryKey)1).Value > 0; } catch { return false; } } private static bool IsFartShroomEffect(Action_RandomMushroomEffect? action) { if ((Object)(object)action == (Object)null) { return false; } if (action.useDebugEffect) { return action.debugEffect == 5; } try { if ((Object)(object)MushroomManager.instance == (Object)null || MushroomManager.instance.mushroomEffects == null || MushroomManager.instance.mushroomEffects.Length == 0) { return false; } int num = action.mushroomTypeIndex % MushroomManager.instance.mushroomEffects.Length; return MushroomManager.instance.mushroomEffects[num] == 5; } catch { return false; } } private void UpdateObservedVelocities(IEnumerable characters) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) HashSet liveViewIds = new HashSet(); foreach (Character character in characters) { if (!((Object)(object)character == (Object)null) && !((Object)(object)((MonoBehaviourPun)character).photonView == (Object)null) && !((Object)(object)character.data == (Object)null)) { int viewID = ((MonoBehaviourPun)character).photonView.ViewID; if (viewID > 0) { liveViewIds.Add(viewID); _lastObservedVelocities[viewID] = character.data.avarageVelocity; } } } foreach (int item in _lastObservedVelocities.Keys.Where((int viewId) => !liveViewIds.Contains(viewId)).ToList()) { _lastObservedVelocities.Remove(item); } DecayRecordedExternalAccelerations(liveViewIds); } private void DecayRecordedExternalAccelerations(HashSet liveViewIds) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) foreach (int item in _recordedExternalAccelerations.Keys.ToList()) { if (!liveViewIds.Contains(item)) { _recordedExternalAccelerations.Remove(item); continue; } Vector3 value = _recordedExternalAccelerations[item] * 0.25f; if (((Vector3)(ref value)).sqrMagnitude < 1f) { _recordedExternalAccelerations.Remove(item); } else { _recordedExternalAccelerations[item] = value; } } } private ChainState BuildChainState() { ChainState chainState = new ChainState(); if (!PhotonNetwork.InRoom || (!PhotonNetwork.IsMasterClient && !_roomHasChainboundHost)) { return chainState; } int num = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1)); Character localCharacter = Character.localCharacter; List list = CollectActiveChainMembers(chainState); Dictionary membersByKey = new Dictionary(StringComparer.Ordinal); foreach (ChainMember item2 in list) { membersByKey[item2.StableKey] = item2; } List effectiveChainOrder = GetEffectiveChainOrder(list.Select((ChainMember member) => member.StableKey)); int num2 = ((_roomMaxGroupSize <= 1) ? effectiveChainOrder.Count : _roomMaxGroupSize); if (num2 <= 1) { return chainState; } for (int i = 0; i < effectiveChainOrder.Count; i += num2) { ChainMember value; List list2 = (from key in effectiveChainOrder.Skip(i).Take(num2) select (!membersByKey.TryGetValue(key, out value)) ? null : value).ToList(); List list3 = list2.OfType().ToList(); if (list3.Count == 0) { continue; } List list4 = list3.Where((ChainMember member) => IsChainAlive(member.Character)).ToList(); bool flag = false; int localSlotIndex = -1; for (int j = 0; j < list2.Count; j++) { ChainMember chainMember = list2[j]; if (chainMember != null) { if (chainMember.ActorNumber == num) { flag = true; localSlotIndex = j; } else if ((Object)(object)chainMember.ForceTarget == (Object)(object)localCharacter) { flag = true; } } } foreach (ChainMember item3 in list4) { chainState.ObservedCharacters.Add(item3.Character); if ((Object)(object)item3.ForceTarget != (Object)null) { chainState.ObservedCharacters.Add(item3.ForceTarget); } } if (flag) { chainState.LocalLivingChunk = list4.Select((ChainMember member) => member.Character).ToList(); chainState.LocalMembers = list4; chainState.LocalChunkSlots = list2; chainState.LocalSlotIndex = localSlotIndex; chainState.LocalHasStrongAnchor = list4.Any(HasStrongAnchor); } for (int k = 0; k < list4.Count - 1; k++) { ChainMember chainMember2 = list4[k]; ChainMember chainMember3 = list4[k + 1]; if (CanLinkConnect(chainMember2.Character, chainMember3.Character)) { ChainLink item = new ChainLink(chainMember2, chainMember3); chainState.Links.Add(item); if (flag) { chainState.LocalLinks.Add(item); } if ((Object)(object)chainMember2.ForceTarget == (Object)(object)localCharacter) { chainState.LocalHasStrongAnchor |= HasStrongAnchor(chainMember2) || HasStrongAnchor(chainMember3) || GetAnchorStrength(localCharacter) >= 0.75f; } if ((Object)(object)chainMember3.ForceTarget == (Object)(object)localCharacter) { chainState.LocalHasStrongAnchor |= HasStrongAnchor(chainMember3) || HasStrongAnchor(chainMember2) || GetAnchorStrength(localCharacter) >= 0.75f; } } } } return chainState; } private List CollectActiveChainMembers(ChainState state) { List list = new List(); HashSet usedKeys = new HashSet(StringComparer.Ordinal); foreach (Player item in from player in PhotonNetwork.PlayerList where player != null && !player.IsInactive orderby player.ActorNumber select player) { if ((PhotonNetwork.LocalPlayer == null || item.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber) && !HasInstalledCompatibleMod(item, out var versionMismatch)) { if (versionMismatch) { state.VersionMismatches.Add(item); } else { state.MissingMod.Add(item); } } else { TryGetCharacterForPlayer(item, out Character character); string uniquePlayerStableKey = GetUniquePlayerStableKey(item, usedKeys); list.Add(new ChainMember(item, uniquePlayerStableKey, character, GetForceTarget(character))); } } return list; } private List GetEffectiveChainOrder(IEnumerable activeKeys) { List list = new List(); HashSet seenKeys = new HashSet(StringComparer.Ordinal); foreach (string item in _roomChainOrder) { AddChainOrderKey(item, list, seenKeys); } foreach (string activeKey in activeKeys) { AddChainOrderKey(activeKey, list, seenKeys); } return list; } private List GetPublishedChainOrder() { List list = new List(); HashSet seenKeys = new HashSet(StringComparer.Ordinal); foreach (string item in _roomChainOrder) { AddChainOrderKey(item, list, seenKeys); } return list; } internal IReadOnlyList> GetApiGroupsSnapshot() { return _apiGroups; } private void RefreshApiGroups() { IReadOnlyList> readOnlyList = BuildApiGroups(); string text = BuildApiGroupSignature(readOnlyList); if (!string.Equals(text, _apiGroupSignature, StringComparison.Ordinal)) { _apiGroups = readOnlyList; _apiGroupSignature = text; ChainboundAPI.NotifyGroupsChanged(_apiGroups); } } private void ClearApiGroups() { if (_apiGroups.Count != 0 || _apiGroupSignature.Length != 0) { _apiGroups = Array.Empty>(); _apiGroupSignature = string.Empty; ChainboundAPI.NotifyGroupsChanged(_apiGroups); } } private IReadOnlyList> BuildApiGroups() { if (!ShouldRunHostEnabledGameplay() || IsLobbyScene()) { return Array.Empty>(); } List publishedChainOrder = GetPublishedChainOrder(); if (!publishedChainOrder.Any((string key) => !IsEmptyChainSlot(key))) { return Array.Empty>(); } List list = CollectActiveChainMembers(new ChainState()); if (list.Count == 0) { return Array.Empty>(); } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (ChainMember item in list) { dictionary[item.StableKey] = item; } int num = ((_roomMaxGroupSize <= 1) ? publishedChainOrder.Count : _roomMaxGroupSize); if (num <= 0) { return Array.Empty>(); } List> list2 = new List>(); for (int i = 0; i < publishedChainOrder.Count; i += num) { List list3 = new List(); foreach (string item2 in publishedChainOrder.Skip(i).Take(num)) { if (dictionary.TryGetValue(item2, out var value)) { list3.Add(ToApiGroupMember(value)); } } if (list3.Count > 0) { list2.Add(list3.ToArray()); } } return list2.ToArray(); } private static ChainboundGroupMember ToApiGroupMember(ChainMember member) { Character character = member.Character; Player localPlayer = PhotonNetwork.LocalPlayer; return new ChainboundGroupMember(member.ActorNumber, PlayerLabel(member.Player), member.StableKey, localPlayer != null && member.ActorNumber == localPlayer.ActorNumber, IsChainAlive(character), character); } private static string BuildApiGroupSignature(IReadOnlyList> groups) { return string.Join("|", groups.Select((IReadOnlyList group) => string.Join(",", group.Select((ChainboundGroupMember member) => member.StableKey + "#" + member.ActorNumber)))); } private List BuildMaintainedChainOrder(List activeMembers) { List effectiveChainOrder = GetEffectiveChainOrder(Array.Empty()); HashSet activeSet = new HashSet(activeMembers.Select((ChainMember member) => member.StableKey), StringComparer.Ordinal); HashSet presentActiveKeys = new HashSet(effectiveChainOrder.Where((string key) => activeSet.Contains(key)), StringComparer.Ordinal); foreach (ChainMember item in (from member in activeMembers where !presentActiveKeys.Contains(member.StableKey) select member into _ orderby Random.value select _).ToList()) { int num = FindRandomEmptySlot(effectiveChainOrder); if (num >= 0) { effectiveChainOrder[num] = item.StableKey; } else { effectiveChainOrder.Add(item.StableKey); } } PadOpenChainSlots(effectiveChainOrder); return effectiveChainOrder; } private void PadOpenChainSlots(List order) { List list = order.Where(IsEmptyChainSlot).ToList(); List collection = order.Where((string key) => !IsEmptyChainSlot(key)).ToList(); order.Clear(); order.AddRange(collection); int roomMaxGroupSize = _roomMaxGroupSize; if (roomMaxGroupSize <= 1 || order.Count == 0) { return; } int num = order.Count % roomMaxGroupSize; if (num != 0) { int num2 = roomMaxGroupSize - num; for (int i = 0; i < num2; i++) { order.Add((i < list.Count) ? list[i] : CreateEmptyChainSlot()); } } } private static int FindRandomEmptySlot(List order) { List list = new List(); for (int i = 0; i < order.Count; i++) { if (IsEmptyChainSlot(order[i])) { list.Add(i); } } if (list.Count <= 0) { return -1; } return list[Random.Range(0, list.Count)]; } private static bool IsEmptyChainSlot(string? key) { string text = (key ?? string.Empty).Trim(); if (text.Length > 0) { return text.StartsWith("empty:", StringComparison.Ordinal); } return false; } private static string CreateEmptyChainSlot() { return "empty:" + Guid.NewGuid().ToString("N"); } private static void AddChainOrderKey(string? key, List orderedKeys, HashSet seenKeys) { string text = (key ?? string.Empty).Trim(); if (text.Length != 0 && seenKeys.Add(text)) { orderedKeys.Add(text); } } private static string GetUniquePlayerStableKey(Player player, HashSet usedKeys) { string playerStableKey = GetPlayerStableKey(player); if (usedKeys.Add(playerStableKey)) { return playerStableKey; } string text = $"{playerStableKey}#a:{player.ActorNumber}"; usedKeys.Add(text); return text; } private static string GetPlayerStableKey(Player player) { if (!string.IsNullOrWhiteSpace(player.UserId)) { return "u:" + player.UserId.Trim(); } if (!string.IsNullOrWhiteSpace(player.NickName)) { return "n:" + player.NickName.Trim(); } return "a:" + player.ActorNumber; } private bool HasStrongAnchor(ChainMember member) { if (!((Object)(object)member.Character != (Object)null) || !(GetAnchorStrength(member.Character) >= 0.75f)) { if ((Object)(object)member.ForceTarget != (Object)null) { return GetAnchorStrength(member.ForceTarget) >= 0.75f; } return false; } return true; } private Character? GetForceTarget(Character? chainMember) { if ((Object)(object)chainMember == (Object)null || (Object)(object)chainMember.data == (Object)null) { return chainMember; } if (chainMember.data.isCarried && (Object)(object)chainMember.data.carrier != (Object)null) { return chainMember.data.carrier; } return chainMember; } private bool CanLinkConnect(Character left, Character right) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (IsRecentlyWarped(left) || IsRecentlyWarped(right)) { return false; } return Vector3.Distance(left.Center, right.Center) <= _roomLinkBreakDistance; } private bool IsPlayerOptedIntoChain(Player? player) { if (player == null) { return false; } bool versionMismatch; if (player != PhotonNetwork.LocalPlayer) { return HasInstalledCompatibleMod(player, out versionMismatch); } return true; } private bool HasInstalledCompatibleMod(Player player, out bool versionMismatch) { versionMismatch = false; if (player.CustomProperties == null || !((Dictionary)(object)player.CustomProperties).TryGetValue((object)"pn.cb.ver", out object value)) { return false; } string text = Convert.ToString(value) ?? string.Empty; if (_requireExactVersion.Value && !string.Equals(text, "0.2.16", StringComparison.Ordinal)) { versionMismatch = true; return false; } return !string.IsNullOrWhiteSpace(text); } private static bool TryGetCharacterForPlayer(Player player, out Character? character) { character = null; try { Character val = default(Character); if (GameHandler.Initialized && PlayerHandler.TryGetCharacter(player.ActorNumber, ref val)) { character = val; return (Object)(object)character != (Object)null; } } catch { } foreach (Character allCharacter in Character.AllCharacters) { if ((Object)(object)allCharacter != (Object)null && (Object)(object)((MonoBehaviourPun)allCharacter).photonView != (Object)null && ((MonoBehaviourPun)allCharacter).photonView.OwnerActorNr == player.ActorNumber) { character = allCharacter; return true; } } return false; } private static bool IsChainAlive(Character? character) { if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null) { return false; } if (!((Behaviour)character).isActiveAndEnabled || character.data.dead || character.IsGhost) { return false; } return true; } private static bool IsSupported(Character character) { CharacterData data = character.data; if ((Object)(object)data == (Object)null) { return false; } if (IsDowned(character)) { return false; } if (data.isGrounded && data.sinceGrounded < 0.4f) { return true; } if (data.isClimbing || data.isRopeClimbing || data.isVineClimbing || (Object)(object)data.currentClimbHandle != (Object)null) { return true; } if (data.isCarried || (Object)(object)data.carrier != (Object)null) { return true; } if (HasOpenParasol(character)) { return true; } try { return character.IsStuck(); } catch { return false; } } private bool IsUnsupported(Character character) { CharacterData data = character.data; if ((Object)(object)data == (Object)null) { return true; } if (IsDowned(character)) { return true; } if (IsSupported(character)) { return false; } if (!(GetAnchorStrength(character) < 0.5f) && !(data.sinceGrounded > 0.4f)) { return data.avarageVelocity.y < -1.5f; } return true; } private float GetAnchorStrength(Character character) { CharacterData data = character.data; if ((Object)(object)data == (Object)null || data.dead || character.IsGhost) { return 0f; } if (data.isCarried && (Object)(object)data.carrier != (Object)null) { return GetAnchorStrength(data.carrier) * 0.9f; } if (IsDowned(character)) { return _roomDownedAnchorMultiplier; } if (data.isGrounded && data.sinceGrounded < 0.4f) { return 1f; } if (data.isClimbing || data.isRopeClimbing || data.isVineClimbing || (Object)(object)data.currentClimbHandle != (Object)null) { return 1f; } if (HasOpenParasol(character)) { return 0.9f; } try { if (character.IsStuck()) { return 1f; } } catch { } if (GetBalloonCount(character) > 0) { return _roomBalloonPullMultiplier; } Affliction val = default(Affliction); if ((Object)(object)character.refs?.afflictions != (Object)null && character.refs.afflictions.HasAfflictionType((AfflictionType)17, ref val)) { return Mathf.Min(_roomAirbornePullMultiplier, 0.25f); } if (data.avarageVelocity.y < -2f || data.sinceGrounded > 0.4f) { return _roomAirbornePullMultiplier; } return Mathf.Max(_roomAirbornePullMultiplier, 0.45f); } private static int GetBalloonCount(Character character) { try { return ((Object)(object)character.refs?.balloons != (Object)null) ? character.refs.balloons.currentBalloonCount : 0; } catch { return 0; } } private static bool HasOpenParasol(Character? character) { try { object obj; if (character == null) { obj = null; } else { CharacterData data = character.data; obj = ((data != null) ? data.currentItem : null); } Item val = (Item)obj; if ((Object)(object)val == (Object)null) { return false; } Parasol component = ((Component)val).GetComponent(); return (Object)(object)component != (Object)null && component.isOpen; } catch { return false; } } private static Vector3 GetParasolExternalAcceleration(Character character) { //IL_0016: 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_007a: 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) if (!HasOpenParasol(character) || (Object)(object)character.data == (Object)null) { return Vector3.zero; } float num = Mathf.Max(new float[3] { 0f, 0f - character.data.avarageVelocity.y, 0f - character.data.avarageLastFrameVelocity.y }); if (num <= 0.25f) { return Vector3.zero; } return Vector3.up * Mathf.Min(14f + num * 8f, 120f); } private static bool IsDowned(Character? character) { if ((Object)(object)character?.data != (Object)null) { if (!character.data.passedOut) { return character.data.fullyPassedOut; } return true; } return false; } private void UpdateChainVisuals() { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if (!_drawChain.Value || !ShouldRunHostEnabledGameplay() || IsLobbyScene()) { ClearChainLines(); return; } ChainState chainState = BuildChainState(); HashSet liveKeys = new HashSet(StringComparer.Ordinal); foreach (ChainLink link in chainState.Links) { if (!((Object)(object)link.Left.Character == (Object)null) && !((Object)(object)link.Right.Character == (Object)null)) { string key2 = link.Key; liveKeys.Add(key2); LineRenderer orCreateChainLine = GetOrCreateChainLine(key2); Vector3 center = link.Left.Character.Center; Vector3 center2 = link.Right.Character.Center; orCreateChainLine.SetPosition(0, center); orCreateChainLine.SetPosition(1, center2); float num = Vector3.Distance(center, center2); bool flag = IsLocalPullPreviewLink(link); bool flag2 = IsLinkBeingPulledIn(link); Color endColor = (orCreateChainLine.startColor = (flag2 ? new Color(1f, 0.86f, 0.18f, 0.95f) : (flag ? new Color(0.25f, 0.95f, 1f, 0.95f) : ((num > _roomLinkLength) ? new Color(1f, 0.62f, 0.24f, 0.78f) : new Color(0.72f, 0.82f, 0.92f, 0.72f))))); orCreateChainLine.endColor = endColor; orCreateChainLine.widthMultiplier = (flag2 ? 0.13f : (flag ? 0.105f : 0.055f)); } } foreach (string item in _chainLines.Keys.Where((string key) => !liveKeys.Contains(key)).ToList()) { Object.Destroy((Object)(object)((Component)_chainLines[item]).gameObject); _chainLines.Remove(item); } } private bool IsLocalPullPreviewLink(ChainLink link) { if (!_localPullPreviewActive || PhotonNetwork.LocalPlayer == null) { return false; } int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber; if (link.Left.ActorNumber != actorNumber || link.Right.ActorNumber != _localPullPreviewTargetActor) { if (link.Right.ActorNumber == actorNumber) { return link.Left.ActorNumber == _localPullPreviewTargetActor; } return false; } return true; } private LineRenderer GetOrCreateChainLine(string key) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (_chainLines.TryGetValue(key, out LineRenderer value) && (Object)(object)value != (Object)null) { return value; } GameObject val = new GameObject("Chainbound Link " + key); Object.DontDestroyOnLoad((Object)val); value = val.AddComponent(); value.positionCount = 2; value.useWorldSpace = true; value.widthMultiplier = 0.055f; value.numCapVertices = 4; value.numCornerVertices = 2; ((Renderer)value).sortingOrder = 32767; ((Renderer)value).allowOcclusionWhenDynamic = false; Material val2 = EnsureLineMaterial(); if ((Object)(object)val2 != (Object)null) { ((Renderer)value).material = val2; } _chainLines[key] = value; return value; } private Material? EnsureLineMaterial() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown if ((Object)(object)_lineMaterial != (Object)null) { return _lineMaterial; } Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Universal Render Pipeline/Unlit"); if ((Object)(object)val == (Object)null) { return null; } _lineMaterial = new Material(val) { name = "Chainbound Line Material", renderQueue = 5000 }; if (_lineMaterial.HasProperty("_ZWrite")) { _lineMaterial.SetInt("_ZWrite", 0); } if (_lineMaterial.HasProperty("_ZTest")) { _lineMaterial.SetInt("_ZTest", 8); } if (_lineMaterial.HasProperty("_Cull")) { _lineMaterial.SetInt("_Cull", 0); } return _lineMaterial; } private void ClearChainLines() { foreach (LineRenderer value in _chainLines.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)((Component)value).gameObject); } } _chainLines.Clear(); } private void OnGUI() { if (!PhotonNetwork.InRoom) { return; } bool flag = IsAirportScene(); if ((flag && !_showLobbyStatus.Value) || (!flag && !_showInGameStatus.Value) || (!PhotonNetwork.IsMasterClient && !_roomHasChainboundHost) || (!PhotonNetwork.IsMasterClient && !_showLobbyStatusToEveryone.Value)) { return; } ChainState chainState = BuildChainState(); bool flag2 = chainState.MissingMod.Count > 0 || chainState.VersionMismatches.Count > 0; if (flag || (_roomHasChainboundHost && _roomEnabled && flag2)) { EnsureLobbyStyles(); List list = new List(); if (!flag) { AddPlayerStatusLines(chainState, list); list.Add("Chainbound is required for this run."); } else if (!_roomEnabled) { list.Add("Disabled by host config."); } else if (!flag2) { list.Add("All players have Chainbound."); } else { AddPlayerStatusLines(chainState, list); } if (flag) { list.Add(string.Format("Link: {0:0.#}m Max group: {1}", _roomLinkLength, (_roomMaxGroupSize <= 1) ? "all" : _roomMaxGroupSize.ToString())); } DrawStatusOverlay(flag ? "Chainbound Lobby Check" : "Chainbound Missing Mods", list); } } private static void AddPlayerStatusLines(ChainState state, List lines) { if (state.MissingMod.Count > 0) { lines.Add("Missing mod: " + string.Join(", ", state.MissingMod.Select(PlayerLabel))); } if (state.VersionMismatches.Count > 0) { lines.Add("Wrong version: " + string.Join(", ", state.VersionMismatches.Select(PlayerLabel))); } } private void DrawStatusOverlay(string title, List lines) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_00a5: 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_012c: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(520f, (float)Screen.width - 32f); float num2 = num - 28f; List list = new List(lines.Count); float num3 = 52f; foreach (string line in lines) { float num4 = Mathf.Max(22f, _lobbyTextStyle.CalcHeight(new GUIContent(line), num2)); list.Add(num4); num3 += num4; } Rect val = default(Rect); ((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, 16f, num, num3); GUI.Box(val, GUIContent.none, _lobbyBoxStyle); GUI.Label(new Rect(((Rect)(ref val)).x + 14f, ((Rect)(ref val)).y + 10f, ((Rect)(ref val)).width - 28f, 24f), title, _lobbyHeaderStyle); float num5 = ((Rect)(ref val)).y + 38f; for (int i = 0; i < lines.Count; i++) { GUI.Label(new Rect(((Rect)(ref val)).x + 14f, num5, ((Rect)(ref val)).width - 28f, list[i]), lines[i], _lobbyTextStyle); num5 += list[i]; } } private void EnsureLobbyStyles() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0077: Expected O, but got Unknown //IL_007c: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown if (_lobbyBoxStyle == null) { _lobbyBoxTexture = new Texture2D(1, 1); _lobbyBoxTexture.SetPixel(0, 0, new Color(0.02f, 0.025f, 0.03f, 0.82f)); _lobbyBoxTexture.Apply(); GUIStyle val = new GUIStyle(GUI.skin.box); val.normal.background = _lobbyBoxTexture; val.padding = new RectOffset(8, 8, 8, 8); _lobbyBoxStyle = val; GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 18, fontStyle = (FontStyle)1 }; val2.normal.textColor = Color.white; val2.clipping = (TextClipping)1; _lobbyHeaderStyle = val2; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 14 }; val3.normal.textColor = new Color(0.9f, 0.94f, 0.98f, 1f); val3.clipping = (TextClipping)1; val3.wordWrap = true; _lobbyTextStyle = val3; } } private static string PlayerLabel(Player player) { if (!string.IsNullOrWhiteSpace(player.NickName)) { return player.NickName; } return "actor " + player.ActorNumber; } private void MaintainHostChainOrderIfNeeded(bool force) { if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && PhotonNetwork.CurrentRoom != null && !IsLobbyScene() && (force || _chainOrderDirty)) { List list = CollectActiveChainMembers(new ChainState()); if (list.Count != 0) { List order = BuildMaintainedChainOrder(list); PublishChainOrder(order, force, "player list"); } } } private void ShuffleChainOrder(string reason) { if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || PhotonNetwork.CurrentRoom == null) { return; } List list = CollectActiveChainMembers(new ChainState()); if (list.Count <= 1) { return; } List collection = BuildDistanceAwareActiveOrder(list); HashSet hashSet = new HashSet(collection, StringComparer.Ordinal); List list2 = new List(collection); HashSet seenKeys = new HashSet(list2, StringComparer.Ordinal); foreach (string item in _roomChainOrder) { if (!hashSet.Contains(item) && !IsEmptyChainSlot(item)) { AddChainOrderKey(item, list2, seenKeys); } } PadOpenChainSlots(list2); PublishChainOrder(list2, force: true, reason); Notify("Chainbound: chain order shuffled"); } private List BuildDistanceAwareActiveOrder(List activeMembers) { int num = ((_roomMaxGroupSize <= 1) ? activeMembers.Count : _roomMaxGroupSize); if (num <= 1) { return activeMembers.Select((ChainMember member) => member.StableKey).ToList(); } List list = activeMembers.OrderBy((ChainMember _) => Random.value).ToList(); List list2 = new List(); while (list.Count > 0) { ChainMember item = TakeRandomMember(list); List list3 = new List { item }; while (list3.Count < num && list.Count > 0) { list3.Add(TakeRandomNearbyMember(list, list3)); } foreach (ChainMember item2 in list3) { list2.Add(item2.StableKey); } } return list2; } private ChainMember TakeRandomNearbyMember(List candidates, List group) { List candidates2 = candidates; float maxDistance = Mathf.Max(_roomLinkBreakDistance, _roomLinkLength); List list = new List(); int i; for (i = 0; i < candidates2.Count; i++) { if (group.Any((ChainMember member) => GetMemberDistance(candidates2[i], member) <= maxDistance)) { list.Add(i); } } int index = ((list.Count > 0) ? list[Random.Range(0, list.Count)] : Random.Range(0, candidates2.Count)); ChainMember result = candidates2[index]; candidates2.RemoveAt(index); return result; } private static ChainMember TakeRandomMember(List members) { int index = Random.Range(0, members.Count); ChainMember result = members[index]; members.RemoveAt(index); return result; } private static float GetMemberDistance(ChainMember left, ChainMember right) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (TryGetMemberPosition(left, out var position) && TryGetMemberPosition(right, out var position2)) { return Vector3.Distance(position, position2); } return 1.7014117E+38f; } private static bool TryGetMemberPosition(ChainMember member, out Vector3 position) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Character val = member.ForceTarget ?? member.Character; if ((Object)(object)val != (Object)null && IsChainAlive(val) && IsFinite(val.Center)) { position = val.Center; return true; } position = Vector3.zero; return false; } private void HandleCampfireSegmentAdvanced() { if (_shuffleAtCampfires.Value && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && !(Time.realtimeSinceStartup - _lastCampfireShuffleTime < 2f)) { _lastCampfireShuffleTime = Time.realtimeSinceStartup; ShuffleChainOrder("campfire"); } } private void PublishChainOrder(List order, bool force, string reason) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || PhotonNetwork.CurrentRoom == null) { return; } List list = new List(); HashSet seenKeys = new HashSet(StringComparer.Ordinal); foreach (string item in order) { AddChainOrderKey(item, list, seenKeys); } string text = EncodeChainOrder(list); object value; string b = ((((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties != null && ((Dictionary)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"pn.cb.r.order", out value)) ? (Convert.ToString(value) ?? string.Empty) : string.Empty); if (!force && string.Equals(text, b, StringComparison.Ordinal)) { _chainOrderDirty = false; return; } PhotonNetwork.CurrentRoom.SetCustomProperties(new Hashtable { [(object)"pn.cb.r.order"] = text }, (Hashtable)null, (WebFlags)null); _roomChainOrder.Clear(); _roomChainOrder.AddRange(list); _chainOrderDirty = false; DebugLog($"Published chain order reason={reason} slots={list.Count}"); } private static string EncodeChainOrder(IEnumerable order) { return string.Join("|", from key in order where !string.IsNullOrWhiteSpace(key) select Convert.ToBase64String(Encoding.UTF8.GetBytes(key.Trim()))); } private static List DecodeChainOrder(object? raw) { List list = new List(); HashSet seenKeys = new HashSet(StringComparer.Ordinal); string[] array2; if (raw is string[] array) { array2 = array; for (int i = 0; i < array2.Length; i++) { AddChainOrderKey(array2[i], list, seenKeys); } return list; } string text = Convert.ToString(raw) ?? string.Empty; if (string.IsNullOrWhiteSpace(text)) { return list; } array2 = text.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array2) { try { AddChainOrderKey(Encoding.UTF8.GetString(Convert.FromBase64String(text2)), list, seenKeys); } catch { AddChainOrderKey(text2, list, seenKeys); } } return list; } private void PublishPlayerPropertiesIfNeeded(bool force) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null && (PhotonNetwork.IsMasterClient || _roomHasChainboundHost)) { bool flag = true; if (force || !(Time.realtimeSinceStartup < _nextPlayerPropertyPublish) || flag != _lastPublishedEnabled) { Hashtable val = new Hashtable { [(object)"pn.cb.ver"] = "0.2.16", [(object)"pn.cb.on"] = flag, [(object)"pn.cb.pull"] = _localPullInHeld, [(object)"pn.cb.ptgt"] = (_localPullInHeld ? _localPullInTargetActor : 0) }; PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); _lastPublishedEnabled = flag; _lastPublishedPullIn = _localPullInHeld; _lastPublishedPullInTargetActor = (_localPullInHeld ? _localPullInTargetActor : 0); _nextPlayerPropertyPublish = Time.realtimeSinceStartup + 2f; _nextPullInPropertyPublish = Time.realtimeSinceStartup + (_localPullInHeld ? 0.12f : 0.4f); DebugLog($"Published player props enabled={flag}"); } } } private void PublishPullInPropertiesIfNeeded(bool force) { //IL_004f: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null && ShouldRunHostEnabledGameplay()) { bool localPullInHeld = _localPullInHeld; int num = (localPullInHeld ? _localPullInTargetActor : 0); if (force || !(Time.realtimeSinceStartup < _nextPullInPropertyPublish) || localPullInHeld != _lastPublishedPullIn || num != _lastPublishedPullInTargetActor) { Hashtable val = new Hashtable { [(object)"pn.cb.pull"] = localPullInHeld, [(object)"pn.cb.ptgt"] = num }; PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); _lastPublishedPullIn = localPullInHeld; _lastPublishedPullInTargetActor = num; _nextPullInPropertyPublish = Time.realtimeSinceStartup + (localPullInHeld ? 0.12f : 0.4f); } } } private void PublishRoomPropertiesIfNeeded(bool force) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_0106: 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_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Expected O, but got Unknown if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && PhotonNetwork.CurrentRoom != null && (force || !(Time.realtimeSinceStartup < _nextRoomPropertyPublish))) { Hashtable val = new Hashtable { [(object)"pn.cb.r.on"] = _enabled.Value, [(object)"pn.cb.r.max"] = _maxGroupSize.Value, [(object)"pn.cb.r.len"] = _linkLength.Value, [(object)"pn.cb.r.acc"] = _maxPullAcceleration.Value, [(object)"pn.cb.r.fall"] = _fallClampSeconds.Value, [(object)"pn.cb.r.brk"] = _linkBreakDistance.Value, [(object)"pn.cb.r.grv"] = _chainGravity.Value, [(object)"pn.cb.r.air"] = _airbornePullMultiplier.Value, [(object)"pn.cb.r.bal"] = _balloonPullMultiplier.Value, [(object)"pn.cb.r.down"] = _downedAnchorMultiplier.Value, [(object)"pn.cb.r.ext"] = _externalForcePropagation.Value, [(object)"pn.cb.r.exth"] = _externalForceThreshold.Value, [(object)"pn.cb.r.extm"] = _externalForceMaxAcceleration.Value, [(object)"pn.cb.r.stuk"] = _stuckBreakAcceleration.Value, [(object)"pn.cb.r.ptrk"] = _proxyTrackStrength.Value, [(object)"pn.cb.r.pcor"] = _proxyCorrectionStrength.Value, [(object)"pn.cb.r.pdmp"] = _proxyCorrectionDamping.Value, [(object)"pn.cb.r.pacc"] = _pullInAcceleration.Value, [(object)"pn.cb.r.ptrg"] = _pullInTargetLengthMultiplier.Value, [(object)"pn.cb.r.psta"] = _pullInStaminaPerSecond.Value, [(object)"pn.cb.r.dsta"] = _danglingStaminaPerPlayer.Value, [(object)"pn.cb.r.clmb"] = _climberLoadMultiplier.Value, [(object)"pn.cb.r.ganc"] = _groundAnchorMaxDownAcceleration.Value, [(object)"pn.cb.r.bext"] = _balloonExternalForceMultiplier.Value, [(object)"pn.cb.r.swng"] = _swingGravityMultiplier.Value, [(object)"pn.cb.r.hstm"] = _hangingStaminaRegenMultiplier.Value, [(object)"pn.cb.r.sbd"] = _speedBasedFallDamage.Value, [(object)"pn.cb.r.sdmi"] = _fallDamageMinSpeed.Value, [(object)"pn.cb.r.sdma"] = _fallDamageMaxSpeed.Value, [(object)"pn.cb.r.sdsc"] = _fallDamageMultiplier.Value, [(object)"pn.cb.r.ptk"] = _punishTK.Value }; PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); RefreshRoomSettingsFromLocalConfig(); _roomHasChainboundHost = true; _nextRoomPropertyPublish = Time.realtimeSinceStartup + 3f; DebugLog("Published host room settings."); } } private void RefreshRoomSettings() { if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null) { Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties; _roomHasChainboundHost = TryReadBool(customProperties, "pn.cb.r.on", out var value); if (!_roomHasChainboundHost) { RefreshRoomSettingsFromLocalConfig(); _roomHasChainboundHost = false; _roomEnabled = false; _roomPunishTK = false; _roomChainOrder.Clear(); ClampRoomSettings(); return; } _roomEnabled = value; _roomMaxGroupSize = (TryReadInt(customProperties, "pn.cb.r.max", out var value2) ? value2 : _maxGroupSize.Value); _roomLinkLength = (TryReadFloat(customProperties, "pn.cb.r.len", out var value3) ? value3 : _linkLength.Value); _roomMaxPullAcceleration = (TryReadFloat(customProperties, "pn.cb.r.acc", out var value4) ? value4 : _maxPullAcceleration.Value); _roomFallClampSeconds = (TryReadFloat(customProperties, "pn.cb.r.fall", out var value5) ? value5 : _fallClampSeconds.Value); _roomLinkBreakDistance = (TryReadFloat(customProperties, "pn.cb.r.brk", out var value6) ? value6 : _linkBreakDistance.Value); _roomChainGravity = (TryReadFloat(customProperties, "pn.cb.r.grv", out var value7) ? value7 : _chainGravity.Value); _roomAirbornePullMultiplier = (TryReadFloat(customProperties, "pn.cb.r.air", out var value8) ? value8 : _airbornePullMultiplier.Value); _roomBalloonPullMultiplier = (TryReadFloat(customProperties, "pn.cb.r.bal", out var value9) ? value9 : _balloonPullMultiplier.Value); _roomDownedAnchorMultiplier = (TryReadFloat(customProperties, "pn.cb.r.down", out var value10) ? value10 : _downedAnchorMultiplier.Value); _roomExternalForcePropagation = (TryReadFloat(customProperties, "pn.cb.r.ext", out var value11) ? value11 : _externalForcePropagation.Value); _roomExternalForceThreshold = (TryReadFloat(customProperties, "pn.cb.r.exth", out var value12) ? value12 : _externalForceThreshold.Value); _roomExternalForceMaxAcceleration = (TryReadFloat(customProperties, "pn.cb.r.extm", out var value13) ? value13 : _externalForceMaxAcceleration.Value); _roomStuckBreakAcceleration = (TryReadFloat(customProperties, "pn.cb.r.stuk", out var value14) ? value14 : _stuckBreakAcceleration.Value); _roomProxyTrackStrength = (TryReadFloat(customProperties, "pn.cb.r.ptrk", out var value15) ? value15 : _proxyTrackStrength.Value); _roomProxyCorrectionStrength = (TryReadFloat(customProperties, "pn.cb.r.pcor", out var value16) ? value16 : _proxyCorrectionStrength.Value); _roomProxyCorrectionDamping = (TryReadFloat(customProperties, "pn.cb.r.pdmp", out var value17) ? value17 : _proxyCorrectionDamping.Value); _roomPullInAcceleration = (TryReadFloat(customProperties, "pn.cb.r.pacc", out var value18) ? value18 : _pullInAcceleration.Value); _roomPullInTargetLengthMultiplier = (TryReadFloat(customProperties, "pn.cb.r.ptrg", out var value19) ? value19 : _pullInTargetLengthMultiplier.Value); _roomPullInStaminaPerSecond = (TryReadFloat(customProperties, "pn.cb.r.psta", out var value20) ? value20 : _pullInStaminaPerSecond.Value); _roomDanglingStaminaPerPlayer = (TryReadFloat(customProperties, "pn.cb.r.dsta", out var value21) ? value21 : _danglingStaminaPerPlayer.Value); _roomClimberLoadMultiplier = (TryReadFloat(customProperties, "pn.cb.r.clmb", out var value22) ? value22 : _climberLoadMultiplier.Value); _roomGroundAnchorMaxDownAcceleration = (TryReadFloat(customProperties, "pn.cb.r.ganc", out var value23) ? value23 : _groundAnchorMaxDownAcceleration.Value); _roomBalloonExternalForceMultiplier = (TryReadFloat(customProperties, "pn.cb.r.bext", out var value24) ? value24 : _balloonExternalForceMultiplier.Value); _roomSwingGravityMultiplier = (TryReadFloat(customProperties, "pn.cb.r.swng", out var value25) ? value25 : _swingGravityMultiplier.Value); _roomHangingStaminaRegenMultiplier = (TryReadFloat(customProperties, "pn.cb.r.hstm", out var value26) ? value26 : _hangingStaminaRegenMultiplier.Value); _roomSpeedBasedFallDamage = (TryReadBool(customProperties, "pn.cb.r.sbd", out var value27) ? value27 : _speedBasedFallDamage.Value); _roomFallDamageMinSpeed = (TryReadFloat(customProperties, "pn.cb.r.sdmi", out var value28) ? value28 : _fallDamageMinSpeed.Value); _roomFallDamageMaxSpeed = (TryReadFloat(customProperties, "pn.cb.r.sdma", out var value29) ? value29 : _fallDamageMaxSpeed.Value); _roomFallDamageMultiplier = (TryReadFloat(customProperties, "pn.cb.r.sdsc", out var value30) ? value30 : _fallDamageMultiplier.Value); _roomPunishTK = (TryReadBool(customProperties, "pn.cb.r.ptk", out var value31) ? value31 : _punishTK.Value); _roomChainOrder.Clear(); if (((Dictionary)(object)customProperties).TryGetValue((object)"pn.cb.r.order", out object value32)) { _roomChainOrder.AddRange(DecodeChainOrder(value32)); } } else { RefreshRoomSettingsFromLocalConfig(); _roomHasChainboundHost = false; _roomChainOrder.Clear(); } ClampRoomSettings(); } private void RefreshRoomSettingsFromLocalConfig() { _roomEnabled = _enabled.Value; _roomMaxGroupSize = _maxGroupSize.Value; _roomLinkLength = _linkLength.Value; _roomMaxPullAcceleration = _maxPullAcceleration.Value; _roomFallClampSeconds = _fallClampSeconds.Value; _roomLinkBreakDistance = _linkBreakDistance.Value; _roomChainGravity = _chainGravity.Value; _roomAirbornePullMultiplier = _airbornePullMultiplier.Value; _roomBalloonPullMultiplier = _balloonPullMultiplier.Value; _roomDownedAnchorMultiplier = _downedAnchorMultiplier.Value; _roomExternalForcePropagation = _externalForcePropagation.Value; _roomExternalForceThreshold = _externalForceThreshold.Value; _roomExternalForceMaxAcceleration = _externalForceMaxAcceleration.Value; _roomStuckBreakAcceleration = _stuckBreakAcceleration.Value; _roomProxyTrackStrength = _proxyTrackStrength.Value; _roomProxyCorrectionStrength = _proxyCorrectionStrength.Value; _roomProxyCorrectionDamping = _proxyCorrectionDamping.Value; _roomPullInAcceleration = _pullInAcceleration.Value; _roomPullInTargetLengthMultiplier = _pullInTargetLengthMultiplier.Value; _roomPullInStaminaPerSecond = _pullInStaminaPerSecond.Value; _roomDanglingStaminaPerPlayer = _danglingStaminaPerPlayer.Value; _roomClimberLoadMultiplier = _climberLoadMultiplier.Value; _roomGroundAnchorMaxDownAcceleration = _groundAnchorMaxDownAcceleration.Value; _roomBalloonExternalForceMultiplier = _balloonExternalForceMultiplier.Value; _roomSwingGravityMultiplier = _swingGravityMultiplier.Value; _roomHangingStaminaRegenMultiplier = _hangingStaminaRegenMultiplier.Value; _roomSpeedBasedFallDamage = _speedBasedFallDamage.Value; _roomFallDamageMinSpeed = _fallDamageMinSpeed.Value; _roomFallDamageMaxSpeed = _fallDamageMaxSpeed.Value; _roomFallDamageMultiplier = _fallDamageMultiplier.Value; _roomPunishTK = _punishTK.Value; ClampRoomSettings(); } private void ClampRoomSettings() { _roomMaxGroupSize = Mathf.Clamp(_roomMaxGroupSize, 0, 8); _roomLinkLength = Mathf.Clamp(_roomLinkLength, 2f, 30f); _roomMaxPullAcceleration = Mathf.Clamp(_roomMaxPullAcceleration, 5f, 250f); _roomFallClampSeconds = Mathf.Clamp(_roomFallClampSeconds, 0.05f, 1.5f); _roomLinkBreakDistance = Mathf.Clamp(_roomLinkBreakDistance, 15f, 300f); _roomChainGravity = Mathf.Clamp(_roomChainGravity, 0f, 60f); _roomAirbornePullMultiplier = Mathf.Clamp01(_roomAirbornePullMultiplier); _roomBalloonPullMultiplier = Mathf.Clamp01(_roomBalloonPullMultiplier); _roomDownedAnchorMultiplier = Mathf.Clamp01(_roomDownedAnchorMultiplier); _roomExternalForcePropagation = Mathf.Clamp(_roomExternalForcePropagation, 0f, 1.5f); _roomExternalForceThreshold = Mathf.Clamp(_roomExternalForceThreshold, 0f, 80f); _roomExternalForceMaxAcceleration = Mathf.Clamp(_roomExternalForceMaxAcceleration, 0f, 200f); _roomStuckBreakAcceleration = Mathf.Clamp(_roomStuckBreakAcceleration, 0f, 200f); _roomProxyTrackStrength = Mathf.Clamp(_roomProxyTrackStrength, 5f, 160f); _roomProxyCorrectionStrength = Mathf.Clamp(_roomProxyCorrectionStrength, 2f, 120f); _roomProxyCorrectionDamping = Mathf.Clamp(_roomProxyCorrectionDamping, 0f, 40f); _roomPullInAcceleration = Mathf.Clamp(_roomPullInAcceleration, 0f, 250f); _roomPullInTargetLengthMultiplier = Mathf.Clamp(_roomPullInTargetLengthMultiplier, 0.15f, 1f); _roomPullInStaminaPerSecond = Mathf.Clamp(_roomPullInStaminaPerSecond, 0f, 1f); _roomDanglingStaminaPerPlayer = Mathf.Clamp(_roomDanglingStaminaPerPlayer, 0f, 0.3f); _roomClimberLoadMultiplier = Mathf.Clamp(_roomClimberLoadMultiplier, 0f, 2f); _roomGroundAnchorMaxDownAcceleration = Mathf.Clamp(_roomGroundAnchorMaxDownAcceleration, 0f, 80f); _roomBalloonExternalForceMultiplier = Mathf.Clamp01(_roomBalloonExternalForceMultiplier); _roomSwingGravityMultiplier = Mathf.Clamp(_roomSwingGravityMultiplier, 0f, 6f); _roomHangingStaminaRegenMultiplier = Mathf.Clamp(_roomHangingStaminaRegenMultiplier, 0f, 3f); _roomFallDamageMinSpeed = Mathf.Clamp(_roomFallDamageMinSpeed, 1f, 40f); _roomFallDamageMaxSpeed = Mathf.Clamp(_roomFallDamageMaxSpeed, Mathf.Max(2f, _roomFallDamageMinSpeed + 0.1f), 60f); _roomFallDamageMultiplier = Mathf.Clamp(_roomFallDamageMultiplier, 0f, 3f); } private static bool TryReadBool(Hashtable? props, string key, out bool value) { value = false; if (props == null || !((Dictionary)(object)props).TryGetValue((object)key, out object value2)) { return false; } if (value2 is bool flag) { value = flag; return true; } if (bool.TryParse(Convert.ToString(value2), out var result)) { value = result; return true; } return false; } private static bool TryReadInt(Hashtable? props, string key, out int value) { value = 0; if (props == null || !((Dictionary)(object)props).TryGetValue((object)key, out object value2)) { return false; } if (!(value2 is int num)) { if (!(value2 is byte b)) { if (!(value2 is short num2)) { if (value2 is long num3) { value = (int)num3; return true; } return int.TryParse(Convert.ToString(value2), out value); } value = num2; return true; } value = b; return true; } value = num; return true; } private static bool TryReadFloat(Hashtable? props, string key, out float value) { value = 0f; if (props == null || !((Dictionary)(object)props).TryGetValue((object)key, out object value2)) { return false; } if (!(value2 is float num)) { if (!(value2 is double num2)) { if (!(value2 is int num3)) { if (value2 is byte b) { value = (int)b; return true; } return float.TryParse(Convert.ToString(value2), out value); } value = num3; return true; } value = (float)num2; return true; } value = num; return true; } private static bool IsAirportScene() { //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) Scene activeScene = SceneManager.GetActiveScene(); return string.Equals(((Scene)(ref activeScene)).name, "Airport", StringComparison.OrdinalIgnoreCase); } private static bool IsLobbyScene() { //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) Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (!string.Equals(name, "Airport", StringComparison.OrdinalIgnoreCase)) { return string.Equals(name, "Title", StringComparison.OrdinalIgnoreCase); } return true; } private static bool IsFinite(Vector3 vector) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(vector.x) && !float.IsInfinity(vector.x) && !float.IsNaN(vector.y) && !float.IsInfinity(vector.y) && !float.IsNaN(vector.z)) { return !float.IsInfinity(vector.z); } return false; } private static string FormatVector(Vector3 value) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) return $"({value.x:0.0}, {value.y:0.0}, {value.z:0.0})"; } private void Notify(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); try { UI_Notifications val = Object.FindFirstObjectByType(); if ((Object)(object)val != (Object)null) { val.AddNotification(message); } } catch (Exception ex) { DebugLog("Notification failed: " + ex.Message); } } private void DebugLog(string message) { if (_debugLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[Debug] " + message)); } } private bool ShouldLogDamage() { if (!_damageLogging.Value) { return _debugLogging.Value; } return true; } private bool ShouldLogDamageFor(Character? character) { if (!ShouldLogDamage() || (Object)(object)character == (Object)null) { return false; } if ((Object)(object)character == (Object)(object)Character.localCharacter) { return true; } if ((Object)(object)((MonoBehaviourPun)character).photonView != (Object)null) { return ((MonoBehaviourPun)character).photonView.IsMine; } return false; } private void DamageLog(string message) { if (ShouldLogDamage()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[Damage] " + message)); } } private void LogInjuryDamageApplied(CharacterAfflictions afflictions, float requestedAmount, bool fromRPC, bool playEffects, bool notify, bool result, DamageLogState? state) { //IL_0061: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) if (!ShouldLogDamage()) { return; } Character component = ((Component)afflictions).GetComponent(); if (ShouldLogDamageFor(component)) { float currentStatus = afflictions.GetCurrentStatus((STATUSTYPE)0); float num = state?.InjuryBefore ?? currentStatus; float num2 = Mathf.Max(0f, currentStatus - num); if (result && !(num2 <= 0f)) { CharacterData data = component.data; Vector3 value = data?.avarageVelocity ?? Vector3.zero; Vector3 value2 = data?.avarageLastFrameVelocity ?? Vector3.zero; float num3 = data?.sinceGrounded ?? 0f; float num4 = data?.sinceJump ?? 0f; float num5 = data?.fallSeconds ?? 0f; bool flag = data?.isGrounded ?? false; bool flag2 = (data != null && data.isClimbing) || (data != null && data.isRopeClimbing) || (data?.isVineClimbing ?? false); bool flag3 = data?.isCarried ?? false; DamageLog($"Injury applied character={GetCharacterDebugName(component)} requested={requestedAmount:0.000} applied={num2:0.000} injury={num:0.000}->{currentStatus:0.000} statusSum={afflictions.statusSum:0.000} fromRPC={fromRPC} effects={playEffects} notify={notify} grounded={flag} climbing={flag2} carried={flag3} fallSeconds={num5:0.00} sinceGrounded={num3:0.00} sinceJump={num4:0.00} avgVel={FormatVector(value)} lastVel={FormatVector(value2)} caller={BuildDamageCallerSummary()}"); } } } private static string GetCharacterDebugName(Character character) { if (!string.IsNullOrEmpty(character.characterName)) { return character.characterName; } return ((Object)character).name; } private static string BuildDamageCallerSummary() { StackTrace stackTrace = new StackTrace(2, fNeedFileInfo: false); List list = new List(); for (int i = 0; i < stackTrace.FrameCount; i++) { if (list.Count >= 5) { break; } MethodBase methodBase = stackTrace.GetFrame(i)?.GetMethod(); if (!(methodBase == null)) { string text = methodBase.DeclaringType?.Name ?? "unknown"; string text2 = methodBase.DeclaringType?.FullName ?? string.Empty; if (!text.Contains("CharacterAfflictions") && !text.Contains("DamageLog") && !methodBase.Name.Contains("Postfix") && !methodBase.Name.Contains("Prefix") && !text2.Contains("Harmony") && !text2.StartsWith("System.", StringComparison.Ordinal)) { list.Add(text + "." + methodBase.Name); } } } if (list.Count <= 0) { return "unknown"; } return string.Join(" <- ", list); } private void HandleJoinedRoom() { RefreshRoomSettings(); PublishPlayerPropertiesIfNeeded(force: true); MaintainHostChainOrderIfNeeded(force: true); PublishPullInPropertiesIfNeeded(force: true); PublishRoomPropertiesIfNeeded(force: true); _settingsDirty = true; _chainOrderDirty = true; } private void HandleLeftRoom() { ClearChainLines(); ClearProxyChain(); ClearApiGroups(); _lastObservedVelocities.Clear(); _recordedExternalAccelerations.Clear(); _fallVelocitySamples.Clear(); RefreshRoomSettingsFromLocalConfig(); _roomHasChainboundHost = false; _roomEnabled = false; _roomPunishTK = false; _localCharacterViewId = 0; _catchUpAttemptsForCharacter = 0; _localPullInHeld = false; _localPullInTargetActor = 0; _localPullPreviewActive = false; _localPullPreviewTargetActor = 0; _lastPublishedPullIn = false; _lastPublishedPullInTargetActor = 0; _roomChainOrder.Clear(); _chainOrderDirty = true; _shuffleKeyWasDown = false; _lastCampfireShuffleTime = float.NegativeInfinity; } private void HandleRoomPropertiesChanged() { RefreshRoomSettings(); } private void HandlePlayerListOrPropertiesChanged() { _nextPlayerPropertyPublish = 0f; _chainOrderDirty = true; } } }