using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SurvivalMovementExertion")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SurvivalMovementExertion")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("21978fe2-ee63-49ee-aad5-3609c97f40b0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace SurvivalMovementExertion; [BepInPlugin("com.marccunningham.survivalmovementexertion", "Realistic Running", "1.2.1")] [BepInProcess("valheim.exe")] public sealed class SurvivalMovementExertionPlugin : BaseUnityPlugin { public const string PluginGuid = "com.marccunningham.survivalmovementexertion"; public const string PluginName = "Realistic Running"; public const string PluginVersion = "1.2.1"; private const float MinimumInputMagnitude = 0.001f; private const float MinimumDuration = 0.01f; private const int TunnelTextureCount = 18; private const int TunnelTextureSize = 160; private const int DefaultWindStreakCount = 28; internal static SurvivalMovementExertionPlugin Instance; private ConfigEntry modEnabled; private ConfigEntry diagnosticKey; private ConfigEntry showDiagnosticHud; private ConfigEntry enableInputSmoothing; private ConfigEntry accelerationSeconds; private ConfigEntry decelerationSeconds; private ConfigEntry backwardSpeedMultiplier; private ConfigEntry sidewaysSpeedMultiplier; private ConfigEntry sprintBuildUpSeconds; private ConfigEntry sprintStartSpeedFraction; private ConfigEntry topSprintSpeedMultiplier; private ConfigEntry sprintBuildRecoverySeconds; private ConfigEntry baseRunStaminaDrainMultiplier; private ConfigEntry maximumCombinedRunDrainMultiplier; private ConfigEntry emergencySprintReleaseStaminaPercentage; private ConfigEntry exertionGainPerSecond; private ConfigEntry exertionRecoveryPerSecond; private ConfigEntry stationaryRecoveryMultiplier; private ConfigEntry highExertionStart; private ConfigEntry highExertionRunSpeedMultiplier; private ConfigEntry highExertionDrainMultiplier; private ConfigEntry exhaustionTriggerStaminaPercentage; private ConfigEntry exhaustedJogSeconds; private ConfigEntry exhaustedJogSpeedMultiplier; private ConfigEntry recoveryStaminaPercentage; private ConfigEntry recoveryExertionPercentage; private ConfigEntry enableHillEffects; private ConfigEntry hillGraceAngle; private ConfigEntry hillFullPenaltyAngle; private ConfigEntry uphillSpeedPenalty; private ConfigEntry uphillDrainMultiplier; private ConfigEntry uphillExertionMultiplier; private ConfigEntry downhillSpeedBonus; private ConfigEntry downhillDrainReduction; private ConfigEntry enableWeatherEffects; private ConfigEntry wetSpeedMultiplier; private ConfigEntry wetDrainMultiplier; private ConfigEntry wetExertionMultiplier; private ConfigEntry coldDrainMultiplier; private ConfigEntry coldExertionMultiplier; private ConfigEntry freezingSpeedMultiplier; private ConfigEntry freezingDrainMultiplier; private ConfigEntry freezingExertionMultiplier; private ConfigEntry enableInjuryCompatibility; private ConfigEntry injuryExertionPenaltyStrength; private ConfigEntry applyInjurySpeedCompatibilityPenalty; private ConfigEntry factorRefreshSeconds; private ConfigEntry enableTunnelVision; private ConfigEntry tunnelVisionStartExertion; private ConfigEntry tunnelVisionFullExertion; private ConfigEntry maximumTunnelVisionAlpha; private ConfigEntry tunnelVisionPulseStrength; private ConfigEntry tunnelVisionClearRadiusAtExhaustion; private ConfigEntry enableWindRushStreaks; private ConfigEntry windRushStreakCount; private ConfigEntry windRushStartSprintBuild; private ConfigEntry windRushMaximumAlpha; private ConfigEntry windRushTravelSpeed; private ConfigEntry enableCameraSway; private ConfigEntry cameraSwayClosestZoomOnly; private ConfigEntry closestZoomTolerance; private ConfigEntry sprintBobVerticalMeters; private ConfigEntry sprintBobSideMeters; private ConfigEntry fatigueBreathSwayMeters; private ConfigEntry sprintSwayFrequencyLow; private ConfigEntry sprintSwayFrequencyHigh; private ConfigEntry breathSwayFrequencyLow; private ConfigEntry breathSwayFrequencyHigh; private ConfigEntry cameraSwaySmoothingSeconds; private ConfigEntry coolEdgeTintStrength; private ConfigEntry enableNativeDepthOfField; private ConfigEntry depthOfFieldClosestZoomOnly; private ConfigEntry depthOfFieldStartVisualIntensity; private ConfigEntry depthOfFieldMaximumBlurSize; private ConfigEntry depthOfFieldFocalSizeAtExhaustion; private ConfigEntry depthOfFieldFallbackFocusDistance; private ConfigEntry depthOfFieldMaximumFocusDistance; private ConfigEntry enableSprintFovBoost; private ConfigEntry sprintFovBoostDegrees; private ConfigEntry sprintFovBoostSmoothingSeconds; private ConfigEntry enablePeripheralBlurOverlay; private ConfigEntry peripheralBlurStartIntensity; private ConfigEntry peripheralBlurMaximumAlpha; private ConfigEntry peripheralBlurClearRadiusAtExhaustion; private ConfigEntry enableExhaustionHeartbeat; private ConfigEntry heartbeatStartPressure; private ConfigEntry heartbeatRecoveryBpm; private ConfigEntry heartbeatMaximumBpm; private ConfigEntry heartbeatMaximumVolume; private ConfigEntry heartbeatIntensitySmoothingSeconds; private Harmony harmony; private bool setControlsPatchInstalled; private bool jogSpeedPatchInstalled; private bool runSpeedPatchInstalled; private bool checkRunPatchInstalled; private bool cameraPositionPatchInstalled; private bool depthOfFieldPatchInstalled; private int setControlsHookCalls; private int jogSpeedHookCalls; private int runSpeedHookCalls; private int checkRunHookCalls; private int cameraHookCalls; private int depthOfFieldHookCalls; private float smoothedInputMagnitude; private float sprintBuild; private float exertion; private float exhaustedJogRemaining; private bool fatigueRecoveryActive; private bool wasSprinting; private float lastRunDrainMultiplier = 1f; private float factorRefreshTimer = 999f; private float terrainSpeedMultiplier = 1f; private float terrainDrainMultiplier = 1f; private float terrainExertionMultiplier = 1f; private float weatherSpeedMultiplier = 1f; private float weatherDrainMultiplier = 1f; private float weatherExertionMultiplier = 1f; private float weatherRecoveryMultiplier = 1f; private float injurySpeedMultiplier = 1f; private float injuryExertionMultiplier = 1f; private float cachedSlopeAngle; private bool cachedWet; private bool cachedCold; private bool cachedFreezing; private float smoothedCameraSwayVertical; private float smoothedCameraSwaySide; private float cameraSwayVerticalVelocity; private float cameraSwaySideVelocity; private float latestCameraDistance = float.MaxValue; private float latestCameraMinimumDistance = float.MaxValue; private float baseCameraFieldOfView = -1f; private float smoothedSprintFovBoost; private float sprintFovBoostVelocity; private Component heartbeatAudioSource; private Object heartbeatClip; private MethodInfo heartbeatPlayOneShotMethod; private MethodInfo heartbeatStopMethod; private float heartbeatNextBeatTime; private float heartbeatCurrentPressure; private float heartbeatPressureVelocity; private float heartbeatCurrentBpm; private string heartbeatStatus = "not loaded"; private string heartbeatAssetPath = string.Empty; private FieldInfo cameraEffectsDofField; private FieldInfo cameraEffectsDofRayMaskField; private MemberInfo dofFocusDistanceMember; private MemberInfo dofFocalSizeMember; private MemberInfo dofMaxBlurSizeMember; private MemberInfo dofApertureMember; private bool depthOfFieldReflectionReady; private bool depthOfFieldAvailable; private string depthOfFieldStatus = "not resolved"; private Type injuryPluginType; private FieldInfo injuryInstanceField; private MethodInfo injuryIsActiveForMethod; private MethodInfo injuryRunSpeedMultiplierMethod; private bool injuryReflectionUsable; private Texture2D[] tunnelTextures; private Texture2D[] peripheralBlurTextures; private WindStreak[] windStreaks; private GUIStyle diagnosticStyle; private void Awake() { Instance = this; BindConfig(); MigratePerceptibilityDefaults(); MigrateEscapeSafetyDefaults(); InstallPatches(); TryLoadHeartbeatAudio(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running 1.2.1 loaded. WindRushMaximumAlpha is now range-limited for a Configuration Manager slider, so wind-streak visibility can be tuned without rebuilding. Press F8 for diagnostics."); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } StopHeartbeatAudio(); if ((Object)(object)heartbeatAudioSource != (Object)null) { Object.Destroy((Object)(object)heartbeatAudioSource); heartbeatAudioSource = null; } if (heartbeatClip != (Object)null) { Object.Destroy(heartbeatClip); heartbeatClip = null; } DestroyTunnelTextures(); DestroyPeripheralBlurTextures(); windStreaks = null; if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(diagnosticKey.Value)) { WriteDiagnostic(); } Player localPlayer = Player.m_localPlayer; if (!IsMovementEligible(localPlayer)) { ResetTransientMovementState(); return; } factorRefreshTimer += Time.deltaTime; if (factorRefreshTimer >= Mathf.Max(0.05f, factorRefreshSeconds.Value)) { factorRefreshTimer = 0f; RefreshWorldFactors(localPlayer); } UpdateExertion(localPlayer); UpdateVisualMotion(localPlayer); UpdateHeartbeatAudio(localPlayer); } private void OnGUI() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && modEnabled.Value) { DrawWindRush(localPlayer); DrawPeripheralBlur(localPlayer); DrawTunnelVision(localPlayer); DrawDiagnosticHud(localPlayer); } } private void BindConfig() { //IL_0803: Unknown result type (might be due to invalid IL or missing references) //IL_0826: Unknown result type (might be due to invalid IL or missing references) //IL_0830: Expected O, but got Unknown //IL_0830: Expected O, but got Unknown modEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Turns Realistic Running on or off without removing the DLL."); diagnosticKey = ((BaseUnityPlugin)this).Config.Bind("General", "DiagnosticKey", (KeyCode)289, "Writes movement, exertion, terrain, weather and compatibility diagnostics to BepInEx/LogOutput.log."); showDiagnosticHud = ((BaseUnityPlugin)this).Config.Bind("Debug", "ShowDiagnosticHud", false, "Shows a small top-left exertion readout for balancing. Leave off for normal play."); enableInputSmoothing = ((BaseUnityPlugin)this).Config.Bind("Movement", "EnableInputSmoothing", true, "Smooths input magnitude while preserving immediate turning direction. This creates acceleration and deceleration without steering lag."); accelerationSeconds = ((BaseUnityPlugin)this).Config.Bind("Movement", "AccelerationSeconds", 0.28f, "Seconds for a stationary player to build toward full movement input. Higher values feel heavier."); decelerationSeconds = ((BaseUnityPlugin)this).Config.Bind("Movement", "DecelerationSeconds", 0.18f, "Seconds for movement input to settle after keys are released. Higher values feel less abrupt."); backwardSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Movement", "BackwardSpeedMultiplier", 0.7f, "Speed while moving directly backward. Diagonal movement blends naturally between forward, sideways and backward values."); sidewaysSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Movement", "SidewaysSpeedMultiplier", 0.86f, "Speed while moving directly sideways."); sprintBuildUpSeconds = ((BaseUnityPlugin)this).Config.Bind("Sprint", "SprintBuildUpSeconds", 1.35f, "Seconds for sprinting to build from the initial run into maximum speed."); sprintStartSpeedFraction = ((BaseUnityPlugin)this).Config.Bind("Sprint", "SprintStartSpeedFraction", 0.72f, "Fraction of top sprint speed available the instant sprinting begins. It rises to full TopSprintSpeedMultiplier over SprintBuildUpSeconds. V1.1.1 starts close to normal run speed, then visibly builds into a faster sprint."); topSprintSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Sprint", "TopSprintSpeedMultiplier", 1.45f, "Maximum healthy forward sprint multiplier relative to Valheim's native running speed. V1.1.4 gives a clearly faster full sprint while retaining build-up, exertion and recovery."); sprintBuildRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind("Sprint", "SprintBuildRecoverySeconds", 0.6f, "Seconds for sprint build-up to fade after the player stops running."); baseRunStaminaDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Sprint", "BaseRunStaminaDrainMultiplier", 0.15f, "Multiplier applied to Valheim's native run stamina drain. 0.15 aims for roughly 45-60 seconds of healthy sustained running with the same stamina pool, before terrain and exertion are considered."); maximumCombinedRunDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Safety", "MaximumCombinedRunDrainMultiplier", 2.25f, "Safety cap for all combined run-drain effects from exertion, terrain, weather and compatible survival mods. It keeps a bad situation difficult without making every sprint attempt instantly empty the bar."); emergencySprintReleaseStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind("Safety", "EmergencySprintReleaseStaminaPercentage", 0.22f, "After the minimum exhausted-jog time ends, sprinting is allowed again once stamina reaches this fraction even while exertion recovery continues. This prevents a long no-sprint lock while keeping escape costly."); exertionGainPerSecond = ((BaseUnityPlugin)this).Config.Bind("Exertion", "SprintExertionGainPerSecond", 1.5f, "Exertion gained per second while sprinting on neutral ground. A long hard run approaches high exertion."); exertionRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind("Exertion", "RecoveryPerSecond", 2.5f, "Exertion removed per second while walking or resting. Recovery is intentionally slower than the old version so hard running has a believable after-effect."); stationaryRecoveryMultiplier = ((BaseUnityPlugin)this).Config.Bind("Exertion", "StationaryRecoveryMultiplier", 1.75f, "Extra exertion recovery while standing still. Resting should recover you faster than walking onward."); highExertionStart = ((BaseUnityPlugin)this).Config.Bind("Exertion", "HighExertionStart", 35f, "Exertion percentage where heavy breathing, tunnel vision and late-run penalties begin building. V1.1.1 starts the feedback earlier so the player can feel effort building before complete exhaustion."); highExertionRunSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Exertion", "HighExertionRunSpeedMultiplier", 0.84f, "Minimum late-run speed multiplier at 100 exertion. Exhaustion should feel heavy, not like walking through glue."); highExertionDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Exertion", "HighExertionDrainMultiplier", 1.9f, "Additional stamina-drain multiplier reached at maximum exertion. Sustained hard running becomes less efficient instead of ending abruptly."); exhaustionTriggerStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind("Fatigue Recovery", "ExhaustionTriggerStaminaPercentage", 0.08f, "Stamina percentage that triggers a hard fatigue recovery state after a hard run. This begins before literal zero so exhaustion is noticeable and reliable."); exhaustedJogSeconds = ((BaseUnityPlugin)this).Config.Bind("Fatigue Recovery", "MinimumExhaustedJogSeconds", 5.5f, "Minimum number of seconds the player remains in a hard-jog recovery state after sprinting to near-zero stamina."); exhaustedJogSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Fatigue Recovery", "ExhaustedJogSpeedMultiplier", 0.88f, "Jog-speed multiplier during hard fatigue recovery."); recoveryStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind("Fatigue Recovery", "RecoveryStaminaPercentage", 0.28f, "Stamina percentage required before hard fatigue can end."); recoveryExertionPercentage = ((BaseUnityPlugin)this).Config.Bind("Fatigue Recovery", "RecoveryExertionPercentage", 55f, "Exertion percentage required before hard fatigue can end. This gives exhaustion a believable recovery period after a long run."); enableHillEffects = ((BaseUnityPlugin)this).Config.Bind("Terrain", "EnableHillEffects", true, "Applies uphill and downhill movement/exertion effects using Valheim's real ground normal."); hillGraceAngle = ((BaseUnityPlugin)this).Config.Bind("Terrain", "HillGraceAngle", 7f, "Slope angle in degrees before hill effects begin."); hillFullPenaltyAngle = ((BaseUnityPlugin)this).Config.Bind("Terrain", "HillFullPenaltyAngle", 35f, "Slope angle in degrees where maximum hill effects apply."); uphillSpeedPenalty = ((BaseUnityPlugin)this).Config.Bind("Terrain", "MaxUphillSpeedPenalty", 0.22f, "Maximum speed reduction while moving directly uphill on a steep slope."); uphillDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Terrain", "MaxUphillDrainMultiplier", 1.5f, "Maximum extra run stamina drain while moving directly uphill on a steep slope."); uphillExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind("Terrain", "MaxUphillExertionMultiplier", 1.65f, "Maximum extra exertion build while moving directly uphill on a steep slope."); downhillSpeedBonus = ((BaseUnityPlugin)this).Config.Bind("Terrain", "MaxDownhillSpeedBonus", 0.04f, "Maximum small speed bonus while moving directly downhill. Kept low to avoid unsafe runaway movement."); downhillDrainReduction = ((BaseUnityPlugin)this).Config.Bind("Terrain", "MaxDownhillDrainReduction", 0.12f, "Maximum reduction in sprint stamina drain while moving directly downhill."); enableWeatherEffects = ((BaseUnityPlugin)this).Config.Bind("Weather", "EnableWeatherEffects", true, "Applies realistic movement and exertion effects for wet, cold and freezing conditions."); wetSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Weather", "WetSpeedMultiplier", 0.97f, "Movement multiplier while wet. Kept mild: wetness should make travel harder without feeling sticky."); wetDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Weather", "WetRunDrainMultiplier", 1.14f, "Sprint stamina-drain multiplier while wet."); wetExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind("Weather", "WetExertionMultiplier", 1.16f, "Exertion-gain multiplier while wet."); coldDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Weather", "ColdRunDrainMultiplier", 1.08f, "Sprint stamina-drain multiplier in cold weather."); coldExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind("Weather", "ColdExertionMultiplier", 1.1f, "Exertion-gain multiplier in cold weather."); freezingSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Weather", "FreezingSpeedMultiplier", 0.95f, "Movement multiplier in freezing conditions."); freezingDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Weather", "FreezingRunDrainMultiplier", 1.25f, "Sprint stamina-drain multiplier in freezing conditions."); freezingExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind("Weather", "FreezingExertionMultiplier", 1.28f, "Exertion-gain multiplier in freezing conditions."); enableInjuryCompatibility = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "EnableYoureInjuredCompatibility", true, "Reads the installed You're Injured mod through safe reflection. It makes leg injuries build exertion faster and can apply its leg-speed penalty to Player overrides in current Valheim builds."); injuryExertionPenaltyStrength = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "InjuryExertionPenaltyStrength", 0.85f, "How strongly leg injuries increase exertion. 0 disables the extra exertion link while preserving any direct injury speed effect."); applyInjurySpeedCompatibilityPenalty = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "ApplyYoureInjuredSpeedCompatibilityPenalty", true, "Applies the existing You're Injured leg-speed multiplier to Player movement. Leave true for current builds where the original injury speed patch targets Character instead of Player. Turn off only if a later You're Injured update already patches Player speed directly."); factorRefreshSeconds = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "FactorRefreshSeconds", 0.15f, "How often terrain, weather and optional-mod factors are refreshed. Lower values react faster; defaults are light on performance."); enableTunnelVision = ((BaseUnityPlugin)this).Config.Bind("Visuals", "EnableExhaustionTunnelVision", true, "Narrows peripheral vision progressively during sustained sprinting. The effect begins mild, then tightens and pulses more strongly as exertion builds toward exhaustion."); tunnelVisionStartExertion = ((BaseUnityPlugin)this).Config.Bind("Visuals", "TunnelVisionStartExertion", 8f, "Exertion percentage where a faint peripheral narrowing begins during a sustained run. The effect then builds continuously instead of appearing only at complete exhaustion."); tunnelVisionFullExertion = ((BaseUnityPlugin)this).Config.Bind("Visuals", "TunnelVisionFullExertion", 88f, "Exertion percentage where the tunnel effect reaches its intended maximum before hard exhaustion. Keep this below 100 so the player feels pressure before their stamina is empty."); maximumTunnelVisionAlpha = ((BaseUnityPlugin)this).Config.Bind("Visuals", "MaximumTunnelVisionAlpha", 0.68f, "Maximum edge opacity of the sprint-exhaustion tunnel vision. V1.1.4 narrows the clear centre more rather than simply making the whole screen darker."); tunnelVisionPulseStrength = ((BaseUnityPlugin)this).Config.Bind("Visuals", "TunnelVisionPulseStrength", 0.3f, "How strongly the tunnel vision gently swells with heavy breathing. This only becomes noticeable as exertion rises."); tunnelVisionClearRadiusAtExhaustion = ((BaseUnityPlugin)this).Config.Bind("Visuals", "TunnelVisionClearRadiusAtExhaustion", 0.82f, "Size of the fully clear central view at heavy exhaustion. Lower values make the field of view feel more tightly narrowed; 0.82 keeps combat readable while making fatigue unmistakable."); enableWindRushStreaks = ((BaseUnityPlugin)this).Config.Bind("Visuals", "EnableWindRushStreaks", true, "Draws subtle pale wind streaks that burst outward from the centre toward all screen edges during a fresh full sprint. The centre remains clear for aiming and combat."); windRushStreakCount = ((BaseUnityPlugin)this).Config.Bind("Visuals", "WindRushStreakCount", 28, "Number of radial wind streaks. Higher values create a fuller all-angle speed field but can feel visually busy."); windRushStartSprintBuild = ((BaseUnityPlugin)this).Config.Bind("Visuals", "WindRushStartSprintBuild", 0.52f, "Sprint build percentage at which wind streaks start. This keeps them out of normal jogging and the first moments of a run."); windRushMaximumAlpha = ((BaseUnityPlugin)this).Config.Bind(new ConfigDefinition("Visuals", "WindRushMaximumAlpha"), 0.24f, new ConfigDescription("Brightness / visibility of individual wind streaks at full sprint. This is a slider in BepInEx Configuration Manager when that mod is installed. 0.24 is the current balanced default; try 0.32 for clearer streaks or 0.40 for a much stronger speed effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 0.65f), Array.Empty())); windRushTravelSpeed = ((BaseUnityPlugin)this).Config.Bind("Visuals", "WindRushTravelSpeed", 1.35f, "How quickly radial wind streaks travel away from the screen centre at full sprint."); enableCameraSway = ((BaseUnityPlugin)this).Config.Bind("Visuals", "EnableCameraSway", true, "Adds subtle sprint bob and heavier breathing sway. It patches the final camera position so it layers after Survival View's Raised Head View."); cameraSwayClosestZoomOnly = ((BaseUnityPlugin)this).Config.Bind("Visuals", "CameraSwayClosestZoomOnly", true, "When true, camera sway appears only at closest zoom / Survival View, avoiding unwanted third-person camera motion."); closestZoomTolerance = ((BaseUnityPlugin)this).Config.Bind("Visuals", "ClosestZoomToleranceMeters", 0.08f, "Tolerance used by CameraSwayClosestZoomOnly to recognise Valheim's closest normal third-person zoom."); sprintBobVerticalMeters = ((BaseUnityPlugin)this).Config.Bind("Visuals", "SprintBobVerticalMeters", 0.013f, "Maximum vertical camera bob while sprinting at low exertion. This is deliberately noticeable in Survival View without becoming nauseating."); sprintBobSideMeters = ((BaseUnityPlugin)this).Config.Bind("Visuals", "SprintBobSideMeters", 0.009f, "Maximum sideways camera bob while sprinting at low exertion."); fatigueBreathSwayMeters = ((BaseUnityPlugin)this).Config.Bind("Visuals", "FatigueBreathSwayMeters", 0.02f, "Maximum slow breathing sway at high exertion or hard fatigue recovery. This is intentionally small so it feels heavy rather than jittery."); sprintSwayFrequencyLow = ((BaseUnityPlugin)this).Config.Bind("Visuals", "SprintSwayFrequencyLowHz", 1.45f, "Slow sprint gait frequency in cycles per second. Lower values feel steadier and less jittery."); sprintSwayFrequencyHigh = ((BaseUnityPlugin)this).Config.Bind("Visuals", "SprintSwayFrequencyHighHz", 2.15f, "Fast sprint gait frequency in cycles per second at full pace."); breathSwayFrequencyLow = ((BaseUnityPlugin)this).Config.Bind("Visuals", "BreathSwayFrequencyLowHz", 0.2f, "Slow breathing sway frequency at the beginning of visible exertion."); breathSwayFrequencyHigh = ((BaseUnityPlugin)this).Config.Bind("Visuals", "BreathSwayFrequencyHighHz", 0.48f, "Heavy breathing sway frequency near exhaustion. 0.48 Hz is about 29 breaths per minute."); cameraSwaySmoothingSeconds = ((BaseUnityPlugin)this).Config.Bind("Visuals", "CameraSwaySmoothingSeconds", 0.2f, "How gently camera sway eases toward its target. Higher values are smoother and reduce jitter."); coolEdgeTintStrength = ((BaseUnityPlugin)this).Config.Bind("Visuals", "CoolEdgeTintStrength", 0.68f, "How much the peripheral haze shifts toward an airy blue-grey before deepening toward charcoal near exhaustion."); enableNativeDepthOfField = ((BaseUnityPlugin)this).Config.Bind("Visuals", "EnableNativeDepthOfField", true, "Uses Valheim's own CameraEffects depth-of-field component during heavy exertion. It focuses on the object in the centre of the view and applies only a mild depth blur."); depthOfFieldClosestZoomOnly = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DepthOfFieldClosestZoomOnly", true, "When true, exhaustion depth of field only runs at closest zoom / Survival View to keep normal third-person gameplay clear."); depthOfFieldStartVisualIntensity = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DepthOfFieldStartVisualIntensity", 0.34f, "Visual-exhaustion intensity where mild focus blur begins. Tunnel tint can start earlier, but focus blur waits until exertion is meaningful."); depthOfFieldMaximumBlurSize = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DepthOfFieldMaximumBlurSize", 0.55f, "Maximum native depth-of-field blur size near exhaustion. Kept deliberately modest so the screen centre remains usable in combat."); depthOfFieldFocalSizeAtExhaustion = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DepthOfFieldFocalSizeAtExhaustion", 1.1f, "Focal range around the point you are looking at near exhaustion. Smaller values create a narrower, more focused view."); depthOfFieldFallbackFocusDistance = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DepthOfFieldFallbackFocusDistance", 18f, "Focus distance used when the centre camera ray does not hit terrain or an object."); depthOfFieldMaximumFocusDistance = ((BaseUnityPlugin)this).Config.Bind("Visuals", "DepthOfFieldMaximumFocusDistance", 80f, "Maximum centre-view ray distance used for exhaustion focus."); enableSprintFovBoost = ((BaseUnityPlugin)this).Config.Bind("Visuals", "EnableSprintFovBoost", true, "Adds a very small field-of-view increase at a fresh full sprint. This stays subtle and fades as heavy exertion takes over."); sprintFovBoostDegrees = ((BaseUnityPlugin)this).Config.Bind("Visuals", "SprintFovBoostDegrees", 2.35f, "Maximum extra FOV at a fresh full sprint. Keep this around 2-3 degrees for a realistic speed feeling rather than an arcade effect."); sprintFovBoostSmoothingSeconds = ((BaseUnityPlugin)this).Config.Bind("Visuals", "SprintFovBoostSmoothingSeconds", 0.34f, "How smoothly the sprint FOV expands and relaxes. Slightly slower values feel more physical."); enablePeripheralBlurOverlay = ((BaseUnityPlugin)this).Config.Bind("Visuals", "EnablePeripheralBlurOverlay", true, "Adds a soft blue-grey focus-softening overlay around the outer edge as exertion builds. It complements Valheim's native depth of field without obscuring the centre."); peripheralBlurStartIntensity = ((BaseUnityPlugin)this).Config.Bind("Visuals", "PeripheralBlurStartIntensity", 0.22f, "Visual-exhaustion intensity where the subtle peripheral blur overlay begins to appear."); peripheralBlurMaximumAlpha = ((BaseUnityPlugin)this).Config.Bind("Visuals", "PeripheralBlurMaximumAlpha", 0.24f, "Maximum opacity of the soft peripheral blur overlay near heavy exhaustion."); peripheralBlurClearRadiusAtExhaustion = ((BaseUnityPlugin)this).Config.Bind("Visuals", "PeripheralBlurClearRadiusAtExhaustion", 0.92f, "Clear central radius that remains crisp when the peripheral blur overlay is at maximum strength. Lower values create more outer-edge focus loss."); enableExhaustionHeartbeat = ((BaseUnityPlugin)this).Config.Bind("Audio", "EnableExhaustionHeartbeat", true, "Plays the supplied double-heartbeat sample as physical exhaustion builds, then spaces the beats out and fades them during recovery."); heartbeatStartPressure = ((BaseUnityPlugin)this).Config.Bind("Audio", "HeartbeatStartPressure", 0.42f, "Exhaustion pressure where the heartbeat first becomes audible. It remains silent during ordinary jogging and light sprinting."); heartbeatRecoveryBpm = ((BaseUnityPlugin)this).Config.Bind("Audio", "HeartbeatRecoveryBPM", 88f, "Slowest audible heartbeat rate during the tail end of recovery."); heartbeatMaximumBpm = ((BaseUnityPlugin)this).Config.Bind("Audio", "HeartbeatMaximumBPM", 150f, "Fastest heartbeat rate at hard exhaustion. Values above 160 tend to feel artificial with this double-beat sample."); heartbeatMaximumVolume = ((BaseUnityPlugin)this).Config.Bind("Audio", "HeartbeatMaximumVolume", 0.3f, "Maximum heartbeat volume at hard exhaustion. Keep low enough that Valheim combat, rain and music still remain audible."); heartbeatIntensitySmoothingSeconds = ((BaseUnityPlugin)this).Config.Bind("Audio", "HeartbeatIntensitySmoothingSeconds", 0.75f, "How gently the heartbeat rate responds to changing exhaustion. This prevents abrupt BPM jumps when you stop running."); } private void MigratePerceptibilityDefaults() { bool flag = false; if (Mathf.Abs(sprintStartSpeedFraction.Value - 0.78f) < 0.001f) { sprintStartSpeedFraction.Value = 0.72f; flag = true; } if (Mathf.Abs(topSprintSpeedMultiplier.Value - 1.2f) < 0.001f || Mathf.Abs(topSprintSpeedMultiplier.Value - 1.32f) < 0.001f) { topSprintSpeedMultiplier.Value = 1.45f; flag = true; } if (Mathf.Abs(highExertionStart.Value - 55f) < 0.001f) { highExertionStart.Value = 35f; flag = true; } if (Mathf.Abs(highExertionRunSpeedMultiplier.Value - 0.89f) < 0.001f) { highExertionRunSpeedMultiplier.Value = 0.84f; flag = true; } if (Mathf.Abs(exhaustionTriggerStaminaPercentage.Value - 0.02f) < 0.001f) { exhaustionTriggerStaminaPercentage.Value = 0.08f; flag = true; } if (Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.42f) < 0.001f || Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.58f) < 0.001f) { maximumTunnelVisionAlpha.Value = 0.78f; flag = true; } if (Mathf.Abs(sprintBobVerticalMeters.Value - 0.018f) < 0.001f) { sprintBobVerticalMeters.Value = 0.032f; flag = true; } if (Mathf.Abs(sprintBobSideMeters.Value - 0.012f) < 0.001f) { sprintBobSideMeters.Value = 0.022f; flag = true; } if (Mathf.Abs(fatigueBreathSwayMeters.Value - 0.032f) < 0.001f) { fatigueBreathSwayMeters.Value = 0.02f; flag = true; } if (Mathf.Abs(sprintBobVerticalMeters.Value - 0.032f) < 0.001f) { sprintBobVerticalMeters.Value = 0.013f; flag = true; } if (Mathf.Abs(sprintBobSideMeters.Value - 0.022f) < 0.001f) { sprintBobSideMeters.Value = 0.009f; flag = true; } if (Mathf.Abs(fatigueBreathSwayMeters.Value - 0.058f) < 0.001f) { fatigueBreathSwayMeters.Value = 0.02f; flag = true; } if (Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.78f) < 0.001f || Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.62f) < 0.001f) { maximumTunnelVisionAlpha.Value = 0.68f; flag = true; } if (Mathf.Abs(coolEdgeTintStrength.Value - 0.62f) < 0.001f) { coolEdgeTintStrength.Value = 0.68f; flag = true; } if (Mathf.Abs(depthOfFieldStartVisualIntensity.Value - 0.34f) < 0.001f) { depthOfFieldStartVisualIntensity.Value = 0.26f; flag = true; } if (Mathf.Abs(depthOfFieldMaximumBlurSize.Value - 0.55f) < 0.001f) { depthOfFieldMaximumBlurSize.Value = 0.7f; flag = true; } if (Mathf.Abs(depthOfFieldFocalSizeAtExhaustion.Value - 1.1f) < 0.001f) { depthOfFieldFocalSizeAtExhaustion.Value = 0.9f; flag = true; } if (windRushStreakCount.Value == 12) { windRushStreakCount.Value = 28; flag = true; } if (Mathf.Abs(windRushMaximumAlpha.Value - 0.2f) < 0.001f) { windRushMaximumAlpha.Value = 0.24f; flag = true; } if (flag) { ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated untouched defaults to V1.1.8 slightly clearer radial wind-rush streaks."); } } private void MigrateEscapeSafetyDefaults() { if (Mathf.Abs(exhaustedJogSeconds.Value - 8f) < 0.001f && Mathf.Abs(exhaustedJogSpeedMultiplier.Value - 0.84f) < 0.001f && Mathf.Abs(recoveryStaminaPercentage.Value - 0.38f) < 0.001f && Mathf.Abs(recoveryExertionPercentage.Value - 45f) < 0.001f) { exhaustedJogSeconds.Value = 5.5f; exhaustedJogSpeedMultiplier.Value = 0.88f; recoveryStaminaPercentage.Value = 0.28f; recoveryExertionPercentage.Value = 55f; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated the exhausted-sprint recovery defaults to the ground-floor escape safety values."); } } private void InstallPatches() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_014f: Expected O, but got Unknown //IL_014f: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown harmony = new Harmony("com.marccunningham.survivalmovementexertion"); setControlsPatchInstalled = TryPatch(FindMethod(typeof(Player), "SetControls", null), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerSetControlsPrefix", (Type[])null), null, null, "Player.SetControls(...)"); jogSpeedPatchInstalled = TryPatch(FindMethod(typeof(Player), "GetJogSpeedFactor", Type.EmptyTypes), null, new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerGetJogSpeedFactorPostfix", (Type[])null), null, "Player.GetJogSpeedFactor()"); runSpeedPatchInstalled = TryPatch(FindMethod(typeof(Player), "GetRunSpeedFactor", Type.EmptyTypes), null, new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerGetRunSpeedFactorPostfix", (Type[])null), null, "Player.GetRunSpeedFactor()"); checkRunPatchInstalled = TryPatch(FindMethod(typeof(Player), "CheckRun", new Type[2] { typeof(Vector3), typeof(float) }), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunPrefix", (Type[])null), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunPostfix", (Type[])null), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunFinalizer", (Type[])null), "Player.CheckRun(Vector3, float)"); HarmonyMethod val = new HarmonyMethod(typeof(SurvivalMovementPatches), "GameCameraGetCameraPositionPostfix", (Type[])null); val.priority = 0; val.after = new string[1] { "com.marccunningham.survivalview" }; cameraPositionPatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "GetCameraPosition", new Type[3] { typeof(float), typeof(Vector3).MakeByRefType(), typeof(Quaternion).MakeByRefType() }), null, val, null, "GameCamera.GetCameraPosition(float, out Vector3, out Quaternion)"); depthOfFieldPatchInstalled = TryPatch(FindMethod(typeof(CameraEffects), "UpdateDOF", Type.EmptyTypes), null, new HarmonyMethod(typeof(SurvivalMovementPatches), "CameraEffectsUpdateDofPostfix", (Type[])null), null, "CameraEffects.UpdateDOF()"); } private bool TryPatch(MethodInfo target, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod finalizer, string targetName) { if (target == null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Realistic Running: could not find " + targetName + ". That feature is disabled.")); return false; } try { harmony.Patch((MethodBase)target, prefix, postfix, (HarmonyMethod)null, finalizer, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Realistic Running: patched " + targetName + ".")); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Realistic Running: failed to patch " + targetName + ": " + ex)); return false; } } private static MethodInfo FindMethod(Type type, string methodName, Type[] parameterTypes) { if (parameterTypes != null) { return type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { if (methods[i].Name == methodName) { return methods[i]; } } return null; } private bool IsMovementEligible(Player player) { return modEnabled.Value && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsAttached() && !((Character)player).IsSwimming() && !((Character)player).IsFlying(); } private void ResetTransientMovementState() { smoothedInputMagnitude = Mathf.MoveTowards(smoothedInputMagnitude, 0f, Time.deltaTime * 5f); sprintBuild = Mathf.MoveTowards(sprintBuild, 0f, Time.deltaTime * 4f); exertion = Mathf.MoveTowards(exertion, 0f, Time.deltaTime * Mathf.Max(0f, exertionRecoveryPerSecond.Value)); exhaustedJogRemaining = 0f; fatigueRecoveryActive = false; wasSprinting = false; lastRunDrainMultiplier = 1f; smoothedCameraSwayVertical = 0f; smoothedCameraSwaySide = 0f; cameraSwayVerticalVelocity = 0f; cameraSwaySideVelocity = 0f; latestCameraDistance = float.MaxValue; latestCameraMinimumDistance = float.MaxValue; smoothedSprintFovBoost = 0f; sprintFovBoostVelocity = 0f; if ((Object)(object)Camera.main != (Object)null && baseCameraFieldOfView > 0f) { Camera.main.fieldOfView = baseCameraFieldOfView; } baseCameraFieldOfView = -1f; heartbeatCurrentPressure = 0f; heartbeatPressureVelocity = 0f; heartbeatCurrentBpm = 0f; heartbeatNextBeatTime = Time.unscaledTime + 0.1f; StopHeartbeatAudio(); ResetWorldFactors(); } private void ResetWorldFactors() { terrainSpeedMultiplier = 1f; terrainDrainMultiplier = 1f; terrainExertionMultiplier = 1f; weatherSpeedMultiplier = 1f; weatherDrainMultiplier = 1f; weatherExertionMultiplier = 1f; weatherRecoveryMultiplier = 1f; injurySpeedMultiplier = 1f; injuryExertionMultiplier = 1f; cachedSlopeAngle = 0f; cachedWet = false; cachedCold = false; cachedFreezing = false; } private void RefreshWorldFactors(Player player) { UpdateTerrainFactors(player); UpdateWeatherFactors(player); UpdateInjuryCompatibility(player); } private void UpdateTerrainFactors(Player player) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) terrainSpeedMultiplier = 1f; terrainDrainMultiplier = 1f; terrainExertionMultiplier = 1f; cachedSlopeAngle = 0f; if (!enableHillEffects.Value || !((Character)player).IsOnGround()) { return; } Vector3 moveDir = ((Character)player).GetMoveDir(); moveDir.y = 0f; if (((Vector3)(ref moveDir)).sqrMagnitude <= 1.0000001E-06f) { return; } Vector3 lastGroundNormal = ((Character)player).GetLastGroundNormal(); if (((Vector3)(ref lastGroundNormal)).sqrMagnitude <= 0.01f) { return; } ((Vector3)(ref lastGroundNormal)).Normalize(); cachedSlopeAngle = Vector3.Angle(lastGroundNormal, Vector3.up); float num = Mathf.Clamp(hillGraceAngle.Value, 0f, 60f); float num2 = Mathf.Max(num + 0.01f, hillFullPenaltyAngle.Value); float num3 = Mathf.Clamp01((cachedSlopeAngle - num) / (num2 - num)); if (num3 <= 0f) { return; } Vector3 val = Vector3.ProjectOnPlane(Vector3.up, lastGroundNormal); if (!(((Vector3)(ref val)).sqrMagnitude <= 0.0001f)) { ((Vector3)(ref val)).Normalize(); float num4 = Vector3.Dot(((Vector3)(ref moveDir)).normalized, val); if (num4 > 0f) { float num5 = num3 * Mathf.Clamp01(num4); terrainSpeedMultiplier = 1f - Mathf.Clamp01(uphillSpeedPenalty.Value) * num5; terrainDrainMultiplier = Mathf.Lerp(1f, Mathf.Max(1f, uphillDrainMultiplier.Value), num5); terrainExertionMultiplier = Mathf.Lerp(1f, Mathf.Max(1f, uphillExertionMultiplier.Value), num5); } else if (num4 < 0f) { float num6 = num3 * Mathf.Clamp01(0f - num4); terrainSpeedMultiplier = 1f + Mathf.Clamp(downhillSpeedBonus.Value, 0f, 0.15f) * num6; terrainDrainMultiplier = Mathf.Lerp(1f, Mathf.Clamp(1f - downhillDrainReduction.Value, 0.65f, 1f), num6); } } } private void UpdateWeatherFactors(Player player) { weatherSpeedMultiplier = 1f; weatherDrainMultiplier = 1f; weatherExertionMultiplier = 1f; weatherRecoveryMultiplier = 1f; cachedWet = false; cachedCold = false; cachedFreezing = false; if (enableWeatherEffects.Value) { SEMan sEMan = ((Character)player).GetSEMan(); bool flag = sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectWet); cachedWet = flag || EnvMan.IsWet(); cachedFreezing = EnvMan.IsFreezing(); cachedCold = !cachedFreezing && EnvMan.IsCold(); if (cachedWet) { weatherSpeedMultiplier *= Mathf.Clamp(wetSpeedMultiplier.Value, 0.7f, 1f); weatherDrainMultiplier *= Mathf.Max(1f, wetDrainMultiplier.Value); weatherExertionMultiplier *= Mathf.Max(1f, wetExertionMultiplier.Value); weatherRecoveryMultiplier *= 0.85f; } if (cachedFreezing) { weatherSpeedMultiplier *= Mathf.Clamp(freezingSpeedMultiplier.Value, 0.7f, 1f); weatherDrainMultiplier *= Mathf.Max(1f, freezingDrainMultiplier.Value); weatherExertionMultiplier *= Mathf.Max(1f, freezingExertionMultiplier.Value); weatherRecoveryMultiplier *= 0.72f; } else if (cachedCold) { weatherDrainMultiplier *= Mathf.Max(1f, coldDrainMultiplier.Value); weatherExertionMultiplier *= Mathf.Max(1f, coldExertionMultiplier.Value); weatherRecoveryMultiplier *= 0.88f; } } } private void UpdateInjuryCompatibility(Player player) { injurySpeedMultiplier = 1f; injuryExertionMultiplier = 1f; if (!enableInjuryCompatibility.Value) { return; } ResolveInjuryReflection(); if (!injuryReflectionUsable) { return; } try { object value = injuryInstanceField.GetValue(null); if (value != null && (bool)injuryIsActiveForMethod.Invoke(value, new object[1] { player })) { float num = Mathf.Clamp((float)injuryRunSpeedMultiplierMethod.Invoke(value, null), 0.3f, 1f); if (applyInjurySpeedCompatibilityPenalty.Value) { injurySpeedMultiplier = num; } float num2 = 1f - num; injuryExertionMultiplier = 1f + num2 * Mathf.Max(0f, injuryExertionPenaltyStrength.Value); } } catch { injuryReflectionUsable = false; injurySpeedMultiplier = 1f; injuryExertionMultiplier = 1f; } } private void ResolveInjuryReflection() { if (injuryReflectionUsable) { return; } if (injuryPluginType == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("YoureInjured.YoureInjuredPlugin"); if (type != null) { injuryPluginType = type; break; } } } if (!(injuryPluginType == null)) { injuryInstanceField = injuryPluginType.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); injuryIsActiveForMethod = injuryPluginType.GetMethod("IsActiveFor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Player) }, null); injuryRunSpeedMultiplierMethod = injuryPluginType.GetMethod("GetRunSpeedMultiplier", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); injuryReflectionUsable = injuryInstanceField != null && injuryIsActiveForMethod != null && injuryRunSpeedMultiplierMethod != null; } } private void TryLoadHeartbeatAudio() { if (!enableExhaustionHeartbeat.Value) { heartbeatStatus = "disabled in config"; return; } try { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); if (string.IsNullOrEmpty(directoryName)) { heartbeatStatus = "plugin folder could not be resolved"; return; } string[] array = new string[4] { Path.Combine(directoryName, "assets", "heartbeat_double.wav"), Path.Combine(directoryName, "heartbeat_double.wav"), Path.Combine(directoryName, "assets", "untitled.wav"), Path.Combine(directoryName, "untitled.wav") }; string text = null; for (int i = 0; i < array.Length; i++) { if (File.Exists(array[i])) { text = array[i]; break; } } if (string.IsNullOrEmpty(text)) { heartbeatStatus = "missing assets/heartbeat_double.wav"; return; } if (!TryReadWaveFile(text, out var samples, out var channels, out var sampleRate, out var status)) { heartbeatStatus = "could not decode WAV: " + status; return; } Type type = FindLoadedType("UnityEngine.AudioClip"); Type type2 = FindLoadedType("UnityEngine.AudioSource"); if (type == null || type2 == null) { heartbeatStatus = "Unity audio types were unavailable"; return; } MethodInfo method = type.GetMethod("Create", BindingFlags.Static | BindingFlags.Public, null, new Type[5] { typeof(string), typeof(int), typeof(int), typeof(int), typeof(bool) }, null); MethodInfo method2 = type.GetMethod("SetData", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(float[]), typeof(int) }, null); if (method == null || method2 == null) { heartbeatStatus = "Unity AudioClip methods were unavailable"; return; } int num = samples.Length / Mathf.Max(1, channels); object obj = method.Invoke(null, new object[5] { "SurvivalMovementExertion_Heartbeat", num, channels, sampleRate, false }); if (obj == null) { heartbeatStatus = "Unity could not create the heartbeat clip"; return; } if (!(bool)method2.Invoke(obj, new object[2] { samples, 0 })) { Object.Destroy((Object)((obj is Object) ? obj : null)); heartbeatStatus = "Unity rejected the heartbeat sample data"; return; } Component val = ((Component)this).gameObject.AddComponent(type2); if ((Object)(object)val == (Object)null) { Object.Destroy((Object)((obj is Object) ? obj : null)); heartbeatStatus = "Unity could not create the heartbeat audio source"; return; } SetNumericProperty(type2, val, "spatialBlend", 0f); SetBooleanProperty(type2, val, "loop", value: false); SetBooleanProperty(type2, val, "playOnAwake", value: false); SetNumericProperty(type2, val, "volume", 1f); MethodInfo method3 = type2.GetMethod("PlayOneShot", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { type, typeof(float) }, null); MethodInfo method4 = type2.GetMethod("Stop", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); if (method3 == null) { Object.Destroy((Object)(object)val); Object.Destroy((Object)((obj is Object) ? obj : null)); heartbeatStatus = "Unity AudioSource.PlayOneShot was unavailable"; return; } heartbeatAudioSource = val; heartbeatClip = (Object)((obj is Object) ? obj : null); heartbeatPlayOneShotMethod = method3; heartbeatStopMethod = method4; heartbeatAssetPath = text; heartbeatNextBeatTime = Time.unscaledTime + 0.2f; heartbeatStatus = "ready " + sampleRate + " Hz, " + channels + " channel(s), " + num + " frames"; } catch (Exception ex) { heartbeatStatus = "load exception: " + ex.GetType().Name; } } private void UpdateHeartbeatAudio(Player player) { if (!enableExhaustionHeartbeat.Value || (Object)(object)heartbeatAudioSource == (Object)null || heartbeatClip == (Object)null || heartbeatPlayOneShotMethod == null) { return; } float heartbeatPressure = GetHeartbeatPressure(player); float num = Mathf.Max(0.05f, heartbeatIntensitySmoothingSeconds.Value); heartbeatCurrentPressure = Mathf.SmoothDamp(heartbeatCurrentPressure, heartbeatPressure, ref heartbeatPressureVelocity, num, float.PositiveInfinity, Time.deltaTime); if (heartbeatCurrentPressure <= 0.002f) { heartbeatCurrentBpm = 0f; heartbeatNextBeatTime = Time.unscaledTime + 0.1f; return; } float num2 = Mathf.Clamp(heartbeatRecoveryBpm.Value, 45f, 120f); float num3 = Mathf.Clamp(heartbeatMaximumBpm.Value, num2 + 1f, 180f); heartbeatCurrentBpm = Mathf.Lerp(num2, num3, SmoothStep01(heartbeatCurrentPressure)); float num4 = 60f / Mathf.Max(1f, heartbeatCurrentBpm); if (Time.unscaledTime < heartbeatNextBeatTime) { return; } float num5 = Mathf.Clamp01(heartbeatMaximumVolume.Value) * Mathf.Lerp(0.26f, 1f, heartbeatCurrentPressure); try { heartbeatPlayOneShotMethod.Invoke(heartbeatAudioSource, new object[2] { heartbeatClip, num5 }); heartbeatNextBeatTime = Time.unscaledTime + num4; } catch (Exception ex) { heartbeatStatus = "playback exception: " + ex.GetType().Name; heartbeatNextBeatTime = Time.unscaledTime + 1f; } } private float GetHeartbeatPressure(Player player) { if (!IsMovementEligible(player)) { return 0f; } float num = Mathf.Clamp(tunnelVisionStartExertion.Value, 0f, 95f); float num2 = Mathf.Clamp(tunnelVisionFullExertion.Value, num + 0.1f, 100f); float num3 = SmoothStep01(Mathf.InverseLerp(num, num2, exertion)); float num4 = Mathf.Clamp01(((Character)player).GetStaminaPercentage()); float num5 = 1f - Mathf.InverseLerp(0.08f, 0.52f, num4); float num6 = Mathf.Max(num3, num5 * 0.7f); if (fatigueRecoveryActive) { float num7 = Mathf.Max(0.1f, exhaustedJogSeconds.Value); float num8 = Mathf.Clamp01(exhaustedJogRemaining / num7); float num9 = Mathf.Lerp(0.34f, 1f, num8); num6 = Mathf.Max(num6, num9); } float num10 = Mathf.Clamp01(heartbeatStartPressure.Value); return SmoothStep01(Mathf.InverseLerp(num10, 1f, num6)); } private void StopHeartbeatAudio() { if ((Object)(object)heartbeatAudioSource == (Object)null || heartbeatStopMethod == null) { return; } try { heartbeatStopMethod.Invoke(heartbeatAudioSource, null); } catch { } } private static Type FindLoadedType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType(fullName, throwOnError: false); if (type != null) { return type; } } return null; } private static void SetNumericProperty(Type type, object instance, string name, float value) { PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(instance, value, null); } } private static void SetBooleanProperty(Type type, object instance, string name, bool value) { PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(instance, value, null); } } private static bool TryReadWaveFile(string path, out float[] samples, out int channels, out int sampleRate, out string status) { samples = null; channels = 0; sampleRate = 0; status = "unknown error"; try { byte[] array = File.ReadAllBytes(path); if (array.Length < 44 || ReadAscii(array, 0, 4) != "RIFF" || ReadAscii(array, 8, 4) != "WAVE") { status = "not a RIFF/WAVE file"; return false; } int num = 0; int num2 = 0; int num3 = -1; int num4 = 0; int num5 = 12; while (num5 + 8 <= array.Length) { string text = ReadAscii(array, num5, 4); int num6 = ReadInt32LittleEndian(array, num5 + 4); int num7 = num5 + 8; if (num6 < 0 || num7 + num6 > array.Length) { status = "invalid WAV chunk length"; return false; } if (text == "fmt " && num6 >= 16) { num = ReadUInt16LittleEndian(array, num7); channels = ReadUInt16LittleEndian(array, num7 + 2); sampleRate = ReadInt32LittleEndian(array, num7 + 4); num2 = ReadUInt16LittleEndian(array, num7 + 14); } else if (text == "data") { num3 = num7; num4 = num6; } num5 = num7 + num6 + num6 % 2; } if (channels < 1 || channels > 2 || sampleRate < 8000 || num3 < 0 || num4 <= 0) { status = "missing supported WAV format or data chunk"; return false; } if (num != 1 && num != 3) { status = "unsupported WAV encoding " + num; return false; } int num8 = num2 / 8; if (num8 < 1 || num8 > 4 || num4 % (channels * num8) != 0) { status = "unsupported sample layout"; return false; } int num9 = num4 / num8; samples = new float[num9]; int num10 = num3; for (int i = 0; i < num9; i++) { if (num == 3 && num2 == 32) { samples[i] = BitConverter.ToSingle(array, num10); } else { switch (num2) { case 8: samples[i] = (float)(array[num10] - 128) / 128f; break; case 16: samples[i] = (float)(short)ReadUInt16LittleEndian(array, num10) / 32768f; break; case 24: { int num11 = array[num10] | (array[num10 + 1] << 8) | (array[num10 + 2] << 16); if ((num11 & 0x800000) != 0) { num11 |= -16777216; } samples[i] = (float)num11 / 8388608f; break; } case 32: samples[i] = (float)ReadInt32LittleEndian(array, num10) / 2.1474836E+09f; break; default: status = "unsupported bit depth " + num2; samples = null; return false; } } num10 += num8; } status = "decoded"; return true; } catch (Exception ex) { status = ex.GetType().Name; samples = null; return false; } } private static string ReadAscii(byte[] bytes, int start, int length) { char[] array = new char[length]; for (int i = 0; i < length; i++) { array[i] = (char)bytes[start + i]; } return new string(array); } private static int ReadInt32LittleEndian(byte[] bytes, int start) { return bytes[start] | (bytes[start + 1] << 8) | (bytes[start + 2] << 16) | (bytes[start + 3] << 24); } private static int ReadUInt16LittleEndian(byte[] bytes, int start) { return bytes[start] | (bytes[start + 1] << 8); } private void UpdateExertion(Player player) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) Vector3 moveDir = ((Character)player).GetMoveDir(); moveDir.y = 0f; bool flag = ((Vector3)(ref moveDir)).sqrMagnitude > 1.0000001E-06f; bool flag2 = ((Character)player).IsRunning() && flag && !ShouldForceExhaustedJog(player); float deltaTime = Time.deltaTime; if (flag2) { float exertionGainMultiplier = SurvivalMovementExertionBridge.GetExertionGainMultiplier(player); float num = terrainExertionMultiplier * weatherExertionMultiplier * injuryExertionMultiplier * exertionGainMultiplier; exertion = Mathf.Clamp(exertion + Mathf.Max(0f, exertionGainPerSecond.Value) * num * deltaTime, 0f, 100f); sprintBuild = Mathf.MoveTowards(sprintBuild, 1f, deltaTime / Mathf.Max(0.01f, sprintBuildUpSeconds.Value)); } else { float num2 = Mathf.Max(0f, exertionRecoveryPerSecond.Value) * weatherRecoveryMultiplier * SurvivalMovementExertionBridge.GetRecoveryMultiplier(player); if (!flag) { num2 *= Mathf.Max(1f, stationaryRecoveryMultiplier.Value); } exertion = Mathf.MoveTowards(exertion, 0f, num2 * deltaTime); sprintBuild = Mathf.MoveTowards(sprintBuild, 0f, deltaTime / Mathf.Max(0.01f, sprintBuildRecoverySeconds.Value)); } float num3 = Mathf.Clamp01(((Character)player).GetStaminaPercentage()); float num4 = Mathf.Clamp(exhaustionTriggerStaminaPercentage.Value, 0f, 0.25f); if ((flag2 || wasSprinting || sprintBuild > 0.2f) && num3 <= num4) { fatigueRecoveryActive = true; exhaustedJogRemaining = Mathf.Max(exhaustedJogRemaining, Mathf.Max(0f, exhaustedJogSeconds.Value)); } if (exhaustedJogRemaining > 0f) { exhaustedJogRemaining = Mathf.Max(0f, exhaustedJogRemaining - deltaTime); } if (fatigueRecoveryActive && exhaustedJogRemaining <= 0f) { float num5 = Mathf.Clamp(recoveryStaminaPercentage.Value, 0.05f, 1f); float num6 = Mathf.Clamp(recoveryExertionPercentage.Value, 0f, 100f); if (num3 >= num5 && exertion <= num6) { fatigueRecoveryActive = false; } } wasSprinting = flag2; } internal void RecordSetControlsHook() { setControlsHookCalls++; } internal void RecordJogSpeedHook() { jogSpeedHookCalls++; } internal void RecordRunSpeedHook() { runSpeedHookCalls++; } internal void RecordCheckRunHook() { checkRunHookCalls++; } internal void RecordCameraHook() { cameraHookCalls++; } internal Vector3 SmoothMoveInput(Player player, Vector3 rawMoveDirection) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (!IsMovementEligible(player) || !enableInputSmoothing.Value) { return rawMoveDirection; } float num = Mathf.Clamp01(((Vector3)(ref rawMoveDirection)).magnitude); float num2 = ((num > smoothedInputMagnitude) ? Mathf.Max(0.01f, accelerationSeconds.Value) : Mathf.Max(0.01f, decelerationSeconds.Value)); smoothedInputMagnitude = Mathf.MoveTowards(smoothedInputMagnitude, num, Time.deltaTime / num2); if (num <= 0.001f) { return Vector3.zero; } return ((Vector3)(ref rawMoveDirection)).normalized * Mathf.Clamp01(smoothedInputMagnitude); } internal float GetJogSpeedMultiplier(Player player) { if (!IsMovementEligible(player)) { return 1f; } float directionalSpeedMultiplier = GetDirectionalSpeedMultiplier(player); directionalSpeedMultiplier *= GetWorldMovementMultiplier(player); if (ShouldForceExhaustedJog(player)) { directionalSpeedMultiplier *= Mathf.Clamp(exhaustedJogSpeedMultiplier.Value, 0.35f, 1f); } return Mathf.Clamp(directionalSpeedMultiplier, 0.2f, 1.35f); } internal float GetRunSpeedMultiplier(Player player) { if (!IsMovementEligible(player)) { return 1f; } if (ShouldForceExhaustedJog(player)) { return GetJogSpeedMultiplier(player); } float num = Mathf.Clamp(topSprintSpeedMultiplier.Value, 0.8f, 1.65f); float num2 = Mathf.Clamp(sprintStartSpeedFraction.Value, 0.35f, 1f); float num3 = Mathf.Lerp(num * num2, num, Mathf.Clamp01(sprintBuild)); float num4 = Mathf.Lerp(1f, Mathf.Clamp(highExertionRunSpeedMultiplier.Value, 0.5f, 1f), GetHighExertionFraction()); float directionalSpeedMultiplier = GetDirectionalSpeedMultiplier(player); directionalSpeedMultiplier *= num3; directionalSpeedMultiplier *= num4; directionalSpeedMultiplier *= GetWorldMovementMultiplier(player); return Mathf.Clamp(directionalSpeedMultiplier, 0.2f, 1.65f); } private float GetWorldMovementMultiplier(Player player) { float num = terrainSpeedMultiplier * weatherSpeedMultiplier * injurySpeedMultiplier; num *= SurvivalMovementExertionBridge.GetMovementMultiplier(player); return Mathf.Clamp(num, 0.2f, 1.35f); } internal bool PrepareCheckRun(Player player, ref float nativeRunStaminaDrain, ref bool result, ref RunDrainPatchState state) { state = default(RunDrainPatchState); RecordCheckRunHook(); if (!IsMovementEligible(player)) { return true; } if (ShouldForceExhaustedJog(player)) { result = false; return false; } state.RestoreDrain = true; state.OriginalDrain = nativeRunStaminaDrain; nativeRunStaminaDrain *= GetRunStaminaDrainMultiplier(player); return true; } internal void RestoreCheckRunDrain(ref float nativeRunStaminaDrain, RunDrainPatchState state) { if (state.RestoreDrain) { nativeRunStaminaDrain = state.OriginalDrain; } } private float GetRunStaminaDrainMultiplier(Player player) { float num = Mathf.Clamp(baseRunStaminaDrainMultiplier.Value, 0.02f, 2f); float num2 = Mathf.Lerp(1f, Mathf.Clamp(highExertionDrainMultiplier.Value, 1f, 4f), GetHighExertionFraction()); float runDrainMultiplier = SurvivalMovementExertionBridge.GetRunDrainMultiplier(player); lastRunDrainMultiplier = num * num2 * terrainDrainMultiplier * weatherDrainMultiplier * runDrainMultiplier; float num3 = Mathf.Clamp(maximumCombinedRunDrainMultiplier.Value, 0.25f, 8f); return Mathf.Clamp(lastRunDrainMultiplier, 0.01f, num3); } private bool ShouldForceExhaustedJog(Player player) { if (!IsMovementEligible(player) || !fatigueRecoveryActive) { return false; } if (exhaustedJogRemaining > 0f) { return true; } float num = Mathf.Clamp(emergencySprintReleaseStaminaPercentage.Value, 0.05f, 0.6f); return ((Character)player).GetStaminaPercentage() < num; } private float GetDirectionalSpeedMultiplier(Player player) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_006e: Unknown result type (might be due to invalid IL or missing references) Vector3 moveDir = ((Character)player).GetMoveDir(); moveDir.y = 0f; if (((Vector3)(ref moveDir)).sqrMagnitude <= 1.0000001E-06f) { return 1f; } Vector3 val = ((Component)player).transform.InverseTransformDirection(((Vector3)(ref moveDir)).normalized); float num = Mathf.Max(0f, val.z); float num2 = Mathf.Max(0f, 0f - val.z); float num3 = Mathf.Abs(val.x); float num4 = num + num2 + num3; if (num4 <= 0.001f) { return 1f; } float num5 = Mathf.Clamp(backwardSpeedMultiplier.Value, 0.35f, 1f); float num6 = Mathf.Clamp(sidewaysSpeedMultiplier.Value, 0.35f, 1f); float num7 = num * 1f + num2 * num5 + num3 * num6; return num7 / num4; } private float GetHighExertionFraction() { float num = Mathf.Clamp(highExertionStart.Value, 1f, 99f); return Mathf.Clamp01((exertion - num) / (100f - num)); } private float GetVisualIntensity(Player player) { if (!IsMovementEligible(player)) { return 0f; } float num = Mathf.Clamp(tunnelVisionStartExertion.Value, 0f, 95f); float num2 = Mathf.Clamp(tunnelVisionFullExertion.Value, num + 0.1f, 100f); float value = Mathf.InverseLerp(num, num2, exertion); float num3 = SmoothStep01(value); float num4 = Mathf.Clamp01(((Character)player).GetStaminaPercentage()); float num5 = 1f - Mathf.InverseLerp(0.05f, 0.42f, num4); float num6 = (fatigueRecoveryActive ? 1f : 0f); return Mathf.Clamp01(Mathf.Max(new float[3] { num3, num5 * 0.6f, num6 * 0.96f })); } private static float SmoothStep01(float value) { value = Mathf.Clamp01(value); return value * value * (3f - 2f * value); } private void UpdateVisualMotion(Player player) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_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 (!enableCameraSway.Value || !IsMovementEligible(player)) { SmoothCameraSwayToward(0f, 0f); return; } Vector3 moveDir = ((Character)player).GetMoveDir(); moveDir.y = 0f; bool flag = ((Vector3)(ref moveDir)).sqrMagnitude > 1.0000001E-06f; float visualIntensity = GetVisualIntensity(player); Vector3 velocity = ((Character)player).GetVelocity(); velocity.y = 0f; float magnitude = ((Vector3)(ref velocity)).magnitude; float num = Mathf.Clamp01(magnitude / Mathf.Max(0.1f, 10f * Mathf.Max(1f, topSprintSpeedMultiplier.Value))); float num2 = ((((Character)player).IsRunning() && flag && !ShouldForceExhaustedJog(player)) ? Mathf.Clamp01(num * 0.65f + Mathf.Clamp01(sprintBuild) * 0.35f) : 0f); float num3 = Mathf.Lerp(Mathf.Clamp(sprintSwayFrequencyLow.Value, 0.2f, 4f), Mathf.Clamp(sprintSwayFrequencyHigh.Value, 0.2f, 4f), num2); float num4 = Mathf.Lerp(Mathf.Clamp(breathSwayFrequencyLow.Value, 0.05f, 1.5f), Mathf.Clamp(breathSwayFrequencyHigh.Value, 0.05f, 1.5f), visualIntensity); float num5 = Time.time * (float)Math.PI * 2f * num3; float num6 = Time.time * (float)Math.PI * 2f * num4; float num7 = Mathf.Sin(num5) * 0.66f + Mathf.Sin(num5 * 2f + 0.55f) * 0.09f; float num8 = Mathf.Sin(num5 * 0.5f + 0.35f); float num9 = Mathf.Sin(num6); float targetVertical = num7 * Mathf.Max(0f, sprintBobVerticalMeters.Value) * num2 + num9 * Mathf.Max(0f, fatigueBreathSwayMeters.Value) * visualIntensity; float targetSide = num8 * Mathf.Max(0f, sprintBobSideMeters.Value) * num2 * 0.85f; SmoothCameraSwayToward(targetVertical, targetSide); } private void SmoothCameraSwayToward(float targetVertical, float targetSide) { float num = Mathf.Max(0.03f, cameraSwaySmoothingSeconds.Value); smoothedCameraSwayVertical = Mathf.SmoothDamp(smoothedCameraSwayVertical, targetVertical, ref cameraSwayVerticalVelocity, num, float.PositiveInfinity, Time.deltaTime); smoothedCameraSwaySide = Mathf.SmoothDamp(smoothedCameraSwaySide, targetSide, ref cameraSwaySideVelocity, num, float.PositiveInfinity, Time.deltaTime); } internal void ApplyCameraSway(Player player, GameCamera camera, ref Vector3 position, float distance, float minimumDistance) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) RecordCameraHook(); latestCameraDistance = distance; latestCameraMinimumDistance = minimumDistance; ApplySprintFov(player, camera, distance, minimumDistance); if (enableCameraSway.Value && IsMovementEligible(player) && !((Object)(object)camera == (Object)null) && (!cameraSwayClosestZoomOnly.Value || !(distance > minimumDistance + Mathf.Max(0f, closestZoomTolerance.Value))) && (!(Mathf.Abs(smoothedCameraSwayVertical) <= 1E-05f) || !(Mathf.Abs(smoothedCameraSwaySide) <= 1E-05f))) { position += ((Component)camera).transform.right * smoothedCameraSwaySide; position += Vector3.up * smoothedCameraSwayVertical; } } private void ApplySprintFov(Player player, GameCamera camera, float distance, float minimumDistance) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if (!((Object)(object)main == (Object)null)) { if (baseCameraFieldOfView <= 0f) { baseCameraFieldOfView = main.fieldOfView; } float num = 0f; bool flag = !cameraSwayClosestZoomOnly.Value || distance <= minimumDistance + Mathf.Max(0f, closestZoomTolerance.Value); if (enableSprintFovBoost.Value && IsMovementEligible(player) && flag) { Vector3 velocity = ((Character)player).GetVelocity(); velocity.y = 0f; float magnitude = ((Vector3)(ref velocity)).magnitude; float value = Mathf.Clamp01(magnitude / Mathf.Max(0.1f, 10f * Mathf.Max(1f, topSprintSpeedMultiplier.Value))); float num2 = Mathf.Clamp01(sprintBuild); float num3 = 1f - Mathf.Clamp01(GetHighExertionFraction() * 0.85f + (fatigueRecoveryActive ? 0.25f : 0f)); num = Mathf.Max(0f, sprintFovBoostDegrees.Value) * SmoothStep01(value) * Mathf.Lerp(0.45f, 1f, num2) * num3; } float num4 = Mathf.Max(0.05f, sprintFovBoostSmoothingSeconds.Value); smoothedSprintFovBoost = Mathf.SmoothDamp(smoothedSprintFovBoost, num, ref sprintFovBoostVelocity, num4, float.PositiveInfinity, Time.deltaTime); main.fieldOfView = baseCameraFieldOfView + smoothedSprintFovBoost; } } private void DrawWindRush(Player player) { //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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) if (!enableWindRushStreaks.Value || !IsMovementEligible(player)) { return; } Vector3 moveDir = ((Character)player).GetMoveDir(); moveDir.y = 0f; if (!((Character)player).IsRunning() || ((Vector3)(ref moveDir)).sqrMagnitude <= 1.0000001E-06f || ShouldForceExhaustedJog(player)) { return; } float num = Mathf.Clamp(windRushStartSprintBuild.Value, 0f, 0.95f); float num2 = Mathf.InverseLerp(num, 1f, Mathf.Clamp01(sprintBuild)); if (num2 <= 0.005f) { return; } EnsureWindStreaks(); if (windStreaks == null || windStreaks.Length == 0) { return; } float num3 = Mathf.Lerp(1f, 0.66f, GetHighExertionFraction()); float num4 = Mathf.Clamp(windRushMaximumAlpha.Value, 0.05f, 0.65f) * num2 * num3; float num5 = Mathf.Max(0.1f, windRushTravelSpeed.Value); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor((float)Screen.width * 0.5f, (float)Screen.height * 0.5f); Matrix4x4 matrix = GUI.matrix; Color color = GUI.color; Vector2 val2 = default(Vector2); for (int i = 0; i < windStreaks.Length; i++) { WindStreak windStreak = windStreaks[i]; float num6 = Mathf.Repeat(Time.time * num5 * windStreak.Speed + windStreak.Phase, 1f); float num7 = SmoothStep01(num6); float num8 = SmoothStep01(Mathf.InverseLerp(0f, 0.13f, num6)); float num9 = 1f - SmoothStep01(Mathf.InverseLerp(0.68f, 1f, num6)); float num10 = num4 * windStreak.Alpha * num8 * num9; if (!(num10 <= 0.002f)) { float num11 = Mathf.Lerp(windStreak.InnerRadius, 1.18f, num7); ((Vector2)(ref val2))..ctor(Mathf.Cos(windStreak.AngleRadians), Mathf.Sin(windStreak.AngleRadians)); Vector2 val3 = val + new Vector2(val2.x * (float)Screen.width * 0.5f * num11, val2.y * (float)Screen.height * 0.5f * num11); float num12 = Mathf.Lerp(22f, (float)Mathf.Max(Screen.width, Screen.height) * windStreak.Length, num7); float num13 = Mathf.Lerp(0.8f, 2.2f, num7); float num14 = Mathf.Atan2(val2.y, val2.x) * 57.29578f; GUI.matrix = matrix; GUIUtility.RotateAroundPivot(num14, val3); GUI.color = new Color(0.7f, 0.84f, 0.96f, num10); GUI.DrawTexture(new Rect(val3.x, val3.y - num13 * 0.5f, num12, num13), (Texture)(object)Texture2D.whiteTexture); } } GUI.matrix = matrix; GUI.color = color; } private void EnsureWindStreaks() { int num = Mathf.Clamp(windRushStreakCount.Value, 4, 48); if (windStreaks == null || windStreaks.Length != num) { windStreaks = new WindStreak[num]; for (int i = 0; i < num; i++) { float num2 = PseudoRandom01(i + 11); float num3 = PseudoRandom01(i + 37); float phase = PseudoRandom01(i + 73); float num4 = PseudoRandom01(i + 101); float num5 = PseudoRandom01(i + 149); float num6 = (float)i / (float)num * (float)Math.PI * 2f; float angleRadians = num6 + Mathf.Lerp(-0.12f, 0.12f, num2); windStreaks[i] = new WindStreak(angleRadians, Mathf.Lerp(0.28f, 0.48f, num3), phase, Mathf.Lerp(0.72f, 1.4f, num4), Mathf.Lerp(0.055f, 0.16f, num5), Mathf.Lerp(0.4f, 1f, PseudoRandom01(i + 197))); } } } private static float PseudoRandom01(int value) { float num = Mathf.Sin((float)value * 12.9898f) * 43758.547f; return num - Mathf.Floor(num); } private void DrawPeripheralBlur(Player player) { //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) if (!enablePeripheralBlurOverlay.Value) { return; } float visualIntensity = GetVisualIntensity(player); float num = Mathf.Clamp01(peripheralBlurStartIntensity.Value); float value = Mathf.InverseLerp(num, 1f, visualIntensity); value = SmoothStep01(value); if (!(value <= 0.003f)) { EnsurePeripheralBlurTextures(); if (peripheralBlurTextures != null && peripheralBlurTextures.Length != 0) { int num2 = Mathf.Clamp(Mathf.RoundToInt(value * (float)(peripheralBlurTextures.Length - 1)), 0, peripheralBlurTextures.Length - 1); float num3 = Mathf.Clamp(peripheralBlurMaximumAlpha.Value, 0f, 0.45f) * Mathf.Lerp(0.12f, 1f, value); float num4 = Mathf.Lerp(0.18f, 0.42f, value); float num5 = 0.5f + 0.5f * Mathf.Sin(Time.time * (float)Math.PI * 2f * num4); num3 *= Mathf.Lerp(0.96f, 1.06f, num5); Color color = GUI.color; GUI.color = new Color(0.92f, 0.95f, 1f, Mathf.Clamp01(num3)); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)peripheralBlurTextures[num2]); GUI.color = color; } } } private void DrawTunnelVision(Player player) { //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) if (!enableTunnelVision.Value) { return; } float visualIntensity = GetVisualIntensity(player); if (!(visualIntensity <= 0.005f)) { EnsureTunnelTextures(); if (tunnelTextures != null && tunnelTextures.Length != 0) { float num = Mathf.Clamp01(tunnelVisionPulseStrength.Value) * visualIntensity; float num2 = Mathf.Lerp(0.2f, 0.48f, visualIntensity); float num3 = 0.5f + 0.5f * Mathf.Sin(Time.time * (float)Math.PI * 2f * num2); float num4 = (num3 - 0.5f) * num * 0.16f; float num5 = Mathf.Clamp01(visualIntensity + num4); int num6 = Mathf.Clamp(Mathf.RoundToInt(num5 * (float)(tunnelTextures.Length - 1)), 0, tunnelTextures.Length - 1); float num7 = Mathf.Clamp(maximumTunnelVisionAlpha.Value, 0f, 0.82f); float num8 = num7 * Mathf.Lerp(0.08f, 1f, visualIntensity); num8 *= Mathf.Lerp(1f - num * 0.1f, 1f + num * 0.1f, num3); Color color = GUI.color; GUI.color = new Color(1f, 1f, 1f, Mathf.Clamp01(num8)); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)tunnelTextures[num6]); GUI.color = color; } } } private void EnsurePeripheralBlurTextures() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Expected O, but got Unknown //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) if (peripheralBlurTextures != null) { return; } peripheralBlurTextures = (Texture2D[])(object)new Texture2D[18]; Color val = default(Color); Color val2 = default(Color); for (int i = 0; i < 18; i++) { float value = (float)i / 17f; float num = SmoothStep01(value); float num2 = Mathf.Clamp(peripheralBlurClearRadiusAtExhaustion.Value, 0.72f, 1.1f); float num3 = Mathf.Lerp(1.22f, num2, num); float num4 = Mathf.Lerp(0.68f, 0.6f, num); float num5 = Mathf.Max(0f, num3 - num4); ((Color)(ref val))..ctor(0.82f, 0.89f, 0.97f, 1f); ((Color)(ref val2))..ctor(0.34f, 0.42f, 0.52f, 1f); Color val3 = Color.Lerp(val, val2, num * 0.55f); Color[] array = (Color[])(object)new Color[25600]; for (int j = 0; j < 160; j++) { for (int k = 0; k < 160; k++) { float num6 = ((float)k / 159f - 0.5f) * 2f; float num7 = ((float)j / 159f - 0.5f) * 2f; float num8 = Mathf.Sqrt(num6 * num6 + num7 * 0.84f * (num7 * 0.84f)); float value2 = Mathf.Clamp01((num8 - num5) / Mathf.Max(0.001f, num3 - num5)); value2 = SmoothStep01(value2); value2 *= Mathf.Lerp(0.1f, 0.82f, num); array[j * 160 + k] = new Color(val3.r, val3.g, val3.b, value2); } } Texture2D val4 = new Texture2D(160, 160, (TextureFormat)4, false); ((Texture)val4).wrapMode = (TextureWrapMode)1; ((Texture)val4).filterMode = (FilterMode)1; val4.SetPixels(array); val4.Apply(); peripheralBlurTextures[i] = val4; } } private void EnsureTunnelTextures() { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) if (tunnelTextures != null) { return; } tunnelTextures = (Texture2D[])(object)new Texture2D[18]; Color val = default(Color); Color val2 = default(Color); for (int i = 0; i < 18; i++) { float value = (float)i / 17f; float num = SmoothStep01(value); float num2 = Mathf.Clamp(tunnelVisionClearRadiusAtExhaustion.Value, 0.55f, 1.1f); float num3 = Mathf.Lerp(1.2f, num2, num); float num4 = Mathf.Lerp(0.64f, 0.56f, num); float num5 = Mathf.Max(0f, num3 - num4); float num6 = Mathf.Clamp01(coolEdgeTintStrength.Value) * Mathf.Lerp(0.95f, 0.38f, num); ((Color)(ref val))..ctor(0.13f, 0.23f, 0.34f, 1f); ((Color)(ref val2))..ctor(0.015f, 0.025f, 0.05f, 1f); Color val3 = Color.Lerp(val2, val, num6); Color[] array = (Color[])(object)new Color[25600]; for (int j = 0; j < 160; j++) { for (int k = 0; k < 160; k++) { float num7 = ((float)k / 159f - 0.5f) * 2f; float num8 = ((float)j / 159f - 0.5f) * 2f; float num9 = Mathf.Sqrt(num7 * num7 + num8 * 0.84f * (num8 * 0.84f)); float value2 = Mathf.Clamp01((num9 - num5) / Mathf.Max(0.001f, num3 - num5)); value2 = SmoothStep01(value2); array[j * 160 + k] = new Color(val3.r, val3.g, val3.b, value2); } } Texture2D val4 = new Texture2D(160, 160, (TextureFormat)4, false); ((Texture)val4).wrapMode = (TextureWrapMode)1; ((Texture)val4).filterMode = (FilterMode)1; val4.SetPixels(array); val4.Apply(); tunnelTextures[i] = val4; } } internal void ApplyExhaustionDepthOfField(CameraEffects cameraEffects) { depthOfFieldHookCalls++; if (!enableNativeDepthOfField.Value || (Object)(object)cameraEffects == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; if (!IsMovementEligible(localPlayer) || (depthOfFieldClosestZoomOnly.Value && latestCameraDistance > latestCameraMinimumDistance + Mathf.Max(0f, closestZoomTolerance.Value))) { return; } float visualIntensity = GetVisualIntensity(localPlayer); float num = Mathf.Clamp(depthOfFieldStartVisualIntensity.Value, 0f, 0.95f); float value = Mathf.InverseLerp(num, 1f, visualIntensity); value = SmoothStep01(value); if (value <= 0.005f || !TryResolveDepthOfField(cameraEffects, out var dof)) { return; } Behaviour val = (Behaviour)((dof is Behaviour) ? dof : null); if ((Object)(object)val != (Object)null) { val.enabled = true; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { depthOfFieldStatus = "native DOF found, Camera.main unavailable"; return; } float depthOfFieldFocusDistance = GetDepthOfFieldFocusDistance(main, cameraEffects); float value2 = Mathf.Lerp(3.5f, Mathf.Clamp(depthOfFieldFocalSizeAtExhaustion.Value, 0.35f, 8f), value); float value3 = Mathf.Lerp(0.1f, Mathf.Clamp(depthOfFieldMaximumBlurSize.Value, 0.1f, 1.25f), value); bool flag = false; flag |= TrySetNumericMember(dof, dofFocusDistanceMember, depthOfFieldFocusDistance); flag |= TrySetNumericMember(dof, dofFocalSizeMember, value2); flag |= TrySetNumericMember(dof, dofMaxBlurSizeMember, value3); if (dofApertureMember != null) { flag |= TrySetNumericMember(dof, dofApertureMember, Mathf.Lerp(4.2f, 2.6f, value)); } depthOfFieldStatus = (flag ? ("active " + dof.GetType().FullName) : "native DOF found but recognised focus members were unavailable"); } private bool TryResolveDepthOfField(CameraEffects cameraEffects, out object dof) { dof = null; if (cameraEffectsDofField == null) { cameraEffectsDofField = typeof(CameraEffects).GetField("m_dof", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); cameraEffectsDofRayMaskField = typeof(CameraEffects).GetField("m_dofRayMask", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (cameraEffectsDofField == null) { depthOfFieldStatus = "CameraEffects.m_dof not found"; return false; } dof = cameraEffectsDofField.GetValue(cameraEffects); if (dof == null) { depthOfFieldStatus = "CameraEffects.m_dof is null"; return false; } if (!depthOfFieldReflectionReady) { Type type = dof.GetType(); dofFocusDistanceMember = FindNumericMember(type, new string[3] { "focusDistance", "focalDistance", "objectFocus" }); dofFocalSizeMember = FindNumericMember(type, new string[2] { "focalSize", "focusRange" }); dofMaxBlurSizeMember = FindNumericMember(type, new string[2] { "maxBlurSize", "blurSize" }); dofApertureMember = FindNumericMember(type, new string[1] { "aperture" }); depthOfFieldReflectionReady = true; depthOfFieldAvailable = dofFocusDistanceMember != null || dofFocalSizeMember != null || dofMaxBlurSizeMember != null; depthOfFieldStatus = (depthOfFieldAvailable ? ("native DOF members resolved on " + type.FullName) : "native DOF component found but no supported members resolved"); } return depthOfFieldAvailable; } private static MemberInfo FindNumericMember(Type type, string[] candidateNames) { for (int i = 0; i < candidateNames.Length; i++) { FieldInfo field = type.GetField(candidateNames[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(float)) { return field; } PropertyInfo property = type.GetProperty(candidateNames[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite && property.PropertyType == typeof(float)) { return property; } } return null; } private static bool TrySetNumericMember(object target, MemberInfo member, float value) { if (target == null || member == null) { return false; } try { FieldInfo fieldInfo = member as FieldInfo; if (fieldInfo != null) { fieldInfo.SetValue(target, value); return true; } PropertyInfo propertyInfo = member as PropertyInfo; if (propertyInfo != null) { propertyInfo.SetValue(target, value, null); return true; } } catch { return false; } return false; } private float GetDepthOfFieldFocusDistance(Camera viewCamera, CameraEffects cameraEffects) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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) float num = Mathf.Max(1f, depthOfFieldMaximumFocusDistance.Value); float result = Mathf.Clamp(depthOfFieldFallbackFocusDistance.Value, 1f, num); int num2 = -1; if (cameraEffectsDofRayMaskField != null) { try { object value = cameraEffectsDofRayMaskField.GetValue(cameraEffects); if (value is LayerMask val) { num2 = ((LayerMask)(ref val)).value; } else if (value != null) { num2 = Convert.ToInt32(value); } } catch { num2 = -1; } } RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(((Component)viewCamera).transform.position, ((Component)viewCamera).transform.forward, ref val2, num, num2)) { return Mathf.Clamp(((RaycastHit)(ref val2)).distance, 1f, num); } return result; } private void DestroyTunnelTextures() { if (tunnelTextures == null) { return; } for (int i = 0; i < tunnelTextures.Length; i++) { if ((Object)(object)tunnelTextures[i] != (Object)null) { Object.Destroy((Object)(object)tunnelTextures[i]); } } tunnelTextures = null; } private void DestroyPeripheralBlurTextures() { if (peripheralBlurTextures == null) { return; } for (int i = 0; i < peripheralBlurTextures.Length; i++) { if ((Object)(object)peripheralBlurTextures[i] != (Object)null) { Object.Destroy((Object)(object)peripheralBlurTextures[i]); } } peripheralBlurTextures = null; } private void DrawDiagnosticHud(Player player) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (showDiagnosticHud.Value) { if (diagnosticStyle == null) { diagnosticStyle = new GUIStyle(GUI.skin.label); diagnosticStyle.fontSize = 15; diagnosticStyle.normal.textColor = Color.white; } GUI.Label(new Rect(12f, 12f, 840f, 44f), "EXERTION " + exertion.ToString("0") + "% | Sprint build " + sprintBuild.ToString("0.00") + " | Fatigue " + fatigueRecoveryActive + " | Slope " + cachedSlopeAngle.ToString("0") + "° | Wet " + cachedWet + " Cold " + cachedCold + " Freezing " + cachedFreezing + " | Run drain x" + lastRunDrainMultiplier.ToString("0.00"), diagnosticStyle); } } private void WriteDiagnostic() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: no local player is available yet."); return; } Vector3 val = ((Character)localPlayer).GetVelocity(); float magnitude = ((Vector3)(ref val)).magnitude; float directionalSpeedMultiplier = GetDirectionalSpeedMultiplier(localPlayer); float worldMovementMultiplier = GetWorldMovementMultiplier(localPlayer); float jogSpeedMultiplier = GetJogSpeedMultiplier(localPlayer); float runSpeedMultiplier = GetRunSpeedMultiplier(localPlayer); float visualIntensity = GetVisualIntensity(localPlayer); float highExertionFraction = GetHighExertionFraction(); ManualLogSource logger = ((BaseUnityPlugin)this).Logger; string[] array = new string[103]; array[0] = "Realistic Running diagnostic: enabled="; array[1] = modEnabled.Value.ToString(); array[2] = ", running="; array[3] = ((Character)localPlayer).IsRunning().ToString(); array[4] = ", moving="; val = ((Character)localPlayer).GetMoveDir(); array[5] = (((Vector3)(ref val)).sqrMagnitude > 1.0000001E-06f).ToString(); array[6] = ", stamina="; array[7] = ((Character)localPlayer).GetStaminaPercentage().ToString("0.000"); array[8] = ", exertion="; array[9] = exertion.ToString("0.0"); array[10] = ", visualIntensity="; array[11] = GetVisualIntensity(localPlayer).ToString("0.00"); array[12] = ", sprintBuild="; array[13] = sprintBuild.ToString("0.00"); array[14] = ", exhaustedJogRemaining="; array[15] = exhaustedJogRemaining.ToString("0.00"); array[16] = ", fatigueRecovery="; array[17] = fatigueRecoveryActive.ToString(); array[18] = ", runDrainMultiplier="; array[19] = lastRunDrainMultiplier.ToString("0.000"); array[20] = ", actualVelocity="; array[21] = magnitude.ToString("0.00"); array[22] = ", multipliers=[direction="; array[23] = directionalSpeedMultiplier.ToString("0.000"); array[24] = ", world="; array[25] = worldMovementMultiplier.ToString("0.000"); array[26] = ", jog="; array[27] = jogSpeedMultiplier.ToString("0.000"); array[28] = ", run="; array[29] = runSpeedMultiplier.ToString("0.000"); array[30] = "], visual=[intensity="; array[31] = visualIntensity.ToString("0.000"); array[32] = ", highExertion="; array[33] = highExertionFraction.ToString("0.000"); array[34] = ", swayVertical="; array[35] = smoothedCameraSwayVertical.ToString("0.0000"); array[36] = ", swaySide="; array[37] = smoothedCameraSwaySide.ToString("0.0000"); array[38] = ", fovBoost="; array[39] = smoothedSprintFovBoost.ToString("0.00"); array[40] = "], nativeDof=[available="; array[41] = depthOfFieldAvailable.ToString(); array[42] = ", status="; array[43] = depthOfFieldStatus; array[44] = "], heartbeat=[status="; array[45] = heartbeatStatus; array[46] = ", pressure="; array[47] = heartbeatCurrentPressure.ToString("0.00"); array[48] = ", bpm="; array[49] = heartbeatCurrentBpm.ToString("0"); array[50] = ", asset="; array[51] = heartbeatAssetPath; array[52] = "], slopeAngle="; array[53] = cachedSlopeAngle.ToString("0.0"); array[54] = ", terrain=[speed="; array[55] = terrainSpeedMultiplier.ToString("0.00"); array[56] = ", drain="; array[57] = terrainDrainMultiplier.ToString("0.00"); array[58] = ", exertion="; array[59] = terrainExertionMultiplier.ToString("0.00"); array[60] = "], weather=[wet="; array[61] = cachedWet.ToString(); array[62] = ", cold="; array[63] = cachedCold.ToString(); array[64] = ", freezing="; array[65] = cachedFreezing.ToString(); array[66] = ", speed="; array[67] = weatherSpeedMultiplier.ToString("0.00"); array[68] = ", drain="; array[69] = weatherDrainMultiplier.ToString("0.00"); array[70] = ", exertion="; array[71] = weatherExertionMultiplier.ToString("0.00"); array[72] = "], injury=[available="; array[73] = injuryReflectionUsable.ToString(); array[74] = ", speed="; array[75] = injurySpeedMultiplier.ToString("0.00"); array[76] = ", exertion="; array[77] = injuryExertionMultiplier.ToString("0.00"); array[78] = "], hookCalls=[controls="; array[79] = setControlsHookCalls.ToString(); array[80] = ", jog="; array[81] = jogSpeedHookCalls.ToString(); array[82] = ", run="; array[83] = runSpeedHookCalls.ToString(); array[84] = ", checkRun="; array[85] = checkRunHookCalls.ToString(); array[86] = ", camera="; array[87] = cameraHookCalls.ToString(); array[88] = ", dof="; array[89] = depthOfFieldHookCalls.ToString(); array[90] = "], patches=[controls="; array[91] = setControlsPatchInstalled.ToString(); array[92] = ", jog="; array[93] = jogSpeedPatchInstalled.ToString(); array[94] = ", run="; array[95] = runSpeedPatchInstalled.ToString(); array[96] = ", checkRun="; array[97] = checkRunPatchInstalled.ToString(); array[98] = ", camera="; array[99] = cameraPositionPatchInstalled.ToString(); array[100] = ", dof="; array[101] = depthOfFieldPatchInstalled.ToString(); array[102] = "]."; logger.LogInfo((object)string.Concat(array)); } } public static class SurvivalMovementExertionBridge { public static Func ExternalMovementMultiplier; public static Func ExternalRunDrainMultiplier; public static Func ExternalExertionGainMultiplier; public static Func ExternalRecoveryMultiplier; public static float GetMovementMultiplier(Player player) { return GetSafeMultiplier(ExternalMovementMultiplier, player, 0.2f, 1.35f); } public static float GetRunDrainMultiplier(Player player) { return GetSafeMultiplier(ExternalRunDrainMultiplier, player, 0.25f, 4f); } public static float GetExertionGainMultiplier(Player player) { return GetSafeMultiplier(ExternalExertionGainMultiplier, player, 0.25f, 4f); } public static float GetRecoveryMultiplier(Player player) { return GetSafeMultiplier(ExternalRecoveryMultiplier, player, 0.1f, 2f); } private static float GetSafeMultiplier(Func provider, Player player, float minimum, float maximum) { if (provider == null) { return 1f; } try { return Mathf.Clamp(provider(player), minimum, maximum); } catch { return 1f; } } } internal struct WindStreak { public readonly float AngleRadians; public readonly float InnerRadius; public readonly float Phase; public readonly float Speed; public readonly float Length; public readonly float Alpha; public WindStreak(float angleRadians, float innerRadius, float phase, float speed, float length, float alpha) { AngleRadians = angleRadians; InnerRadius = innerRadius; Phase = phase; Speed = speed; Length = length; Alpha = alpha; } } internal struct RunDrainPatchState { public bool RestoreDrain; public float OriginalDrain; } internal static class SurvivalMovementPatches { public static void PlayerSetControlsPrefix(Player __instance, ref Vector3 __0) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) SurvivalMovementExertionPlugin instance = SurvivalMovementExertionPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.RecordSetControlsHook(); __0 = instance.SmoothMoveInput(__instance, __0); } } public static void PlayerGetJogSpeedFactorPostfix(Player __instance, ref float __result) { SurvivalMovementExertionPlugin instance = SurvivalMovementExertionPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.RecordJogSpeedHook(); __result *= instance.GetJogSpeedMultiplier(__instance); } } public static void PlayerGetRunSpeedFactorPostfix(Player __instance, ref float __result) { SurvivalMovementExertionPlugin instance = SurvivalMovementExertionPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.RecordRunSpeedHook(); __result *= instance.GetRunSpeedMultiplier(__instance); } } public static bool PlayerCheckRunPrefix(Player __instance, ref float ___m_runStaminaDrain, ref bool __result, ref RunDrainPatchState __state) { SurvivalMovementExertionPlugin instance = SurvivalMovementExertionPlugin.Instance; if ((Object)(object)instance == (Object)null) { __state = default(RunDrainPatchState); return true; } return instance.PrepareCheckRun(__instance, ref ___m_runStaminaDrain, ref __result, ref __state); } public static void PlayerCheckRunPostfix(ref float ___m_runStaminaDrain, RunDrainPatchState __state) { SurvivalMovementExertionPlugin instance = SurvivalMovementExertionPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.RestoreCheckRunDrain(ref ___m_runStaminaDrain, __state); } } public static Exception PlayerCheckRunFinalizer(Exception __exception, ref float ___m_runStaminaDrain, RunDrainPatchState __state) { SurvivalMovementExertionPlugin instance = SurvivalMovementExertionPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.RestoreCheckRunDrain(ref ___m_runStaminaDrain, __state); } return __exception; } public static void GameCameraGetCameraPositionPostfix(GameCamera __instance, ref Vector3 pos, float ___m_distance, float ___m_minDistance) { SurvivalMovementExertionPlugin instance = SurvivalMovementExertionPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.ApplyCameraSway(Player.m_localPlayer, __instance, ref pos, ___m_distance, ___m_minDistance); } } public static void CameraEffectsUpdateDofPostfix(CameraEffects __instance) { SurvivalMovementExertionPlugin instance = SurvivalMovementExertionPlugin.Instance; if ((Object)(object)instance != (Object)null) { instance.ApplyExhaustionDepthOfField(__instance); } } }