using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Peak.Network; using Photon.Pun; using Photon.Realtime; using Photon.Voice; using Photon.Voice.PUN; using Photon.Voice.Unity; using SpongePEAK.Core.Logging; using SpongePEAK.Core.Patching; using SpongePEAK.Core.Reflection; using SpongePEAK.Lib.Events; using SpongePEAK.Lib.Features; using SpongePEAK.Lib.Net; using SpongePEAK.Lib.Platform; using SpongePEAK.Lib.Plugin; using SpongePEAK.Optimized.Fixes; using SpongePEAK.Optimized.Rejoin; using Unity.Mathematics; using UnityEngine; using UnityEngine.SceneManagement; using Zorro.Core; using Zorro.Core.CLI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("sponge")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) sponge")] [assembly: AssemblyDescription("Bundled fixes and optimizations, each individually toggleable.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ddcbf023fcb4c2065ad9b038910633cd4a3a93b0")] [assembly: AssemblyProduct("SpongePEAKOptimized")] [assembly: AssemblyTitle("com.sponge.peakoptimized")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SpongePEAK.Optimized { public static class Capabilities { public static ModHandshake Handshake { get; set; } public static bool HostSupportsUs { get { if (Handshake != null) { return Handshake.HostHasMod("com.sponge.peakoptimized"); } return false; } } public static bool CanSendToHost { get { if (NetRoleInfo.IsClient) { return HostSupportsUs; } return false; } } public static bool DisconnectPersistenceActive { get { if (!NetRoleInfo.HasAuthority) { return HostSupportsUs; } return true; } } public static bool EveryoneSupportsUs { get { if (Handshake != null) { return Handshake.EveryoneHasMod("com.sponge.peakoptimized"); } return false; } } } [BepInPlugin("com.sponge.peakoptimized", "SpongePEAKOptimized", "1.0.0")] public sealed class OptimizedPlugin : SpongePlugin { public const string Guid = "com.sponge.peakoptimized"; private FeatureRegistry _registry; private AdaptiveNetworkFeature _adaptiveNetwork; private JoinArbiter _joinArbiter; private GameEvents _events; private ModHandshake _handshake; private LateJoinFixFeature _lateJoin; private ReconnectCatchupFeature _reconnectCatchup; private RejoinPositionFeature _rejoinPosition; private GhostPlayerFeature _ghostPlayer; private RopeShooterFixFeature _ropeShooterFix; private AudioFixFeature _audioFix; private DecorationCullingFeature _decorationCulling; private VisualQualityFeature _visualQuality; private TelemetryFeature _telemetry; private LobbyJoinFixFeature _lobbyJoinFix; protected override string DisplayName => "SpongePEAKOptimized"; protected override void OnLoad() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown _registry = new FeatureRegistry(((BaseUnityPlugin)this).Config, ((SpongePlugin)this).Log); _joinArbiter = new JoinArbiter(((SpongePlugin)this).Log, (MonoBehaviour)(object)this); _events = new GameEvents(((SpongePlugin)this).Log); _handshake = new ModHandshake(((SpongePlugin)this).Log); _handshake.Start(); Capabilities.Handshake = _handshake; _lateJoin = new LateJoinFixFeature(); _lateJoin.Configure(((BaseUnityPlugin)this).Config, _joinArbiter, _events); _reconnectCatchup = new ReconnectCatchupFeature(); _reconnectCatchup.Configure(((BaseUnityPlugin)this).Config, _joinArbiter); _rejoinPosition = new RejoinPositionFeature(); _rejoinPosition.Configure(((BaseUnityPlugin)this).Config, _joinArbiter, _events); _ropeShooterFix = new RopeShooterFixFeature(); _ghostPlayer = new GhostPlayerFeature(); _ghostPlayer.Configure(((BaseUnityPlugin)this).Config, _events); _audioFix = new AudioFixFeature(); _audioFix.Configure(((BaseUnityPlugin)this).Config); _lobbyJoinFix = new LobbyJoinFixFeature(); PerformanceFeature performanceFeature = new PerformanceFeature(); performanceFeature.Configure(((BaseUnityPlugin)this).Config); ZeroAllocFeature zeroAllocFeature = new ZeroAllocFeature(); zeroAllocFeature.Configure(((BaseUnityPlugin)this).Config); DistanceCullingFeature distanceCullingFeature = new DistanceCullingFeature(); distanceCullingFeature.Configure(((BaseUnityPlugin)this).Config); LightSampleCacheFeature lightSampleCacheFeature = new LightSampleCacheFeature(); lightSampleCacheFeature.Configure(((BaseUnityPlugin)this).Config); PhysicsThrottleFeature physicsThrottleFeature = new PhysicsThrottleFeature(); physicsThrottleFeature.Configure(((BaseUnityPlugin)this).Config); _decorationCulling = new DecorationCullingFeature(); _decorationCulling.Configure(((BaseUnityPlugin)this).Config); _visualQuality = new VisualQualityFeature(); _visualQuality.Configure(((BaseUnityPlugin)this).Config); ProximityGateFeature proximityGateFeature = new ProximityGateFeature(); proximityGateFeature.Configure(((BaseUnityPlugin)this).Config); _telemetry = new TelemetryFeature(); _telemetry.Configure(((BaseUnityPlugin)this).Config); PlatformTuningFeature platformTuningFeature = new PlatformTuningFeature(); platformTuningFeature.Configure(((BaseUnityPlugin)this).Config); _adaptiveNetwork = new AdaptiveNetworkFeature(); _adaptiveNetwork.Configure(((BaseUnityPlugin)this).Config); _registry.Register((ModFeature)(object)new VineClimbFixFeature()); _registry.Register((ModFeature)(object)performanceFeature); _registry.Register((ModFeature)(object)zeroAllocFeature); _registry.Register((ModFeature)(object)distanceCullingFeature); _registry.Register((ModFeature)(object)_audioFix); _registry.Register((ModFeature)(object)new RejoinVoiceFixFeature()); _registry.Register((ModFeature)(object)_lobbyJoinFix); _registry.Register((ModFeature)(object)new SoftDependencyFixFeature()); _registry.Register((ModFeature)(object)_lateJoin); _registry.Register((ModFeature)(object)_rejoinPosition); _registry.Register((ModFeature)(object)_reconnectCatchup); _registry.Register((ModFeature)(object)new DisconnectedCarryFeature()); _registry.Register((ModFeature)(object)_ropeShooterFix); _registry.Register((ModFeature)(object)_ghostPlayer); _registry.Register((ModFeature)(object)lightSampleCacheFeature); _registry.Register((ModFeature)(object)physicsThrottleFeature); _registry.Register((ModFeature)(object)_decorationCulling); _registry.Register((ModFeature)(object)new GrassAllocationFeature()); _registry.Register((ModFeature)(object)new GrassCullingFeature()); _registry.Register((ModFeature)(object)proximityGateFeature); _registry.Register((ModFeature)(object)new NullGuardFeature()); _registry.Register((ModFeature)(object)_visualQuality); _registry.Register((ModFeature)(object)_telemetry); _registry.Register((ModFeature)(object)platformTuningFeature); _registry.Register((ModFeature)(object)_adaptiveNetwork); _registry.EnableAll(((SpongePlugin)this).Patches); if (_telemetry != null && _adaptiveNetwork != null) { _telemetry.Quality = _adaptiveNetwork.Quality; } if (AnyJoinFeatureActive()) { _events.OnPlayerConnected((Action)OnPlayerConnected); if (PhotonNetwork.InRoom && PhotonNetwork.PlayerList != null) { _joinArbiter.SnapshotExistingPlayers(PhotonNetwork.PlayerList); } } } private bool AnyJoinFeatureActive() { if ((_lateJoin == null || !((ModFeature)_lateJoin).IsActive) && (_rejoinPosition == null || !((ModFeature)_rejoinPosition).IsActive)) { if (_reconnectCatchup != null) { return ((ModFeature)_reconnectCatchup).IsActive; } return false; } return true; } private void OnPlayerConnected(Player player) { if (!NetRoleInfo.HasAuthority) { _joinArbiter.MarkSeen(player); } else { _joinArbiter.HandleJoin(player); } } private void Update() { if (_audioFix != null && ((ModFeature)_audioFix).IsActive) { _audioFix.Tick(); } if (_decorationCulling != null && ((ModFeature)_decorationCulling).IsActive) { _decorationCulling.Tick(); } if (_telemetry != null && ((ModFeature)_telemetry).IsActive) { _telemetry.Tick(); } if (_adaptiveNetwork != null && ((ModFeature)_adaptiveNetwork).IsActive) { _adaptiveNetwork.Tick(); } } private void OnGUI() { if (_telemetry != null && ((ModFeature)_telemetry).IsActive) { _telemetry.Draw(); } } protected override void OnUnload() { ModHandshake handshake = _handshake; if (handshake != null) { handshake.Stop(); } Capabilities.Handshake = null; GameEvents events = _events; if (events != null) { events.UnsubscribeAll(); } _lateJoin?.Detach(); _reconnectCatchup?.Detach(); _rejoinPosition?.Detach(); _audioFix?.RestoreAll(); _adaptiveNetwork?.Cleanup(); _decorationCulling?.Cleanup(); _visualQuality?.Cleanup(); LightSampleCacheFeature.Clear(); PerformanceFeature.Reset(); DisconnectedPlayerRegistry.Reset(); _joinArbiter?.Reset(); } } } namespace SpongePEAK.Optimized.Rejoin { public static class DisconnectedPlayerRegistry { public sealed class DisconnectedState { public string PlayerKey; public string CharacterName; public Vector3 LastPosition; public float FogHeightAtDisconnect; public Character Character; public float DisconnectedAt; public bool DiedWhileDisconnected; } private static readonly Dictionary States = new Dictionary(); private static readonly HashSet AwayCharacters = new HashSet(); public static IEnumerable All => States.Values; public static string GetStableKey(Player player) { return PlayerUtil.GetStableKey(player); } public static DisconnectedState Record(Player player, Character character, float fogHeight, ModLog log) { //IL_004c: 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_0051: 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) string stableKey = GetStableKey(player); if (string.IsNullOrEmpty(stableKey)) { return null; } DisconnectedState disconnectedState = new DisconnectedState { PlayerKey = stableKey, CharacterName = (((Object)(object)character != (Object)null) ? character.characterName : player.NickName), LastPosition = (((Object)(object)character != (Object)null) ? character.Center : Vector3.zero), FogHeightAtDisconnect = fogHeight, Character = character, DisconnectedAt = Time.realtimeSinceStartup }; States[stableKey] = disconnectedState; if ((Object)(object)character != (Object)null) { AwayCharacters.Add(character); } if (log != null) { log.Info((object)$"Recorded disconnect for '{disconnectedState.CharacterName}' at {disconnectedState.LastPosition}."); } return disconnectedState; } public static DisconnectedState Find(Player player) { string stableKey = GetStableKey(player); if (string.IsNullOrEmpty(stableKey)) { return null; } if (!States.TryGetValue(stableKey, out var value)) { return null; } return value; } public static void Clear(Player player) { string stableKey = GetStableKey(player); if (!string.IsNullOrEmpty(stableKey) && States.TryGetValue(stableKey, out var value)) { if ((Object)(object)value.Character != (Object)null) { AwayCharacters.Remove(value.Character); } States.Remove(stableKey); } } public static bool IsAway(Character character) { if ((Object)(object)character != (Object)null) { return AwayCharacters.Contains(character); } return false; } public static void Reset() { States.Clear(); AwayCharacters.Clear(); } } public enum JoinKind { None, LateJoin, RestorePosition, CatchUp } public sealed class JoinArbiter { private readonly ModLog _log; private readonly MonoBehaviour _coroutineHost; private readonly HashSet _knownPlayers = new HashSet(); private readonly HashSet _inFlight = new HashSet(); public Func LateJoinHandler; public Func RestoreHandler; public Func CatchUpHandler; public Func CanRestorePosition; public JoinArbiter(ModLog log, MonoBehaviour coroutineHost) { _log = log; _coroutineHost = coroutineHost; } public void SnapshotExistingPlayers(IEnumerable players) { if (players == null) { return; } foreach (Player player in players) { string stableKey = PlayerUtil.GetStableKey(player); if (!string.IsNullOrEmpty(stableKey)) { _knownPlayers.Add(stableKey); } } ModLog log = _log; if (log != null) { log.Debug((object)$"Join arbiter snapshot: {_knownPlayers.Count} player(s) already present."); } } public void MarkSeen(Player player) { string stableKey = PlayerUtil.GetStableKey(player); if (!string.IsNullOrEmpty(stableKey)) { _knownPlayers.Add(stableKey); } } public bool HasSeen(Player player) { string stableKey = PlayerUtil.GetStableKey(player); if (!string.IsNullOrEmpty(stableKey)) { return _knownPlayers.Contains(stableKey); } return false; } public JoinKind Classify(Player player) { if (player == null || PlayerUtil.InAirport) { return JoinKind.None; } if (!HasSeen(player)) { if (LateJoinHandler == null) { return JoinKind.None; } return JoinKind.LateJoin; } if (RestoreHandler != null && CanRestorePosition != null && CanRestorePosition(player)) { return JoinKind.RestorePosition; } if (CatchUpHandler == null) { return JoinKind.None; } return JoinKind.CatchUp; } public void HandleJoin(Player player) { if (player == null) { return; } if (!_inFlight.Add(player.ActorNumber)) { ModLog log = _log; if (log != null) { log.Debug((object)("Already handling '" + player.NickName + "'; ignoring duplicate join event.")); } return; } JoinKind joinKind = Classify(player); MarkSeen(player); if (joinKind == JoinKind.None) { _inFlight.Remove(player.ActorNumber); return; } ModLog log2 = _log; if (log2 != null) { log2.Info((object)$"Join classified for '{player.NickName}': {joinKind}."); } if ((Object)(object)_coroutineHost != (Object)null) { _coroutineHost.StartCoroutine(Dispatch(player, joinKind)); } else { _inFlight.Remove(player.ActorNumber); } } private IEnumerator Dispatch(Player player, JoinKind kind) { Character character = null; yield return PlayerUtil.WaitForCharacter(player, (Action)delegate(Character c) { character = c; }, 30f, 0.1f); if ((Object)(object)character == (Object)null) { ModLog log = _log; if (log != null) { log.Warning((object)("'" + player.NickName + "' never produced a character; nothing to do.")); } _inFlight.Remove(player.ActorNumber); yield break; } Func func = kind switch { JoinKind.LateJoin => LateJoinHandler, JoinKind.RestorePosition => RestoreHandler, JoinKind.CatchUp => CatchUpHandler, _ => null, }; if (func != null) { yield return func(player, character); } _inFlight.Remove(player.ActorNumber); } public void Reset() { _knownPlayers.Clear(); _inFlight.Clear(); } } } namespace SpongePEAK.Optimized.Fixes { public sealed class AdaptiveNetworkFeature : ModFeature { private const int VanillaSendRate = 30; private const int VanillaSerializationRate = 30; public const string RatePropertyKey = "sponge.netrate"; private ConfigEntry _adapt; private ConfigEntry _interval; private ConfigEntry _floor; private ConfigEntry _report; private LinkQuality _quality; private LinkReporter _reporter; private ModLog _log; private float _timer; private int _appliedRate = 30; private const int RateStep = 5; public override string Name => "AdaptiveNetwork"; public override string Description => "Measures each player's connection and lowers the room's send rate when someone is struggling, so weak connections stop rubber-banding. Host decides, clients match."; public override string Replaces => ""; public override string Section => "Network"; public LinkQuality Quality => _quality; public void Configure(ConfigFile config) { _adapt = config.Bind("Network", "AdaptSendRate", true, "Lower the room's network send rate when a player's connection cannot keep up. Host decides; clients follow the host so everyone's interpolation matches. Off means always use the vanilla 30Hz."); _interval = config.Bind("Network", "SampleIntervalSeconds", 5f, "How often to read connection quality. This costs no packets: it reads counters Photon already maintains, so a short interval is cheap and reacts sooner."); _floor = config.Bind("Network", "MinimumSerializationRate", 15, "Lowest serialisation rate the host may drop to, in Hz. Vanilla is 30. Below about 15 the game's own interpolation starts to look obviously soft."); _report = config.Bind("Network", "LogConnectionQuality", true, "Log connection tier changes and rate adjustments. Useful for diagnosing whose connection is actually causing trouble."); } protected override void OnEnable(PatchHost patches, ModLog log) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown _log = log; _quality = new LinkQuality(log); _reporter = new LinkReporter(_quality, log); _reporter.Start(); log.Info((object)"Adaptive networking active: measuring connection quality from Photon telemetry."); } public void Tick() { if (!((ModFeature)this).IsActive || _quality == null || !PhotonNetwork.InRoom) { return; } _timer += Time.unscaledDeltaTime; if (_timer < Mathf.Max(1f, _interval?.Value ?? 5f)) { return; } _timer = 0f; _quality.Sample(); ConfigEntry adapt = _adapt; if (adapt == null || adapt.Value) { if (PhotonNetwork.IsMasterClient) { DecideAsHost(); } else { FollowHost(); } } } private int PublishedRate() { try { Room currentRoom = PhotonNetwork.CurrentRoom; Hashtable val = ((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null); if (val != null && ((Dictionary)(object)val).TryGetValue((object)"sponge.netrate", out object value) && value is byte b) { return Mathf.Clamp((int)b, 10, 30); } } catch (Exception) { } return 30; } private void DecideAsHost() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00bb: Expected I4, but got Unknown //IL_0150: Unknown result type (might be due to invalid IL or missing references) if (!Capabilities.EveryoneSupportsUs) { if (_appliedRate == 30 && PublishedRate() == 30) { return; } ApplyRate(30); PublishRate(30); ConfigEntry report = _report; if (report == null || report.Value) { ModLog log = _log; if (log != null) { log.Info((object)"A player without the mod is present; returned to vanilla 30Hz so nobody is left interpolating against the wrong rate."); } } return; } int num = PublishedRate(); if (num != _appliedRate) { ApplyRate(num); ConfigEntry report2 = _report; if (report2 == null || report2.Value) { ModLog log2 = _log; if (log2 != null) { log2.Info((object)$"Adopted the room's current send rate: {num}Hz."); } } } LinkTier val = LinkReporter.WorstReported(); int num2 = (val - 2) switch { 2 => 15, 1 => 20, 0 => 25, _ => 30, }; int num3 = Mathf.Clamp(_floor?.Value ?? 15, 10, 30); num2 = Mathf.Clamp(num2, num3, 30); if (num2 == _appliedRate) { return; } int num4 = StepToward(_appliedRate, num2); ApplyRate(num4); PublishRate(num4); ConfigEntry report3 = _report; if (report3 == null || report3.Value) { ModLog log3 = _log; if (log3 != null) { log3.Info((object)($"Room send rate -> {num4}Hz (worst reported connection: {val}). " + "Clients will match.")); } } } internal static int StepToward(int current, int target) { if (target > current) { return Math.Min(current + 5, target); } return Math.Max(current - 5, target); } private void FollowHost() { try { int num = PublishedRate(); if (num == _appliedRate) { return; } ApplyRate(num); ConfigEntry report = _report; if (report == null || report.Value) { ModLog log = _log; if (log != null) { log.Info((object)$"Matched host's send rate: {num}Hz."); } } } catch (Exception ex) { ModLog log2 = _log; if (log2 != null) { log2.Exception("Could not read the host's send rate", ex); } } } private void ApplyRate(int rate) { try { PhotonNetwork.SerializationRate = rate; PhotonNetwork.SendRate = Mathf.Max(rate, 15); _appliedRate = rate; } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Could not apply the network rate", ex); } } } private void PublishRate(int rate) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0021: Expected O, but got Unknown if (!PhotonNetwork.IsMasterClient) { return; } try { Hashtable val = new Hashtable(); ((Dictionary)val).Add((object)"sponge.netrate", (object)(byte)rate); Hashtable val2 = val; PhotonNetwork.CurrentRoom.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null); } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Could not publish the network rate", ex); } } } public void Cleanup() { LinkReporter reporter = _reporter; if (reporter != null) { reporter.Stop(); } try { PhotonNetwork.SerializationRate = 30; PhotonNetwork.SendRate = 30; } catch (Exception) { } } } public sealed class AudioFixFeature : ModFeature { private readonly struct PausedLoop { public readonly AudioSource Source; public readonly float Time; public PausedLoop(AudioSource source, float time) { Source = source; Time = time; } } private const string VoiceClipName = "UnityAudioOut"; private const float SilenceThreshold = 0.001f; private const float ResumeThreshold = 0.01f; private const int VoicePriority = 0; private const int GlobalPriority = 20; private const float NearPriority = 80f; private const float FarPriority = 220f; private const float GlobalSpatialBlendThreshold = 0.05f; private ModLog _log; private ConfigEntry _scanInterval; private readonly Dictionary _pausedLoops = new Dictionary(); private readonly List _scratch = new List(); private float _nextScanAt; private int _totalParked; private int _totalResumed; public override string Name => "AudioFix"; public override string Description => "Stops audio dropouts by parking silent looping sounds and prioritising voice and nearby audio."; public override string Replaces => "PatchNote-PeakAudioFix"; internal void Configure(ConfigFile config) { _scanInterval = config.Bind("AudioFix", "ScanInterval", 0.5f, "Seconds between audio source scans. Lower reacts faster but costs more CPU; FindObjectsByType is not cheap."); } protected override void OnEnable(PatchHost patches, ModLog log) { _log = log; } internal void Tick() { //IL_004a: 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_004f: 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) float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup < _nextScanAt)) { _nextScanAt = realtimeSinceStartup + (_scanInterval?.Value ?? 0.5f); Camera main = Camera.main; Vector3 listenerPosition = (((Object)(object)main != (Object)null) ? ((Component)main).transform.position : Vector3.zero); ScanForSilentLoops(realtimeSinceStartup, listenerPosition); ResumeAudibleSources(realtimeSinceStartup); } } private void ScanForSilentLoops(float now, Vector3 listenerPosition) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) AudioSource[] array = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (AudioSource val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val.clip == (Object)null) { continue; } int instanceID = ((Object)val).GetInstanceID(); if (!_pausedLoops.ContainsKey(instanceID)) { ApplyPriorityPolicy(val, listenerPosition); if (val.isPlaying && IsParkCandidate(val) && IsSilent(val)) { Park(val, instanceID, now); } } } } private void ResumeAudibleSources(float now) { if (_pausedLoops.Count == 0) { return; } _scratch.Clear(); foreach (int key in _pausedLoops.Keys) { _scratch.Add(key); } foreach (int item in _scratch) { if (_pausedLoops.TryGetValue(item, out var value)) { AudioSource source = value.Source; if ((Object)(object)source == (Object)null) { _pausedLoops.Remove(item); } else if (ShouldResume(source)) { Resume(source, value, item); } } } } private void Park(AudioSource source, int id, float now) { _pausedLoops[id] = new PausedLoop(source, source.time); source.Pause(); _totalParked++; } private void Resume(AudioSource source, PausedLoop parked, int id) { _pausedLoops.Remove(id); if (!source.isPlaying) { AudioClip clip = source.clip; if ((Object)(object)clip != (Object)null && parked.Time > 0f && parked.Time < clip.length) { source.time = parked.Time; } source.UnPause(); } _totalResumed++; } private static bool IsParkCandidate(AudioSource source) { if (!source.loop || (Object)(object)source.clip == (Object)null) { return false; } return ((Object)source.clip).name != "UnityAudioOut"; } private static bool IsSilent(AudioSource source) { return source.volume <= 0.001f; } private static bool ShouldResume(AudioSource source) { if (!((Behaviour)source).enabled || !((Component)source).gameObject.activeInHierarchy || source.mute) { return false; } return source.volume >= 0.01f; } private void ApplyPriorityPolicy(AudioSource source, Vector3 listenerPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) int targetPriority = GetTargetPriority(source, listenerPosition); if (source.priority != targetPriority) { source.priority = targetPriority; } } private static int GetTargetPriority(AudioSource source, Vector3 listenerPosition) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (IsVoiceSource(source)) { return 0; } if (IsGlobalSource(source)) { return 20; } float num = Mathf.Max(1f, source.maxDistance); float num2 = Mathf.Clamp01(Vector3.Distance(listenerPosition, ((Component)source).transform.position) / num); return Mathf.RoundToInt(Mathf.Lerp(80f, 220f, num2)); } private static bool IsVoiceSource(AudioSource source) { if ((Object)(object)source.clip != (Object)null) { return ((Object)source.clip).name == "UnityAudioOut"; } return false; } private static bool IsGlobalSource(AudioSource source) { if (source.spatialBlend <= 0.05f) { return true; } if ((Object)(object)source.clip != (Object)null && ((Object)source.clip).name.StartsWith("Music", StringComparison.OrdinalIgnoreCase)) { return true; } return HasAncestorNamed(((Component)source).transform, "Music"); } private static bool HasAncestorNamed(Transform transform, string name) { Transform val = transform; while ((Object)(object)val != (Object)null) { if (string.Equals(((Object)val).name, name, StringComparison.OrdinalIgnoreCase)) { return true; } val = val.parent; } return false; } internal void RestoreAll() { foreach (KeyValuePair pausedLoop in _pausedLoops) { AudioSource source = pausedLoop.Value.Source; if ((Object)(object)source != (Object)null && !source.isPlaying) { source.UnPause(); } } _pausedLoops.Clear(); ModLog log = _log; if (log != null) { log.Debug((object)$"Audio fix summary: parked={_totalParked}, resumed={_totalResumed}."); } } } public sealed class DecorationCullingFeature : ModFeature { private ConfigEntry _distance; private ConfigEntry _maxExtent; private ConfigEntry _perFrame; public override string Name => "DecorationCulling"; public override string Description => "Hides small decorative meshes beyond a distance, spreading the work across frames."; public override string Replaces => "reis637-PeakOptimizer"; public override string Section => "Performance"; public void Configure(ConfigFile config) { _distance = config.Bind("Performance", "DecorationCullDistance", 90f, "Distance beyond which small decorations stop being drawn."); _maxExtent = config.Bind("Performance", "DecorationMaxExtent", 1.5f, "Largest bounds extent, in metres, that counts as a decoration. Anything bigger is left alone, so climbable geometry is never hidden."); _perFrame = config.Bind("Performance", "DecorationChecksPerFrame", 64, "How many decorations to test each frame. Lower spreads the cost further."); } protected override void OnEnable(PatchHost patches, ModLog log) { DecorationRegistry.Configure(_distance?.Value ?? 90f, _maxExtent?.Value ?? 1.5f, _perFrame?.Value ?? 64, log); MethodInfo methodInfo = AccessTools.Method(typeof(DecorationRegistry), "RegisterFrom", (Type[])null, (Type[])null); (Type, string)[] array = new(Type, string)[4] { (typeof(RockSpawner), "Go"), (typeof(DecorSpawner), "ExecuteImmediately"), (typeof(DesertRockSpawner), "ExecuteImmediately"), (typeof(PropSpawner), "ExecuteImmediately") }; int num = 0; (Type, string)[] array2 = array; for (int i = 0; i < array2.Length; i++) { (Type, string) tuple = array2[i]; Type item = tuple.Item1; string item2 = tuple.Item2; MethodInfo methodInfo2 = AccessTools.Method(item, item2, (Type[])null, (Type[])null); if (methodInfo2 == null) { log.Warning((object)(item.Name + "." + item2 + " not found; its decorations will not be culled.")); } else if (patches.PatchMethod((MethodBase)methodInfo2, (MethodInfo)null, methodInfo, (MethodInfo)null, (MethodInfo)null)) { num++; } } if (num == 0) { ((ModFeature)this).Fail("no decoration spawners could be patched"); } else { log.Info((object)$"Decoration culling active on {num} of {array.Length} spawners."); } } public void Tick() { DecorationRegistry.Tick(); } public void Cleanup() { DecorationRegistry.RestoreAll(); } } internal static class DecorationRegistry { private struct Entry { public MeshRenderer Renderer; public Vector3 Position; public bool Visible; } private static readonly List Entries = new List(1024); private static readonly HashSet Known = new HashSet(); private static float _distanceSqr = 8100f; private static float _maxExtentSqr = 2.25f; private static int _perFrame = 64; private static int _cursor; private static ModLog _log; internal static int CulledCount { get; private set; } internal static int TrackedCount => Entries.Count; internal static void Configure(float distance, float maxExtent, int perFrame, ModLog log) { _distanceSqr = distance * distance; _maxExtentSqr = maxExtent * maxExtent; _perFrame = Mathf.Max(1, perFrame); _log = log; } internal static void RegisterFrom(Component __instance) { //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_0044: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return; } MeshRenderer[] componentsInChildren = __instance.GetComponentsInChildren(true); foreach (MeshRenderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } int instanceID = ((Object)val).GetInstanceID(); if (!Known.Contains(instanceID)) { Bounds bounds = ((Renderer)val).bounds; Vector3 extents = ((Bounds)(ref bounds)).extents; if (!(((Vector3)(ref extents)).sqrMagnitude > _maxExtentSqr)) { Known.Add(instanceID); Entries.Add(new Entry { Renderer = val, Position = ((Component)val).transform.position, Visible = true }); } } } } internal static void Tick() { //IL_001f: 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_008b: 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_0091: 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 (Entries.Count == 0) { return; } Vector3? val = Viewer(); if (!val.HasValue) { return; } Vector3 value = val.Value; int num = Mathf.Min(_perFrame, Entries.Count); for (int i = 0; i < num; i++) { if (_cursor >= Entries.Count) { _cursor = 0; } Entry value2 = Entries[_cursor]; if ((Object)(object)value2.Renderer == (Object)null) { Entries.RemoveAt(_cursor); continue; } Vector3 val2 = value2.Position - value; bool flag = ((Vector3)(ref val2)).sqrMagnitude <= _distanceSqr; if (flag != value2.Visible) { ((Renderer)value2.Renderer).enabled = flag; value2.Visible = flag; CulledCount += ((!flag) ? 1 : (-1)); Entries[_cursor] = value2; } _cursor++; } } private static Vector3? Viewer() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) Character observedCharacter = Character.observedCharacter; if ((Object)(object)observedCharacter != (Object)null) { return observedCharacter.Center; } MainCamera instance = MainCamera.instance; if ((Object)(object)instance != (Object)null) { return ((Component)instance).transform.position; } return null; } internal static void RestoreAll() { foreach (Entry entry in Entries) { if ((Object)(object)entry.Renderer != (Object)null) { ((Renderer)entry.Renderer).enabled = true; } } Entries.Clear(); Known.Clear(); _cursor = 0; CulledCount = 0; ModLog log = _log; if (log != null) { log.Debug((object)"Decoration culling reset."); } } } public sealed class DisconnectedCarryFeature : ModFeature { public override string Name => "CarryDisconnectedPlayers"; public override string Description => "Lets you pick up and carry teammates who disconnected while alive, and marks them (Disconnected). Ghosts cannot be carried."; public override string Replaces => "(new behaviour)"; public override string Section => "Rejoin"; protected override void OnEnable(PatchHost patches, ModLog log) { if (!patches.PatchType(typeof(DisconnectedCarryPatch))) { ((ModFeature)this).Fail("could not apply DisconnectedCarryPatch"); } if (!patches.PatchType(typeof(DisconnectedNamePatch))) { ((ModFeature)this).Fail("could not apply DisconnectedNamePatch"); } } } [HarmonyPatch(typeof(CharacterInteractible), "CanBeCarried")] internal static class DisconnectedCarryPatch { [HarmonyPostfix] private static void Postfix(CharacterInteractible __instance, ref bool __result) { if (!__result) { Character val = __instance?.character; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.data == (Object)null) && DisconnectedPlayerRegistry.IsAway(val) && !val.IsGhost && !val.data.dead && !val.isBot && !((Object)(object)val.data.carrier != (Object)null)) { __result = true; } } } } [HarmonyPatch(typeof(CharacterInteractible), "GetName")] internal static class DisconnectedNamePatch { [HarmonyPostfix] private static void Postfix(CharacterInteractible __instance, ref string __result) { Character val = __instance?.character; if (!((Object)(object)val == (Object)null) && DisconnectedPlayerRegistry.IsAway(val)) { __result += " (Disconnected)"; } } } public sealed class DistanceCullingFeature : ModFeature { private const float CappedUpdateRateHz = 30f; internal static ConfigEntry CullDynamicBones; internal static ConfigEntry DynamicBoneDistance; internal static ConfigEntry CapUpdateRate; public override string Name => "DistanceCulling"; public override string Description => "Skips dynamic-bone secondary motion beyond a distance from the camera, and caps its update rate."; public override string Replaces => "reis637-PeakOptimizer (partial)"; public override string Section => "Performance"; internal static float CappedRate => 30f; internal void Configure(ConfigFile config) { CullDynamicBones = config.Bind("Performance", "CullDistantDynamicBones", true, "Skips dynamic-bone updates beyond DynamicBoneDistance from the camera. Purely visual."); DynamicBoneDistance = config.Bind("Performance", "DynamicBoneDistance", 40f, "Metres from the camera beyond which dynamic bones stop updating. Lower is faster; too low shows stiff foliage nearby."); CapUpdateRate = config.Bind("Performance", "CapDynamicBoneUpdateRate", true, $"Caps dynamic-bone update rate at {30f} Hz instead of the default 60."); } protected override void OnEnable(PatchHost patches, ModLog log) { if (!patches.PatchType(typeof(DynamicBoneCullPatch))) { ((ModFeature)this).Fail("could not apply DynamicBoneCullPatch"); } } } [HarmonyPatch(typeof(DynamicBone), "UpdateDynamicBones")] internal static class DynamicBoneCullPatch { [HarmonyPrefix] private static bool Prefix(DynamicBone __instance) { //IL_0078: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (DistanceCullingFeature.CullDynamicBones == null) { return true; } if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.m_Root == (Object)null) { return true; } if (DistanceCullingFeature.CapUpdateRate.Value && __instance.m_UpdateRate > DistanceCullingFeature.CappedRate) { __instance.m_UpdateRate = DistanceCullingFeature.CappedRate; } if (!DistanceCullingFeature.CullDynamicBones.Value) { return true; } MainCamera instance = MainCamera.instance; if ((Object)(object)instance == (Object)null) { return true; } float value = DistanceCullingFeature.DynamicBoneDistance.Value; float num = value * value; Vector3 val = ((Component)instance).transform.position - ((Component)__instance).transform.position; return ((Vector3)(ref val)).sqrMagnitude <= num; } } public sealed class GhostPlayerFeature : ModFeature { internal static ModLog Log; internal static ConfigEntry PlayerTtl; private ModLog _log; private GameEvents _events; private bool _reportedState; public override string Name => "KeepDisconnectedPlayersInWorld"; public override string Description => "Keeps a disconnected player's character alive and simulated until they rejoin, die, or the timeout expires. Room settings are applied when you host; every client tracks who is away."; public override string Replaces => "(new behaviour)"; public override string Section => "Rejoin"; public override bool DefaultEnabled => true; internal void Configure(ConfigFile config, GameEvents events) { _events = events; PlayerTtl = config.Bind("Rejoin", "DisconnectedPlayerTimeoutSeconds", 300, "How long a disconnected player's character stays in the world before Photon reclaims it. They occupy a player slot for this whole period, so keep it in line with your player cap. Only applies to lobbies you host."); } protected override void OnEnable(PatchHost patches, ModLog log) { _log = log; Log = log; if (!patches.PatchType(typeof(RoomOptionsPlayerTtlPatch))) { ((ModFeature)this).Fail("could not apply RoomOptionsPlayerTtlPatch"); } _events.OnCharacterOwnerDisconnected((Action)OnCharacterOwnerDisconnected); _events.OnCharacterDied((Action)OnCharacterDied); _events.OnPlayerConnected((Action)delegate { ReportPersistenceStateOnce(); }); } private void ReportPersistenceStateOnce() { if (!_reportedState) { _reportedState = true; LogRoleState(_log); } } private void LogRoleState(ModLog log) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000a: 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_000e: Invalid comparison between Unknown and I4 NetRole current = NetRoleInfo.Current; if ((int)current != 1) { if (current - 2 <= 1) { if (log != null) { log.Info((object)"Disconnected-player persistence: active (we host, so every client sees it)."); } } else if (log != null) { log.Info((object)"Disconnected-player persistence: waiting until we are in a room."); } } else if (Capabilities.HostSupportsUs) { if (log != null) { log.Info((object)"Disconnected-player persistence: active (the host is running this mod)."); } } else if (log != null) { log.Info((object)"Disconnected-player persistence: inactive. The host is not running this mod, so disconnected characters are removed by Photon. Labels and carrying still work for anyone who does persist."); } } private void OnCharacterOwnerDisconnected(Character character) { if (!((Object)(object)character == (Object)null)) { ModLog log = _log; if (log != null) { log.Info((object)("'" + character.characterName + "' disconnected; their character stays in the world.")); } } } private void OnCharacterDied(Character character) { if ((Object)(object)character == (Object)null || !DisconnectedPlayerRegistry.IsAway(character)) { return; } foreach (DisconnectedPlayerRegistry.DisconnectedState item in DisconnectedPlayerRegistry.All) { if ((Object)(object)item.Character == (Object)(object)character) { item.DiedWhileDisconnected = true; ModLog log = _log; if (log != null) { log.Info((object)("'" + item.CharacterName + "' died while disconnected; they are a ghost now and cannot be carried.")); } break; } } } } [HarmonyPatch(typeof(NetworkingUtilities), "HostRoomOptions")] internal static class RoomOptionsPlayerTtlPatch { [HarmonyPostfix] private static void Postfix(ref RoomOptions __result) { if (__result != null && GhostPlayerFeature.PlayerTtl != null) { __result.PlayerTtl = GhostPlayerFeature.PlayerTtl.Value * 1000; __result.CleanupCacheOnLeave = false; ModLog log = GhostPlayerFeature.Log; if (log != null) { log.Info((object)$"Hosting with disconnected-player persistence: PlayerTtl={__result.PlayerTtl}ms."); } } } } public sealed class GrassAllocationFeature : ModFeature { public override string Name => "GrassAllocations"; public override string Description => "Reuses one MaterialPropertyBlock for grass instead of allocating a new one every frame."; public override string Replaces => "reis637-PeakOptimizer"; public override string Section => "Performance"; protected override void OnEnable(PatchHost patches, ModLog log) { MethodInfo methodInfo = AccessTools.Method(typeof(GrassRenderer), "Render", (Type[])null, (Type[])null); if (methodInfo == null) { ((ModFeature)this).Fail("GrassRenderer.Render not found"); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(GrassAllocations), "Transpiler", (Type[])null, (Type[])null); if (!patches.PatchMethod((MethodBase)methodInfo, (MethodInfo)null, (MethodInfo)null, methodInfo2, (MethodInfo)null)) { ((ModFeature)this).Fail("could not transpile GrassRenderer.Render"); } else { log.Info((object)"Grass property block reuse active."); } } } internal static class GrassAllocations { private static readonly MaterialPropertyBlock Shared = new MaterialPropertyBlock(); internal static MaterialPropertyBlock Get() { return Shared; } internal static IEnumerable Transpiler(IEnumerable instructions) { List list = new List(instructions); ConstructorInfo constructorInfo = AccessTools.Constructor(typeof(MaterialPropertyBlock), (Type[])null, false); MethodInfo operand = AccessTools.Method(typeof(GrassAllocations), "Get", (Type[])null, (Type[])null); bool flag = false; for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Newobj && list[i].operand is ConstructorInfo constructorInfo2 && constructorInfo2 == constructorInfo) { list[i].opcode = OpCodes.Call; list[i].operand = operand; flag = true; } } if (!flag) { return instructions; } return list; } } public sealed class GrassCullingFeature : ModFeature { public override string Name => "GrassFrustumCulling"; public override string Description => "Skips grass chunks outside the camera frustum. Grass casts no shadows, so this cannot change what you see."; public override string Replaces => "reis637-PeakOptimizer"; public override string Section => "Performance"; protected override void OnEnable(PatchHost patches, ModLog log) { MethodInfo methodInfo = AccessTools.Method(typeof(GrassChunking), "ShouldDrawChunk", (Type[])null, (Type[])null); if (methodInfo == null) { ((ModFeature)this).Fail("GrassChunking.ShouldDrawChunk not found"); } else if (!patches.PatchMethod((MethodBase)methodInfo, (MethodInfo)null, AccessTools.Method(typeof(GrassCulling), "Postfix", (Type[])null, (Type[])null), (MethodInfo)null, (MethodInfo)null)) { ((ModFeature)this).Fail("could not patch GrassChunking.ShouldDrawChunk"); } else { log.Info((object)"Grass frustum culling active."); } } } internal static class GrassCulling { private static readonly Plane[] Planes = (Plane[])(object)new Plane[6]; private static Camera _camera; private static int _planesFrame = -1; internal static void Postfix(int3 renderChunk, ref bool __result) { //IL_003c: 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_005a: 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_0074: 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) if (!__result) { return; } Camera val = Camera(); if (!((Object)(object)val == (Object)null)) { int frameCount = Time.frameCount; if (_planesFrame != frameCount) { GeometryUtility.CalculateFrustumPlanes(val, Planes); _planesFrame = frameCount; } float cHUNK_SIZE = GrassChunking.CHUNK_SIZE; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(((float)renderChunk.x + 0.5f) * cHUNK_SIZE, ((float)renderChunk.y + 0.5f) * cHUNK_SIZE, ((float)renderChunk.z + 0.5f) * cHUNK_SIZE); Bounds val3 = default(Bounds); ((Bounds)(ref val3))..ctor(val2, new Vector3(cHUNK_SIZE, cHUNK_SIZE, cHUNK_SIZE)); if (!GeometryUtility.TestPlanesAABB(Planes, val3)) { __result = false; } } } private static Camera Camera() { if ((Object)(object)_camera != (Object)null) { return _camera; } MainCamera instance = MainCamera.instance; if ((Object)(object)instance != (Object)null) { _camera = ((Component)instance).GetComponent(); } if (!((Object)(object)_camera != (Object)null)) { return _camera = Camera.main; } return _camera; } } public sealed class LateJoinFixFeature : ModFeature { private ModLog _log; private JoinArbiter _arbiter; private GameEvents _events; private ConfigEntry _afterWarpDelay; private ConfigEntry _warpForwardOffset; private ConfigEntry _reviveHeightOffset; public override string Name => "LateJoinFix"; public override string Description => "Warps players who join mid-run to the party member furthest from the summit, then revives them."; public override string Replaces => "Sapphire009-LateJoinFix"; public override string Section => "Rejoin"; internal void Configure(ConfigFile config, JoinArbiter arbiter, GameEvents events) { _arbiter = arbiter; _events = events; _afterWarpDelay = config.Bind("Rejoin", "LateJoin_AfterWarpDelay", 2f, "Seconds between warping a late joiner and reviving them. Too short and the revive can land at their pre-warp position."); _warpForwardOffset = config.Bind("Rejoin", "LateJoin_WarpForwardOffset", 2f, "How far (world forward) to offset the warp from the target player, so the two do not spawn inside each other."); _reviveHeightOffset = config.Bind("Rejoin", "LateJoin_ReviveHeightOffset", 3f, "How far above the target player to revive the late joiner."); } protected override void OnEnable(PatchHost patches, ModLog log) { _log = log; _arbiter.LateJoinHandler = HandleLateJoin; _events.OnCharacterSpawned((Action)OnCharacterSpawned); } private IEnumerator HandleLateJoin(Player player, Character character) { Character target = PlayerUtil.FindFurthestFromSummit(character); if ((Object)(object)target == (Object)null) { ModLog log = _log; if (log != null) { log.Warning((object)"No living player to warp to; leaving the late joiner where they spawned."); } yield break; } Vector3 val = target.Center + Vector3.forward * _warpForwardOffset.Value; if (PlayerUtil.Warp(character, val)) { ModLog log2 = _log; if (log2 != null) { log2.Info((object)("Warped '" + character.characterName + "' to '" + target.characterName + "' (lowest climber).")); } } else { ModLog log3 = _log; if (log3 != null) { log3.Warning((object)("Failed to warp '" + character.characterName + "'.")); } } yield return (object)new WaitForSeconds(_afterWarpDelay.Value); Vector3 val2 = target.Center + new Vector3(0f, _reviveHeightOffset.Value, 0f); if (PlayerUtil.ReviveAt(character, val2)) { ModLog log4 = _log; if (log4 != null) { log4.Info((object)("Revived '" + character.characterName + "'.")); } } else { ModLog log5 = _log; if (log5 != null) { log5.Warning((object)("Failed to revive '" + character.characterName + "'.")); } } } private void OnCharacterSpawned(Character character) { if (!NetRoleInfo.HasAuthority || (Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null) { return; } PhotonView photonView = ((MonoBehaviourPun)character).photonView; Player val = ((photonView != null) ? photonView.Owner : null); if (val == null || _arbiter == null || (_arbiter.Classify(val) == JoinKind.None && !_arbiter.HasSeen(val))) { return; } bool flag = false; if (character.data.passedOut) { character.data.passedOut = false; flag = true; } if (character.data.deathTimer > 0f) { character.data.deathTimer = 0f; flag = true; } if (flag) { ModLog log = _log; if (log != null) { log.Info((object)("Cleared stuck downed state on '" + character.characterName + "'.")); } } } internal void Detach() { if (_arbiter != null) { _arbiter.LateJoinHandler = null; } } } internal static class LightSampleCache { private static readonly Dictionary Cache = new Dictionary(); private static float _gridSize = 1f; private static float _inverseGrid = 1f; private static int _capacity = 4096; private static ModLog _log; internal static long Hits; internal static long Misses; internal static void Configure(float gridSize, int capacity, ModLog log) { _gridSize = Mathf.Max(0.05f, gridSize); _inverseGrid = 1f / _gridSize; _capacity = Mathf.Max(256, capacity); _log = log; } internal static void Clear() { Cache.Clear(); Hits = 0L; Misses = 0L; } internal static bool Prefix(Vector3 worldPos, ref Color __result, out long __state) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) __state = Key(worldPos); if (Cache.TryGetValue(__state, out var value)) { __result = value; Hits++; return false; } Misses++; return true; } internal static void Postfix(Color __result, long __state) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (Cache.Count >= _capacity) { Cache.Clear(); ModLog log = _log; if (log != null) { log.Debug((object)"Light sample cache full; cleared."); } } Cache[__state] = __result; } private static long Key(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) long num = (long)Mathf.Floor(position.x * _inverseGrid) & 0x1FFFFF; long num2 = (long)Mathf.Floor(position.y * _inverseGrid) & 0x1FFFFF; long num3 = (long)Mathf.Floor(position.z * _inverseGrid) & 0x1FFFFF; return num | (num2 << 21) | (num3 << 42); } } public sealed class LightSampleCacheFeature : ModFeature { private ConfigEntry _gridSize; private ConfigEntry _capacity; public override string Name => "LightSampleCache"; public override string Description => "Caches baked light volume samples, which cost a CPU 3D-texture readback per call."; public override string Replaces => "reis637-PeakOptimizer"; public override string Section => "Performance"; public void Configure(ConfigFile config) { _gridSize = config.Bind("Performance", "LightSampleGridSize", 1f, "World-space cell size for cached light samples, in metres. Smaller is more accurate and hits the cache less often."); _capacity = config.Bind("Performance", "LightSampleCacheEntries", 4096, "Maximum cached samples. The cache clears wholesale when full, which is cheaper than tracking per-entry age for a value this cheap to recompute."); } protected override void OnEnable(PatchHost patches, ModLog log) { LightSampleCache.Configure(_gridSize?.Value ?? 1f, _capacity?.Value ?? 4096, log); Type type = AccessTools.TypeByName("LightVolume"); if (type == null) { ((ModFeature)this).Fail("LightVolume type not found"); return; } MethodInfo methodInfo = AccessTools.Method(type, "SamplePosition", new Type[2] { typeof(Vector3), typeof(bool) }, (Type[])null); if (methodInfo == null) { ((ModFeature)this).Fail("LightVolume.SamplePosition not found"); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(LightSampleCache), "Prefix", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(LightSampleCache), "Postfix", (Type[])null, (Type[])null); if (!patches.PatchMethod((MethodBase)methodInfo, methodInfo2, methodInfo3, (MethodInfo)null, (MethodInfo)null)) { ((ModFeature)this).Fail("could not patch LightVolume.SamplePosition"); } else { log.Info((object)$"Light sample cache active ({_gridSize?.Value ?? 1f}m grid)."); } } public static void Clear() { LightSampleCache.Clear(); } } public sealed class LobbyJoinFixFeature : ModFeature { public override string Name => "LobbyJoinFix"; public override string Description => "Retired. PEAK now defers lobby invites until the session is connected, so this is no longer needed."; public override string Replaces => "IceMods-PeakLobbyJoinFix"; public override bool DefaultEnabled => true; protected override void OnEnable(PatchHost patches, ModLog log) { if (log != null) { log.Info((object)"LobbyJoinFix is retired: PEAK's GameBooter already waits for ConnectedAndReady before consuming a pending invite. Nothing to patch."); } } } public sealed class NullGuardFeature : ModFeature { public override string Name => "NullGuards"; public override string Description => "Stops two vanilla per-frame exceptions: pocket updates before a player exists, and particle culling with no observed character."; public override string Replaces => "reis637-PeakOptimizer"; public override string Section => "Fixes"; protected override void OnEnable(PatchHost patches, ModLog log) { int num = 0; MethodInfo methodInfo = AccessTools.Method(typeof(CharacterItems), "UpdatePocketBehaviors", (Type[])null, (Type[])null); if (methodInfo != null && patches.PatchMethod((MethodBase)methodInfo, AccessTools.Method(typeof(NullGuards), "PocketPrefix", (Type[])null, (Type[])null), (MethodInfo)null, (MethodInfo)null, (MethodInfo)null)) { num++; } MethodInfo methodInfo2 = AccessTools.Method(typeof(ParticleCountCuller), "Update", (Type[])null, (Type[])null); if (methodInfo2 != null && patches.PatchMethod((MethodBase)methodInfo2, AccessTools.Method(typeof(NullGuards), "ParticlePrefix", (Type[])null, (Type[])null), (MethodInfo)null, (MethodInfo)null, (MethodInfo)null)) { num++; } if (num == 0) { ((ModFeature)this).Fail("neither guard could be applied"); } else { log.Info((object)$"Applied {num} of 2 null guards."); } } } internal static class NullGuards { internal static bool PocketPrefix(Character ___character) { if ((Object)(object)___character == (Object)null) { return false; } if ((Object)(object)___character.player == (Object)null || ___character.player.itemSlots == null) { return false; } return true; } internal static bool ParticlePrefix() { Character observedCharacter = Character.observedCharacter; if ((Object)(object)observedCharacter == (Object)null) { return false; } if (observedCharacter.refs != null) { return (Object)(object)observedCharacter.refs.head != (Object)null; } return false; } } public sealed class PerformanceFeature : ModFeature { internal static ModLog Log; internal static readonly Dictionary LastUpdate = new Dictionary(); internal static ConfigEntry NearRate; internal static ConfigEntry MediumRate; internal static ConfigEntry FarRate; internal static ConfigEntry MediumDistance; internal static ConfigEntry FarDistance; public override string Name => "PerformanceLOD"; public override string Description => "Throttles physics updates for distant characters and avoids redundant rigidbody writes."; public override string Replaces => "KinTheInfinite-BetterFPS"; public override string Section => "Performance"; internal void Configure(ConfigFile config) { NearRate = config.Bind("Performance", "NearUpdateRate", 60f, "Physics updates per second for nearby remote characters. 0 disables their updates entirely."); MediumRate = config.Bind("Performance", "MediumUpdateRate", 30f, "Updates per second for characters past MediumDistance."); FarRate = config.Bind("Performance", "FarUpdateRate", 10f, "Updates per second for characters past FarDistance."); MediumDistance = config.Bind("Performance", "MediumDistance", 30f, "Distance (metres) at which a character drops to MediumUpdateRate."); FarDistance = config.Bind("Performance", "FarDistance", 60f, "Distance (metres) at which a character drops to FarUpdateRate."); } protected override void OnEnable(PatchHost patches, ModLog log) { Log = log; if (!patches.PatchType(typeof(RagdollThrottlePatch))) { ((ModFeature)this).Fail("could not apply RagdollThrottlePatch"); } if (!patches.PatchType(typeof(CenterOfMassCachePatch))) { ((ModFeature)this).Fail("could not apply CenterOfMassCachePatch"); } } internal static float DistanceFromLocalPlayer(Character character) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null || (Object)(object)character == (Object)null) { return 0f; } Vector3 val = character.Center - localCharacter.Center; return ((Vector3)(ref val)).magnitude; } internal static void Reset() { LastUpdate.Clear(); } } [HarmonyPatch(typeof(CharacterRagdoll), "FixedUpdate")] internal static class RagdollThrottlePatch { [HarmonyPrefix] private static bool Prefix(CharacterRagdoll __instance) { if ((Object)(object)__instance == (Object)null) { return true; } Character field = ReflectionCache.GetField((object)__instance, "character", (Character)null); if ((Object)(object)field == (Object)null) { return true; } if (field.IsLocal || field.isScoutmaster) { return true; } float value = PerformanceFeature.NearRate.Value; float num = PerformanceFeature.DistanceFromLocalPlayer(field); if (num > PerformanceFeature.FarDistance.Value) { value = PerformanceFeature.FarRate.Value; } else if (num > PerformanceFeature.MediumDistance.Value) { value = PerformanceFeature.MediumRate.Value; } if (value <= 0f) { return false; } float num2 = 1f / value; float time = Time.time; if (!PerformanceFeature.LastUpdate.TryGetValue(__instance, out var value2)) { PerformanceFeature.LastUpdate[__instance] = time; return true; } if (time - value2 < num2) { return false; } PerformanceFeature.LastUpdate[__instance] = time; return true; } } [HarmonyPatch(typeof(CenterOfMass), "FixedUpdate")] internal static class CenterOfMassCachePatch { [HarmonyPrefix] private static bool Prefix(CenterOfMass __instance) { //IL_0067: 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_0042: 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_006e: 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_007c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return true; } Rigidbody field = ReflectionCache.GetField((object)__instance, "rb", (Rigidbody)null); if ((Object)(object)field == (Object)null) { return true; } if (__instance.onlyOnGround) { Item field2 = ReflectionCache.GetField((object)__instance, "item", (Item)null); if ((Object)(object)field2 != (Object)null && (int)field2.itemState != 0) { return false; } } Vector3 val = (((Object)(object)__instance.centerOfMassTransform != (Object)null) ? __instance.centerOfMassTransform.localPosition : __instance.localCenterOfMass); if (field.centerOfMass != val) { field.centerOfMass = val; } if (field.angularDamping != __instance.angularDamping) { field.angularDamping = __instance.angularDamping; } return false; } } public sealed class PhysicsThrottleFeature : ModFeature { private ConfigEntry _shelterInterval; private ConfigEntry _optimizeBots; public override string Name => "PhysicsThrottle"; public override string Description => "Caches wind shelter raycasts and removes the per-search scene scan from bot vision."; public override string Replaces => "reis637-PeakOptimizer"; public override string Section => "Performance"; public void Configure(ConfigFile config) { _shelterInterval = config.Bind("Performance", "WindShelterInterval", 0.1f, "Seconds between wind shelter raycasts per character. Terrain does not move, so this only needs to keep up with the player."); _optimizeBots = config.Bind("Performance", "OptimizeBotVision", true, "Replaces the scene scan in bot vision with the list the game already maintains."); } protected override void OnEnable(PatchHost patches, ModLog log) { PhysicsThrottle.Configure(_shelterInterval?.Value ?? 0.1f, log); MethodInfo methodInfo = AccessTools.Method(typeof(WindChillZone), "AddWindForceToCharacter", (Type[])null, (Type[])null); if (methodInfo == null) { ((ModFeature)this).Fail("WindChillZone.AddWindForceToCharacter not found"); return; } if (!patches.PatchMethod((MethodBase)methodInfo, AccessTools.Method(typeof(PhysicsThrottle), "WindPrefix", (Type[])null, (Type[])null), (MethodInfo)null, (MethodInfo)null, AccessTools.Method(typeof(PhysicsThrottle), "WindFinalizer", (Type[])null, (Type[])null))) { ((ModFeature)this).Fail("could not patch WindChillZone.AddWindForceToCharacter"); return; } ConfigEntry optimizeBots = _optimizeBots; if (optimizeBots == null || optimizeBots.Value) { MethodInfo methodInfo2 = AccessTools.Method(typeof(Bot), "LookForPlayerHead", (Type[])null, (Type[])null); if (methodInfo2 == null || !patches.PatchMethod((MethodBase)methodInfo2, AccessTools.Method(typeof(PhysicsThrottle), "BotPrefix", (Type[])null, (Type[])null), (MethodInfo)null, (MethodInfo)null, (MethodInfo)null)) { log.Warning((object)"Bot vision not optimized; Bot.LookForPlayerHead could not be patched."); } } log.Info((object)"Physics throttling active."); } } internal static class PhysicsThrottle { private sealed class Shelter { public float Multiplier = 1f; public float NextQuery; } private static readonly ConditionalWeakTable Shelters = new ConditionalWeakTable(); private static float _interval = 0.1f; private static ModLog _log; internal static void Configure(float interval, ModLog log) { _interval = Mathf.Max(0.02f, interval); _log = log; } internal static bool WindPrefix(WindChillZone __instance, Character character, out bool __state) { __state = false; if ((Object)(object)__instance == (Object)null || (Object)(object)character == (Object)null || !__instance.useRaycast) { return true; } Shelter orCreateValue = Shelters.GetOrCreateValue(character); if (Time.time >= orCreateValue.NextQuery) { orCreateValue.NextQuery = Time.time + _interval; return true; } __instance.useRaycast = false; __state = true; return true; } internal static void WindFinalizer(WindChillZone __instance, bool __state) { if (__state && (Object)(object)__instance != (Object)null) { __instance.useRaycast = true; } } internal static bool BotPrefix(Bot __instance, Vector3 searcherHeadPos, float maxRange, float maxAngle, ref Rigidbody __result) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) __result = null; List allCharacters = Character.AllCharacters; if (allCharacters == null || allCharacters.Count == 0) { return false; } Character val = null; for (int i = 0; i < allCharacters.Count; i++) { Character val2 = allCharacters[i]; if (!((Object)(object)val2 == (Object)null) && !val2.isBot) { val = val2; break; } } if ((Object)(object)val == (Object)null) { return false; } Vector3 center = __instance.Center; Vector3 center2 = val.Center; if (Vector3.Distance(center, center2) > maxRange) { return false; } if (Vector3.Angle(center2 - center, __instance.LookDirection) > maxAngle) { return false; } Bodypart val3 = val.refs?.head; if ((Object)(object)val3 == (Object)null || (Object)(object)val3.Rig == (Object)null) { return false; } RaycastHit val4 = HelperFunctions.LineCheck(searcherHeadPos, val3.Rig.position, (LayerType)1, 0f, (QueryTriggerInteraction)1); if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val4)).transform)) { return false; } __result = val3.Rig; return false; } } public sealed class PlatformTuningFeature : ModFeature { private ConfigEntry _reportPlatform; private ConfigEntry _protonLoadingPriority; private ConfigEntry _maxQueuedFrames; private ModLog _log; private const int EngineDefaultQueuedFrames = -1; public override string Name => "PlatformTuning"; public override string Description => "Applies the few engine settings that genuinely differ under Proton/Wine versus native Windows. Does nothing on Windows unless explicitly configured."; public override string Replaces => ""; public override string Section => "Performance"; public void Configure(ConfigFile config) { _reportPlatform = config.Bind("Performance", "ReportPlatform", true, "Log which platform was detected and the evidence for it. Useful when reporting a performance problem, since Proton and Windows behave differently."); _protonLoadingPriority = config.Bind("Performance", "ProtonBackgroundLoadingPriority", 2, "Proton/Wine only. How much time per frame the engine may spend on background loading, which is when DXVK compiles shader pipelines. 0 leaves the engine default, 1 is low, 2 is normal, 3 is high. Higher trades slightly longer loads for fewer first-encounter stutters. Ignored on native Windows."); _maxQueuedFrames = config.Bind("Performance", "MaxQueuedFrames", -1, "Frames the CPU may queue ahead of the GPU. -1 leaves the engine default (2). Setting 1 can reduce input latency under DXVK, at some risk to throughput. Applies on any platform, because it is a preference rather than a fix."); } protected override void OnEnable(PatchHost patches, ModLog log) { //IL_0007: 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_0027: Unknown result type (might be due to invalid IL or missing references) _log = log; HostPlatform current = PlatformInfo.Current; ConfigEntry reportPlatform = _reportPlatform; if (reportPlatform == null || reportPlatform.Value) { log.Info((object)$"Platform: {current} ({PlatformInfo.Detail})."); } ApplyQueuedFrames(log); if (PlatformInfo.IsTranslated) { ApplyProtonTuning(log); } else { log.Debug((object)"Native platform: no translation-layer tuning applied."); } } private void ApplyProtonTuning(ModLog log) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) int num = _protonLoadingPriority?.Value ?? 2; if (num <= 0) { log.Debug((object)"Proton detected; background loading priority left at the engine default."); return; } try { ThreadPriority val = (Application.backgroundLoadingPriority = (ThreadPriority)(num switch { 1 => 0, 2 => 2, _ => 4, })); log.Info((object)($"Proton detected: background loading priority set to {val}, so more " + "shader pipeline compilation happens during loads.")); } catch (Exception ex) { log.Exception("Could not set background loading priority", ex); ((ModFeature)this).Fail("background loading priority could not be set"); } } private void ApplyQueuedFrames(ModLog log) { int num = _maxQueuedFrames?.Value ?? (-1); if (num < 0) { return; } try { QualitySettings.maxQueuedFrames = Mathf.Clamp(num, 1, 4); log.Info((object)$"Max queued frames set to {QualitySettings.maxQueuedFrames}."); } catch (Exception ex) { log.Exception("Could not set maxQueuedFrames", ex); } } } public sealed class ProximityGateFeature : ModFeature { private ConfigEntry _trapDistance; public override string Name => "ProximityGating"; public override string Description => "Skips per-step updates for traps and ambient particle spawners with no player nearby."; public override string Replaces => "reis637-PeakOptimizer"; public override string Section => "Performance"; public void Configure(ConfigFile config) { _trapDistance = config.Bind("Performance", "TrapActiveDistance", 80f, "Distance within which traps keep updating. Well beyond their own reach, so this cannot stop a trap that could actually hit someone."); } protected override void OnEnable(PatchHost patches, ModLog log) { ProximityGate.Configure(_trapDistance?.Value ?? 80f, log); MethodInfo methodInfo = AccessTools.Method(typeof(ProximityGate), "TrapPrefix", (Type[])null, (Type[])null); int num = 0; Type[] array = new Type[2] { typeof(ArrowShooter), typeof(VenusFlyTrap) }; foreach (Type type in array) { MethodInfo methodInfo2 = AccessTools.Method(type, "FixedUpdate", (Type[])null, (Type[])null); if (methodInfo2 == null) { log.Warning((object)(type.Name + ".FixedUpdate not found; it will not be gated.")); } else if (patches.PatchMethod((MethodBase)methodInfo2, methodInfo, (MethodInfo)null, (MethodInfo)null, (MethodInfo)null)) { num++; } } if (num == 0) { ((ModFeature)this).Fail("no trap updates could be gated"); } else { log.Info((object)$"Proximity gating active on {num} trap type(s)."); } } } internal static class ProximityGate { private static float _distanceSqr = 6400f; private static ModLog _log; internal static void Configure(float distance, ModLog log) { _distanceSqr = distance * distance; _log = log; } internal static bool TrapPrefix(MonoBehaviour __instance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return true; } return IsAnyPlayerNear(((Component)__instance).transform.position); } internal static bool IsAnyPlayerNear(Vector3 position) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0033: 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_006e: 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) List allCharacters = Character.AllCharacters; Vector3 val; if (allCharacters == null || allCharacters.Count == 0) { MainCamera instance = MainCamera.instance; if ((Object)(object)instance == (Object)null) { return true; } val = ((Component)instance).transform.position - position; return ((Vector3)(ref val)).sqrMagnitude <= _distanceSqr; } for (int i = 0; i < allCharacters.Count; i++) { Character val2 = allCharacters[i]; if (!((Object)(object)val2 == (Object)null) && !val2.IsGhost) { val = val2.Center - position; if (((Vector3)(ref val)).sqrMagnitude <= _distanceSqr) { return true; } } } return false; } } public sealed class ReconnectCatchupFeature : ModFeature { private ModLog _log; private JoinArbiter _arbiter; private ConfigEntry _heightOffset; public override string Name => "ReconnectCatchup"; public override string Description => "Warps returning players to the party member furthest from the summit instead of the level start."; public override string Replaces => "Ayzax-Reconnect_Catchup"; public override string Section => "Rejoin"; internal void Configure(ConfigFile config, JoinArbiter arbiter) { _arbiter = arbiter; _heightOffset = config.Bind("Rejoin", "CatchUp_HeightOffset", 1f, "Metres above the target player's head to place a returning player."); } protected override void OnEnable(PatchHost patches, ModLog log) { _log = log; _arbiter.CatchUpHandler = HandleCatchUp; } private IEnumerator HandleCatchUp(Player player, Character character) { Character val = PlayerUtil.FindFurthestFromSummit(character); if ((Object)(object)val == (Object)null) { ModLog log = _log; if (log != null) { log.Warning((object)"No living player to catch up to; leaving the returning player where they spawned."); } yield break; } Vector3 val2 = val.Head + Vector3.up * _heightOffset.Value; if (PlayerUtil.Warp(character, val2)) { ModLog log2 = _log; if (log2 != null) { log2.Info((object)("Caught '" + character.characterName + "' up to '" + val.characterName + "' (lowest climber).")); } } else { ModLog log3 = _log; if (log3 != null) { log3.Warning((object)("Failed to warp '" + character.characterName + "'.")); } } } internal void Detach() { if (_arbiter != null) { _arbiter.CatchUpHandler = null; } } } public sealed class RejoinPositionFeature : ModFeature { private ModLog _log; private JoinArbiter _arbiter; private GameEvents _events; private ConfigEntry _fogSafetyMargin; private ConfigEntry _maxAwayTime; private Fog _fog; public override string Name => "RestoreRejoinPosition"; public override string Description => "Returns a rejoining player to where they disconnected, if the gloom has not risen past it."; public override string Replaces => "(new behaviour)"; public override string Section => "Rejoin"; internal void Configure(ConfigFile config, JoinArbiter arbiter, GameEvents events) { _arbiter = arbiter; _events = events; _fogSafetyMargin = config.Bind("Rejoin", "Restore_FogSafetyMargin", 10f, "Metres of clearance required between the gloom and a player's saved position before restoring them there."); _maxAwayTime = config.Bind("Rejoin", "Restore_MaxAwayTimeSeconds", 300f, "Longest disconnect, in seconds, that still restores the original position. Past this they are caught up to the party instead."); } protected override void OnEnable(PatchHost patches, ModLog log) { _log = log; _arbiter.RestoreHandler = HandleRestore; _arbiter.CanRestorePosition = CanRestore; _events.OnPlayerDisconnected((Action)OnPlayerDisconnected); } internal float GetFogHeight() { if ((Object)(object)_fog == (Object)null) { _fog = Object.FindObjectOfType(); } if (!((Object)(object)_fog != (Object)null)) { return float.MinValue; } return _fog.fogHeight; } private void OnPlayerDisconnected(Player player) { if (player != null && !PlayerUtil.InAirport) { Character character = PlayerUtil.GetCharacter(player); DisconnectedPlayerRegistry.Record(player, character, GetFogHeight(), _log); } } private bool CanRestore(Player player) { DisconnectedPlayerRegistry.DisconnectedState disconnectedState = DisconnectedPlayerRegistry.Find(player); if (disconnectedState == null) { return false; } float num = Time.realtimeSinceStartup - disconnectedState.DisconnectedAt; if (num > _maxAwayTime.Value) { ModLog log = _log; if (log != null) { log.Info((object)$"Not restoring '{disconnectedState.CharacterName}': away too long ({num:F0}s)."); } return false; } if (disconnectedState.DiedWhileDisconnected) { ModLog log2 = _log; if (log2 != null) { log2.Info((object)("Not restoring '" + disconnectedState.CharacterName + "': they died while disconnected.")); } return false; } float fogHeight = GetFogHeight(); if (fogHeight > float.MinValue && fogHeight + _fogSafetyMargin.Value >= disconnectedState.LastPosition.y) { ModLog log3 = _log; if (log3 != null) { log3.Info((object)($"Not restoring '{disconnectedState.CharacterName}': the gloom has risen to {fogHeight:F1} " + $"and their spot was {disconnectedState.LastPosition.y:F1}.")); } return false; } return true; } private IEnumerator HandleRestore(Player player, Character character) { DisconnectedPlayerRegistry.DisconnectedState disconnectedState = DisconnectedPlayerRegistry.Find(player); if (disconnectedState == null) { yield break; } if (PlayerUtil.Warp(character, disconnectedState.LastPosition)) { ModLog log = _log; if (log != null) { log.Info((object)$"Restored '{character.characterName}' to their disconnect position {disconnectedState.LastPosition}."); } } else { ModLog log2 = _log; if (log2 != null) { log2.Warning((object)("Failed to restore '" + character.characterName + "'.")); } } DisconnectedPlayerRegistry.Clear(player); } internal void Detach() { if (_arbiter != null) { _arbiter.RestoreHandler = null; _arbiter.CanRestorePosition = null; } } } public sealed class RejoinVoiceFixFeature : ModFeature { internal static ModLog Log; public override string Name => "RejoinVoiceFix"; public override string Description => "Resets Photon Voice when leaving a game so voice chat works in the next lobby."; public override string Replaces => "PatchNote-RejoinVoiceFix"; protected override void OnEnable(PatchHost patches, ModLog log) { Log = log; if (!patches.PatchType(typeof(LeaveCurrentGameVoiceResetPatch))) { ((ModFeature)this).Fail("could not apply LeaveCurrentGameVoiceResetPatch"); } } internal static void ResetVoice(string source) { PunVoiceClient instance = PunVoiceClient.Instance; LoadBalancingTransport val = ((instance != null) ? ((VoiceConnection)instance).Client : null); if (val == null) { return; } string text = ((((LoadBalancingClient)val).InRoom && ((LoadBalancingClient)val).CurrentRoom != null) ? (((LoadBalancingClient)val).CurrentRoom.Name ?? "") : ""); try { ((LoadBalancingClient)val).Disconnect(); ModLog log = Log; if (log != null) { log.Info((object)("Voice disconnect requested. source=" + source + " room=" + text)); } } catch (Exception ex) { ModLog log2 = Log; if (log2 != null) { log2.Exception("Voice disconnect threw while handling " + source, ex); } } } } [HarmonyPatch(typeof(Player), "LeaveCurrentGame")] internal static class LeaveCurrentGameVoiceResetPatch { [HarmonyPrefix] private static void Prefix() { RejoinVoiceFixFeature.ResetVoice("Player.LeaveCurrentGame"); } } public sealed class RopeShooterFixFeature : ModFeature { [HarmonyPatch(typeof(RopeShooter), "Update")] private static class UpdatePatch { private static readonly FieldInfo OverrideUsability = AccessTools.Field(typeof(Item), "overrideUsability"); private static readonly object SomeTrue = MakeSome(value: true); private static readonly object SomeFalse = MakeSome(value: false); private static readonly object NoneValue = MakeNone(); private static bool Ready { get { if (OverrideUsability != null && SomeTrue != null && SomeFalse != null) { return NoneValue != null; } return false; } } private static object MakeSome(bool value) { Type type = OverrideUsability?.FieldType; if (!(type == null)) { return AccessTools.Method(type, "Some", (Type[])null, (Type[])null)?.Invoke(null, new object[1] { value }); } return null; } private static object MakeNone() { Type type = OverrideUsability?.FieldType; object obj; if (!(type == null)) { obj = AccessTools.Property(type, "None")?.GetValue(null); if (obj == null) { return AccessTools.Field(type, "None")?.GetValue(null); } } else { obj = null; } return obj; } private static bool Prefix(RopeShooter __instance) { if (!Ready) { return true; } Item item = ((ItemComponent)__instance).item; if ((Object)(object)item == (Object)null) { return false; } Character holderCharacter = item.holderCharacter; if ((Object)(object)holderCharacter == (Object)null || !holderCharacter.IsLocal) { OverrideUsability.SetValue(item, NoneValue); return false; } if (item.isUsingPrimary && !item.finishedCast) { OverrideUsability.SetValue(item, SomeTrue); return false; } RaycastHit val = default(RaycastHit); OverrideUsability.SetValue(item, __instance.WillAttach(ref val) ? SomeTrue : SomeFalse); return false; } } internal static ModLog Log; public override string Name => "RopeShooterFix"; public override string Description => "Fixes the vanilla rope cannon refusing to fire: a single frame of lost footing or aim wobble cancelled the whole cast. Also stops spare cannons raycasting every frame."; public override string Replaces => "(vanilla bug)"; public override string Section => "Fixes"; public override bool DefaultEnabled => true; protected override void OnEnable(PatchHost patches, ModLog log) { Log = log; patches.PatchType(typeof(UpdatePatch)); } } public sealed class SoftDependencyFixFeature : ModFeature { internal static ModLog Log; public override string Name => "SoftDependencyFix"; public override string Description => "Keeps partially-loaded assemblies usable, so a mod with a missing optional dependency does not hide unrelated console commands."; public override string Replaces => "PEAKModding-SoftDependencyFix"; public override bool DefaultEnabled => true; protected override void OnEnable(PatchHost patches, ModLog log) { Log = log; if (!patches.PatchType(typeof(ReflectionUtilityGetTypesPatch))) { ((ModFeature)this).Fail("could not apply ReflectionUtilityGetTypesPatch"); } } } internal static class ReflectionUtilityGetTypesPatch { [HarmonyTargetMethod] private static MethodBase TargetMethod() { return AccessTools.Method(typeof(ReflectionUtility), "GetMethodsWithAttribute", (Type[])null, new Type[1] { typeof(ConsoleCommandAttribute) }); } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { MethodInfo original = AccessTools.Method(typeof(Assembly), "GetTypes", (Type[])null, (Type[])null); MethodInfo replacement = AccessTools.Method(typeof(ReflectionUtilityGetTypesPatch), "GetTypesSafe", (Type[])null, (Type[])null); int replaced = 0; foreach (CodeInstruction instruction in instructions) { if (original != null && replacement != null && (instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Call) && instruction.operand is MethodInfo methodInfo && methodInfo == original) { replaced++; instruction.opcode = OpCodes.Call; instruction.operand = replacement; yield return instruction; } else { yield return instruction; } } if (replaced == 0) { ModLog log = SoftDependencyFixFeature.Log; if (log != null) { log.Warning((object)"SoftDependencyFix found no Assembly.GetTypes() call to patch; the game may have changed."); } } else { ModLog log2 = SoftDependencyFixFeature.Log; if (log2 != null) { log2.Info((object)$"SoftDependencyFix active: rewrote {replaced} Assembly.GetTypes() call(s) to tolerate missing optional dependencies."); } } } public static Type[] GetTypesSafe(Assembly assembly) { if (assembly == null) { return Array.Empty(); } try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { if (ex.Types == null) { return Array.Empty(); } List list = new List(ex.Types.Length); Type[] types = ex.Types; foreach (Type type in types) { if (type != null) { list.Add(type); } } ModLog log = SoftDependencyFixFeature.Log; if (log != null) { log.Info((object)("'" + assembly.GetName().Name + "' has an unresolved optional dependency; " + $"recovered {list.Count} of {ex.Types.Length} types instead of discarding the assembly.")); } return list.ToArray(); } catch (Exception ex2) { ModLog log2 = SoftDependencyFixFeature.Log; if (log2 != null) { log2.Debug((object)("Could not read types from '" + assembly.GetName().Name + "': " + ex2.GetType().Name + ".")); } return Array.Empty(); } } } public sealed class TelemetryFeature : ModFeature { private ConfigEntry _interval; private ConfigEntry _hotkey; private string _text = ""; private float _nextRefresh; private bool _visible = true; private float _smoothedMs; public override string Name => "Telemetry"; public override string Description => "Shows frame time and what each optimization is doing, so the effect can be measured."; public override string Replaces => "reis637-PeakOptimizer"; public override bool DefaultEnabled => false; public override string Section => "Diagnostics"; public LinkQuality Quality { get; set; } public void Configure(ConfigFile config) { _interval = config.Bind("Diagnostics", "TelemetryInterval", 0.5f, "Seconds between readout refreshes."); _hotkey = config.Bind("Diagnostics", "TelemetryToggleKey", (KeyCode)289, "Key that shows or hides the readout while the feature is enabled."); } protected override void OnEnable(PatchHost patches, ModLog log) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) ConfigEntry hotkey = _hotkey; log.Info((object)$"Telemetry enabled; press {(object)(KeyCode)((hotkey == null) ? 289 : ((int)hotkey.Value))} to toggle it."); } public void Tick() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) ConfigEntry hotkey = _hotkey; if (Input.GetKeyDown((KeyCode)((hotkey == null) ? 289 : ((int)hotkey.Value)))) { _visible = !_visible; } float num = Time.unscaledDeltaTime * 1000f; _smoothedMs = ((_smoothedMs <= 0f) ? num : Mathf.Lerp(_smoothedMs, num, 0.1f)); if (!(Time.unscaledTime < _nextRefresh)) { _nextRefresh = Time.unscaledTime + Mathf.Max(0.1f, _interval?.Value ?? 0.5f); Rebuild(); } } private void AppendNetwork(StringBuilder sb) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) try { if (!PhotonNetwork.InRoom) { return; } LinkQuality quality = Quality; if (quality != null && quality.SmoothedRtt > 0) { sb.Append("link ").Append(quality.Tier).Append(" ") .Append(quality.SmoothedRtt) .Append("ms jitter ") .Append(quality.SmoothedJitter) .Append("ms"); if (quality.RecentResends > 0) { sb.Append(" resends ").Append(quality.RecentResends); } sb.AppendLine(); if (quality.UploadBytesPerSecond > 0 || quality.DownloadBytesPerSecond > 0) { sb.Append("traffic up ").Append(((float)quality.UploadBytesPerSecond / 1024f).ToString("0.0")).Append(" KiB/s down ") .Append(((float)quality.DownloadBytesPerSecond / 1024f).ToString("0.0")) .AppendLine(" KiB/s"); } } sb.Append("send rate ").Append(PhotonNetwork.SerializationRate).AppendLine("Hz"); List> list = (from pair in LinkReporter.All() where (int)pair.Value > 0 select pair).ToList(); if (list.Count <= 1) { return; } foreach (KeyValuePair item in list) { sb.Append(" ").Append(item.Key).Append(" ") .AppendLine(((object)item.Value/*cast due to .constrained prefix*/).ToString()); } } catch (Exception) { } } private void Rebuild() { StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append("SpongePEAK ").Append(_smoothedMs.ToString("0.0")).Append(" ms (") .Append((1000f / Mathf.Max(0.01f, _smoothedMs)).ToString("0")) .AppendLine(" fps)"); long hits = LightSampleCache.Hits; long misses = LightSampleCache.Misses; long num = hits + misses; if (num > 0) { stringBuilder.Append("light cache ").Append((100f * (float)hits / (float)num).ToString("0.0")).Append("% of ") .Append(num) .AppendLine(" samples"); } if (DecorationRegistry.TrackedCount > 0) { stringBuilder.Append("decorations ").Append(DecorationRegistry.CulledCount).Append(" hidden of ") .AppendLine(DecorationRegistry.TrackedCount.ToString()); } AppendNetwork(stringBuilder); _text = stringBuilder.ToString(); } public void Draw() { //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) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (_visible && !string.IsNullOrEmpty(_text)) { Rect val = default(Rect); ((Rect)(ref val))..ctor(12f, 12f, 420f, 90f); Color color = GUI.color; GUI.color = Color.black; GUI.Label(new Rect(((Rect)(ref val)).x + 1f, ((Rect)(ref val)).y + 1f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), _text); GUI.color = Color.white; GUI.Label(val, _text); GUI.color = color; } } } public sealed class VineClimbFixFeature : ModFeature { public override string Name => "VineClimbFix"; public override string Description => "Stops rubber-banding when climbing vines and chains."; public override string Replaces => "Cryo-PEAK_VineFix"; protected override void OnEnable(PatchHost patches, ModLog log) { if (!patches.PatchType(typeof(VineClimbSyncPatch))) { ((ModFeature)this).Fail("could not apply VineClimbSyncPatch"); } } } [HarmonyPatch(typeof(CharacterVineClimbing), "RPCA_SyncVineClimb")] internal static class VineClimbSyncPatch { [HarmonyPrefix] private static bool Prefix(CharacterVineClimbing __instance) { if ((Object)(object)__instance == (Object)null) { return true; } Character field = ReflectionCache.GetField((object)__instance, "character", (Character)null); if ((Object)(object)field == (Object)null) { return true; } return !field.IsLocal; } } public sealed class VisualQualityFeature : ModFeature { private ConfigEntry _lodBias; private ConfigEntry _tuneShadows; private ConfigEntry _shadowDistance; private ModLog _log; private bool _hooked; public override string Name => "VisualQuality"; public override string Description => "Trades visual fidelity for frames: LOD bias, shadow bias and directional shadow tuning."; public override string Replaces => "reis637-PeakOptimizer"; public override bool DefaultEnabled => true; public override string Section => "Visuals"; public void Configure(ConfigFile config) { _lodBias = config.Bind("Visuals", "LodBias", 1f, "Level-of-detail bias. Below 1 swaps to simpler meshes sooner: more frames, more visible popping. 1.0 leaves it alone."); _tuneShadows = config.Bind("Visuals", "TuneShadowBias", true, "Adjusts directional light shadow bias to reduce acne, which allows a lower shadow distance without obvious artefacts."); _shadowDistance = config.Bind("Visuals", "ShadowDistance", 0f, "Maximum shadow draw distance in metres. 0 leaves the game's value alone."); } protected override void OnEnable(PatchHost patches, ModLog log) { _log = log; if (!_hooked) { SceneManager.sceneLoaded += OnSceneLoaded; _hooked = true; } Apply(); log.Info((object)"Visual quality adjustments active."); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { Apply(); } private void Apply() { float num = _lodBias?.Value ?? 1f; if (num > 0f && !Mathf.Approximately(num, 1f)) { QualitySettings.lodBias = num; } float num2 = _shadowDistance?.Value ?? 0f; if (num2 > 0f) { QualitySettings.shadowDistance = num2; } ConfigEntry tuneShadows = _tuneShadows; if (tuneShadows == null || tuneShadows.Value) { TuneDirectionalShadows(); } } private void TuneDirectionalShadows() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 Light[] array = Object.FindObjectsByType((FindObjectsSortMode)0); int num = 0; Light[] array2 = array; foreach (Light val in array2) { if (!((Object)(object)val == (Object)null) && (int)val.type == 1) { val.shadowNormalBias = 0.4f; val.shadowBias = 0.05f; num++; } } if (num > 0) { ModLog log = _log; if (log != null) { log.Debug((object)$"Tuned shadow bias on {num} directional light(s)."); } } } public void Cleanup() { if (_hooked) { SceneManager.sceneLoaded -= OnSceneLoaded; _hooked = false; } } } public sealed class ZeroAllocFeature : ModFeature { internal const int OverlapBufferSize = 64; internal static readonly Collider[] OverlapBuffer = (Collider[])(object)new Collider[64]; internal static ConfigEntry OptimizeShakyRock; internal static ConfigEntry OptimizeProximity; public override string Name => "ZeroAllocHotPaths"; public override string Description => "Removes per-frame allocations from falling-rock physics and player proximity checks, reducing GC micro-stutter."; public override string Replaces => "reis637-PeakOptimizer (partial)"; public override string Section => "Performance"; internal void Configure(ConfigFile config) { OptimizeShakyRock = config.Bind("Performance", "ZeroAlloc_ShakyRock", true, "Replaces allocating physics queries and leftover debug logging in falling-rock updates."); OptimizeProximity = config.Bind("Performance", "ZeroAlloc_ProximityChecks", true, "Uses squared-distance comparison instead of Vector3.Distance for player proximity checks."); } protected override void OnEnable(PatchHost patches, ModLog log) { if (!patches.PatchType(typeof(ShakyRockNonAllocPatch))) { ((ModFeature)this).Fail("could not apply ShakyRockNonAllocPatch"); } if (!patches.PatchType(typeof(ProximityCheckPatch))) { ((ModFeature)this).Fail("could not apply ProximityCheckPatch"); } } } [HarmonyPatch(typeof(ShakyRock), "FixedUpdate")] internal static class ShakyRockNonAllocPatch { [HarmonyPrefix] private static bool Prefix(ShakyRock __instance, ref bool ___isFinished, ref bool ___isFalling, ref bool ___once, Rigidbody ___rig, MeshCollider ___meshCollider, ref Vector3 ___scaleOnChange, ref Vector3 ___positionOnChange, ref Quaternion ___rotationOnChange) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_0044: 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_00b1: 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_00be: 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_0149: 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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017a: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) if (ZeroAllocFeature.OptimizeShakyRock == null || !ZeroAllocFeature.OptimizeShakyRock.Value) { return true; } if ((Object)(object)__instance == (Object)null || (Object)(object)___rig == (Object)null || (Object)(object)___meshCollider == (Object)null) { return true; } if (___isFinished || !___isFalling) { return false; } if (!___once) { ___rig.AddForce(Vector3.back * __instance.pushOutForce, (ForceMode)2); ___once = true; } Bounds bounds = ((Collider)___meshCollider).bounds; Vector3 center = ((Bounds)(ref bounds)).center; Vector3 extents = ((Bounds)(ref bounds)).extents; int num = Physics.OverlapSphereNonAlloc(center, ((Vector3)(ref extents)).magnitude / 2f, ZeroAllocFeature.OverlapBuffer); for (int i = 0; i < num; i++) { if ((Object)(object)ZeroAllocFeature.OverlapBuffer[i] != (Object)(object)___meshCollider) { return false; } } int num2 = Physics.OverlapBoxNonAlloc(center, extents, ZeroAllocFeature.OverlapBuffer, ((Component)__instance).transform.rotation); Vector3 val2 = default(Vector3); float num3 = default(float); for (int j = 0; j < num2; j++) { Collider val = ZeroAllocFeature.OverlapBuffer[j]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)___meshCollider) && Physics.ComputePenetration((Collider)(object)___meshCollider, ((Component)___meshCollider).transform.position, ((Component)___meshCollider).transform.rotation, val, ((Component)val).transform.position, ((Component)val).transform.rotation, ref val2, ref num3)) { return false; } } ___scaleOnChange = ((Component)___meshCollider).transform.lossyScale; ___positionOnChange = ((Component)___meshCollider).transform.position; ___rotationOnChange = ((Component)___meshCollider).transform.rotation; ___isFinished = true; ___rig.excludeLayers = LayerMask.op_Implicit(0); return false; } } [HarmonyPatch(typeof(PlayerHandler), "IsAnyPlayerNear")] internal static class ProximityCheckPatch { [HarmonyPrefix] private static bool Prefix(Vector3 point, float threshold, ref bool __result) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (ZeroAllocFeature.OptimizeProximity == null || !ZeroAllocFeature.OptimizeProximity.Value) { return true; } List allCharacters = Character.AllCharacters; if (allCharacters == null) { return true; } float num = threshold * threshold; for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.data == (Object)null) && !val.data.dead && !val.IsGhost) { Vector3 val2 = val.Center - point; if (((Vector3)(ref val2)).sqrMagnitude <= num) { __result = true; return false; } } } __result = false; return false; } } }