Decompiled source of ShieldSledding v1.1.1

ShieldSledding.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("ShieldSledding")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1")]
[assembly: AssemblyProduct("ShieldSledding")]
[assembly: AssemblyTitle("ShieldSledding")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ShieldSledding
{
	internal sealed class AudioController
	{
		private AudioSource _slideSource;

		private AudioSource _windSource;

		private float _lastImpactTime;

		private float _warmSlideVolume;

		private float _warmWindVolume;

		private bool _warmPlaying;

		private static AudioClip _slideClip;

		private static AudioClip _windClip;

		private static AudioClip _impactClip;

		internal static AudioController Instance { get; private set; }

		internal AudioController()
		{
			Instance = this;
		}

		internal static void Prewarm()
		{
			if (!Utility.IsDedicatedServer())
			{
				EnsureClips();
			}
		}

		internal void Begin(Player player)
		{
			EnsureSources(player);
		}

		internal void End(Player player)
		{
			if ((Object)(object)_slideSource != (Object)null)
			{
				_slideSource.Stop();
			}
			if ((Object)(object)_windSource != (Object)null)
			{
				_windSource.Stop();
			}
		}

		internal bool OwnsObject(GameObject go)
		{
			if ((Object)(object)go != (Object)null && (Object)(object)_slideSource != (Object)null)
			{
				return (Object)(object)go == (Object)(object)((Component)_slideSource).gameObject;
			}
			return false;
		}

		internal void WarmPlaybackStart()
		{
			if (!((Object)(object)_slideSource == (Object)null))
			{
				_warmSlideVolume = _slideSource.volume;
				_warmWindVolume = (((Object)(object)_windSource != (Object)null) ? _windSource.volume : 0f);
				_slideSource.volume = 0f;
				_slideSource.Play();
				if ((Object)(object)_windSource != (Object)null)
				{
					_windSource.volume = 0f;
					_windSource.Play();
				}
				_warmPlaying = true;
			}
		}

		internal void WarmPlaybackStop()
		{
			if (_warmPlaying)
			{
				if ((Object)(object)_slideSource != (Object)null)
				{
					_slideSource.Stop();
					_slideSource.volume = _warmSlideVolume;
				}
				if ((Object)(object)_windSource != (Object)null)
				{
					_windSource.Stop();
					_windSource.volume = _warmWindVolume;
				}
				_warmPlaying = false;
			}
		}

		internal void Update(Player player, float speed)
		{
			if (!ConfigManager.EnableSoundEffects.Value || (Object)(object)player == (Object)null || Utility.IsDedicatedServer())
			{
				if ((Object)(object)_slideSource != (Object)null && _slideSource.isPlaying)
				{
					_slideSource.Stop();
				}
				if ((Object)(object)_windSource != (Object)null && _windSource.isPlaying)
				{
					_windSource.Stop();
				}
				return;
			}
			EnsureSources(player);
			float num = 12f;
			if (Utility.TrySampleGround(player, out var sample))
			{
				num = Mathf.Max(6f, ShieldSpeedRegistry.EstimateNaturalSpeed(in sample, player));
			}
			float num2 = Mathf.Clamp01(speed / num);
			if ((Object)(object)_slideSource != (Object)null)
			{
				if (speed > 1.5f)
				{
					if (!_slideSource.isPlaying)
					{
						_slideSource.Play();
					}
					_slideSource.volume = 0.15f + num2 * 0.45f;
					_slideSource.pitch = 0.85f + num2 * 0.45f;
				}
				else
				{
					_slideSource.Stop();
				}
			}
			if (!((Object)(object)_windSource != (Object)null))
			{
				return;
			}
			if (speed > 6f)
			{
				if (!_windSource.isPlaying)
				{
					_windSource.Play();
				}
				_windSource.volume = num2 * 0.4f;
				_windSource.pitch = 0.95f + num2 * 0.7f;
			}
			else
			{
				_windSource.Stop();
			}
		}

		internal void OnLanding(Player player, float impact)
		{
			PlayImpact(player, impact);
		}

		internal void PlayImpact(Player player, float impact)
		{
			if (ConfigManager.EnableSoundEffects.Value && !((Object)(object)player == (Object)null) && !(impact < 4f) && !(Time.time - _lastImpactTime < 0.2f))
			{
				_lastImpactTime = Time.time;
				EnsureSources(player);
				if ((Object)(object)_slideSource != (Object)null && (Object)(object)_impactClip != (Object)null)
				{
					_slideSource.PlayOneShot(_impactClip, Mathf.Clamp01(impact / 20f) * 0.85f);
				}
			}
		}

		private void EnsureSources(Player player)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			EnsureClips();
			if (!((Object)(object)_slideSource != (Object)null))
			{
				GameObject val = new GameObject("ShieldSledding_Audio");
				val.transform.SetParent(((Component)player).transform, false);
				_slideSource = val.AddComponent<AudioSource>();
				_slideSource.loop = true;
				_slideSource.spatialBlend = 0f;
				_slideSource.playOnAwake = false;
				_slideSource.clip = _slideClip;
				_slideSource.volume = 0.4f;
				_windSource = val.AddComponent<AudioSource>();
				_windSource.loop = true;
				_windSource.spatialBlend = 0f;
				_windSource.playOnAwake = false;
				_windSource.clip = _windClip;
				_windSource.volume = 0.25f;
				_windSource.pitch = 1.1f;
			}
		}

		private static void EnsureClips()
		{
			if ((Object)(object)_slideClip == (Object)null)
			{
				_slideClip = CreateNoiseClip("ShieldSled_Slide", 0.55f, 0.35f, soft: true);
			}
			if ((Object)(object)_windClip == (Object)null)
			{
				_windClip = CreateNoiseClip("ShieldSled_Wind", 0.8f, 0.22f, soft: true);
			}
			if ((Object)(object)_impactClip == (Object)null)
			{
				_impactClip = CreateNoiseClip("ShieldSled_Impact", 0.12f, 0.85f, soft: false);
			}
		}

		private static AudioClip CreateNoiseClip(string name, float seconds, float amplitude, bool soft)
		{
			int num = 22050;
			int num2 = Mathf.Max(256, Mathf.RoundToInt((float)num * seconds));
			float[] array = new float[num2];
			float num3 = 0f;
			for (int i = 0; i < num2; i++)
			{
				float num4 = (float)i / (float)(num2 - 1);
				float num5 = (soft ? 1f : (Mathf.Exp((0f - num4) * 14f) * (1f - num4)));
				float num6 = Random.value * 2f - 1f;
				float num7 = (soft ? ((num3 + 0.02f * num6) / 1.02f) : num6);
				num3 = num7;
				array[i] = num7 * amplitude * num5;
			}
			AudioClip obj = AudioClip.Create(name, num2, 1, num, false);
			if (!TrySetClipData(obj, array))
			{
				Plugin.Log.LogWarning((object)"Shield Sledding: AudioClip.SetData unavailable — using empty baked clip.");
			}
			return obj;
		}

		private static bool TrySetClipData(AudioClip clip, float[] buffer)
		{
			if ((Object)(object)clip == (Object)null || buffer == null)
			{
				return false;
			}
			try
			{
				MethodInfo method = typeof(AudioClip).GetMethod("SetData", new Type[2]
				{
					typeof(float[]),
					typeof(int)
				});
				if (method == null)
				{
					return false;
				}
				return !(method.Invoke(clip, new object[2] { buffer, 0 }) is bool flag) || flag;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Shield Sledding: AudioClip.SetData failed — " + ex.Message));
				return false;
			}
		}
	}
	internal sealed class CollisionController
	{
		private Vector3 _lastVelocity;

		private float _cooldownUntil;

		internal void Begin(Player player)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			_lastVelocity = (((Object)(object)player != (Object)null) ? ((Character)player).GetVelocity() : Vector3.zero);
			_cooldownUntil = 0f;
		}

		internal void Tick(Player player, ItemData shield, PhysicsResult result)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//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)
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			WildlifeImpact.TryRam(player, shield, result);
			VegetationImpact.TryRam(player, shield, result);
			if (Time.time < _cooldownUntil)
			{
				_lastVelocity = result.Velocity;
				return;
			}
			float horizontalSpeed = result.HorizontalSpeed;
			if (horizontalSpeed < ConfigManager.CollisionSpeedThreshold.Value)
			{
				_lastVelocity = result.Velocity;
				return;
			}
			Vector3 val = Utility.Flatten(result.Velocity - _lastVelocity);
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 4f)
			{
				_lastVelocity = result.Velocity;
				return;
			}
			if (!TryFindObstacle(player, out var hit))
			{
				_lastVelocity = result.Velocity;
				return;
			}
			float impact = magnitude * ConfigManager.CollisionSpeedDamageScale.Value;
			ApplyImpact(player, shield, ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, impact, horizontalSpeed);
			_cooldownUntil = Time.time + 0.35f;
			_lastVelocity = result.Velocity;
		}

		internal void OnLanding(Player player, float impact)
		{
			if (!(impact < 8f) && Utility.IsLocalPlayer(player))
			{
				EffectController.Instance?.ShakeCamera(impact * ConfigManager.CameraShakeStrength.Value * 0.05f);
				AudioController.Instance?.PlayImpact(player, impact);
			}
		}

		private bool TryFindObstacle(Player player, out RaycastHit hit)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			hit = default(RaycastHit);
			Vector3 val = ((Component)player).transform.position + Vector3.up * 0.6f;
			Vector3 val2 = Utility.Flatten((ShieldSledController.Instance != null) ? ShieldSledController.Instance.SimulatedVelocity : ((Character)player).GetVelocity());
			if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
			{
				val2 = ((Component)player).transform.forward;
			}
			((Vector3)(ref val2)).Normalize();
			return Physics.SphereCast(val, 0.4f, val2, ref hit, 1.2f, -1);
		}

		private void ApplyImpact(Player player, ItemData shield, Vector3 point, Vector3 normal, float impact, float speed)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			EffectController.Instance?.OnCollision(player, point, normal, impact);
			AudioController.Instance?.PlayImpact(player, impact);
			MultiplayerSync.Instance?.SendImpactEvent(player, point, impact);
		}
	}
	internal static class ConfigManager
	{
		internal static ConfigEntry<bool> EnableShieldSledding;

		internal static ConfigEntry<KeyboardShortcut> ActivationKey;

		internal static ConfigEntry<float> ActivationWindow;

		internal static ConfigEntry<float> ArmedWindow;

		internal static ConfigEntry<float> MinimumSlope;

		internal static ConfigEntry<bool> ShowActivationHints;

		internal static ConfigEntry<float> SledGroundClearance;

		internal static ConfigEntry<bool> EnableWaterSledding;

		internal static ConfigEntry<float> WaterSledMinSpeed;

		internal static ConfigEntry<float> WaterSledSustainSpeed;

		internal static ConfigEntry<float> WaterSledFriction;

		internal static ConfigEntry<float> MinimumSledSpeed;

		internal static ConfigEntry<float> BaseAcceleration;

		internal static ConfigEntry<float> MaximumSpeed;

		internal static ConfigEntry<float> MinBlockSkillSpeedScale;

		internal static ConfigEntry<float> MaxBlockSkillSpeedScale;

		internal static ConfigEntry<float> WoodSoftCoastMin;

		internal static ConfigEntry<float> WoodSoftCoastMax;

		internal static ConfigEntry<float> GravityMultiplier;

		internal static ConfigEntry<float> FrictionMultiplier;

		internal const float CoastFrictionScale = 0.28f;

		internal const float CoastFlatDecelScale = 0.35f;

		internal static ConfigEntry<float> AirControl;

		internal static ConfigEntry<float> SteeringStrength;

		internal static ConfigEntry<bool> InvertSteering;

		internal static ConfigEntry<bool> CameraRelativeSteering;

		internal static ConfigEntry<float> BrakeStrength;

		internal static ConfigEntry<float> ForwardLeanBonus;

		internal static ConfigEntry<float> SteeringSpeedFalloff;

		internal static ConfigEntry<float> UphillPenalty;

		internal static ConfigEntry<float> SlopeTransitionRetention;

		internal const float ClimbFrictionScale = 0.38f;

		internal static ConfigEntry<float> FlatDeceleration;

		internal static ConfigEntry<bool> AbsorbDamageToShield;

		internal static ConfigEntry<bool> EndSledOnCombatHit;

		internal static ConfigEntry<bool> StaggerOnCombatHit;

		internal static ConfigEntry<float> CombatHitMinDamage;

		internal static ConfigEntry<bool> EnableDurabilityLoss;

		internal static ConfigEntry<float> DurabilityPerMeter;

		internal static ConfigEntry<float> DurabilityPerSecond;

		internal static ConfigEntry<float> LandingDamageMultiplier;

		internal static ConfigEntry<float> DamageToDurabilityMultiplier;

		internal static ConfigEntry<bool> StumbleOnShieldBreak;

		internal static ConfigEntry<float> SnowFriction;

		internal static ConfigEntry<float> IceFriction;

		internal static ConfigEntry<float> IceSteeringScale;

		internal static ConfigEntry<float> GrassFriction;

		internal static ConfigEntry<float> BlackForestFriction;

		internal static ConfigEntry<float> SwampFriction;

		internal static ConfigEntry<float> AshlandsFriction;

		internal static ConfigEntry<float> MountainFriction;

		internal static ConfigEntry<float> MeadowsFriction;

		internal static ConfigEntry<float> MistlandsFriction;

		internal static ConfigEntry<float> OceanFriction;

		internal static ConfigEntry<float> DeepNorthFriction;

		internal static ConfigEntry<float> AshlandsDurabilityWearMultiplier;

		internal static ConfigEntry<bool> EnableShieldSurf;

		internal static ConfigEntry<float> ShieldSurfFriction;

		internal static ConfigEntry<float> CollisionSpeedThreshold;

		internal static ConfigEntry<float> CollisionSpeedDamageScale;

		internal static ConfigEntry<bool> EnableWildlifeImpactKill;

		internal static ConfigEntry<SledStaminaMode> StaminaMode;

		internal static ConfigEntry<float> StaminaActivationCost;

		internal static ConfigEntry<float> StaminaPerSecond;

		internal static ConfigEntry<float> StaminaJumpCost;

		internal static ConfigEntry<bool> EnableParticles;

		internal static ConfigEntry<bool> EnableCameraEffects;

		internal static ConfigEntry<bool> EnableSoundEffects;

		internal static ConfigEntry<bool> EnableSpeedometer;

		internal static ConfigEntry<float> CameraShakeStrength;

		internal static ConfigEntry<float> SpeedFovIncrease;

		internal static ConfigEntry<float> CameraTiltStrength;

		internal static ConfigEntry<bool> EnableShieldSparks;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<int> ConfigSchemaVersion;

		private static ConfigDescription FloatRange(float min, float max, string description = "")
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			return new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>());
		}

		private static ConfigDescription IntRange(int min, int max, string description = "")
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			return new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(min, max), Array.Empty<object>());
		}

		internal static void Init(ConfigFile config)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Expected O, but got Unknown
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Expected O, but got Unknown
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Expected O, but got Unknown
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Expected O, but got Unknown
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Expected O, but got Unknown
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Expected O, but got Unknown
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Expected O, but got Unknown
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Expected O, but got Unknown
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Expected O, but got Unknown
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Expected O, but got Unknown
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Expected O, but got Unknown
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Expected O, but got Unknown
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Expected O, but got Unknown
			//IL_050d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0517: Expected O, but got Unknown
			//IL_0545: Unknown result type (might be due to invalid IL or missing references)
			//IL_054f: Expected O, but got Unknown
			//IL_057d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0587: Expected O, but got Unknown
			//IL_05b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bf: Expected O, but got Unknown
			//IL_05ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f7: Expected O, but got Unknown
			//IL_0625: Unknown result type (might be due to invalid IL or missing references)
			//IL_062f: Expected O, but got Unknown
			//IL_06ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b8: Expected O, but got Unknown
			//IL_06e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f0: Expected O, but got Unknown
			//IL_0a7d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a87: Expected O, but got Unknown
			//IL_0ab5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0abf: Expected O, but got Unknown
			ConfigSchemaVersion = config.Bind<int>("General", "ConfigSchemaVersion", 1, "Internal config migration version. Do not edit unless you know what you are doing.");
			EnableShieldSledding = config.Bind<bool>("General", "EnableShieldSledding", true, "Master toggle for shield sledding.");
			ActivationKey = config.Bind<KeyboardShortcut>("General", "ActivationKey", new KeyboardShortcut((KeyCode)327, Array.Empty<KeyCode>()), "Press while airborne after a jump to arm shield sled mode. Default Mouse4 (side mouse button) — vanilla 1.0 uses G. Only this bind is active after you rebind.");
			ActivationKey.SettingChanged += delegate
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"Shield Sledding: ActivationKey is now {ActivationKey.Value}.");
				}
			};
			ActivationWindow = config.Bind<float>("General", "ActivationWindow", 2.5f, new ConfigDescription("Seconds after jumping during which the activation key can arm sled mode.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			ArmedWindow = config.Bind<float>("General", "ArmedWindow", 6f, new ConfigDescription("Seconds after arming to land and start sledding before the arm expires.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), Array.Empty<object>()));
			MinimumSlope = config.Bind<float>("General", "MinimumSlope", 8f, new ConfigDescription("Minimum ground slope in degrees required to start sledding on landing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 45f), Array.Empty<object>()));
			ShowActivationHints = config.Bind<bool>("General", "ShowActivationHints", true, "Show on-screen center messages for arming, flat landing, and other sled hints.");
			SledGroundClearance = config.Bind<float>("Physics", "SledGroundClearance", 0f, new ConfigDescription("Target height of the player's feet above the slope while sledding (meters). 0 = full contact.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.6f), Array.Empty<object>()));
			EnableWaterSledding = config.Bind<bool>("Physics", "EnableWaterSledding", true, "Allow sledding across water when moving fast enough.");
			WaterSledMinSpeed = config.Bind<float>("Physics", "WaterSledMinSpeed", 6f, new ConfigDescription("Minimum speed (m/s) to START water skim. Clamped up to WaterSledSustainSpeed so skim cannot engage below the cancel floor.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
			WaterSledSustainSpeed = config.Bind<float>("Physics", "WaterSledSustainSpeed", 6f, new ConfigDescription("ONLY water speed restriction while skimming: end skim when horizontal speed falls below this (m/s). Default 6. Short flicker grace only — cancel should read ~6, not ~3.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 25f), Array.Empty<object>()));
			WaterSledFriction = config.Bind<float>("Physics", "WaterSledFriction", 0.4f, new ConfigDescription("Friction while skimming water only (not multiplied by OceanFriction). Lower = longer skim. No W-propulsion on water — skim must coast in.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), Array.Empty<object>()));
			MinimumSledSpeed = config.Bind<float>("Physics", "MinimumSledSpeed", 4f, new ConfigDescription("Minimum horizontal speed (m/s) required to stay in sledding on ground. Drop below this (with a short grace) and sledding ends. 0 = disabled. Skipped while water-skimming.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			BaseAcceleration = config.Bind<float>("Physics", "BaseAcceleration", 10f, new ConfigDescription("Slope pull strength (~10 ≈ gravity). Higher = faster coast on the same hill.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			MaximumSpeed = config.Bind<float>("Physics", "MaximumSpeed", 0f, new ConfigDescription("Optional safety speed cap in m/s. 0 = disabled — speed follows slope steepness and terrain friction.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 80f), Array.Empty<object>()));
			WoodSoftCoastMin = config.Bind<float>("Physics", "WoodSoftCoastMin", 18f, new ConfigDescription("Legacy. Max speed uses [ShieldCoastSpeeds] Prefab_Skill0 / Prefab_Skill100 instead.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 40f), Array.Empty<object>()));
			WoodSoftCoastMax = config.Bind<float>("Physics", "WoodSoftCoastMax", 25f, new ConfigDescription("Legacy. Max speed uses [ShieldCoastSpeeds] Prefab_Skill0 / Prefab_Skill100 instead.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 50f), Array.Empty<object>()));
			MinBlockSkillSpeedScale = config.Bind<float>("Physics", "BlockSkillSpeedScaleMin", 1.35f, new ConfigDescription("Legacy unused. Blocking only sets max speed via [ShieldCoastSpeeds].", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.35f, 3f), Array.Empty<object>()));
			MaxBlockSkillSpeedScale = config.Bind<float>("Physics", "BlockSkillSpeedScaleMax", 1.9f, new ConfigDescription("Legacy unused. Blocking only sets max speed via [ShieldCoastSpeeds].", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), Array.Empty<object>()));
			GravityMultiplier = config.Bind<float>("Physics", "GravityMultiplier", 1f, new ConfigDescription("Multiplier applied to downhill gravity acceleration.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			FrictionMultiplier = config.Bind<float>("Physics", "FrictionMultiplier", 1f, new ConfigDescription("Global friction multiplier. Always applied (including downhill). Free-coast uses a lighter fraction so glide stays long; braking uses full strength. Biome/shield frictions still scale with this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			AirControl = config.Bind<float>("Physics", "AirControl", 0.15f, new ConfigDescription("Fraction of ground steering applied while airborne.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			SteeringStrength = config.Bind<float>("Physics", "SteeringStrength", 4.75f, new ConfigDescription("How quickly velocity direction can change while sledding.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			InvertSteering = config.Bind<bool>("Physics", "InvertSteering", false, "Swap A/D while sledding. Leave false for natural left/right; enable if steering feels backwards.");
			CameraRelativeSteering = config.Bind<bool>("Physics", "CameraRelativeSteering", true, "When true, A/D lean uses screen left/right when the camera has a clear lateral view of the slide; sideways freelook and slope-align keep sled/body left/right. Looking against travel stays sled-natural (no lean swap). When false, A/D always turn relative to slide direction.");
			BrakeStrength = config.Bind<float>("Physics", "BrakeStrength", 1.5f, new ConfigDescription("Extra friction multiplier when holding S.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			ForwardLeanBonus = config.Bind<float>("Physics", "ForwardLeanBonus", 1.5f, new ConfigDescription("Extra acceleration when holding W on real downhill slopes. No effect on flat / near-flat ground (cannot sustain sledding forever with Shift+W).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			SteeringSpeedFalloff = config.Bind<float>("Physics", "SteeringSpeedFalloff", 0.035f, new ConfigDescription("Higher values reduce steering responsiveness at speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			UphillPenalty = config.Bind<float>("Physics", "UphillPenalty", 0.75f, new ConfigDescription("Uphill deceleration relative to downhill slope pull (1 = mirror gravity × grade). Scaled by slope steepness. Lower = more climb carry from downhill runs.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			SlopeTransitionRetention = config.Bind<float>("Physics", "SlopeTransitionRetention", 0.9f, new ConfigDescription("How much speed to keep when the ground normal changes (valleys / downhill→uphill). 1 = full retain, 0 = raw ProjectOnPlane bleed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			FlatDeceleration = config.Bind<float>("Physics", "FlatDeceleration", 8f, new ConfigDescription("Deceleration on flat ground (m/s² scale). Free-coast applies a lighter fraction; braking uses full strength.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			AbsorbDamageToShield = config.Bind<bool>("Damage", "AbsorbDamageToShield", true, "When true, fall and impact damage go to shield durability instead of player HP while sledding.");
			EndSledOnCombatHit = config.Bind<bool>("Damage", "EndSledOnCombatHit", true, "When true, creature or player attacks knock you off the sled while sledding.");
			StaggerOnCombatHit = config.Bind<bool>("Damage", "StaggerOnCombatHit", true, "Apply a stagger when knocked off the sled by a creature or player attack.");
			CombatHitMinDamage = config.Bind<float>("Damage", "CombatHitMinDamage", 1f, new ConfigDescription("Minimum damage before a combat hit can knock you off the sled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			DamageToDurabilityMultiplier = config.Bind<float>("Damage", "DamageToDurabilityMultiplier", 0.15f, new ConfigDescription("Shield durability lost per point of HP damage absorbed while sledding.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			EnableDurabilityLoss = config.Bind<bool>("Durability", "EnableDurabilityLoss", true, "Whether sledding wears down the equipped shield.");
			DurabilityPerMeter = config.Bind<float>("Durability", "DurabilityPerMeter", 0.02f, FloatRange(0f, 5f));
			DurabilityPerSecond = config.Bind<float>("Durability", "DurabilityPerSecond", 0.05f, FloatRange(0f, 5f));
			LandingDamageMultiplier = config.Bind<float>("Durability", "LandingDamageMultiplier", 1.5f, FloatRange(0f, 10f));
			StumbleOnShieldBreak = config.Bind<bool>("Durability", "StumbleOnShieldBreak", true, "Apply a stagger when the shield breaks from sledding.");
			SnowFriction = config.Bind<float>("Terrain", "SnowFriction", 0.55f, FloatRange(0.1f, 3f, "Snow-surface friction blended with MountainFriction / DeepNorthFriction."));
			IceFriction = config.Bind<float>("Terrain", "IceFriction", 0.38f, FloatRange(0.1f, 3f, "Friction on ice sheets / floes (Deep North and mountain ice). Lower = faster than snow."));
			IceSteeringScale = config.Bind<float>("Terrain", "IceSteeringScale", 0.58f, FloatRange(0.2f, 1.5f, "A/D turn rate on ice. Lower = slipperier / less handling."));
			GrassFriction = config.Bind<float>("Terrain", "GrassFriction", 0.85f, FloatRange(0.1f, 3f));
			BlackForestFriction = config.Bind<float>("Terrain", "BlackForestFriction", 0.95f, FloatRange(0.1f, 3f));
			SwampFriction = config.Bind<float>("Terrain", "SwampFriction", 1.45f, FloatRange(0.1f, 3f));
			AshlandsFriction = config.Bind<float>("Terrain", "AshlandsFriction", 0.75f, FloatRange(0.1f, 3f));
			MountainFriction = config.Bind<float>("Terrain", "MountainFriction", 0.5f, FloatRange(0.1f, 3f));
			MeadowsFriction = config.Bind<float>("Terrain", "MeadowsFriction", 1f, FloatRange(0.1f, 3f));
			MistlandsFriction = config.Bind<float>("Terrain", "MistlandsFriction", 0.9f, FloatRange(0.1f, 3f));
			OceanFriction = config.Bind<float>("Terrain", "OceanFriction", 1.2f, FloatRange(0.1f, 3f));
			DeepNorthFriction = config.Bind<float>("Terrain", "DeepNorthFriction", 0.5f, FloatRange(0.1f, 3f));
			AshlandsDurabilityWearMultiplier = config.Bind<float>("Terrain", "AshlandsDurabilityWearMultiplier", 1.35f, FloatRange(1f, 5f));
			EnableShieldSurf = config.Bind<bool>("Terrain", "EnableShieldSurf", true, "Reduced friction when sledding on player-built pieces / wood ramps (piece layer, wood WearNTear, ramp-like names).");
			ShieldSurfFriction = config.Bind<float>("Terrain", "ShieldSurfFriction", 0.4f, FloatRange(0.1f, 3f, "Friction multiplier on built wood/piece surfaces. Lower = faster (0.4 default)."));
			CollisionSpeedThreshold = config.Bind<float>("Impacts", "CollisionSpeedThreshold", 6f, new ConfigDescription("Minimum speed (m/s) before impact camera/audio effects trigger.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			CollisionSpeedDamageScale = config.Bind<float>("Impacts", "CollisionSpeedDamageScale", 1.25f, new ConfigDescription("Impact intensity scale for camera shake and sound.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			EnableWildlifeImpactKill = config.Bind<bool>("Impacts", "EnableWildlifeImpactKill", true, "Instantly kill small wildlife when sledding into them at or above CollisionSpeedThreshold (Boar, Greyling, Neck, Crow, Gull, Hare, Ash crow). Deer are not killed.");
			StaminaMode = config.Bind<SledStaminaMode>("Stamina", "StaminaMode", SledStaminaMode.None, "Stamina drain behavior while sledding.");
			StaminaActivationCost = config.Bind<float>("Stamina", "StaminaActivationCost", 10f, FloatRange(0f, 100f));
			StaminaPerSecond = config.Bind<float>("Stamina", "StaminaPerSecond", 2f, FloatRange(0f, 50f));
			StaminaJumpCost = config.Bind<float>("Stamina", "StaminaJumpCost", 8f, FloatRange(0f, 100f));
			EnableParticles = config.Bind<bool>("Effects", "EnableParticles", true, (ConfigDescription)null);
			EnableCameraEffects = config.Bind<bool>("Effects", "EnableCameraEffects", true, "Master switch for sled camera FOV boost, tilt, and shake.");
			EnableSoundEffects = config.Bind<bool>("Effects", "EnableSoundEffects", true, "Slide / wind / impact audio while sledding.");
			EnableSpeedometer = config.Bind<bool>("Effects", "EnableSpeedometer", false, (ConfigDescription)null);
			CameraShakeStrength = config.Bind<float>("Effects", "CameraShakeStrength", 0.35f, FloatRange(0f, 2f, "Impact camera shake scale. Requires EnableCameraEffects=true."));
			SpeedFovIncrease = config.Bind<float>("Effects", "SpeedFovIncrease", 8f, FloatRange(0f, 30f, "Extra FOV (degrees) at full sled speed. Requires EnableCameraEffects=true. Restores when you exit the sled."));
			CameraTiltStrength = config.Bind<float>("Effects", "CameraTiltStrength", 4f, FloatRange(0f, 20f, "Steer roll (degrees) while sledding. Requires EnableCameraEffects=true."));
			EnableShieldSparks = config.Bind<bool>("Effects", "EnableShieldSparks", true, "Spawn brief spark bursts on collisions / wildlife impacts. Also requires EnableParticles.");
			DebugLogging = config.Bind<bool>("Debug", "DebugLogging", false, "Write sled diagnostics (activation details, stuck / hitch / shore traces, tick dumps) to the BepInEx log. Leave off for normal play — logging while sledding causes hitches.");
			ShieldWearConfig.Init(config);
			ShieldSpeedConfig.Init(config);
			MigrateLegacyConfig(config);
		}

		private unsafe static void MigrateLegacyConfig(ConfigFile config)
		{
			//IL_0bd0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bd5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bd8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bdf: Invalid comparison between Unknown and I4
			//IL_0c10: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e55: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e5f: Expected O, but got Unknown
			//IL_0e6b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e75: Expected O, but got Unknown
			//IL_0e81: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e8b: Expected O, but got Unknown
			//IL_0e97: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ea1: Expected O, but got Unknown
			//IL_0ead: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eb7: Expected O, but got Unknown
			if (ConfigSchemaVersion.Value < 27)
			{
				MigrateRenamedFloat(config, "Physics", "MinBlockSkillSpeedScale", MinBlockSkillSpeedScale);
				MigrateRenamedFloat(config, "Physics", "MaxBlockSkillSpeedScale", MaxBlockSkillSpeedScale);
			}
			if (ConfigSchemaVersion.Value < 2)
			{
				if (ActivationWindow.Value <= 0.6f)
				{
					ActivationWindow.Value = 2.5f;
					Plugin.Log.LogInfo((object)"Shield Sledding: raised ActivationWindow to 2.5s (was too short).");
				}
				if (MinimumSlope.Value >= 10f)
				{
					MinimumSlope.Value = 2f;
					Plugin.Log.LogInfo((object)"Shield Sledding: lowered MinimumSlope to 2° (was too steep).");
				}
			}
			if (ConfigSchemaVersion.Value < 3)
			{
				if (MinimumSlope.Value > 0f)
				{
					MinimumSlope.Value = 0f;
					Plugin.Log.LogInfo((object)"Shield Sledding: lowered MinimumSlope to 0° so flat ground works.");
				}
				ConfigSchemaVersion.Value = 3;
			}
			if (ConfigSchemaVersion.Value < 4)
			{
				ConfigSchemaVersion.Value = 4;
			}
			if (ConfigSchemaVersion.Value < 5)
			{
				if (SledGroundClearance.Value > 0.1f)
				{
					SledGroundClearance.Value = 0.06f;
					Plugin.Log.LogInfo((object)"Shield Sledding: lowered SledGroundClearance to 0.06m for slope contact.");
				}
				ConfigSchemaVersion.Value = 5;
			}
			if (ConfigSchemaVersion.Value < 6)
			{
				SledGroundClearance.Value = 0f;
				Plugin.Log.LogInfo((object)"Shield Sledding: set SledGroundClearance to 0m for full slope contact.");
				ConfigSchemaVersion.Value = 6;
			}
			if (ConfigSchemaVersion.Value < 7)
			{
				if (DamageToDurabilityMultiplier.Value >= 0.99f)
				{
					DamageToDurabilityMultiplier.Value = 0.15f;
					Plugin.Log.LogInfo((object)"Shield Sledding: lowered DamageToDurabilityMultiplier to 0.15 (was melting shields).");
				}
				ConfigSchemaVersion.Value = 7;
			}
			if (ConfigSchemaVersion.Value < 8)
			{
				ConfigSchemaVersion.Value = 8;
			}
			if (ConfigSchemaVersion.Value < 9)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v9 — removed legacy collision/ghost options.");
				ConfigSchemaVersion.Value = 9;
			}
			if (ConfigSchemaVersion.Value < 10)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v10 — simplified damage toggle and per-shield speed entries in [ShieldSpeeds].");
				ConfigSchemaVersion.Value = 10;
			}
			if (ConfigSchemaVersion.Value < 11)
			{
				if (MaximumSpeed.Value >= 20f)
				{
					MaximumSpeed.Value = 13f;
				}
				if (BaseAcceleration.Value >= 16f)
				{
					BaseAcceleration.Value = 10f;
				}
				if (ForwardLeanBonus.Value >= 3f)
				{
					ForwardLeanBonus.Value = 1.5f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v11 — lowered default speeds and removed stats section.");
				ConfigSchemaVersion.Value = 11;
			}
			if (ConfigSchemaVersion.Value < 12)
			{
				if (MaximumSpeed.Value <= 13.5f)
				{
					MaximumSpeed.Value = 10f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v12 — ShieldBanded baseline 10 m/s, tier scaling, Blocking skill affects speed.");
				ConfigSchemaVersion.Value = 12;
			}
			if (ConfigSchemaVersion.Value < 13)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v13 — Blocking skill scales 80% to 100% of max speed (10 m/s on banded at skill 100).");
				ConfigSchemaVersion.Value = 13;
			}
			if (ConfigSchemaVersion.Value < 14)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v14 — uniform sled speed; shield tier affects durability wear ([ShieldWear]).");
				ConfigSchemaVersion.Value = 14;
			}
			if (ConfigSchemaVersion.Value < 15)
			{
				ResetObsoleteSpeedConfig(config);
				Plugin.Log.LogInfo((object)"Shield Sledding: config v15 — cleared obsolete [ShieldSpeeds] values. Speed is uniform; edit [ShieldWear] only.");
				ConfigSchemaVersion.Value = 15;
			}
			if (ConfigSchemaVersion.Value < 16)
			{
				MaximumSpeed.Value = 0f;
				Plugin.Log.LogInfo((object)"Shield Sledding: config v16 — slope-natural speed (MaximumSpeed 0 = no cap; speed follows hill steepness).");
				ConfigSchemaVersion.Value = 16;
			}
			if (ConfigSchemaVersion.Value < 17)
			{
				ResetObsoleteSpeedConfig(config);
				ShieldWearConfig.MigrateLegacyWearDefaults(config);
				Plugin.Log.LogInfo((object)"Shield Sledding: config v17 — updated [ShieldWear] defaults; use ModdedWolf.ShieldSledding.cfg only.");
				ConfigSchemaVersion.Value = 17;
			}
			if (ConfigSchemaVersion.Value < 18)
			{
				if (MinimumSlope.Value < 12f)
				{
					MinimumSlope.Value = 12f;
					Plugin.Log.LogInfo((object)"Shield Sledding: restored MinimumSlope to 12° — flat ground cannot start sledding.");
				}
				ConfigSchemaVersion.Value = 18;
			}
			if (ConfigSchemaVersion.Value < 19)
			{
				if (MinimumSlope.Value < 12f)
				{
					MinimumSlope.Value = 12f;
					Plugin.Log.LogInfo((object)"Shield Sledding: set MinimumSlope to 12° (flat ground cannot start sledding).");
				}
				ConfigSchemaVersion.Value = 19;
			}
			if (ConfigSchemaVersion.Value < 20)
			{
				if (UphillPenalty.Value >= 2.9f)
				{
					UphillPenalty.Value = 1f;
					Plugin.Log.LogInfo((object)"Shield Sledding: lowered UphillPenalty to 1 (was stopping hard on climbs; now grade-scaled).");
				}
				ConfigSchemaVersion.Value = 20;
			}
			if (ConfigSchemaVersion.Value < 21)
			{
				ShieldWearConfig.MigrateWoodWearDefault(config);
				Plugin.Log.LogInfo((object)"Shield Sledding: config v21 — ShieldWood wear default 6.00 (2× prior); [ShieldWear] range max 10.");
				ConfigSchemaVersion.Value = 21;
			}
			if (ConfigSchemaVersion.Value < 22)
			{
				ShieldWearConfig.MigrateEarlyShieldWearDoubling(config);
				Plugin.Log.LogInfo((object)"Shield Sledding: config v22 — early shield wear (Wood→Banded) defaults doubled.");
				ConfigSchemaVersion.Value = 22;
			}
			if (ConfigSchemaVersion.Value < 23)
			{
				ShieldWearConfig.MigrateTowerWearAdvantage(config);
				Plugin.Log.LogInfo((object)"Shield Sledding: config v23 — tower shields wear slower than matching non-tower boards.");
				ConfigSchemaVersion.Value = 23;
			}
			if (ConfigSchemaVersion.Value < 24)
			{
				if (Mathf.Approximately(MinimumSlope.Value, 12f))
				{
					MinimumSlope.Value = 8f;
					Plugin.Log.LogInfo((object)"Shield Sledding: config v24 — MinimumSlope default 8° (was 12°).");
				}
				else
				{
					Plugin.Log.LogInfo((object)"Shield Sledding: config v24 — MinimumSledSpeed added (default 2 m/s to stay sledding).");
				}
				ConfigSchemaVersion.Value = 24;
			}
			if (ConfigSchemaVersion.Value < 25)
			{
				if (Mathf.Approximately(MinBlockSkillSpeedScale.Value, 0.8f))
				{
					MinBlockSkillSpeedScale.Value = 1f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v25 — Blocking skill speed scale 1.0 at skill 0 → 1.7 at skill 100.");
				ConfigSchemaVersion.Value = 25;
			}
			if (ConfigSchemaVersion.Value < 26)
			{
				if (Mathf.Approximately(MinBlockSkillSpeedScale.Value, 1f))
				{
					MinBlockSkillSpeedScale.Value = 0.8f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v26 — Blocking skill speed scale 0.80 at skill 0 → 1.7 at skill 100.");
				ConfigSchemaVersion.Value = 26;
			}
			if (ConfigSchemaVersion.Value < 27)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v27 — renamed Blocking skill scales to BlockSkillSpeedScaleMin / BlockSkillSpeedScaleMax (kept adjacent in config UI).");
				ConfigSchemaVersion.Value = 27;
			}
			if (ConfigSchemaVersion.Value < 28)
			{
				if (Mathf.Approximately(SteeringStrength.Value, 2.5f))
				{
					SteeringStrength.Value = 4.75f;
				}
				if (Mathf.Approximately(SteeringSpeedFalloff.Value, 0.08f))
				{
					SteeringSpeedFalloff.Value = 0.035f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v28 — stronger default steering; softer rock/obstacle sled collisions.");
				ConfigSchemaVersion.Value = 28;
			}
			if (ConfigSchemaVersion.Value < 29)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v29 — aggressive rock skim (pass-through low obstacles; heightmap ride plane).");
				ConfigSchemaVersion.Value = 29;
			}
			if (ConfigSchemaVersion.Value < 30)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v30 — fixed canopy/roof upward snaps; restored water skim ground.");
				ConfigSchemaVersion.Value = 30;
			}
			if (ConfigSchemaVersion.Value < 31)
			{
				if (Mathf.Approximately(WaterSledMinSpeed.Value, 6f))
				{
					WaterSledMinSpeed.Value = 3.5f;
				}
				if (Mathf.Approximately(WaterSledFriction.Value, 0.35f))
				{
					WaterSledFriction.Value = 0.22f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v31 — water skim latch/hysteresis; lower engage speed; fixed water friction.");
				ConfigSchemaVersion.Value = 31;
			}
			if (ConfigSchemaVersion.Value < 32)
			{
				if (Mathf.Approximately(ShieldSurfFriction.Value, 0.65f))
				{
					ShieldSurfFriction.Value = 0.4f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v32 — water skim blocks shore terrain; faster wood/piece ramp friction.");
				ConfigSchemaVersion.Value = 32;
			}
			if (ConfigSchemaVersion.Value < 33)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v33 — wood ramp lock (no micro-bounce); solid collision inside dungeons.");
				ConfigSchemaVersion.Value = 33;
			}
			if (ConfigSchemaVersion.Value < 34)
			{
				if (Mathf.Approximately(WaterSledFriction.Value, 0.22f))
				{
					WaterSledFriction.Value = 0.48f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v34 — water skim rides live wave height; higher water friction + sustain speed.");
				ConfigSchemaVersion.Value = 34;
			}
			if (ConfigSchemaVersion.Value < 35)
			{
				if (Mathf.Approximately(WaterSledMinSpeed.Value, 3.5f))
				{
					WaterSledMinSpeed.Value = 5.5f;
				}
				if (Mathf.Approximately(WaterSledSustainSpeed.Value, 5f))
				{
					WaterSledSustainSpeed.Value = 6.5f;
				}
				if (Mathf.Approximately(WaterSledFriction.Value, 0.48f) || Mathf.Approximately(WaterSledFriction.Value, 0.22f))
				{
					WaterSledFriction.Value = 0.55f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v35 — no water W-propulsion; harder skim engage/decay; soft particle spray.");
				ConfigSchemaVersion.Value = 35;
			}
			if (ConfigSchemaVersion.Value < 36)
			{
				if (Mathf.Approximately(WaterSledMinSpeed.Value, 5.5f))
				{
					WaterSledMinSpeed.Value = 4.5f;
				}
				if (Mathf.Approximately(WaterSledSustainSpeed.Value, 6.5f))
				{
					WaterSledSustainSpeed.Value = 5f;
				}
				if (Mathf.Approximately(WaterSledFriction.Value, 0.55f))
				{
					WaterSledFriction.Value = 0.4f;
				}
				if (Mathf.Approximately(MinimumSledSpeed.Value, 2f))
				{
					MinimumSledSpeed.Value = 0.75f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v36 — softer water coast/exit; end sled when submerged; gentler ground min speed.");
				ConfigSchemaVersion.Value = 36;
			}
			if (ConfigSchemaVersion.Value < 37)
			{
				if (Mathf.Approximately(WaterSledSustainSpeed.Value, 5f))
				{
					WaterSledSustainSpeed.Value = 6f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v37 — water skim sustain/exit near ~6 m/s (no longer cancels around ~4).");
				ConfigSchemaVersion.Value = 37;
			}
			if (ConfigSchemaVersion.Value < 38)
			{
				WaterSledSustainSpeed.Value = 6f;
				if (WaterSledMinSpeed.Value < 6f)
				{
					WaterSledMinSpeed.Value = 6f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v38 — water skim cancel hard-forced to 6 m/s (sole water speed restriction).");
				ConfigSchemaVersion.Value = 38;
			}
			if (ConfigSchemaVersion.Value < 39)
			{
				if (Mathf.Approximately(MinimumSledSpeed.Value, 0.75f))
				{
					MinimumSledSpeed.Value = 2f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v39 — ground min speed default 2 m/s (water cancel stays at 6).");
				ConfigSchemaVersion.Value = 39;
			}
			if (ConfigSchemaVersion.Value < 40)
			{
				if (Mathf.Approximately(UphillPenalty.Value, 1f))
				{
					UphillPenalty.Value = 0.75f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v40 — better downhill→uphill momentum (UphillPenalty 0.75 + SlopeTransitionRetention).");
				ConfigSchemaVersion.Value = 40;
			}
			if (ConfigSchemaVersion.Value < 41)
			{
				if (Mathf.Approximately(MinimumSledSpeed.Value, 2f))
				{
					MinimumSledSpeed.Value = 4f;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v41 — ground min speed default 4 m/s (water cancel stays at 6).");
				ConfigSchemaVersion.Value = 41;
			}
			if (ConfigSchemaVersion.Value < 42)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v42 — InvertSteering + CameraRelativeSteering (natural A/D default).");
				ConfigSchemaVersion.Value = 42;
			}
			if (ConfigSchemaVersion.Value < 43)
			{
				ConfigSchemaVersion.Value = 43;
			}
			if (ConfigSchemaVersion.Value < 44)
			{
				KeyboardShortcut value = ActivationKey.Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey == 103 && (((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).ToString() ?? string.Empty).IndexOf('+') < 0)
				{
					ActivationKey.Value = new KeyboardShortcut((KeyCode)327, Array.Empty<KeyCode>());
					Plugin.Log.LogInfo((object)"Shield Sledding: config v44 — ActivationKey G -> Mouse4 (vanilla 1.0 uses G).");
				}
				ConfigSchemaVersion.Value = 44;
			}
			if (ConfigSchemaVersion.Value < 45)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v45 — IceFriction / IceSteeringScale (faster, slipperier ice).");
				ConfigSchemaVersion.Value = 45;
			}
			if (ConfigSchemaVersion.Value < 46)
			{
				ShieldWearConfig.MigrateShieldRootsToSilverTier(config);
				Plugin.Log.LogInfo((object)"Shield Sledding: config v46 — Shield of Roots wear matches Silver (swamp-tier).");
				ConfigSchemaVersion.Value = 46;
			}
			if (ConfigSchemaVersion.Value < 47)
			{
				if (Mathf.Approximately(MaxBlockSkillSpeedScale.Value, 1.7f))
				{
					MaxBlockSkillSpeedScale.Value = 2.25f;
					Plugin.Log.LogInfo((object)"Shield Sledding: config v47 — BlockSkillSpeedScaleMax raised to 2.25 (was 1.7).");
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v47.");
				ConfigSchemaVersion.Value = 47;
			}
			if (ConfigSchemaVersion.Value < 48)
			{
				bool num = Mathf.Approximately(MinBlockSkillSpeedScale.Value, 0.8f) || Mathf.Approximately(MinBlockSkillSpeedScale.Value, 1f);
				bool flag = Mathf.Approximately(MaxBlockSkillSpeedScale.Value, 2.25f) || Mathf.Approximately(MaxBlockSkillSpeedScale.Value, 1.7f);
				if (num || flag)
				{
					MinBlockSkillSpeedScale.Value = 1.35f;
					MaxBlockSkillSpeedScale.Value = 1.9f;
					Plugin.Log.LogInfo((object)"Shield Sledding: config v48 — BlockSkillSpeedScaleMin/Max → 1.35 / 1.90 (wood soft ~18→25).");
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v48 — wood soft speed band; other shields scale from wood.");
				ConfigSchemaVersion.Value = 48;
			}
			if (ConfigSchemaVersion.Value < 49)
			{
				Plugin.Log.LogInfo((object)"Shield Sledding: config v49 — WoodSoftCoastMin/Max (18→25 m/s) drive coast aims.");
				ConfigSchemaVersion.Value = 49;
			}
			if (ConfigSchemaVersion.Value < 50)
			{
				bool saveOnConfigSet = config.SaveOnConfigSet;
				config.SaveOnConfigSet = false;
				try
				{
					ConfigEntry<bool> val = config.Bind<bool>("Effects", "EnableSlideSound", true, (ConfigDescription)null);
					ConfigEntry<bool> val2 = config.Bind<bool>("Effects", "EnableWindSound", true, (ConfigDescription)null);
					ConfigEntry<bool> val3 = config.Bind<bool>("Effects", "EnableImpactSound", true, (ConfigDescription)null);
					EnableSoundEffects.Value = val.Value || val2.Value || val3.Value;
					config.Remove(new ConfigDefinition("Effects", "EnableSlideSound"));
					config.Remove(new ConfigDefinition("Effects", "EnableWindSound"));
					config.Remove(new ConfigDefinition("Effects", "EnableImpactSound"));
					config.Remove(new ConfigDefinition("Effects", "SlideVolumeScale"));
					config.Remove(new ConfigDefinition("Effects", "WindVolumeScale"));
				}
				finally
				{
					config.SaveOnConfigSet = saveOnConfigSet;
				}
				Plugin.Log.LogInfo((object)"Shield Sledding: config v50 — restored single EnableSoundEffects (slide/wind/impact).");
				ConfigSchemaVersion.Value = 50;
			}
			if (ConfigSchemaVersion.Value < 51)
			{
				ShieldSpeedConfig.RemoveObsoleteShieldSpeedsSection(config);
				Plugin.Log.LogInfo((object)"Shield Sledding: config v51 — per-shield coast aims in [ShieldCoastSpeeds] (Prefab_Skill0 / Prefab_Skill100).");
				ConfigSchemaVersion.Value = 51;
			}
		}

		private static void MigrateRenamedFloat(ConfigFile config, string section, string oldKey, ConfigEntry<float> newEntry)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			ConfigDefinition val = new ConfigDefinition(section, oldKey);
			bool saveOnConfigSet = config.SaveOnConfigSet;
			config.SaveOnConfigSet = false;
			try
			{
				ConfigEntry<float> val2 = config.Bind<float>(section, oldKey, float.NegativeInfinity, (ConfigDescription)null);
				if (!float.IsNegativeInfinity(val2.Value))
				{
					newEntry.Value = val2.Value;
				}
				config.Remove(val);
			}
			finally
			{
				config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		private static void ResetObsoleteSpeedConfig(ConfigFile config)
		{
			for (int i = 0; i < ShieldSpeedRegistry.VanillaShieldPrefabs.Length; i++)
			{
				string text = ShieldSpeedRegistry.VanillaShieldPrefabs[i];
				ConfigEntry<float> val = config.Bind<float>("ShieldSpeeds", text, 1f, (ConfigDescription)null);
				if (!Mathf.Approximately(val.Value, 1f))
				{
					val.Value = 1f;
					Plugin.Log.LogInfo((object)("Shield Sledding: reset obsolete ShieldSpeeds." + text + " to 1.0 (unused)."));
				}
			}
			ConfigEntry<float> val2 = config.Bind<float>("ShieldSpeeds", "DefaultModdedSpeed", 1f, (ConfigDescription)null);
			if (!Mathf.Approximately(val2.Value, 1f))
			{
				val2.Value = 1f;
			}
			ConfigEntry<string> val3 = config.Bind<string>("ShieldSpeeds", "CustomModdedSpeeds", string.Empty, (ConfigDescription)null);
			if (!string.IsNullOrEmpty(val3.Value))
			{
				val3.Value = string.Empty;
			}
		}
	}
	internal static class DamageAbsorption
	{
		internal static bool ShouldAbsorb(Player player)
		{
			if (!Utility.IsLocalPlayer(player))
			{
				return false;
			}
			ShieldSledController instance = ShieldSledController.Instance;
			if (instance != null)
			{
				if (!instance.IsSledding)
				{
					return instance.IsArmed;
				}
				return true;
			}
			return false;
		}

		internal static bool TryAbsorb(Character character, HitData hit)
		{
			if (!ConfigManager.AbsorbDamageToShield.Value)
			{
				return false;
			}
			Player player = (Player)(object)((character is Player) ? character : null);
			if (!ShouldAbsorb(player) || hit == null)
			{
				return false;
			}
			float totalDamage = ((DamageTypes)(ref hit.m_damage)).GetTotalDamage();
			if (totalDamage <= 0.001f)
			{
				return false;
			}
			ShieldSledController instance = ShieldSledController.Instance;
			bool isSledding = instance.IsSledding;
			Character attacker = null;
			if (isSledding && ConfigManager.EndSledOnCombatHit.Value && totalDamage >= ConfigManager.CombatHitMinDamage.Value && TryGetCombatAttacker(hit, character, out attacker))
			{
				if (totalDamage > 1f)
				{
					EffectController.Instance?.ShakeCamera(totalDamage * 0.02f * ConfigManager.CameraShakeStrength.Value);
				}
				instance.EndSledding(player, SledEndReason.CombatHit);
				if (ConfigManager.StaggerOnCombatHit.Value)
				{
					ApplyCombatStagger(player, hit, attacker);
				}
				ClearHitDamage(hit);
				return true;
			}
			if (isSledding)
			{
				ItemData handShield = Utility.GetHandShield(player);
				if (handShield != null)
				{
					instance.ReportDamageAsShieldWear(player, handShield, totalDamage);
				}
			}
			if (totalDamage > 1f)
			{
				EffectController.Instance?.ShakeCamera(totalDamage * 0.01f * ConfigManager.CameraShakeStrength.Value);
			}
			ClearHitDamage(hit);
			return true;
		}

		internal static bool TryGetCombatAttacker(HitData hit, Character victim, out Character attacker)
		{
			attacker = hit.GetAttacker();
			if ((Object)(object)attacker == (Object)null || (Object)(object)attacker == (Object)(object)victim || attacker.IsDead())
			{
				return false;
			}
			return true;
		}

		private static void ApplyCombatStagger(Player player, HitData hit, Character attacker)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = hit.m_dir;
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f && (Object)(object)attacker != (Object)null)
			{
				val = ((Component)player).transform.position - ((Component)attacker).transform.position;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = -((Component)player).transform.forward;
			}
			((Character)player).Stagger(((Vector3)(ref val)).normalized);
		}

		internal static void ApplyLandingDamage(Player player, float impact)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || impact <= 0.5f)
			{
				return;
			}
			float num = impact * ConfigManager.LandingDamageMultiplier.Value;
			if (!(num <= 0.001f))
			{
				HitData val = new HitData();
				val.m_damage.m_blunt = num;
				val.m_point = ((Component)player).transform.position;
				val.m_dir = Vector3.down;
				((Character)player).Damage(val);
				if (num > 1f)
				{
					EffectController.Instance?.ShakeCamera(num * 0.01f * ConfigManager.CameraShakeStrength.Value);
				}
			}
		}

		internal static void ClearHitDamage(HitData hit)
		{
			if (hit != null)
			{
				hit.m_damage.m_blunt = 0f;
				hit.m_damage.m_slash = 0f;
				hit.m_damage.m_pierce = 0f;
				hit.m_damage.m_fire = 0f;
				hit.m_damage.m_frost = 0f;
				hit.m_damage.m_lightning = 0f;
				hit.m_damage.m_poison = 0f;
				hit.m_damage.m_spirit = 0f;
				hit.m_damage.m_chop = 0f;
				hit.m_damage.m_pickaxe = 0f;
				hit.m_staggerMultiplier = 0f;
				hit.m_pushForce = 0f;
			}
		}
	}
	internal sealed class DurabilityController
	{
		private Vector3 _lastPosition;

		private float _sessionTime;

		internal void Begin(Player player)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			_lastPosition = (((Object)(object)player != (Object)null) ? ((Component)player).transform.position : Vector3.zero);
			_sessionTime = 0f;
		}

		internal void Tick(Player player, ItemData shield, PhysicsResult result)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (ConfigManager.EnableDurabilityLoss.Value && !((Object)(object)player == (Object)null) && shield != null)
			{
				Vector3 position = ((Component)player).transform.position;
				float num = Vector3.Distance(position, _lastPosition);
				if (num > 3f)
				{
					num = 3f;
				}
				_lastPosition = position;
				_sessionTime += Time.fixedDeltaTime;
				float num2 = 1f;
				if ((int)result.Ground.Biome != 0)
				{
					num2 = Utility.GetDurabilityWearBiomeMultiplier(result.Ground.Biome);
				}
				float num3 = 0f;
				num3 += num * ConfigManager.DurabilityPerMeter.Value;
				num3 += Time.fixedDeltaTime * ConfigManager.DurabilityPerSecond.Value;
				num3 += result.HorizontalSpeed * 0.001f * ConfigManager.DurabilityPerMeter.Value;
				num3 *= num2;
				num3 *= ShieldSpeedRegistry.GetWearMultiplier(shield);
				ApplyWear(player, shield, num3);
			}
		}

		internal void OnLanding(Player player, ItemData shield, float impact)
		{
			if (ConfigManager.EnableDurabilityLoss.Value && shield != null && !(impact <= 0.5f))
			{
				float num = impact * ConfigManager.LandingDamageMultiplier.Value * 0.15f;
				num *= ShieldSpeedRegistry.GetWearMultiplier(shield);
				ApplyWear(player, shield, num);
			}
		}

		internal void OnCollision(Player player, ItemData shield, float impactForce)
		{
		}

		internal void OnDamage(Player player, ItemData shield, float damage)
		{
			if (ConfigManager.EnableDurabilityLoss.Value && shield != null && !(damage <= 0f))
			{
				float num = damage * ConfigManager.DamageToDurabilityMultiplier.Value;
				num *= ShieldSpeedRegistry.GetWearMultiplier(shield);
				num = Mathf.Min(num, shield.GetMaxDurability() * 0.08f);
				ApplyWear(player, shield, num);
			}
		}

		private void ApplyWear(Player player, ItemData shield, float wear)
		{
			if (!(wear <= 0f))
			{
				float num = shield.GetMaxDurability() * 0.05f;
				if (num > 0f)
				{
					wear = Mathf.Min(wear, num);
				}
				shield.m_durability -= wear;
				if (shield.m_durability <= 0f)
				{
					shield.m_durability = 0f;
					((Humanoid)player).UnequipItem(shield, true);
					ShieldSledController.Instance?.EndSledding(player, SledEndReason.ShieldBroken);
				}
			}
		}
	}
	internal sealed class EffectController
	{
		private readonly Dictionary<int, ParticleSystem> _remoteParticles = new Dictionary<int, ParticleSystem>();

		private ParticleSystem _localParticles;

		private float _fovOffset;

		private bool _tempFovActive;

		private static Material _sharedParticleMaterial;

		private static Texture2D _sharedParticleTexture;

		internal static EffectController Instance { get; private set; }

		internal float CurrentFovOffset => _fovOffset;

		internal EffectController()
		{
			Instance = this;
		}

		internal static void Prewarm()
		{
			if (!Utility.IsDedicatedServer())
			{
				EnsureSharedParticleMaterial();
			}
		}

		internal void Begin(Player player)
		{
			EnsureLocalParticles(player);
			if ((Object)(object)_localParticles != (Object)null && !_localParticles.isPlaying)
			{
				_localParticles.Stop(true, (ParticleSystemStopBehavior)0);
			}
		}

		internal void End(Player player)
		{
			CleanupForPlayer(player);
			ClearCameraEffects();
		}

		internal bool OwnsObject(GameObject go)
		{
			if ((Object)(object)go != (Object)null && (Object)(object)_localParticles != (Object)null)
			{
				return (Object)(object)go == (Object)(object)((Component)_localParticles).gameObject;
			}
			return false;
		}

		internal void WarmSimulate()
		{
			if (!((Object)(object)_localParticles == (Object)null))
			{
				_localParticles.Simulate(0.1f, true, true);
				_localParticles.Stop(true, (ParticleSystemStopBehavior)0);
			}
		}

		internal void CleanupOrphans()
		{
			if ((Object)(object)_localParticles != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_localParticles).gameObject);
				_localParticles = null;
			}
		}

		internal void CleanupForPlayer(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				if ((Object)(object)_localParticles != (Object)null)
				{
					_localParticles.Stop(true, (ParticleSystemStopBehavior)0);
				}
				ClearCameraEffects();
			}
		}

		internal void Update(Player player, float speed, float steerX)
		{
			if (!((Object)(object)player == (Object)null) && !Utility.IsDedicatedServer())
			{
				UpdateParticles(player, speed);
				if (!ConfigManager.EnableCameraEffects.Value)
				{
					ClearCameraEffects();
					UpdateRemoteEffects();
				}
				else
				{
					UpdateCamera(player, speed, steerX);
					UpdateRemoteEffects();
				}
			}
		}

		private void UpdateParticles(Player player, float speed)
		{
			if (!ConfigManager.EnableParticles.Value)
			{
				if ((Object)(object)_localParticles != (Object)null)
				{
					_localParticles.Stop(true, (ParticleSystemStopBehavior)1);
				}
			}
			else if (speed > 1f)
			{
				EnsureLocalParticles(player);
				if ((Object)(object)_localParticles != (Object)null && !_localParticles.isPlaying)
				{
					_localParticles.Play();
				}
			}
			else if ((Object)(object)_localParticles != (Object)null)
			{
				_localParticles.Stop(true, (ParticleSystemStopBehavior)1);
			}
		}

		internal void OnLanding(Player player, float impact)
		{
			if (Utility.IsLocalPlayer(player))
			{
				ShakeCamera(impact * ConfigManager.CameraShakeStrength.Value * 0.02f);
			}
		}

		internal void OnCollision(Player player, Vector3 point, Vector3 normal, float impact)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (Utility.IsLocalPlayer(player))
			{
				ShakeCamera(impact * ConfigManager.CameraShakeStrength.Value * 0.03f);
			}
			if (ConfigManager.EnableShieldSparks.Value && ConfigManager.EnableParticles.Value)
			{
				SpawnBurst(point, normal, new Color(1f, 0.7f, 0.2f), 12);
			}
		}

		internal void OnRemoteCollision(Vector3 point, Vector3 normal, float impact)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!(impact < 1f) && !Utility.IsDedicatedServer() && ConfigManager.EnableShieldSparks.Value && ConfigManager.EnableParticles.Value)
			{
				SpawnBurst(point, normal, new Color(1f, 0.7f, 0.2f), 12);
			}
		}

		internal void OnWildlifeImpact(Player player, Vector3 point, Vector3 direction, float impact)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (Utility.IsLocalPlayer(player))
			{
				ShakeCamera(impact * ConfigManager.CameraShakeStrength.Value * 0.04f);
			}
			if (ConfigManager.EnableShieldSparks.Value && ConfigManager.EnableParticles.Value)
			{
				SpawnBurst(point, direction, new Color(1f, 0.7f, 0.2f), 18);
			}
		}

		internal void ShakeCamera(float strength)
		{
		}

		private void EnsureLocalParticles(Player player)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Expected O, but got Unknown
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_localParticles != (Object)null)
			{
				Transform feetAttach = ShieldSledVisual.GetFeetAttach(player);
				Transform val = (((Object)(object)feetAttach != (Object)null) ? feetAttach : ((Component)player).transform);
				if ((Object)(object)((Component)_localParticles).transform.parent != (Object)(object)val)
				{
					((Component)_localParticles).transform.SetParent(val, false);
					((Component)_localParticles).transform.localPosition = (Vector3)(((Object)(object)feetAttach != (Object)null) ? Vector3.zero : new Vector3(0f, 0.1f, 0.4f));
				}
				return;
			}
			Transform feetAttach2 = ShieldSledVisual.GetFeetAttach(player);
			GameObject val2 = new GameObject("ShieldSledding_LocalParticles");
			val2.transform.SetParent(((Object)(object)feetAttach2 != (Object)null) ? feetAttach2 : ((Component)player).transform, false);
			val2.transform.localPosition = (Vector3)(((Object)(object)feetAttach2 != (Object)null) ? Vector3.zero : new Vector3(0f, 0.1f, 0.4f));
			_localParticles = val2.AddComponent<ParticleSystem>();
			MainModule main = _localParticles.main;
			((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.45f);
			((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(1.5f);
			((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.08f);
			((MainModule)(ref main)).maxParticles = 48;
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
			((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.92f, 0.96f, 1f, 0.65f));
			EmissionModule emission = _localParticles.emission;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(18f);
			ShapeModule shape = _localParticles.shape;
			((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4;
			((ShapeModule)(ref shape)).angle = 14f;
			((ShapeModule)(ref shape)).radius = 0.15f;
			ColorOverLifetimeModule colorOverLifetime = _localParticles.colorOverLifetime;
			((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true;
			Gradient val3 = new Gradient();
			val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
			{
				new GradientColorKey(new Color(0.95f, 0.98f, 1f), 0f),
				new GradientColorKey(new Color(0.75f, 0.88f, 1f), 1f)
			}, (GradientAlphaKey[])(object)new GradientAlphaKey[2]
			{
				new GradientAlphaKey(0.65f, 0f),
				new GradientAlphaKey(0f, 1f)
			});
			((ColorOverLifetimeModule)(ref colorOverLifetime)).color = MinMaxGradient.op_Implicit(val3);
			ApplyParticleMaterial(_localParticles);
			_localParticles.Stop(true, (ParticleSystemStopBehavior)0);
		}

		private static Shader FindParticleShader()
		{
			string[] array = new string[7] { "Legacy Shaders/Particles/Alpha Blended", "Particles/Standard Unlit", "Mobile/Particles/Alpha Blended", "Particles/Additive", "Mobile/Particles/Additive", "Sprites/Default", "Unlit/Transparent" };
			for (int i = 0; i < array.Length; i++)
			{
				Shader val = Shader.Find(array[i]);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static Texture2D CreateSoftParticleTexture()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false)
			{
				name = "ShieldSledding_SoftParticle",
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)1
			};
			float num = 31.5f;
			float num2 = num;
			Color[] array = (Color[])(object)new Color[4096];
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					float num3 = ((float)j - num) / num2;
					float num4 = ((float)i - num) / num2;
					float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4);
					float num6 = ((num5 >= 1f) ? 0f : Mathf.Pow(1f - num5, 1.65f));
					array[i * 64 + j] = new Color(1f, 1f, 1f, num6);
				}
			}
			val.SetPixels(array);
			val.Apply(false, true);
			return val;
		}

		private static Material EnsureSharedParticleMaterial()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_sharedParticleMaterial != (Object)null)
			{
				return _sharedParticleMaterial;
			}
			Shader val = FindParticleShader();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			if ((Object)(object)_sharedParticleTexture == (Object)null)
			{
				_sharedParticleTexture = CreateSoftParticleTexture();
			}
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.92f, 0.96f, 1f, 0.55f);
			Material val3 = new Material(val);
			((Object)val3).name = "ShieldSledding_ParticleMat";
			val3.mainTexture = (Texture)(object)_sharedParticleTexture;
			if (val3.HasProperty("_MainTex"))
			{
				val3.SetTexture("_MainTex", (Texture)(object)_sharedParticleTexture);
			}
			if (val3.HasProperty("_Color"))
			{
				val3.SetColor("_Color", val2);
			}
			if (val3.HasProperty("_TintColor"))
			{
				val3.SetColor("_TintColor", val2);
			}
			val3.color = val2;
			if (val3.HasProperty("_Mode"))
			{
				val3.SetFloat("_Mode", 2f);
			}
			val3.SetInt("_SrcBlend", 5);
			val3.SetInt("_DstBlend", 10);
			val3.SetInt("_ZWrite", 0);
			val3.DisableKeyword("_ALPHATEST_ON");
			val3.EnableKeyword("_ALPHABLEND_ON");
			val3.DisableKeyword("_ALPHAPREMULTIPLY_ON");
			val3.renderQueue = 3000;
			_sharedParticleMaterial = val3;
			return _sharedParticleMaterial;
		}

		private static void ApplyParticleMaterial(ParticleSystem particles)
		{
			if ((Object)(object)particles == (Object)null)
			{
				return;
			}
			ParticleSystemRenderer component = ((Component)particles).GetComponent<ParticleSystemRenderer>();
			if (!((Object)(object)component == (Object)null))
			{
				Material val = EnsureSharedParticleMaterial();
				if (!((Object)(object)val == (Object)null))
				{
					component.renderMode = (ParticleSystemRenderMode)0;
					((Renderer)component).sharedMaterial = val;
				}
			}
		}

		private void UpdateCamera(Player player, float speed, float steerX)
		{
		}

		private void ClearTempFov(GameCamera gameCamera)
		{
			if (_tempFovActive)
			{
				if (gameCamera != null)
				{
					gameCamera.ResetTempFOV();
				}
				_tempFovActive = false;
			}
		}

		private void ClearCameraEffects()
		{
			_fovOffset = 0f;
			ClearTempFov(GameCamera.instance);
		}

		private void UpdateRemoteEffects()
		{
			List<Player> allPlayers = Player.GetAllPlayers();
			if (allPlayers == null)
			{
				return;
			}
			for (int i = 0; i < allPlayers.Count; i++)
			{
				Player val = allPlayers[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)Player.m_localPlayer))
				{
					if (!MultiplayerSync.Instance.TryReadRemoteState(val, out var active, out var speed, out var _))
					{
						StopRemote(val);
					}
					else if (!active || speed < 1f || !ConfigManager.EnableParticles.Value)
					{
						StopRemote(val);
					}
					else
					{
						EnsureRemoteParticles(val);
					}
				}
			}
		}

		private void EnsureRemoteParticles(Player player)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			int instanceID = ((Object)player).GetInstanceID();
			if (!_remoteParticles.ContainsKey(instanceID))
			{
				GameObject val = new GameObject("ShieldSledding_RemoteParticles");
				val.transform.SetParent(((Component)player).transform, false);
				val.transform.localPosition = new Vector3(0f, 0.1f, 0.4f);
				ParticleSystem val2 = val.AddComponent<ParticleSystem>();
				MainModule main = val2.main;
				((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.4f);
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(1.2f);
				((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.08f);
				((MainModule)(ref main)).maxParticles = 24;
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.95f, 0.98f, 1f, 0.5f));
				ApplyParticleMaterial(val2);
				val2.Play();
				_remoteParticles[instanceID] = val2;
			}
		}

		private void StopRemote(Player player)
		{
			int instanceID = ((Object)player).GetInstanceID();
			if (_remoteParticles.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null)
			{
				value.Stop(true, (ParticleSystemStopBehavior)1);
			}
		}

		private static void SpawnBurst(Vector3 point, Vector3 normal, Color color, int count)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!Utility.IsDedicatedServer())
			{
				GameObject val = new GameObject("ShieldSledding_SparkBurst");
				val.transform.position = point;
				if (((Vector3)(ref normal)).sqrMagnitude > 0.01f)
				{
					val.transform.rotation = Quaternion.LookRotation(((Vector3)(ref normal)).normalized);
				}
				ParticleSystem val2 = val.AddComponent<ParticleSystem>();
				MainModule main = val2.main;
				((MainModule)(ref main)).duration = 0.2f;
				((MainModule)(ref main)).loop = false;
				((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.35f);
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(2.5f);
				((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.06f);
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(color);
				((MainModule)(ref main)).maxParticles = count;
				((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
				EmissionModule emission = val2.emission;
				((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f);
				((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1]
				{
					new Burst(0f, (short)count)
				});
				ShapeModule shape = val2.shape;
				((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4;
				((ShapeModule)(ref shape)).angle = 35f;
				((ShapeModule)(ref shape)).radius = 0.05f;
				ApplyParticleMaterial(val2);
				val2.Play();
				Object.Destroy((Object)(object)val, 1.25f);
			}
		}
	}
	internal sealed class MultiplayerSync
	{
		private struct RemoteSledState
		{
			internal bool Active;

			internal float Speed;

			internal string ShieldPrefab;
		}

		internal const string ImpactRpc = "ShieldSledding_Impact";

		internal const string StateRpc = "ShieldSledding_State";

		private static readonly int ZdoActive = StringExtensionMethods.GetStableHashCode("SS_Active");

		private static readonly int ZdoShieldPrefab = StringExtensionMethods.GetStableHashCode("SS_ShieldPrefab");

		private static readonly int ZdoSpeed = StringExtensionMethods.GetStableHashCode("SS_Speed");

		private readonly HashSet<int> _registeredViews = new HashSet<int>();

		private readonly Dictionary<int, RemoteSledState> _remoteStates = new Dictionary<int, RemoteSledState>();

		private float _lastWriteTime;

		private bool _lastActive;

		private float _lastSpeed;

		private string _lastShield = string.Empty;

		internal static MultiplayerSync Instance { get; private set; }

		internal MultiplayerSync()
		{
			Instance = this;
		}

		internal static void EnsureRegistered(ZNetView nview)
		{
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return;
			}
			MultiplayerSync sync = Instance;
			if (sync == null)
			{
				return;
			}
			int id = ((Object)nview).GetInstanceID();
			if (!sync._registeredViews.Add(id))
			{
				return;
			}
			nview.Register<Vector3, float>("ShieldSledding_Impact", (Action<long, Vector3, float>)delegate(long sender, Vector3 point, float impact)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				if (!(impact < 1f) && sender != ZNet.GetUID())
				{
					EffectController.Instance?.OnRemoteCollision(point, Vector3.up, impact);
					AudioController.Instance?.PlayImpact(Player.m_localPlayer, impact);
				}
			});
			nview.Register<bool, float, string>("ShieldSledding_State", (Action<long, bool, float, string>)delegate(long sender, bool active, float speed, string shieldPrefab)
			{
				if (sender != ZNet.GetUID())
				{
					sync._remoteStates[id] = new RemoteSledState
					{
						Active = active,
						Speed = speed,
						ShieldPrefab = (shieldPrefab ?? string.Empty)
					};
				}
			});
		}

		internal void WriteLocalState(Player player, bool active, float speed)
		{
			if ((Object)(object)player == (Object)null || !Utility.IsLocalPlayer(player))
			{
				return;
			}
			ZDO playerZdo = Utility.GetPlayerZdo(player);
			if (playerZdo == null)
			{
				return;
			}
			string text = string.Empty;
			ItemData val = Utility.GetEquippedShield(player);
			if (val == null)
			{
				val = ShieldSledController.Instance?.LockedShield;
			}
			if (val != null)
			{
				text = Utility.GetShieldPrefabName(val);
			}
			if ((active && Time.time - _lastWriteTime >= 1f) || active != _lastActive || !Mathf.Approximately(speed, _lastSpeed) || !(text == _lastShield) || !(Time.time - _lastWriteTime < 0.1f))
			{
				playerZdo.Set(ZdoActive, active ? 1 : 0, false);
				playerZdo.Set(ZdoSpeed, speed);
				if (!string.IsNullOrEmpty(text))
				{
					playerZdo.Set(ZdoShieldPrefab, text);
				}
				else if (!active)
				{
					playerZdo.Set(ZdoShieldPrefab, string.Empty);
				}
				_lastActive = active;
				_lastSpeed = speed;
				_lastShield = text;
				_lastWriteTime = Time.time;
				BroadcastLocalState(player, active, speed, text);
			}
		}

		private static void BroadcastLocalState(Player player, bool active, float speed, string shield)
		{
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				EnsureRegistered(component);
				component.InvokeRPC(ZNetView.Everybody, "ShieldSledding_State", new object[3]
				{
					active,
					speed,
					shield ?? string.Empty
				});
			}
		}

		internal bool TryReadRemoteState(Player player, out bool active, out float speed, out string shieldPrefab)
		{
			active = false;
			speed = 0f;
			shieldPrefab = string.Empty;
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				EnsureRegistered(component);
				if (_remoteStates.TryGetValue(((Object)component).GetInstanceID(), out var value))
				{
					active = value.Active;
					speed = value.Speed;
					shieldPrefab = value.ShieldPrefab ?? string.Empty;
					return true;
				}
			}
			ZDO playerZdo = Utility.GetPlayerZdo(player);
			if (playerZdo == null)
			{
				return false;
			}
			active = playerZdo.GetInt(ZdoActive, 0) != 0;
			speed = playerZdo.GetFloat(ZdoSpeed, 0f);
			shieldPrefab = playerZdo.GetString(ZdoShieldPrefab, string.Empty);
			return true;
		}

		internal void ClearRemoteState(ZNetView nview)
		{
			if (!((Object)(object)nview == (Object)null))
			{
				int instanceID = ((Object)nview).GetInstanceID();
				_remoteStates.Remove(instanceID);
				_registeredViews.Remove(instanceID);
			}
		}

		internal void UpdateRemotePlayers()
		{
			List<Player> allPlayers = Player.GetAllPlayers();
			if (allPlayers == null)
			{
				return;
			}
			for (int i = 0; i < allPlayers.Count; i++)
			{
				Player val = allPlayers[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)Player.m_localPlayer))
				{
					EnsureRegistered(((Component)val).GetComponent<ZNetView>());
				}
			}
			ShieldSledVisual.UpdateRemotePlayers();
		}

		internal void SendImpactEvent(Player player, Vector3 point, float impact)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null))
			{
				ZNetView component = ((Component)player).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					EnsureRegistered(component);
					component.InvokeRPC(ZNetView.Everybody, "ShieldSledding_Impact", new object[2] { point, impact });
				}
			}
		}
	}
	internal struct SledRunRecord
	{
		public float Distance;

		public float MaxSpeed;

		public float LongestJump;

		public string TimestampUtc;
	}
	internal struct GhostFrame
	{
		public Vector3 Position;

		public Quaternion Rotation;

		public float Time;
	}
	internal static class GhostReplaySystem
	{
		private static readonly List<GhostFrame> Frames = new List<GhostFrame>();

		private static GameObject _ghost;

		private static float _sessionStart;

		internal static void BeginSession()
		{
			Frames.Clear();
			_sessionStart = Time.time;
			DestroyGhost();
		}

		internal static void RecordFrame(Player player)
		{
		}

		internal static void EndSession()
		{
			Frames.Clear();
			DestroyGhost();
		}

		private static void SpawnGhostPlayback()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			DestroyGhost();
			_ghost = new GameObject("ShieldSledding_Ghost");
			_ghost.AddComponent<GhostPlayback>().Initialize(Frames.ToArray());
		}

		private static void DestroyGhost()
		{
			if ((Object)(object)_ghost != (Object)null)
			{
				Object.Destroy((Object)(object)_ghost);
				_ghost = null;
			}
		}
	}
	internal sealed class GhostPlayback : MonoBehaviour
	{
		private GhostFrame[] _frames;

		private int _index;

		private float _startTime;

		internal void Initialize(GhostFrame[] frames)
		{
			_frames = frames;
			_index = 0;
			_startTime = Time.time;
			TryCreateGhostVisual(((Component)this).transform);
		}

		private static void TryCreateGhostVisual(Transform parent)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_00b3: 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)
			Shader val = FindGhostShader();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)1);
			val2.transform.SetParent(parent, false);
			val2.transform.localScale = new Vector3(0.5f, 0.9f, 0.5f);
			Collider component = val2.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Renderer component2 = val2.GetComponent<Renderer>();
			if ((Object)(object)component2 == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return;
			}
			Material val3 = new Material(val);
			Color val4 = default(Color);
			((Color)(ref val4))..ctor(0.4f, 0.8f, 1f, 0.35f);
			if (val3.HasProperty("_Color"))
			{
				val3.SetColor("_Color", val4);
			}
			else
			{
				val3.color = val4;
			}
			component2.material = val3;
		}

		private static Shader FindGhostShader()
		{
			string[] array = new string[4] { "Custom/StandardClear", "Custom/StandardDoubleSided", "Unlit/Color", "Sprites/Default" };
			for (int i = 0; i < array.Length; i++)
			{
				Shader val = Shader.Find(array[i]);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private void Update()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (_frames == null || _frames.Length == 0)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			float num = Time.time - _startTime;
			while (_index < _frames.Length - 1 && _frames[_index + 1].Time <= num)
			{
				_index++;
			}
			GhostFrame ghostFrame = _frames[_index];
			((Component)this).transform.SetPositionAndRotation(ghostFrame.Position, ghostFrame.Rotation);
			if (_index >= _frames.Length - 1 && num > _frames[_frames.Length - 1].Time + 1f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	internal static class RecordsManager
	{
		private static string FilePath => Path.Combine(Paths.ConfigPath, "ShieldSledding_Records.json");

		internal static void SaveRun(SledRunRecord record)
		{
			List<string> list = new List<string>();
			if (File.Exists(FilePath))
			{
				list.AddRange(File.ReadAllLines(FilePath));
			}
			list.Add($"{record.TimestampUtc}|{record.Distance:F2}|{record.MaxSpeed:F2}|{record.LongestJump:F2}");
			if (list.Count > 200)
			{
				list.RemoveAt(0);
			}
			File.WriteAllLines(FilePath, list);
		}
	}
	internal static class LeaderboardManager
	{
		private static readonly List<SledRunRecord> Entries = new List<SledRunRecord>();

		private static string FilePath => Path.Combine(Paths.ConfigPath, "ShieldSledding_Leaderboard.json");

		internal static void Submit(SledRunRecord record)
		{
			Entries.Add(record);
			Entries.Sort((SledRunRecord a, SledRunRecord b) => b.MaxSpeed.CompareTo(a.MaxSpeed));
			if (Entries.Count > 25)
			{
				Entries.RemoveAt(Entries.Count - 1);
			}
			List<string> list = new List<string>(Entries.Count);
			for (int num = 0; num < Entries.Count; num++)
			{
				SledRunRecord sledRunRecord = Entries[num];
				list.Add($"{sledRunRecord.TimestampUtc}|{sledRunRecord.Distance:F2}|{sledRunRecord.MaxSpeed:F2}|{sledRunRecord.LongestJump:F2}");
			}
			File.WriteAllLines(FilePath, list);
		}
	}
	internal static class TimeTrialManager
	{
		private static float _startTime;

		private static bool _active;

		internal static void BeginSession()
		{
		}

		internal static void EndSession()
		{
		}
	}
	internal static class SledPatches
	{
		internal static bool UpdateMotionPatched;

		internal static void Apply(Harmony harmony)
		{
			PatchMethod(harmony, typeof(Character), "Jump", "CharacterJumpPrefix", "CharacterJumpPostfix");
			PatchMethod(harmony, typeof(Player), "SetControls", "PlayerSetControlsPrefix");
			PatchMethod(harmony, typeof(Humanoid), "UpdateBlock", "HumanoidUpdateBlockPrefix");
			PatchMethod(harmony, typeof(Humanoid), "EquipItem", "HumanoidEquipItemPrefix");
			PatchMethod(harmony, typeof(Humanoid), "UnequipItem", "HumanoidUnequipItemPrefix");
			PatchMethod(harmony, typeof(Character), "UpdateMotion", "CharacterUpdateMotionPrefix", null, new Type[1] { typeof(float) });
			PatchDeclaredMethod(harmony, typeof(Character), "Damage", "CharacterDamagePrefix", null, new Type[1] { typeof(HitData) });
			PatchAllDeclaredMethods(harmony, typeof(Character), "RPC_Damage", "CharacterRpcDamagePrefix");
			PatchMethod(harmony, typeof(Character), "UpdateGroundContact", "CharacterUpdateGroundContactPrefix", "CharacterUpdateGroundContactPostfix");
			PatchMethod(harmony, typeof(Character), "UpdateWater", "CharacterUpdateWaterPrefix");
			PatchMethod(harmony, typeof(Character), "UnderWorldCheck", "CharacterUnderWorldCheckPrefix", null, new Type[1] { typeof(float) });
			PatchMethod(harmony, typeof(VisEquipment), "UpdateEquipmentVisuals", "VisEquipmentUpdateEquipmentVisualsPrefix", "VisEquipmentUpdateEquipmentPostfix");
			PatchMethod(harmony, typeof(ZNetView), "OnDestroy", "ZNetViewOnDestroyPrefix");
		}

		private static void PatchMethod(Harmony harmony, Type type, string methodName, string prefix = null, string postfix = null, Type[] argTypes = null)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = ((argTypes == null) ? AccessTools.Method(type, methodName, (Type[])null, (Type[])null) : AccessTools.Method(type, methodName, argTypes, (Type[])null));
			if (methodInfo == null)
			{
				Plugin.Log.LogError((object)("Shield Sledding: could not patch " + type.Name + "." + methodName));
				return;
			}
			if (type == typeof(Character) && methodName == "UpdateMotion")
			{
				UpdateMotionPatched = true;
			}
			harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(SledPatches), prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(SledPatches), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			if (Plugin.DebugLogEnabled)
			{
				Plugin.Log.LogInfo((object)("Shield Sledding: patched " + type.Name + "." + methodName));
			}
		}

		private static void PatchDeclaredMethod(Harmony harmony, Type type, string methodName, string prefix = null, string postfix = null, Type[] argTypes = null)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = ((argTypes == null) ? AccessTools.DeclaredMethod(type, methodName, (Type[])null, (Type[])null) : AccessTools.DeclaredMethod(type, methodName, argTypes, (Type[])null));
			if (methodInfo == null)
			{
				Plugin.Log.LogError((object)("Shield Sledding: could not patch declared " + type.Name + "." + methodName));
				return;
			}
			harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(SledPatches), prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(SledPatches), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			if (Plugin.DebugLogEnabled)
			{
				Plugin.Log.LogInfo((object)("Shield Sledding: patched declared " + type.Name + "." + methodName));
			}
		}

		private static void PatchAllDeclaredMethods(Harmony harm