Decompiled source of WinterSled v0.1.2

plugins/WinterSled.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Rendering;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace WinterSled
{
	internal class CartSnowDrag : MonoBehaviour
	{
		private const float ProbeInterval = 0.25f;

		private Vagon m_vagon;

		private float m_probeTimer;

		public static CartSnowDrag LocalPulled { get; private set; }

		public Surface Surface { get; private set; }

		private void Awake()
		{
			m_vagon = ((Component)this).GetComponent<Vagon>();
		}

		private void OnDestroy()
		{
			if ((Object)(object)LocalPulled == (Object)(object)this)
			{
				LocalPulled = null;
			}
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)m_vagon == (Object)null)
			{
				return;
			}
			if (!Plugin.Cfg.SlowCartsInSnow.Value || !m_vagon.IsAttached((Character)(object)localPlayer))
			{
				if ((Object)(object)LocalPulled == (Object)(object)this)
				{
					LocalPulled = null;
					CartSnowEffect.Remove(localPlayer);
				}
				return;
			}
			if ((m_probeTimer -= Time.deltaTime) < 0f)
			{
				m_probeTimer = 0.25f;
				Surface = Probe();
			}
			LocalPulled = this;
			if (SurfaceProbe.IsSnowy(Surface) && Surface != Surface.Ice)
			{
				CartSnowEffect.Ensure(localPlayer);
			}
			else
			{
				CartSnowEffect.Remove(localPlayer);
			}
		}

		private Surface Probe()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			SurfaceProbe.ProbeBelow(((Component)this).transform, ((Component)this).transform.position + Vector3.up * 1.5f, 3f, out var surface);
			return surface;
		}

		public float SpeedFactor()
		{
			return Surface switch
			{
				Surface.Snow => Plugin.Cfg.CartSnowPullSpeed.Value, 
				Surface.Powder => Plugin.Cfg.CartPowderPullSpeed.Value, 
				_ => 1f, 
			};
		}
	}
	internal class CartSnowEffect : StatusEffect
	{
		public const string EffectName = "SE_WinterSledCartSnow";

		public static readonly int Hash = StringExtensionMethods.GetStableHashCode("SE_WinterSledCartSnow");

		public static StatusEffect Create(Sprite icon)
		{
			CartSnowEffect cartSnowEffect = ScriptableObject.CreateInstance<CartSnowEffect>();
			((Object)cartSnowEffect).name = "SE_WinterSledCartSnow";
			((StatusEffect)cartSnowEffect).m_name = "$se_wintersled_cart";
			((StatusEffect)cartSnowEffect).m_tooltip = "$se_wintersled_cart_tooltip";
			((StatusEffect)cartSnowEffect).m_icon = icon;
			((StatusEffect)cartSnowEffect).m_ttl = 0f;
			return (StatusEffect)(object)cartSnowEffect;
		}

		public static void Ensure(Player player)
		{
			SEMan sEMan = ((Character)player).GetSEMan();
			if (!sEMan.HaveStatusEffect(Hash))
			{
				sEMan.AddStatusEffect(Hash, false, 0, 0f, (short)(-1));
			}
		}

		public static void Remove(Player player)
		{
			if (((Character)player).GetSEMan().HaveStatusEffect(Hash))
			{
				((Character)player).GetSEMan().RemoveStatusEffect(Hash, true);
			}
		}

		public override void ModifySpeed(float baseSpeed, ref float speed, Character character, Vector3 dir)
		{
			CartSnowDrag localPulled = CartSnowDrag.LocalPulled;
			if ((Object)(object)localPulled != (Object)null)
			{
				speed -= baseSpeed * (1f - localPulled.SpeedFactor());
			}
		}

		public override string GetIconText()
		{
			CartSnowDrag localPulled = CartSnowDrag.LocalPulled;
			if (!((Object)(object)localPulled != (Object)null))
			{
				return "";
			}
			return Localization.instance.Localize(SurfaceProbe.LocalizationKey(localPulled.Surface));
		}

		public override bool IsDone()
		{
			return (Object)(object)CartSnowDrag.LocalPulled == (Object)null;
		}
	}
	[HarmonyPatch(typeof(Vagon), "Awake")]
	internal static class AddCartSnowDrag
	{
		private static void Postfix(Vagon __instance)
		{
			if (__instance.m_wheels != null && __instance.m_wheels.Length != 0 && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<SledController>()) && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<CartSnowDrag>()))
			{
				((Component)__instance).gameObject.AddComponent<CartSnowDrag>();
			}
		}
	}
	internal static class LiveSettings
	{
		public static void Hook()
		{
			SledConfig cfg = Plugin.Cfg;
			cfg.BaseMass.SettingChanged += delegate
			{
				ApplyBody();
			};
			cfg.CrashMinSpeed.SettingChanged += delegate
			{
				ApplyBody();
			};
			cfg.CrashMaxSpeed.SettingChanged += delegate
			{
				ApplyBody();
			};
			cfg.Recipe.SettingChanged += delegate
			{
				ApplyRecipe();
			};
			cfg.SeasonalRecipe.SettingChanged += delegate
			{
				ApplyRecipe();
			};
			PrefabManager.OnPrefabsRegistered += ApplyRecipe;
			ItemManager.OnItemsRegistered += ApplyRecipe;
		}

		private static GameObject Prefab()
		{
			return PrefabManager.Instance.GetPrefab("WinterSled");
		}

		private static void ApplyBody()
		{
			GameObject val = Prefab();
			IEnumerable<GameObject> enumerable = SledController.Instances.Select((SledController s) => ((Component)s).gameObject);
			if ((Object)(object)val != (Object)null)
			{
				enumerable = enumerable.Concat((IEnumerable<GameObject>)(object)new GameObject[1] { val });
			}
			Vagon val2 = default(Vagon);
			ImpactEffect val3 = default(ImpactEffect);
			foreach (GameObject item in enumerable)
			{
				if (item.TryGetComponent<Vagon>(ref val2))
				{
					val2.m_baseMass = Plugin.Cfg.BaseMass.Value;
					if ((Object)(object)val2.m_nview != (Object)null && val2.m_nview.IsValid() && val2.m_nview.IsOwner())
					{
						val2.UpdateMass();
					}
				}
				if (item.TryGetComponent<ImpactEffect>(ref val3))
				{
					val3.m_minVelocity = Plugin.Cfg.CrashMinSpeed.Value;
					val3.m_maxVelocity = Plugin.Cfg.CrashMaxSpeed.Value;
				}
			}
		}

		public static void ApplyRecipe()
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			GameObject val = Prefab();
			if ((Object)(object)val == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			bool seasonal;
			string text = Plugin.Cfg.ActiveRecipe(out seasonal);
			List<Requirement> list = new List<Requirement>();
			foreach (KeyValuePair<string, int> item in Plugin.Cfg.ParseRecipe(text))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.Key);
				ItemDrop val2 = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log.LogWarning((object)("Recipe item '" + item.Key + "' doesn't exist, skipped"));
					continue;
				}
				list.Add(new Requirement
				{
					m_resItem = val2,
					m_amount = item.Value,
					m_recover = true
				});
			}
			if (list.Count > 0)
			{
				val.GetComponent<Piece>().m_resources = list.ToArray();
				Plugin.Log.LogInfo((object)("Sled recipe now: " + text));
			}
		}
	}
	internal static class ObjMesh
	{
		public static Mesh Load(string resourceName, out List<string> materials)
		{
			using Stream stream = typeof(ObjMesh).Assembly.GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				throw new FileNotFoundException("embedded resource missing", resourceName);
			}
			using StreamReader reader = new StreamReader(stream);
			return Parse(reader, resourceName, out materials);
		}

		private static Mesh Parse(TextReader reader, string name, out List<string> materials)
		{
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			List<Vector2> list2 = new List<Vector2>();
			List<Vector3> list3 = new List<Vector3>();
			List<Vector3> list4 = new List<Vector3>();
			List<Vector2> list5 = new List<Vector2>();
			List<Vector3> list6 = new List<Vector3>();
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			List<List<int>> list7 = new List<List<int>>();
			materials = new List<string>();
			List<int> list8 = null;
			string text;
			while ((text = reader.ReadLine()) != null)
			{
				string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length == 0)
				{
					continue;
				}
				switch (array[0])
				{
				case "v":
					list.Add(new Vector3(0f - F(array[1]), F(array[2]), F(array[3])));
					break;
				case "vt":
					list2.Add(new Vector2(F(array[1]), F(array[2])));
					break;
				case "vn":
					list3.Add(new Vector3(0f - F(array[1]), F(array[2]), F(array[3])));
					break;
				case "usemtl":
				{
					int num = materials.IndexOf(array[1]);
					if (num < 0)
					{
						materials.Add(array[1]);
						list7.Add(new List<int>());
						num = materials.Count - 1;
					}
					list8 = list7[num];
					break;
				}
				case "f":
				{
					if (list8 == null)
					{
						materials.Add("default");
						list8 = new List<int>();
						list7.Add(list8);
					}
					int[] array2 = new int[array.Length - 1];
					for (int i = 1; i < array.Length; i++)
					{
						if (!dictionary.TryGetValue(array[i], out var value))
						{
							string[] array3 = array[i].Split(new char[1] { '/' });
							value = list4.Count;
							list4.Add(list[int.Parse(array3[0]) - 1]);
							list5.Add((array3.Length > 1 && array3[1].Length > 0) ? list2[int.Parse(array3[1]) - 1] : Vector2.zero);
							list6.Add((array3.Length > 2 && array3[2].Length > 0) ? list3[int.Parse(array3[2]) - 1] : Vector3.up);
							dictionary[array[i]] = value;
						}
						array2[i - 1] = value;
					}
					for (int j = 1; j + 1 < array2.Length; j++)
					{
						list8.Add(array2[0]);
						list8.Add(array2[j + 1]);
						list8.Add(array2[j]);
					}
					break;
				}
				}
			}
			Mesh val = new Mesh
			{
				name = name
			};
			if (list4.Count > 65000)
			{
				val.indexFormat = (IndexFormat)1;
			}
			val.SetVertices(list4);
			val.SetUVs(0, list5);
			val.SetNormals(list6);
			val.subMeshCount = list7.Count;
			for (int k = 0; k < list7.Count; k++)
			{
				val.SetTriangles(list7[k], k);
			}
			val.RecalculateBounds();
			val.RecalculateTangents();
			return val;
		}

		private static float F(string s)
		{
			return float.Parse(s, CultureInfo.InvariantCulture);
		}
	}
	[HarmonyPatch(typeof(Vagon), "UpdateLoadVisualization")]
	internal static class HideLoadUnderRider
	{
		private const float FrontOfRider = 0.3f;

		private static void Postfix(Vagon __instance)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			SledSeat componentInChildren = ((Component)__instance).GetComponentInChildren<SledSeat>();
			if ((Object)(object)componentInChildren == (Object)null || !componentInChildren.HaveValidRider())
			{
				return;
			}
			foreach (LoadData loadVi in __instance.m_loadVis)
			{
				if (((Component)__instance).transform.InverseTransformPoint(loadVi.m_gameobject.transform.position).z < 0.3f)
				{
					loadVi.m_gameobject.SetActive(false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Floating), "CustomFixedUpdate")]
	internal static class NoFloatingOnIce
	{
		private static bool Prefix(Floating __instance)
		{
			SledController sledController = default(SledController);
			if (((Component)__instance).TryGetComponent<SledController>(ref sledController) && sledController.OnSolidGround)
			{
				__instance.SetSurfaceEffect(false);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateWalking")]
	internal static class SureFootedWhilePulling
	{
		private static void Prefix(Character __instance, ref bool __state)
		{
			__state = (Object)(object)__instance == (Object)(object)Player.m_localPlayer && !__instance.m_iceShoes && (Object)(object)SledController.LocalPulled != (Object)null && Plugin.Cfg.SureFootedPulling.Value && LosesFooting(__instance.m_lastGroundCollider);
			if (__state)
			{
				__instance.m_iceShoes = true;
			}
		}

		private static void Postfix(Character __instance, bool __state)
		{
			if (__state)
			{
				__instance.m_iceShoes = false;
			}
		}

		private static bool LosesFooting(Collider ground)
		{
			if ((Object)(object)ground == (Object)null)
			{
				return false;
			}
			if (((Object)ground).name == "IceSurface")
			{
				return true;
			}
			PhysicsMaterial sharedMaterial = ground.sharedMaterial;
			if ((Object)(object)sharedMaterial != (Object)null && sharedMaterial.dynamicFriction <= 0f)
			{
				return (Character.s_slipperyStuffMask & ((Component)ground).gameObject.layer) != 0;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ImpactEffect), "OnCollisionEnter")]
	internal static class CrashOnlyHeadOn
	{
		private static bool Prefix(ImpactEffect __instance, Collision info)
		{
			//IL_0020: 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_002c: 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)
			SledController sledController = default(SledController);
			if (info.contactCount == 0 || !((Component)__instance).TryGetComponent<SledController>(ref sledController))
			{
				return true;
			}
			float num = 0f;
			for (int i = 0; i < info.contactCount; i++)
			{
				float num2 = num;
				Vector3 relativeVelocity = info.relativeVelocity;
				ContactPoint contact = info.GetContact(i);
				num = Mathf.Max(num2, Mathf.Abs(Vector3.Dot(relativeVelocity, ((ContactPoint)(ref contact)).normal)));
			}
			return num >= __instance.m_minVelocity;
		}
	}
	[BepInPlugin("rgeraskin.WinterSled", "WinterSled", "0.1.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class Plugin : BaseUnityPlugin
	{
		public const string Guid = "rgeraskin.WinterSled";

		public const string Name = "WinterSled";

		public const string Version = "0.1.2";

		internal static ManualLogSource Log;

		internal static SledConfig Cfg;

		private void Awake()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new SledConfig(((BaseUnityPlugin)this).Config);
			Translations.Register();
			SeasonsCompat.Init();
			SeasonalityCompat.Init();
			LiveSettings.Hook();
			PrefabManager.OnVanillaPrefabsAvailable += SledBuilder.Register;
			new Harmony("rgeraskin.WinterSled").PatchAll(typeof(Plugin).Assembly);
		}
	}
	internal static class SeasonsCompat
	{
		public const string Guid = "shudnal.Seasons";

		private static bool s_ready;

		private static FieldInfo s_seasonState;

		private static MethodInfo s_getCurrentSeason;

		private static PropertyInfo s_isActive;

		private static MethodInfo s_useTextures;

		private static MethodInfo s_hasBiomeOverride;

		private static object s_season;

		private static float s_seasonTime = -1f;

		private static float s_looksTime = float.MinValue;

		private static readonly Dictionary<Biome, Biome> s_looks = new Dictionary<Biome, Biome>();

		public static bool Installed { get; private set; }

		public static void Init()
		{
			if (!Chainloader.PluginInfos.TryGetValue("shudnal.Seasons", out var value) || (Object)(object)value.Instance == (Object)null)
			{
				return;
			}
			Installed = true;
			try
			{
				Assembly assembly = ((object)value.Instance).GetType().Assembly;
				Type type = assembly.GetType("Seasons.Seasons");
				Type type2 = assembly.GetType("Seasons.SeasonState");
				Type? type3 = assembly.GetType("Seasons.Heightmap_GetBiomeColor_TerrainColor");
				s_seasonState = type?.GetField("seasonState", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				s_getCurrentSeason = type2?.GetMethod("GetCurrentSeason", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				s_isActive = type2?.GetProperty("IsActive", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				s_useTextures = type?.GetMethod("UseTextureControllers", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				s_hasBiomeOverride = type3?.GetMethod("HasBiomeOverride", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				s_ready = s_seasonState != null && s_getCurrentSeason != null && s_hasBiomeOverride != null;
				Plugin.Log.LogInfo((object)(s_ready ? $"Seasons {value.Metadata.Version} found: snow follows the seasons" : $"Seasons {value.Metadata.Version} found, but its internals changed; seasonal snow is ignored"));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Seasons support disabled: " + ex.Message));
			}
		}

		public static Biome LooksLike(Biome biome)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (!s_ready && !SeasonalityCompat.Installed)
			{
				return biome;
			}
			if (Time.time - s_looksTime > 2f)
			{
				s_looksTime = Time.time;
				s_looks.Clear();
			}
			if (!s_looks.TryGetValue(biome, out var value))
			{
				value = LooksLikeNow(biome);
				s_looks[biome] = value;
			}
			return value;
		}

		private static Biome LooksLikeNow(Biome biome)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0071: 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_0066: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			biome = SeasonalityCompat.LooksLike(biome);
			if (!s_ready)
			{
				return biome;
			}
			try
			{
				if (s_isActive != null && !(bool)s_isActive.GetValue(null))
				{
					return biome;
				}
				if (s_useTextures != null && !(bool)s_useTextures.Invoke(null, null))
				{
					return biome;
				}
				object obj = CurrentSeason();
				if (obj == null)
				{
					return biome;
				}
				object[] array = new object[3] { biome, obj, null };
				if ((bool)s_hasBiomeOverride.Invoke(null, array) && array[2] != null)
				{
					return (Biome)Convert.ToInt32(array[2]);
				}
			}
			catch (Exception ex)
			{
				s_ready = false;
				Plugin.Log.LogWarning((object)("Seasons support disabled after an error: " + ex.Message));
			}
			return biome;
		}

		private static object CurrentSeason()
		{
			if (Time.time - s_seasonTime > 2f || s_season == null)
			{
				s_seasonTime = Time.time;
				object value = s_seasonState.GetValue(null);
				s_season = ((value != null) ? s_getCurrentSeason.Invoke(value, null) : null);
			}
			return s_season;
		}

		public static string CurrentSeasonName()
		{
			if (!s_ready)
			{
				return null;
			}
			return CurrentSeason()?.ToString();
		}
	}
	internal static class SeasonalityCompat
	{
		public const string Guid = "RustyMods.Seasonality";

		private static PropertyInfo s_value;

		private static object s_entry;

		public static bool Installed => s_entry != null;

		public static void Init()
		{
			if (!Chainloader.PluginInfos.TryGetValue("RustyMods.Seasonality", out var value) || (Object)(object)value.Instance == (Object)null)
			{
				return;
			}
			try
			{
				s_entry = (((object)value.Instance).GetType().Assembly.GetType("Seasonality.Configs")?.GetField("m_season", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null);
				s_value = s_entry?.GetType().GetProperty("Value");
				if (s_value == null)
				{
					s_entry = null;
				}
				Plugin.Log.LogInfo((object)(Installed ? $"Seasonality {value.Metadata.Version} found: snow follows the seasons" : $"Seasonality {value.Metadata.Version} found, but its internals changed; seasonal snow is ignored"));
			}
			catch (Exception ex)
			{
				s_entry = null;
				Plugin.Log.LogWarning((object)("Seasonality support disabled: " + ex.Message));
			}
		}

		public static Biome LooksLike(Biome biome)
		{
			//IL_003e: 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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (!Installed)
			{
				return biome;
			}
			try
			{
				if (s_value.GetValue(s_entry)?.ToString() != "Winter")
				{
					return biome;
				}
			}
			catch (Exception)
			{
				s_entry = null;
				return biome;
			}
			return WinterLooksLike(biome);
		}

		public static Biome WinterLooksLike(Biome biome)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)biome <= 8)
			{
				if (biome - 1 <= 1 || (int)biome == 8)
				{
					goto IL_001d;
				}
			}
			else if ((int)biome == 16 || (int)biome == 512)
			{
				goto IL_001d;
			}
			return biome;
			IL_001d:
			return (Biome)4;
		}
	}
	internal class SledAudio : MonoBehaviour
	{
		internal enum Loop
		{
			Snow,
			Ice,
			Ground,
			Frozen,
			Wind
		}

		internal const int Rate = 22050;

		internal const float LoopSeconds = 5f;

		private const float SpeedSmoothing = 0.4f;

		private static readonly Dictionary<Loop, AudioClip> s_clips = new Dictionary<Loop, AudioClip>();

		private static readonly MethodInfo s_setData = typeof(AudioClip).GetMethod("SetData", new Type[2]
		{
			typeof(float[]),
			typeof(int)
		});

		private readonly Dictionary<Loop, AudioSource> m_sources = new Dictionary<Loop, AudioSource>();

		private SledController m_sled;

		private float m_speed;

		private void Start()
		{
			m_sled = ((Component)this).GetComponent<SledController>();
			AudioSource componentInChildren = ((Component)this).GetComponentInChildren<AudioSource>(true);
			AudioMixerGroup val = ((componentInChildren != null) ? componentInChildren.outputAudioMixerGroup : null);
			if ((Object)(object)val == (Object)null && (Object)(object)AudioMan.instance != (Object)null && (Object)(object)AudioMan.instance.m_masterMixer != (Object)null)
			{
				AudioMixerGroup[] array = AudioMan.instance.m_masterMixer.FindMatchingGroups("SFX");
				val = ((array.Length != 0) ? array[0] : null);
			}
			foreach (Loop value in Enum.GetValues(typeof(Loop)))
			{
				AudioSource val2 = ((Component)this).gameObject.AddComponent<AudioSource>();
				val2.clip = Clip(value);
				val2.loop = true;
				val2.playOnAwake = false;
				val2.spatialBlend = 1f;
				val2.rolloffMode = (AudioRolloffMode)1;
				val2.minDistance = 2f;
				val2.maxDistance = 40f;
				val2.dopplerLevel = 0f;
				val2.volume = 0f;
				val2.outputAudioMixerGroup = val;
				val2.time = Random.Range(0f, 5f);
				m_sources[value] = val2;
			}
		}

		private void Update()
		{
			if ((Object)(object)m_sled == (Object)null)
			{
				return;
			}
			m_speed += (m_sled.Speed - m_speed) * (1f - Mathf.Exp((0f - Time.deltaTime) / 0.4f));
			float speed = m_speed;
			float value = Plugin.Cfg.SoundVolume.Value;
			float num = Mathf.Clamp01(speed / 8f);
			Surface shownSurface = m_sled.ShownSurface;
			bool touching = m_sled.Touching;
			Loop? loop = null;
			switch (shownSurface)
			{
			case Surface.Snow:
			case Surface.Powder:
				loop = Loop.Snow;
				break;
			case Surface.Ice:
				loop = Loop.Ice;
				break;
			case Surface.Ground:
			case Surface.Wood:
			case Surface.Stone:
				loop = Loop.Ground;
				break;
			case Surface.FrozenGround:
				loop = Loop.Frozen;
				break;
			}
			float deltaTime = Time.deltaTime;
			foreach (KeyValuePair<Loop, AudioSource> source in m_sources)
			{
				float num2 = 0f;
				float num3 = 1f;
				if (source.Key == Loop.Wind)
				{
					num2 = (m_sled.HasRider() ? (Mathf.Clamp01((speed - 6f) / 10f) * 0.5f) : 0f);
					num3 = Mathf.Lerp(0.8f, 1.3f, Mathf.Clamp01(speed / 18f));
				}
				else if (touching && loop == source.Key && speed > 0.15f)
				{
					num2 = Mathf.Lerp(0.15f, 1f, num) * Mathf.Clamp01(speed / 0.8f);
					num3 = ((shownSurface == Surface.Ice) ? Mathf.Lerp(0.95f, 1.08f, num) : Mathf.Lerp(0.85f, 1.25f, num));
					if (shownSurface == Surface.Powder)
					{
						num3 *= 0.8f;
						num2 = Mathf.Min(1f, num2 * 1.2f);
					}
				}
				AudioSource value2 = source.Value;
				value2.volume = Mathf.MoveTowards(value2.volume, num2 * value, deltaTime * 2.5f);
				value2.pitch = Mathf.MoveTowards(value2.pitch, num3, deltaTime * 2f);
				if (value2.volume > 0.001f && !value2.isPlaying)
				{
					value2.Play();
				}
				else if (value2.volume <= 0.001f && value2.isPlaying)
				{
					value2.Stop();
				}
			}
		}

		public float VolumeOf(string loop)
		{
			if (!Enum.TryParse<Loop>(loop, ignoreCase: true, out var result) || !m_sources.TryGetValue(result, out var value))
			{
				return 0f;
			}
			return value.volume;
		}

		public string Describe()
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<Loop, AudioSource> source in m_sources)
			{
				list.Add(string.Format("{0}={1:0.00}{2}@{3:0.00}", source.Key, source.Value.volume, source.Value.isPlaying ? "▶" : "", source.Value.pitch));
			}
			return string.Join(" ", list);
		}

		private static AudioClip Clip(Loop loop)
		{
			if (!s_clips.TryGetValue(loop, out var value) || (Object)(object)value == (Object)null)
			{
				value = AudioClip.Create("wintersled_" + loop.ToString().ToLowerInvariant(), 110250, 1, 22050, false);
				s_setData.Invoke(value, new object[2]
				{
					Synthesize(loop),
					0
				});
				s_clips[loop] = value;
			}
			return value;
		}

		internal static float[] Synthesize(Loop loop)
		{
			int num = 110250;
			int num2 = 11025;
			Random random = new Random((int)(1000 + loop));
			float[] array = new float[num + num2];
			float num3 = 0f;
			float num4 = 0f;
			float num5 = 0f;
			float num6 = 0f;
			float num7 = 0f;
			float num8 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float num9 = (float)(random.NextDouble() * 2.0 - 1.0);
				float num10;
				switch (loop)
				{
				case Loop.Snow:
					num3 += (num9 - num3) * 0.18f;
					if (random.NextDouble() < 0.0025)
					{
						num7 = 0.9f * (float)(random.NextDouble() * 0.6 + 0.4);
					}
					num7 *= 0.985f;
					num10 = num3 * 0.55f + num9 * num7 * 0.6f;
					break;
				case Loop.Ice:
				{
					num3 += (num9 - num3) * 0.6f;
					num4 += (num3 - num4) * 0.06f;
					if (random.NextDouble() < 0.035)
					{
						num7 = (float)(random.NextDouble() * 0.5 + 0.5);
					}
					num7 *= 0.65f;
					num5 += (num9 - num5) * 0.12f;
					num6 += (num5 - num6) * 0.02f;
					float num11 = (float)Math.Tanh((num5 - num6) * 10f) * 0.6f;
					num10 = num3 - num4 + num3 * num7 * 1.7f + num11;
					break;
				}
				case Loop.Ground:
				case Loop.Frozen:
				{
					bool flag = loop == Loop.Frozen;
					num3 += (num9 - num3) * (flag ? 0.12f : 0.05f);
					num4 += (num3 - num4) * (flag ? 0.25f : 0.12f);
					if (random.NextDouble() < (flag ? 0.006 : 0.004))
					{
						num7 = (float)(random.NextDouble() * 0.7 + 0.3);
					}
					num7 *= (flag ? 0.93f : 0.9f);
					num10 = num4 * (flag ? 2.2f : 3.2f) + num9 * num7 * (flag ? 0.45f : 0.35f);
					break;
				}
				default:
					num3 += (num9 - num3) * 0.03f;
					num8 += 4.5351473E-05f;
					num10 = num3 * (1.6f + 0.6f * Mathf.Sin(num8 * 2.1f) * Mathf.Sin(num8 * 0.7f));
					break;
				}
				array[i] = num10;
			}
			float[] array2 = new float[num];
			Array.Copy(array, array2, num);
			for (int j = 0; j < num2; j++)
			{
				float num12 = (float)j / (float)num2;
				array2[j] = array[num + j] * Mathf.Cos(num12 * (float)Math.PI / 2f) + array[j] * Mathf.Sin(num12 * (float)Math.PI / 2f);
			}
			float num13 = 0.0001f;
			float[] array3 = array2;
			foreach (float num14 in array3)
			{
				num13 = Mathf.Max(num13, Mathf.Abs(num14));
			}
			for (int l = 0; l < num; l++)
			{
				array2[l] *= 0.8f / num13;
			}
			return array2;
		}
	}
	internal static class SledBuilder
	{
		public const string PrefabName = "WinterSled";

		public const float BodyDrop = 0.1f;

		public const float DeckTop = 0.48200002f;

		private const float RunnerX = 0.7f;

		private const float RunnerRadius = 0.05f;

		private const string MeshResource = "WinterSled.sled_undercarriage.obj";

		public static int GroundMask { get; private set; }

		public static void Register()
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Expected O, but got Unknown
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			try
			{
				GroundMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "terrain", "piece", "Default_small", "vehicle" });
				GameObject val = PrefabManager.Instance.CreateClonedPrefab("WinterSled", "Cart");
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogError((object)"The vanilla Cart prefab is missing, the sled can't be built");
					return;
				}
				Build(val);
				Sprite val2 = RenderIcon(val) ?? val.GetComponent<Piece>().m_icon;
				PieceConfig val3 = new PieceConfig
				{
					Name = "$piece_wintersled",
					Description = "$piece_wintersled_desc",
					PieceTable = PieceTables.Hammer,
					Category = PieceCategories.Misc,
					CraftingStation = CraftingStations.Workbench,
					Icon = val2
				};
				bool seasonal;
				string text = Plugin.Cfg.ActiveRecipe(out seasonal);
				Plugin.Log.LogInfo((object)("Sled recipe (" + (seasonal ? "seasons mod found" : "regular") + "): " + text));
				foreach (KeyValuePair<string, int> item in Plugin.Cfg.ParseRecipe(text))
				{
					val3.AddRequirement(new RequirementConfig(item.Key, item.Value, 0, true));
				}
				PieceManager.Instance.AddPiece(new CustomPiece(val, false, val3));
				ItemManager.Instance.AddStatusEffect(new CustomStatusEffect(SledHaulEffect.Create(val2), false));
				GameObject prefab = PrefabManager.Instance.GetPrefab("Cart");
				ItemManager.Instance.AddStatusEffect(new CustomStatusEffect(CartSnowEffect.Create(((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>().m_icon : val2), false));
				Vagon vagon = default(Vagon);
				if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent<Vagon>(ref vagon))
				{
					BuildSeat(prefab.transform, vagon, 0.582f);
				}
				Plugin.Log.LogInfo((object)"Winter sled registered");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Building the sled failed: {arg}");
			}
		}

		private static void Build(GameObject prefab)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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)
			Transform transform = prefab.transform;
			Vagon component = prefab.GetComponent<Vagon>();
			foreach (Rigidbody item in component.m_wheels.Where((Rigidbody w) => (Object)(object)w != (Object)null))
			{
				Object.DestroyImmediate((Object)(object)((Component)item).gameObject);
			}
			component.m_wheels = Array.Empty<Rigidbody>();
			foreach (Transform item2 in transform)
			{
				item2.localPosition += Vector3.down * 0.1f;
			}
			component.m_attachPoint.localPosition = new Vector3(0f, 0.8f, component.m_attachPoint.localPosition.z + 0.05f);
			component.m_name = "$piece_wintersled";
			component.m_baseMass = Plugin.Cfg.BaseMass.Value;
			component.m_slipperyCollider = null;
			foreach (LoadData loadVi in component.m_loadVis)
			{
				loadVi.m_gameobject.SetActive(false);
			}
			prefab.GetComponent<Piece>().m_allowedInDeepSnow = true;
			WearNTear component2 = prefab.GetComponent<WearNTear>();
			if ((Object)(object)component2 != (Object)null && component2.m_fragmentRoots != null)
			{
				component2.m_fragmentRoots = component2.m_fragmentRoots.Where((GameObject r) => (Object)(object)r != (Object)null).ToArray();
			}
			ImpactEffect component3 = prefab.GetComponent<ImpactEffect>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.m_minVelocity = Plugin.Cfg.CrashMinSpeed.Value;
				component3.m_maxVelocity = Plugin.Cfg.CrashMaxSpeed.Value;
			}
			int layer = (from r in prefab.GetComponentsInChildren<MeshRenderer>(true)
				select ((Component)r).gameObject.layer).FirstOrDefault();
			Renderer renderer = BuildUndercarriage(transform, layer, component);
			AddToLods(prefab, renderer);
			BuildRunnerColliders(transform, component);
			BuildSeat(transform, component, 0.48200002f);
			prefab.AddComponent<SledController>();
			prefab.AddComponent<SledAudio>();
		}

		private static Renderer BuildUndercarriage(Transform root, int layer, Vagon vagon)
		{
			//IL_0012: 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)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			List<string> materials;
			Mesh sharedMesh = ObjMesh.Load("WinterSled.sled_undercarriage.obj", out materials);
			GameObject val = new GameObject("sled_undercarriage")
			{
				layer = layer
			};
			val.transform.SetParent(root, false);
			val.AddComponent<MeshFilter>().sharedMesh = sharedMesh;
			MeshRenderer val2 = val.AddComponent<MeshRenderer>();
			Material fallback = (from r in ((Component)root).GetComponentsInChildren<MeshRenderer>(true)
				select ((Renderer)r).sharedMaterial).FirstOrDefault((Func<Material, bool>)((Material m) => (Object)(object)m != (Object)null));
			((Renderer)val2).sharedMaterials = SledMaterials.Resolve(materials, fallback);
			Plugin.Log.LogInfo((object)("Undercarriage materials: " + string.Join(", ", materials.Zip(((Renderer)val2).sharedMaterials, (string n, Material m) => n + "=" + ((m != null) ? ((Object)m).name : null)))));
			return (Renderer)(object)val2;
		}

		private static void AddToLods(GameObject prefab, Renderer renderer)
		{
			LODGroup component = prefab.GetComponent<LODGroup>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			LOD[] lODs = component.GetLODs();
			if (lODs.Length == 0)
			{
				return;
			}
			lODs[0].renderers = lODs[0].renderers.Where((Renderer r) => (Object)(object)r != (Object)null).Concat((IEnumerable<Renderer>)(object)new Renderer[1] { renderer }).ToArray();
			for (int num = 1; num < lODs.Length; num++)
			{
				lODs[num].renderers = lODs[num].renderers.Where((Renderer r) => (Object)(object)r != (Object)null).ToArray();
			}
			component.SetLODs(lODs);
		}

		private static void BuildRunnerColliders(Transform root, Vagon vagon)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("sled_runners");
			Transform obj = root.Find("Vagon");
			Collider val2 = ((obj != null) ? ((Component)obj).GetComponent<Collider>() : null);
			val.layer = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject.layer : ((Component)root).gameObject.layer);
			val.transform.SetParent(root, false);
			float[] array = new float[2] { -0.7f, 0.7f };
			Vector3 val3 = default(Vector3);
			Vector3 val4 = default(Vector3);
			Vector3 val5 = default(Vector3);
			Vector3 val6 = default(Vector3);
			foreach (float num in array)
			{
				string text = ((num < 0f) ? "left" : "right");
				AddCapsule(val.transform, "runner_" + text, new Vector3(num, 0.05f, 0.02f), 2.12f, Quaternion.identity);
				((Vector3)(ref val3))..ctor(num, 0.060000002f, 1f);
				((Vector3)(ref val4))..ctor(num, 0.36f, 1.24f);
				AddCapsule(val.transform, "runner_" + text + "_curl", (val3 + val4) / 2f, Vector3.Distance(val3, val4) + 0.1f, Quaternion.LookRotation(val4 - val3));
				((Vector3)(ref val5))..ctor(num, 0.05f, -1f);
				((Vector3)(ref val6))..ctor(num, 0.11f, -1.16f);
				AddCapsule(val.transform, "runner_" + text + "_tail", (val5 + val6) / 2f, Vector3.Distance(val5, val6) + 0.1f, Quaternion.LookRotation(val6 - val5));
				GameObject val7 = new GameObject("runner_tail");
				val7.transform.SetParent(val.transform, false);
				val7.transform.localPosition = new Vector3(num, 0.05f, -1.15f);
			}
		}

		private static void AddCapsule(Transform parent, string name, Vector3 center, float length, Quaternion rotation)
		{
			//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_0017: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name)
			{
				layer = ((Component)parent).gameObject.layer
			};
			val.transform.SetParent(parent, false);
			val.transform.localPosition = center;
			val.transform.localRotation = rotation;
			CapsuleCollider obj = val.AddComponent<CapsuleCollider>();
			obj.direction = 2;
			obj.radius = 0.05f;
			obj.height = length;
		}

		private static void BuildSeat(Transform root, Vagon vagon, float deckTop)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_003f: 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_009e: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)vagon.m_container != (Object)null)
			{
				Transform transform = ((Component)vagon.m_container).transform;
				transform.localPosition += new Vector3(0f, 0f, 0.25f);
				transform.localScale = Vector3.Scale(transform.localScale, new Vector3(1f, 1f, 0.72f));
			}
			GameObject val = new GameObject("sled_seat")
			{
				layer = (((Object)(object)vagon.m_container != (Object)null) ? ((Component)vagon.m_container).gameObject.layer : ((Component)root).gameObject.layer)
			};
			val.transform.SetParent(root, false);
			val.transform.localPosition = new Vector3(0f, deckTop + 0.33f, -0.66f);
			BoxCollider obj = val.AddComponent<BoxCollider>();
			((Collider)obj).isTrigger = true;
			obj.size = new Vector3(1.2f, 0.4f, 0.62f);
			GameObject val2 = new GameObject("attach");
			val2.transform.SetParent(val.transform, false);
			val2.transform.position = root.TransformPoint(new Vector3(0f, deckTop + 0.02f, -0.58f));
			val.AddComponent<SledSeat>().m_attachPoint = val2.transform;
		}

		private static Sprite RenderIcon(GameObject prefab)
		{
			//IL_0005: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_005d: Expected O, but got Unknown
			try
			{
				Quaternion rotation = Quaternion.AngleAxis(25f, Vector3.right) * Quaternion.Euler(0f, 145f, 0f);
				return RenderManager.Instance.Render(new RenderRequest(prefab)
				{
					Rotation = rotation,
					Width = 128,
					Height = 128,
					UseCache = false
				});
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Icon render failed, using the cart's icon: " + ex.Message));
				return null;
			}
		}
	}
	internal class SledConfig
	{
		public readonly ConfigEntry<string> Recipe;

		public readonly ConfigEntry<string> SeasonalRecipe;

		public readonly ConfigEntry<float> BaseMass;

		public readonly ConfigEntry<float> SnowFriction;

		public readonly ConfigEntry<float> PowderFriction;

		public readonly ConfigEntry<float> IceFriction;

		public readonly ConfigEntry<float> WoodFriction;

		public readonly ConfigEntry<float> StoneFriction;

		public readonly ConfigEntry<float> GroundFriction;

		public readonly ConfigEntry<float> FrozenGroundFriction;

		public readonly ConfigEntry<float> RunnerGrip;

		public readonly ConfigEntry<float> IceGrip;

		public readonly ConfigEntry<float> MaxSpeed;

		public readonly ConfigEntry<float> AirDrag;

		public readonly ConfigEntry<float> Stability;

		public readonly ConfigEntry<float> StaticFrictionSpeed;

		public readonly ConfigEntry<float> CliffAngle;

		public readonly ConfigEntry<float> PowderDepth;

		public readonly ConfigEntry<float> CrashMinSpeed;

		public readonly ConfigEntry<float> CrashMaxSpeed;

		public readonly ConfigEntry<float> GroundPullSpeed;

		public readonly ConfigEntry<float> FloorPullSpeed;

		public readonly ConfigEntry<float> FrozenPullSpeed;

		public readonly ConfigEntry<float> LoadPenalty;

		public readonly ConfigEntry<float> FullLoadWeight;

		public readonly ConfigEntry<float> GroundStaminaDrain;

		public readonly ConfigEntry<bool> SureFootedPulling;

		public readonly ConfigEntry<bool> SlowCartsInSnow;

		public readonly ConfigEntry<float> CartSnowPullSpeed;

		public readonly ConfigEntry<float> CartPowderPullSpeed;

		public readonly ConfigEntry<bool> CartSeat;

		public readonly ConfigEntry<float> SteerStrength;

		public readonly ConfigEntry<float> BrakeFriction;

		public readonly ConfigEntry<float> PushImpulse;

		public readonly ConfigEntry<float> PushStamina;

		public readonly ConfigEntry<float> PushMaxSpeed;

		public readonly ConfigEntry<float> SteerResponse;

		public readonly ConfigEntry<string> SeatAnimation;

		public readonly ConfigEntry<bool> SnowSpray;

		public readonly ConfigEntry<float> SoundVolume;

		public readonly ConfigEntry<bool> DebugLog;

		private const string General = "1 - General";

		private const string Effects = "2 - Sound and effects";

		private const string Hauling = "3 - Hauling";

		private const string Riding = "4 - Riding";

		private const string Surfaces = "5 - Advanced: runner friction";

		private const string Physics = "6 - Advanced: physics";

		private readonly ConfigFile m_config;

		private int m_order = 1000;

		public SledConfig(ConfigFile config)
		{
			m_config = config;
			Recipe = Bind("1 - General", "Requirements", "Wood:20,FineWood:10,Iron:4,WolfPelt:2", "Build cost, ItemName:amount pairs separated by commas. Applies right away.");
			SeasonalRecipe = Bind("1 - General", "SeasonalRequirements", "Wood:20,LeatherScraps:8,BronzeNails:10", "Build cost used instead when Seasons or Seasonality is installed: their winter brings snow to the Meadows and Black Forest long before the Mountains, so the sled unlocks with bronze, like the cart. Leave it empty to always use Requirements. Applies right away.");
			SlowCartsInSnow = Bind("1 - General", "SlowCartsInSnow", value: true, "Wheeled vehicles (the vanilla cart) slow you down in snow, where the sled glides.");
			CartSnowPullSpeed = BindNumber("1 - General", "CartSnowPullSpeed", 0.8f, "Speed multiplier while pulling a cart over snow.");
			CartPowderPullSpeed = BindNumber("1 - General", "CartPowderPullSpeed", 0.6f, "Speed multiplier while pulling a cart through Deep North powder.");
			CartSeat = Bind("1 - General", "CartSeat", value: true, "Players can sit in the vanilla cart too, as passengers (no steering or brakes: someone pulls, or it rolls).");
			SoundVolume = BindNumber("2 - Sound and effects", "SoundVolume", 0.6f, "Volume of the runners' sound (snow hiss, ice song, ground scrape) and the wind when riding.", 0f, 1f, synced: false);
			SnowSpray = Bind("2 - Sound and effects", "SnowSpray", value: true, "Kick up snow behind the runners when moving fast on snow.", synced: false);
			SeatAnimation = Bind("2 - Sound and effects", "SeatAnimation", "emote_sit", "Animator flag used while riding: emote_sit sits on the deck with legs forward, attach_chair sits upright.", synced: false);
			GroundPullSpeed = BindNumber("3 - Hauling", "GroundPullSpeed", 0.8f, "Walk/run speed multiplier while dragging an empty sled over bare ground, on top of the runners' own drag.");
			FrozenPullSpeed = BindNumber("3 - Hauling", "FrozenPullSpeed", 0.9f, "Speed multiplier while dragging the sled over frozen bare ground, on top of the runners' own drag.");
			FloorPullSpeed = BindNumber("3 - Hauling", "FloorPullSpeed", 0.9f, "Speed multiplier while dragging the sled over wood or stone floors.");
			LoadPenalty = BindNumber("3 - Hauling", "LoadPenalty", 0.1f, "Extra speed lost on bare ground with a fully loaded sled (cargo already makes the runners drag harder).");
			FullLoadWeight = BindNumber("3 - Hauling", "FullLoadWeight", 400f, "Cargo weight that counts as fully loaded for LoadPenalty.", 50f, 2000f);
			GroundStaminaDrain = BindNumber("3 - Hauling", "GroundStaminaDrain", 1.5f, "Run stamina drain multiplier while dragging the sled over bare ground.", 1f, 5f);
			SureFootedPulling = Bind("3 - Hauling", "SureFootedPulling", value: true, "Pulling a sled, you keep your footing where the game takes it away on ice (Deep North ice, and with Seasons frozen water shallower than 4 m), as in ice shoes: you run with the sled there as on other ice. More than vanilla allows: there the vanilla cart can't be pulled at all. Off: vanilla rules, the sled drags you to a crawl there.");
			MaxSpeed = BindNumber("4 - Riding", "MaxSpeed", 16f, "Speed (m/s) above which air drag grows steeply.", 4f, 40f);
			SteerStrength = BindNumber("4 - Riding", "SteerStrength", 1f, "How hard A/D turn the sled when you ride it downhill.", 0f, 4f);
			BrakeFriction = BindNumber("4 - Riding", "BrakeFriction", 0.2f, "Extra runner friction while you hold S to brake.");
			PushImpulse = BindNumber("4 - Riding", "PushImpulse", 1f, "Speed (m/s) one push-off adds, at low speed: one push per press of W, like a kick; on a sled that has stopped, S kicks back the same way.", 0f, 3f);
			PushStamina = BindNumber("4 - Riding", "PushStamina", 6f, "Stamina one push-off costs.", 0f, 30f);
			PushMaxSpeed = BindNumber("4 - Riding", "PushMaxSpeed", 3f, "Pushing off works below this speed (m/s), in the direction of the push.", 0f, 15f);
			CrashMinSpeed = BindNumber("4 - Riding", "CrashMinSpeed", 6f, "Impact speed (m/s) from which hitting something damages the sled and what it hits.", 1f, 40f);
			CrashMaxSpeed = BindNumber("4 - Riding", "CrashMaxSpeed", 14f, "Impact speed (m/s) of full crash damage.", 1f, 60f);
			SnowFriction = BindNumber("5 - Advanced: runner friction", "SnowFriction", 0.06f, "Runner friction along the sled on packed snow (mountains, Deep North).");
			PowderFriction = BindNumber("5 - Advanced: runner friction", "PowderFriction", 0.15f, "Runner friction in deep Deep North powder.");
			IceFriction = BindNumber("5 - Advanced: runner friction", "IceFriction", 0.012f, "Runner friction on ice.");
			FrozenGroundFriction = BindNumber("5 - Advanced: runner friction", "FrozenGroundFriction", 0.25f, "Runner friction on frozen bare ground: snow-free (dirt-cleared) ground in the cold biomes, or anywhere a seasons mod has winter.");
			WoodFriction = BindNumber("5 - Advanced: runner friction", "WoodFriction", 0.22f, "Runner friction on wooden floors and ramps.");
			StoneFriction = BindNumber("5 - Advanced: runner friction", "StoneFriction", 0.35f, "Runner friction on stone and metal floors, rock, and paved roads in the cold biomes.");
			GroundFriction = BindNumber("5 - Advanced: runner friction", "GroundFriction", 0.55f, "Runner friction on bare, unfrozen ground: grass, dirt, sand.");
			RunnerGrip = BindNumber("5 - Advanced: runner friction", "RunnerGrip", 0.6f, "Sideways friction of the runners: how well the sled holds its line on slopes and in turns.");
			IceGrip = BindNumber("5 - Advanced: runner friction", "IceGrip", 0.15f, "Sideways friction of the runners on ice.");
			BaseMass = BindNumber("6 - Advanced: physics", "BaseMass", 40f, "Empty sled mass. Cargo adds 10% of its weight, like the cart.", 10f, 200f);
			AirDrag = BindNumber("6 - Advanced: physics", "AirResistance", 0.12f, "Air drag (N per (m/s)²) of a sled with a rider. MaxSpeed tops out a downhill run; this is what a sled coasting on the flat loses.", 0f, 5f);
			Stability = BindNumber("6 - Advanced: physics", "Stability", 1f, "How hard the sled keeps itself level with the ground under it (and flat in the air), against tipping over on bumps. 0 = none.", 0f, 3f);
			StaticFrictionSpeed = BindNumber("6 - Advanced: physics", "StaticFrictionSpeed", 1.5f, "Below this speed (m/s) a sled nobody pulls or rides is held by the runners' static friction (they settle into the snow), so it stays put on a slope; not on ice.", 0f, 10f);
			SteerResponse = BindNumber("6 - Advanced: physics", "SteerResponse", 20f, "How quickly the sled answers A/D (turn rate gain); the runners' grip fights it.", 1f, 60f);
			CliffAngle = BindNumber("6 - Advanced: physics", "CliffAngle", 52f, "Slopes steeper than this (degrees) in the cold biomes are bare rock, not snow.", 20f, 89f);
			PowderDepth = BindNumber("6 - Advanced: physics", "PowderDepth", 0.3f, "Deep North snow deeper than this (m) is powder.");
			DebugLog = Bind("6 - Advanced: physics", "DebugLog", value: false, "Log the surface and forces under the sled once a second.", synced: false);
		}

		private ConfigurationManagerAttributes Attributes(string section, bool synced)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			return new ConfigurationManagerAttributes
			{
				IsAdminOnly = synced,
				IsAdvanced = (section == "5 - Advanced: runner friction" || section == "6 - Advanced: physics"),
				Order = m_order--
			};
		}

		private ConfigEntry<float> BindNumber(string section, string key, float value, string description, float min = 0f, float max = 2f, bool synced = true)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			return m_config.Bind<float>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), new object[1] { Attributes(section, synced) }));
		}

		private ConfigEntry<T> Bind<T>(string section, string key, T value, string description, bool synced = true)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			return m_config.Bind<T>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { Attributes(section, synced) }));
		}

		public string ActiveRecipe(out bool seasonal)
		{
			seasonal = (SeasonsCompat.Installed || SeasonalityCompat.Installed) && !string.IsNullOrWhiteSpace(SeasonalRecipe.Value);
			if (!seasonal)
			{
				return Recipe.Value;
			}
			return SeasonalRecipe.Value;
		}

		public IEnumerable<KeyValuePair<string, int>> ParseRecipe(string recipe)
		{
			string[] array = recipe.Split(new char[1] { ',' });
			foreach (string text in array)
			{
				string[] array2 = text.Split(new char[1] { ':' });
				if (array2.Length == 2 && int.TryParse(array2[1].Trim(), out var result) && result > 0)
				{
					yield return new KeyValuePair<string, int>(array2[0].Trim(), result);
				}
				else if (text.Trim().Length > 0)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)("Ignoring recipe entry '" + text + "', expected ItemName:amount"));
					}
				}
			}
		}
	}
	internal class SledController : MonoBehaviour
	{
		private struct Contact
		{
			public Vector3 Point;

			public Vector3 Normal;

			public Surface Surface;
		}

		public const string RunnerPrefix = "runner_";

		private const float FrictionSolverScale = 0.8f;

		private const float ProbeInterval = 0.2f;

		private const float SprayInterval = 0.12f;

		private const float TrailStep = 1f;

		private const float StabilitySpring = 40f;

		private const float StabilityDamping = 9f;

		private static readonly HashSet<SledController> s_instances = new HashSet<SledController>();

		private readonly SurfaceHold m_shownSurface = new SurfaceHold();

		private bool m_probeHit;

		private float m_lastContactTime = -1f;

		private ZNetView m_nview;

		private Vagon m_vagon;

		private Rigidbody m_body;

		private Floating m_floating;

		private SledSeat m_seat;

		private readonly HashSet<Collider> m_runners = new HashSet<Collider>();

		private readonly List<Transform> m_runnerTails = new List<Transform>();

		private PhysicsMaterial m_slideMaterial;

		private PhysicsMaterial m_restMaterial;

		private bool m_resting;

		private readonly List<Contact> m_contacts = new List<Contact>();

		private readonly List<ContactPoint> m_contactBuffer = new List<ContactPoint>(32);

		private readonly int[] m_surfaceVotes = new int[Enum.GetValues(typeof(Surface)).Length];

		private Vector3 m_controls;

		private long m_lastOwner;

		private float m_controlsTime;

		private Vector3 m_sentControls;

		private bool m_pushHeld;

		private bool m_backHeld;

		private bool m_brakeOff;

		private float m_nextPush;

		private const float PushInterval = 0.35f;

		private const float BackPushSpeed = 1f;

		private float m_sentTime;

		private float m_probeTimer;

		private float m_sprayTimer;

		private Vector3 m_lastTrailPos;

		private Vector3 m_groundUp = Vector3.up;

		private float m_debugTimer;

		private float m_debugAlong;

		private float m_debugAcross;

		private float m_debugTime;

		private static GameObject s_sprayPrefab;

		private static GameObject s_trailPrefab;

		private float m_nextOwnRequest;

		public static IEnumerable<SledController> Instances => s_instances;

		public static SledController LocalPulled { get; private set; }

		public Surface Surface { get; private set; }

		public Surface ShownSurface => m_shownSurface.Shown;

		public bool Touching
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid() || !m_nview.IsOwner())
				{
					return m_probeHit;
				}
				return OnSolidGround;
			}
		}

		public bool OnSolidGround => Time.fixedTime - m_lastContactTime < 0.1f;

		public float Speed { get; private set; }

		private void Awake()
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Expected O, but got Unknown
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			m_nview = ((Component)this).GetComponent<ZNetView>();
			m_vagon = ((Component)this).GetComponent<Vagon>();
			m_body = ((Component)this).GetComponent<Rigidbody>();
			m_floating = ((Component)this).GetComponent<Floating>();
			m_seat = ((Component)this).GetComponentInChildren<SledSeat>(true);
			Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (((Object)val).name.StartsWith("runner_"))
				{
					m_runners.Add(val);
				}
			}
			Transform[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren2)
			{
				if (((Object)val2).name == "runner_tail")
				{
					m_runnerTails.Add(val2);
				}
			}
			if ((Object)(object)m_nview == (Object)null || m_nview.GetZDO() == null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			m_body.centerOfMass = new Vector3(0f, 0.12f, -0.08f);
			m_body.linearDamping = 0.02f;
			m_body.angularDamping = 0.6f;
			m_slideMaterial = new PhysicsMaterial("sled_runner_slide")
			{
				dynamicFriction = 0f,
				staticFriction = 0f,
				frictionCombine = (PhysicsMaterialCombine)2,
				bounceCombine = (PhysicsMaterialCombine)2
			};
			m_restMaterial = new PhysicsMaterial("sled_runner_resting")
			{
				dynamicFriction = 1f,
				staticFriction = 1f,
				frictionCombine = (PhysicsMaterialCombine)3,
				bounceCombine = (PhysicsMaterialCombine)2
			};
			SetResting(resting: true);
			m_lastTrailPos = ((Component)this).transform.position;
		}

		private void Start()
		{
			if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
			{
				m_nview.Register<Vector3>("WinterSled_Controls", (Action<long, Vector3>)RPC_Controls);
				m_nview.Register("WinterSled_Push", (Action<long>)RPC_Push);
				m_nview.Register("WinterSled_PushBack", (Action<long>)RPC_PushBack);
			}
		}

		private void OnEnable()
		{
			s_instances.Add(this);
		}

		private void OnDisable()
		{
			s_instances.Remove(this);
		}

		private void OnDestroy()
		{
			if ((Object)(object)LocalPulled == (Object)(object)this)
			{
				LocalPulled = null;
			}
		}

		public bool IsPulled()
		{
			if ((Object)(object)m_vagon != (Object)null)
			{
				return m_vagon.IsAttached();
			}
			return false;
		}

		public bool HasRider()
		{
			if ((Object)(object)m_seat != (Object)null)
			{
				return m_seat.HaveValidRider();
			}
			return false;
		}

		public float CargoWeight()
		{
			if (!((Object)(object)m_vagon.m_container != (Object)null))
			{
				return 0f;
			}
			return m_vagon.m_container.GetInventory().GetTotalWeight();
		}

		public void SetLocalControls(Vector3 moveDir)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0095: 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)
			//IL_00a1: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			m_controls = moveDir;
			m_controlsTime = Time.time;
			bool flag = moveDir.z > 0.5f;
			if (flag && !m_pushHeld && Time.time >= m_nextPush)
			{
				TryPush(back: false);
			}
			m_pushHeld = flag;
			bool flag2 = moveDir.z < -0.5f;
			if (flag2 && !m_backHeld && Time.time >= m_nextPush && Speed < 1f)
			{
				TryPush(back: true);
			}
			m_backHeld = flag2;
			if (!m_nview.IsOwner())
			{
				Vector3 val = moveDir - m_sentControls;
				if (((Vector3)(ref val)).sqrMagnitude > 0.01f || Time.time - m_sentTime > 0.25f)
				{
					m_sentControls = moveDir;
					m_sentTime = Time.time;
					m_nview.InvokeRPC("WinterSled_Controls", new object[1] { moveDir });
				}
			}
		}

		private void TryPush(bool back)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || IsPulled() || !SurfaceProbe.IsSnowy(ShownSurface))
			{
				return;
			}
			float value = Plugin.Cfg.PushStamina.Value;
			if (!((Character)localPlayer).HaveStamina(value))
			{
				Hud instance = Hud.instance;
				if (instance != null)
				{
					instance.StaminaBarEmptyFlash();
				}
				return;
			}
			((Character)localPlayer).UseStamina(value);
			m_nextPush = Time.time + 0.35f;
			if (m_nview.IsOwner())
			{
				Push(back);
			}
			else
			{
				m_nview.InvokeRPC(back ? "WinterSled_PushBack" : "WinterSled_Push", Array.Empty<object>());
			}
		}

		private void RPC_Push(long sender)
		{
			if (m_nview.IsOwner())
			{
				Push(back: false);
			}
		}

		private void RPC_PushBack(long sender)
		{
			if (m_nview.IsOwner())
			{
				Push(back: true);
			}
		}

		private void Push(bool back)
		{
			//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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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)
			Vector3 val = Vector3.ProjectOnPlane(((Component)this).transform.forward, Vector3.up);
			Vector3 val2 = ((Vector3)(ref val)).normalized * (back ? (-1f) : 1f);
			if (!(Vector3.Dot(m_body.linearVelocity, val2) >= Plugin.Cfg.PushMaxSpeed.Value))
			{
				m_brakeOff |= back;
				m_body.WakeUp();
				m_body.AddForce(val2 * Plugin.Cfg.PushImpulse.Value, (ForceMode)2);
			}
		}

		private void RPC_Controls(long sender, Vector3 moveDir)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			m_controls = moveDir;
			m_controlsTime = Time.time;
		}

		private Vector3 CurrentControls()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (!(Time.time - m_controlsTime < 0.6f) || !HasRider() || IsPulled())
			{
				return Vector3.zero;
			}
			return m_controls;
		}

		public void OnLocalRiderSeated()
		{
			if (!m_nview.IsOwner() && !IsPulled())
			{
				m_nview.InvokeRPC("RPC_RequestOwn", Array.Empty<object>());
			}
		}

		private void OnCollisionEnter(Collision collision)
		{
			GatherContacts(collision);
		}

		private void OnCollisionStay(Collision collision)
		{
			GatherContacts(collision);
		}

		private void GatherContacts(Collision collision)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			if (!m_nview.IsValid() || !m_nview.IsOwner())
			{
				return;
			}
			int contacts = collision.GetContacts(m_contactBuffer);
			for (int i = 0; i < contacts; i++)
			{
				ContactPoint val = m_contactBuffer[i];
				if (m_runners.Contains(((ContactPoint)(ref val)).thisCollider))
				{
					Vector3 val2 = ((ContactPoint)(ref val)).normal;
					if (Vector3.Dot(val2, ((Component)this).transform.up) < 0f)
					{
						val2 = -val2;
					}
					m_contacts.Add(new Contact
					{
						Point = ((ContactPoint)(ref val)).point,
						Normal = val2,
						Surface = SurfaceProbe.Classify(((ContactPoint)(ref val)).otherCollider, ((ContactPoint)(ref val)).point, val2)
					});
				}
			}
		}

		private void FixedUpdate()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if (!m_nview.IsValid())
			{
				return;
			}
			Vector3 linearVelocity = m_body.linearVelocity;
			Speed = ((Vector3)(ref linearVelocity)).magnitude;
			if (!m_nview.IsOwner())
			{
				m_contacts.Clear();
				return;
			}
			if (m_contacts.Count > 0)
			{
				m_lastContactTime = Time.fixedTime;
			}
			bool flag = IsPulled() || HasRider();
			SetResting(!flag && Speed < Plugin.Cfg.StaticFrictionSpeed.Value && Surface != Surface.Ice);
			if (flag && m_body.IsSleeping())
			{
				m_body.WakeUp();
			}
			UpdateOwnerSurface();
			if (!m_resting)
			{
				Vector3 val = CurrentControls();
				bool flag2 = val.z < -0.5f;
				m_brakeOff &= flag2;
				ApplyRunnerFriction(flag2 && !m_brakeOff);
				ApplyAirDrag();
				ApplyStability();
				if (m_contacts.Count > 0)
				{
					ApplyRiderControls(val);
				}
			}
			if (Plugin.Cfg.DebugLog.Value && (m_debugTimer -= Time.fixedDeltaTime) < 0f)
			{
				m_debugTimer = 1f;
				float num = Mathf.Max(Time.fixedTime - m_debugTime, 0.001f);
				float num2 = m_debugAlong / m_body.mass / num;
				float num3 = m_debugAcross / m_body.mass / num;
				m_debugAlong = (m_debugAcross = 0f);
				m_debugTime = Time.fixedTime;
				Plugin.Log.LogInfo((object)$"sled {m_nview.GetZDO().m_uid}: friction along={num2:0.000} across={num3:0.000} m/s2, mu={SurfaceProbe.Friction(Surface):0.000}; surface={Surface} speed={Speed:0.00} contacts={m_contacts.Count} mass={m_body.mass:0} resting={m_resting} pulled={IsPulled()} rider={HasRider()}");
			}
			m_contacts.Clear();
		}

		private void SetResting(bool resting)
		{
			if (resting == m_resting && m_runners.Count > 0)
			{
				return;
			}
			m_resting = resting;
			PhysicsMaterial sharedMaterial = (resting ? m_restMaterial : m_slideMaterial);
			foreach (Collider runner in m_runners)
			{
				runner.sharedMaterial = sharedMaterial;
			}
			if (!resting)
			{
				m_body.WakeUp();
			}
		}

		private void UpdateOwnerSurface()
		{
			if (m_contacts.Count == 0)
			{
				if ((Object)(object)m_floating != (Object)null && m_floating.BeenFloating())
				{
					Surface = Surface.Water;
				}
				return;
			}
			Array.Clear(m_surfaceVotes, 0, m_surfaceVotes.Length);
			foreach (Contact contact in m_contacts)
			{
				m_surfaceVotes[(int)contact.Surface]++;
			}
			int num = 0;
			for (int i = 1; i < m_surfaceVotes.Length; i++)
			{
				if (m_surfaceVotes[i] > m_surfaceVotes[num])
				{
					num = i;
				}
			}
			Surface = (Surface)num;
		}

		private void ApplyRunnerFriction(bool braking)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			int count = m_contacts.Count;
			if (count == 0)
			{
				return;
			}
			float fixedDeltaTime = Time.fixedDeltaTime;
			float mass = m_body.mass;
			Vector3 gravity = Physics.gravity;
			float num = mass * ((Vector3)(ref gravity)).magnitude / (float)count;
			float num2 = m_body.mass / (float)count * 0.8f;
			float num3 = (braking ? Plugin.Cfg.BrakeFriction.Value : 0f);
			foreach (Contact contact in m_contacts)
			{
				float num4 = num * Mathf.Max(0f, contact.Normal.y);
				if (!(num4 <= 0f))
				{
					Vector3 val = Vector3.ProjectOnPlane(((Component)this).transform.forward, contact.Normal);
					if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
					{
						((Vector3)(ref val)).Normalize();
						Vector3 val2 = Vector3.Cross(contact.Normal, val);
						Vector3 pointVelocity = m_body.GetPointVelocity(contact.Point);
						float num5 = Vector3.Dot(pointVelocity, val);
						float num6 = Vector3.Dot(pointVelocity, val2);
						float num7 = (SurfaceProbe.Friction(contact.Surface) + num3) * num4 * fixedDeltaTime;
						float num8 = SurfaceProbe.Grip(contact.Surface) * num4 * fixedDeltaTime;
						float num9 = Mathf.Clamp((0f - num5) * num2, 0f - num7, num7);
						float num10 = Mathf.Clamp((0f - num6) * num2, 0f - num8, num8);
						m_body.AddForceAtPosition(val * num9 + val2 * num10, contact.Point, (ForceMode)1);
						m_debugAlong += num9;
						m_debugAcross += Mathf.Abs(num10);
					}
				}
			}
		}

		private void ApplyAirDrag()
		{
			//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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			Vector3 linearVelocity = m_body.linearVelocity;
			float magnitude = ((Vector3)(ref linearVelocity)).magnitude;
			if (!(magnitude < 0.5f))
			{
				float num = Plugin.Cfg.AirDrag.Value * magnitude * magnitude;
				float value = Plugin.Cfg.MaxSpeed.Value;
				if (magnitude > value)
				{
					num += m_body.mass * (magnitude - value) * 6f;
				}
				m_body.AddForce(-linearVelocity / magnitude * num, (ForceMode)0);
			}
		}

		private void ApplyStability()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			float value = Plugin.Cfg.Stability.Value;
			if (value <= 0f)
			{
				return;
			}
			if (m_contacts.Count > 0)
			{
				Vector3 val = Vector3.zero;
				foreach (Contact contact in m_contacts)
				{
					val += contact.Normal;
				}
				m_groundUp = Vector3.Slerp(m_groundUp, ((Vector3)(ref val)).normalized, 0.2f);
			}
			else
			{
				m_groundUp = Vector3.Slerp(m_groundUp, Vector3.up, Time.fixedDeltaTime);
			}
			Vector3 up = ((Component)this).transform.up;
			Vector3 angularVelocity = m_body.angularVelocity;
			Vector3 val2 = angularVelocity - Vector3.Dot(angularVelocity, up) * up;
			m_body.AddTorque((Vector3.Cross(up, m_groundUp) * 40f - val2 * 9f) * value, (ForceMode)5);
		}

		private void ApplyRiderControls(Vector3 controls)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if (!(controls == Vector3.zero))
			{
				Vector3 up = ((Component)this).transform.up;
				float num = Vector3.Dot(m_body.linearVelocity, ((Component)this).transform.forward);
				float num2 = Mathf.Clamp(controls.x, -1f, 1f);
				if (Mathf.Abs(num2) > 0.1f)
				{
					float num3 = Mathf.Clamp(Mathf.Abs(num) / 3f, 0.35f, 1f);
					float num4 = num2 * 1.4f * Plugin.Cfg.SteerStrength.Value * num3 * Mathf.Sign(num + 0.01f);
					float num5 = Vector3.Dot(m_body.angularVelocity, up);
					m_body.AddTorque(up * (num4 - num5) * Plugin.Cfg.SteerResponse.Value, (ForceMode)5);
				}
			}
		}

		private void Update()
		{
			m_shownSurface.Update(Surface, Time.time);
			if (m_nview.IsValid())
			{
				float deltaTime = Time.deltaTime;
				if (!m_nview.IsOwner() && (m_probeTimer -= deltaTime) < 0f)
				{
					m_probeTimer = 0.2f;
					Surface = ProbeSurface();
				}
				UpdateRiderOwnership();
				UpdateAudio(deltaTime);
				UpdateSnowEffects(deltaTime);
				UpdateHauling();
			}
		}

		private void UpdateRiderOwnership()
		{
			long owner = m_nview.GetZDO().GetOwner();
			if (owner != m_lastOwner)
			{
				m_lastOwner = owner;
				m_nextOwnRequest = Mathf.Max(m_nextOwnRequest, Time.time + 2f);
			}
			if (!((Object)(object)m_seat == (Object)null) && !m_nview.IsOwner() && !IsPulled() && !(Time.time < m_nextOwnRequest) && m_seat.IsLocalRider())
			{
				m_nextOwnRequest = Time.time + 1f;
				m_nview.InvokeRPC("RPC_RequestOwn", Array.Empty<object>());
			}
		}

		private Surface ProbeSurface()
		{
			//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)
			m_probeHit = SurfaceProbe.ProbeBelow(((Component)this).transform, ((Component)this).transform.position + Vector3.up * 0.6f, 0.75f, out var surface);
			if (m_probeHit)
			{
				return surface;
			}
			if (!((Object)(object)m_floating != (Object)null) || !m_floating.BeenFloating())
			{
				return Surface;
			}
			return Surface.Water;
		}

		private void UpdateAudio(float dt)
		{
			ZSFX[] wheelLoops = m_vagon.m_wheelLoops;
			if (wheelLoops == null)
			{
				return;
			}
			ZSFX[] array = wheelLoops;
			foreach (ZSFX val in array)
			{
				if ((Object)(object)val != (Object)null && val.GetVolumeModifier() > 0f)
				{
					val.SetVolumeModifier(0f);
				}
			}
		}

		private void UpdateSnowEffects(float dt)
		{
			//IL_0018: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			if (!SurfaceProbe.IsSnowy(Surface) || Surface == Surface.Ice)
			{
				return;
			}
			bool flag = CurrentControls().z < -0.5f || (m_nview.IsOwner() && m_controls.z < -0.5f && HasRider());
			if (Plugin.Cfg.SnowSpray.Value && (Object)(object)Player.m_localPlayer != (Object)null && (Speed > 4f || (flag && Speed > 1.5f)) && (m_sprayTimer -= dt) < 0f)
			{
				m_sprayTimer = 0.12f * (flag ? 0.5f : Mathf.Lerp(1.5f, 0.6f, Speed / 12f));
				GameObject val = SprayPrefab();
				if ((Object)(object)val != (Object)null)
				{
					foreach (Transform runnerTail in m_runnerTails)
					{
						Object.Instantiate<GameObject>(val, runnerTail.position, Quaternion.LookRotation(-((Component)this).transform.forward));
					}
				}
			}
			if (Surface != Surface.Powder || !m_nview.IsOwner() || !(Vector3.Distance(m_lastTrailPos, ((Component)this).transform.position) > 1f))
			{
				return;
			}
			m_lastTrailPos = ((Component)this).transform.position;
			GameObject val2 = TrailPrefab();
			if (!((Object)(object)val2 != (Object)null))
			{
				return;
			}
			foreach (Transform runnerTail2 in m_runnerTails)
			{
				Object.Instantiate<GameObject>(val2, runnerTail2.position, ((Component)this).transform.rotation);
			}
		}

		private void UpdateHauling()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				if (m_vagon.IsAttached((Character)(object)localPlayer))
				{
					LocalPulled = this;
					SledHaulEffect.Ensure(localPlayer);
				}
				else if ((Object)(object)LocalPulled == (Object)(object)this)
				{
					LocalPulled = null;
					SledHaulEffect.Remove(localPlayer);
				}
			}
		}

		private static GameObject SprayPrefab()
		{
			if ((Object)(object)s_sprayPrefab == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
			{
				s_sprayPrefab = ZNetScene.instance.GetPrefab("fx_footstep_snow_run");
			}
			return s_sprayPrefab;
		}

		private static GameObject TrailPrefab()
		{
			if ((Object)(object)s_trailPrefab == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
			{
				s_trailPrefab = ZNetScene.instance.GetPrefab("snow_walk_medium");
				if ((Object)(object)s_trailPrefab == (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					s_trailPrefab = ((Character)Player.m_localPlayer).m_deepSnowWalkObj;
				}
			}
			return s_trailPrefab;
		}
	}
	internal class SledHaulEffect : StatusEffect
	{
		public const string EffectName = "SE_WinterSledHaul";

		public static readonly int Hash = StringExtensionMethods.GetStableHashCode("SE_WinterSledHaul");

		public static StatusEffect Create(Sprite icon)
		{
			SledHaulEffect sledHaulEffect = ScriptableObject.CreateInstance<SledHaulEffect>();
			((Object)sledHaulEffect).name = "SE_WinterSledHaul";
			((StatusEffect)sledHaulEffect).m_name = "$se_wintersled";
			((StatusEffect)sledHaulEffect).m_tooltip = "$se_wintersled_tooltip";
			((StatusEffect)sledHaulEffect).m_icon = icon;
			((StatusEffect)sledHaulEffect).m_ttl = 0f;
			return (StatusEffect)(object)sledHaulEffect;
		}

		public static void Ensure(Player player)
		{
			SEMan sEMan = ((Character)player).GetSEMan();
			if (!sEMan.HaveStatusEffect(Hash))
			{
				sEMan.AddStatusEffect(Hash, false, 0, 0f, (short)(-1));
			}
		}

		public static void Remove(Player player)
		{
			((Character)player).GetSEMan().RemoveStatusEffect(Hash, true);
		}

		private static Surface CurrentSurface()
		{
			SledController localPulled = SledController.LocalPulled;
			if (!((Object)(object)localPulled != (Object)null))
			{
				return Surface.Snow;
			}
			return localPulled.ShownSurface;
		}

		public static float SpeedFactor()
		{
			SledController localPulled = SledController.LocalPulled;
			if (!((Object)(object)localPulled != (Object)null))
			{
				return 1f;
			}
			return SpeedFactorFor(localPulled.ShownSurface, localPulled.CargoWeight());
		}

		public static float SpeedFactorFor(Surface surface, float cargoWeight)
		{
			SledConfig cfg = Plugin.Cfg;
			switch (surface)
			{
			case Surface.Ground:
			{
				float num = Mathf.Clamp01(cargoWeight / cfg.FullLoadWeight.Value);
				return Mathf.Max(0.2f, cfg.GroundPullSpeed.Value - cfg.LoadPenalty.Value * num);
			}
			case Surface.FrozenGround:
				return cfg.FrozenPullSpeed.Value;
			case Surface.Wood:
			case Surface.Stone:
				return cfg.FloorPullSpeed.Value;
			default:
				return 1f;
			}
		}

		public override void ModifySpeed(float baseSpeed, ref float speed, Character character, Vector3 dir)
		{
			speed -= baseSpeed * (1f - SpeedFactor());
		}

		public override void ModifyRunStaminaDrain(float baseDrain, ref float drain, Vector3 dir)
		{
			if (CurrentSurface() == Surface.Ground)
			{
				drain += baseDrain * (Plugin.Cfg.GroundStaminaDrain.Value - 1f);
			}
		}

		public override string GetIconText()
		{
			return Localization.instance.Localize(SurfaceProbe.LocalizationKey(CurrentSurface()));
		}

		public override bool IsDone()
		{
			return (Object)(object)SledController.LocalPulled == (Object)null;
		}
	}
	internal static class SledMaterials
	{
		private struct Source
		{
			public string Material;

			public string[] Prefabs;
		}

		private static readonly Dictionary<string, Source> Sources = new Dictionary<string, Source>
		{
			{
				"wood",
				new Source
				{
					Material = "DarkWood_mat",
					Prefabs = new string[3] { "darkwood_beam", "darkwood_pole", "darkwood_beam_26" }
				}
			},
			{
				"iron",
				new Source
				{
					Material = "metalwall",
					Prefabs = new string[4] { "iron_grate", "iron_wall_2x2", "iron_wall_1x1", "iron_floor_2x2" }
				}
			},
			{
				"rope",
				new Source
				{
					Material = "cart_rope",
					Prefabs = new string[1] { "Cart" }
				}
			},
			{
				"fur",
				new Source
				{
					Material = "rug_wolf",
					Prefabs = new string[1] { "rug_wolf" }
				}
			}
		};

		public static Material[] Resolve(IList<string> names, Material fallback)
		{
			Material[] array = (Material[])(object)new Material[names.Count];
			for (int i = 0; i < names.Count; i++)
			{
				array[i] = Find(names[i]) ?? fallback;
				if ((Object)(object)array[i] == (Object)(object)fallback)
				{
					Plugin.Log.LogWarning((object)("No game material found for '" + names[i] + "', using " + ((fallback != null) ? ((Object)fallback).name : null)));
				}
			}
			return array;
		}

		private static Material Find(string key)
		{
			if (!Sources.TryGetValue(key, out var src))
			{
				return null;
			}
			string[] prefabs = src.Prefabs;
			LineRenderer val3 = default(LineRenderer);
			foreach (string text in prefabs)
			{
				GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(text) : null);
				if (!((Object)(object)val == (Object)null))
				{
					Material val2 = val.GetComponentsInChildren<Renderer>(true).SelectMany((Renderer r) => r.sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => (Object)(object)m != (Object)null && ((Object)m).name.StartsWith(src.Material)));
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
					if (val.TryGetComponent<LineRenderer>(ref val3) && (Object)(object)((Renderer)val3).sharedMaterial != (Object)null && ((Object)((Renderer)val3).sharedMaterial).name.StartsWith(src.Material))
					{
						return ((Renderer)val3).sharedMaterial;
					}
				}
			}
			return ((IEnumerable<Material>)Resources.FindObjectsOfTypeAll<Material>()).FirstOrDefault((Func<Material, bool>)((Material m) => ((Object)m).name == src.Material));
		}
	}
	internal class SledSeat : MonoBehaviour, Interactable, Hoverable, IDoodadController
	{
		public Transform m_attachPoint;

		public Vector3 m_detachOffset = new Vector3(0f, 0.05f, 0f);

		public float m_useDistance = 3f;

		private static readonly int s_rider = StringExtensionMethods.GetStableHashCode("wintersled_rider");

		private ZNetView m_nview;

		private SledController m_sled;

		private Vagon m_vagon;

		private Rigidbody m_body;

		private bool InCart => (Object)(object)m_sled == (Object)null;

		private void Start()
		{
			m_nview = ((Component)this).GetComponentInParent<ZNetView>();
			m_sled = ((Component)this).GetComponentInParent<SledController>();
			m_vagon = ((Component)this).GetComponentInParent<Vagon>();
			m_body = ((Component)this).GetComponentInParent<Rigidbody>();
			if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid())
			{
				((Behaviour)this).enabled = false;
				return;
			}
			m_nview.Register<long>("WinterSled_RequestSeat", (Action<long, long>)RPC_RequestSeat);
			m_nview.Register<long>("WinterSled_ReleaseSeat", (Action<long, long>)RPC_ReleaseSeat);
			m_nview.Register<bool>("WinterSled_SeatResponse", (Action<long, bool>)RPC_SeatResponse);
			if (m_nview.IsOwner())
			{
				m_nview.GetZDO().Set(s_rider, 0L);
			}
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold || (Object)(object)m_nview == (Object)null || !m_nview.IsValid())
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null || ((Character)val).IsEncumbered() || ((Character)val).IsAttached() || !InUseDistance((Humanoid)(object)val) || (InCart && !Plugin.Cfg.CartSeat.Value))
			{
				return false;
			}
			m_nview.InvokeRPC("WinterSled_RequestSeat", new object[1] { val.GetPlayerID() });
			return false;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}

		public string GetHoverText()
		{
			if (InCart && !Plugin.Cfg.CartSeat.Value)
			{
				return "";
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || !InUseDistance((Humanoid)(object)Player.m_localPlayer))
			{
				return Localization.instance.Localize("<color=#888888>$piece_toofar</color>");
			}
			return Localization.instance.Localize(VehicleName() + "\n[<color=yellow><b>$KEY_Use</b></color>] $wintersled_ride");
		}

		public string GetHoverName()
		{
			return Localization.instance.Localize(VehicleName());
		}

		private string VehicleName()
		{
			if (!InCart || !((Object)(object)m_vagon != (Object)null))
			{
				return "$piece_wintersled";
			}
			return m_vagon.m_name;
		}

		public void ApplyControlls(Vector3 moveDir, Vector3 lookDir, bool run, bool autoRun, bool block)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)m_sled != (Object)null)
			{
				m_sled.SetLocalControls(moveDir);
			}
		}

		public void OnUseStop(Player player)
		{
			if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
			{
				m_nview.InvokeRPC("WinterSled_ReleaseSeat", new object[1] { player.GetPlayerID() });
			}
			((Character)player).AttachStop();
			StepOff(player);
			RefreshLoad();
		}

		private void RefreshLoad()
		{
			if ((Object)(object)m_vagon != (Object)null)
			{
				m_vagon.UpdateLoadVisualization();
			}
		}

		private void StepOff(Player player)
		{
			//IL_0006: Unknown result type (might b