Decompiled source of Rollin v1.0.4

Rollin.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using Chassis.Api;
using HarmonyLib;
using Il2CppFishNet;
using Il2CppFishNet.Connection;
using Il2CppFishNet.Managing;
using Il2CppFishNet.Managing.Object;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.AvatarFramework;
using Il2CppScheduleOne.Core.Weather;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Interaction;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Lighting;
using Il2CppScheduleOne.Persistence;
using Il2CppScheduleOne.Persistence.Datas;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Quests;
using Il2CppScheduleOne.Storage;
using Il2CppScheduleOne.Vehicles;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using Rollin;
using Rollin.Chair;
using Rollin.Compat;
using Rollin.Net;
using Rollin.Tuning;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Rollin", "1.0.4", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-Rollin")]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonAdditionalDependencies(new string[] { "Chassis" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DooDesch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © DooDesch")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.0.4+4e8710ba50014fbc91c558555aae115256d96cd3")]
[assembly: AssemblyProduct("Rollin")]
[assembly: AssemblyTitle("Rollin")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially created with the assistance of Generative AI.")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic/OpenAI")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.4.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 DooDesch
{
	internal static class ModVersion
	{
		internal const string Current = "1.0.4";
	}
}
namespace Rollin
{
	public sealed class Core : MelonMod
	{
		private bool _inWorld;

		private static readonly Dictionary<string, float> _lastError = new Dictionary<string, float>();

		private static readonly Dictionary<string, int> _muted = new Dictionary<string, int>();

		public static Core Instance { get; private set; }

		public static Instance Log { get; private set; }

		public override void OnInitializeMelon()
		{
			Instance = this;
			Log = ((MelonBase)this).LoggerInstance;
			int num = 0;
			foreach (MethodBase patchedMethod in ((MelonBase)this).HarmonyInstance.GetPatchedMethods())
			{
				_ = patchedMethod;
				num++;
			}
			Log.Msg("[Core] Harmony patches applied by MelonLoader on " + num + " method(s).");
			RollinNet.Apply(((MelonBase)this).HarmonyInstance);
			Start("sync", Sync.Init);
			Start("wheelchair profile", WheelchairProfile.Register);
			Start("garage", Garage.Init);
			Start("tuning effects", Effects.Init);
			Start("tuning menu", Menu.Init);
			Start("stock trim", StockTrim.Init);
			Log.Msg("Rollin loaded.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			_inWorld = sceneName == "Main";
			if (!_inWorld)
			{
				ResetWorld();
			}
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			_inWorld = false;
			ResetWorld();
		}

		private static void ResetWorld()
		{
			Sync.Reset();
			Ids.Reset();
			Push.Reset();
			PropSwap.Reset();
			WheelchairModel.Reset();
			Garage.Reset();
			Effects.Reset();
			GameMeshes.Reset();
			Menu.Reset();
			Cargo.Reset();
			StockTrim.Reset();
		}

		public override void OnLateUpdate()
		{
			if (_inWorld)
			{
				Guard("push placement", Push.LateTick);
				Guard("tuning effects", Effects.LateTick);
			}
		}

		public override void OnUpdate()
		{
			if (_inWorld)
			{
				Guard("sync", Sync.Tick);
				Guard("prop swap", PropSwap.Tick);
				Guard("push", Push.Tick);
				Guard("garage", Garage.Tick);
				Guard("cargo", Cargo.Tick);
				Guard("tuning menu", Menu.Tick);
			}
		}

		private static void Start(string what, Action a)
		{
			try
			{
				a();
			}
			catch (Exception ex)
			{
				Log.Error("[Core] " + what + " did not start and stays off: " + ex);
			}
		}

		private static void Guard(string what, Action a)
		{
			try
			{
				a();
			}
			catch (Exception ex)
			{
				if (_lastError.TryGetValue(what, out var value) && Time.time - value < 5f)
				{
					_muted.TryGetValue(what, out var value2);
					_muted[what] = value2 + 1;
					return;
				}
				_lastError[what] = Time.time;
				_muted.TryGetValue(what, out var value3);
				_muted[what] = 0;
				Log.Error("[Core] " + what + " failed this frame" + ((value3 > 0) ? (" (and " + value3 + " more time(s) in the last 5 s)") : "") + ": " + ex);
			}
		}
	}
}
namespace Rollin.Tuning
{
	internal static class Cargo
	{
		[HarmonyPatch(typeof(LandVehicle), "Hovered")]
		private static class HullHover
		{
			[HarmonyPriority(0)]
			private static void Postfix(LandVehicle __instance)
			{
				InteractableObject intObj = __instance.intObj;
				if (!WheelchairType.Is(__instance) || (Object)(object)intObj == (Object)null)
				{
					return;
				}
				BoxCollider val = (Push.LocalPushing ? null : AimedBox(__instance));
				if ((Object)(object)val == (Object)null)
				{
					if (_labelHome.TryGetValue(((Il2CppObjectBase)intObj).Pointer, out var value))
					{
						intObj.displayLocationCollider = value;
						_labelHome.Remove(((Il2CppObjectBase)intObj).Pointer);
					}
					return;
				}
				if (!_labelHome.ContainsKey(((Il2CppObjectBase)intObj).Pointer))
				{
					_labelHome[((Il2CppObjectBase)intObj).Pointer] = intObj.displayLocationCollider;
				}
				intObj.displayLocationCollider = (Collider)(object)val;
				Hovered(intObj);
			}
		}

		[HarmonyPatch(typeof(LandVehicle), "Interacted")]
		private static class HullInteract
		{
			private static bool Prefix(LandVehicle __instance)
			{
				if (!WheelchairType.Is(__instance) || (Object)(object)__instance.intObj == (Object)null || Push.LocalPushing || !Aimed(__instance))
				{
					return true;
				}
				Core.Log.Msg("[Cargo] E on net " + Ids.Of((Component)(object)__instance) + " aims at the Moving Box, opening it instead of getting in.");
				Open(__instance.intObj);
				return false;
			}
		}

		internal const int Slots = 4;

		internal const string BoxName = "Moving Box";

		internal const string TriggerName = "rollin_box_open";

		private const float StandKmh = 1f;

		private static readonly Dictionary<int, KeyValuePair<string, float>> _pending = new Dictionary<int, KeyValuePair<string, float>>();

		private const float LoadDelay = 1f;

		private static readonly Dictionary<IntPtr, Collider> _labelHome = new Dictionary<IntPtr, Collider>();

		internal static void Reset()
		{
			_pending.Clear();
		}

		internal static void Setup(LandVehicle lv)
		{
			StorageEntity val = (((Object)(object)lv != (Object)null) ? lv.Storage : null);
			if ((Object)(object)val == (Object)null)
			{
				Core.Log.Warning("[Cargo] net " + Ids.Of((Component)(object)lv) + " has no trunk - the Moving Box stores nothing.");
				return;
			}
			List<ItemSlot> itemSlots = val.ItemSlots;
			int num = itemSlots?.Count ?? 0;
			if (itemSlots != null)
			{
				while (itemSlots.Count > 4)
				{
					itemSlots.RemoveAt(itemSlots.Count - 1);
				}
			}
			val.SlotCount = 4;
			val.StorageEntityName = "Moving Box";
			val.AccessSettings = (EAccessSettings)2;
			val.MaxAccessDistance = 3f;
			Core.Log.Msg("[Cargo] net " + Ids.Of((Component)(object)lv) + ": trunk is the Moving Box, " + num + " -> " + (itemSlots?.Count ?? 0) + " slot(s), open to everyone.");
		}

		internal static bool HasItems(LandVehicle lv)
		{
			if ((Object)(object)lv != (Object)null && (Object)(object)lv.Storage != (Object)null)
			{
				return lv.Storage.ItemCount > 0;
			}
			return false;
		}

		internal static string Serialize(LandVehicle lv)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!HasItems(lv))
			{
				return null;
			}
			return new ItemSet(lv.Storage.ItemSlots).GetJSON();
		}

		internal static void LoadLater(LandVehicle lv, string json)
		{
			if (!((Object)(object)lv == (Object)null) && !string.IsNullOrEmpty(json))
			{
				_pending[Ids.Of((Component)(object)lv)] = new KeyValuePair<string, float>(json, Time.time + 1f);
			}
		}

		internal static void Tick()
		{
			if (_pending.Count == 0 || !RollinNet.IsHost)
			{
				return;
			}
			foreach (int item in new List<int>(_pending.Keys))
			{
				KeyValuePair<string, float> keyValuePair = _pending[item];
				if (!(Time.time < keyValuePair.Value))
				{
					LandVehicle val = Ids.Find<LandVehicle>(item);
					if ((Object)(object)val == (Object)null)
					{
						_pending.Remove(item);
						Core.Log.Warning("[Cargo] net " + item + " is gone before its box contents came back - they stay in the store.");
					}
					else if (((NetworkBehaviour)val).IsSpawned)
					{
						_pending.Remove(item);
						Load(val, keyValuePair.Key);
					}
				}
			}
		}

		private static void Load(LandVehicle lv, string json)
		{
			if ((Object)(object)lv.Storage == (Object)null)
			{
				Core.Log.Error("[Cargo] net " + Ids.Of((Component)(object)lv) + " has no trunk - its saved box contents are not loaded.");
				return;
			}
			DeserializedItemSet val = default(DeserializedItemSet);
			if (!ItemSet.TryDeserialize(json, ref val) || val == null)
			{
				Core.Log.Error("[Cargo] the saved box contents of net " + Ids.Of((Component)(object)lv) + " do not read as an item set - not loaded.");
				return;
			}
			val.LoadTo(lv.Storage.ItemSlots);
			Core.Log.Msg("[Cargo] net " + Ids.Of((Component)(object)lv) + ": " + lv.Storage.ItemCount + " item(s) back in the Moving Box.");
		}

		internal static void AddTrigger(Transform root, Bounds box)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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)
			GameObject val = new GameObject("rollin_box_open");
			val.transform.SetParent(root, false);
			val.layer = WheelchairType.InteractionLayer;
			Vector3 size = ((Bounds)(ref box)).size + new Vector3(0.04f, 0.02f, 0.04f);
			float num = Mathf.Min(((Bounds)(ref box)).max.y + 0.01f, 0.465f);
			float num2 = ((Bounds)(ref box)).min.y - 0.01f;
			size.y = Mathf.Max(0.05f, num - num2);
			val.transform.localPosition = new Vector3(((Bounds)(ref box)).center.x, (num + num2) * 0.5f, ((Bounds)(ref box)).center.z);
			BoxCollider obj = val.AddComponent<BoxCollider>();
			((Collider)obj).isTrigger = true;
			obj.size = size;
			InteractableObject io = val.AddComponent<InteractableObject>();
			io.MaxInteractionRange = 2.5f;
			io.SetMessage("Open Moving Box");
			io.SetInteractableState((EInteractableState)0);
			io.onHovered.AddListener(UnityAction.op_Implicit((Action)delegate
			{
				Hovered(io);
			}));
			io.onInteractStart.AddListener(UnityAction.op_Implicit((Action)delegate
			{
				Open(io);
			}));
		}

		private static bool Aimed(LandVehicle lv)
		{
			return (Object)(object)AimedBox(lv) != (Object)null;
		}

		private static BoxCollider AimedBox(LandVehicle lv)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)lv == (Object)null)
			{
				return null;
			}
			RaycastHit val = default(RaycastHit);
			foreach (BoxCollider componentsInChild in ((Component)lv).GetComponentsInChildren<BoxCollider>(false))
			{
				if (!(((Object)((Component)componentsInChild).gameObject).name != "rollin_box_open"))
				{
					Transform transform = ((Component)instance).transform;
					return ((Collider)componentsInChild).Raycast(new Ray(transform.position, transform.forward), ref val, 2.5f) ? componentsInChild : null;
				}
			}
			return null;
		}

		private static void Hovered(InteractableObject io)
		{
			StorageEntity st;
			string text = Blocked(io, out st);
			io.SetMessage(text ?? "Open Moving Box");
			io.SetInteractableState((EInteractableState)(text != null));
		}

		private static string Blocked(InteractableObject io, out StorageEntity st)
		{
			st = null;
			LandVehicle val = (((Object)(object)io != (Object)null) ? ((Component)io).GetComponentInParent<LandVehicle>() : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.Storage == (Object)null)
			{
				return "No storage";
			}
			st = val.Storage;
			if (Mathf.Abs(val.Speed_Kmh) > 1f)
			{
				return "Stop to open";
			}
			if (!st.CanBeOpened())
			{
				return "In use";
			}
			return null;
		}

		private static void Open(InteractableObject io)
		{
			StorageEntity st;
			string text = Blocked(io, out st);
			if (text != null)
			{
				Core.Log.Msg("[Cargo] box not opened: " + text + ".");
				return;
			}
			Player local = Player.Local;
			if ((Object)(object)local == (Object)null || (Object)(object)local.CurrentVehicle != (Object)null)
			{
				Core.Log.Msg("[Cargo] box not opened: the local player is in a vehicle or not there.");
				return;
			}
			st.Open();
			Core.Log.Msg("[Cargo] opened the Moving Box of net " + Ids.Of((Component)(object)((Component)io).GetComponentInParent<LandVehicle>()) + " (" + st.ItemCount + " item(s)).");
		}
	}
	internal static class Effects
	{
		private sealed class State
		{
			internal LandVehicle Lv;

			internal float NextScan;

			internal Transform PivotL;

			internal Transform PivotR;

			internal Transform SpinL;

			internal Transform SpinR;

			internal Transform Hat;

			internal Transform HatHome;

			internal readonly List<Renderer> HatRenderers = new List<Renderer>();

			internal readonly List<ParticleSystem> Smokes = new List<ParticleSystem>();

			internal readonly List<Wheel> Tyres = new List<Wheel>();

			internal bool Squealing;

			internal readonly List<Transform> Pulses = new List<Transform>();

			internal Transform Red;

			internal Transform Blue;

			internal Vector3 LastPos;

			internal bool HasPos;

			internal float Speed;

			internal float Accel;

			internal Player HeadOf;

			internal Transform Head;
		}

		private static readonly Dictionary<IntPtr, State> _chairs = new Dictionary<IntPtr, State>();

		private static readonly List<IntPtr> _gone = new List<IntPtr>();

		private const float HatLift = 0.14f;

		private const float MaxLift = 0.24f;

		internal static int Count => _chairs.Count;

		internal static void Init()
		{
			WheelchairSpawn.Started += delegate(LandVehicle lv)
			{
				if ((Object)(object)lv != (Object)null)
				{
					_chairs[((Il2CppObjectBase)lv).Pointer] = new State
					{
						Lv = lv
					};
				}
			};
			ChassisApi.TuningChanged += delegate(LandVehicle lv, string key)
			{
				if ((Object)(object)lv != (Object)null && _chairs.TryGetValue(((Il2CppObjectBase)lv).Pointer, out var value))
				{
					value.NextScan = 0f;
				}
			};
		}

		internal static void Reset()
		{
			_chairs.Clear();
		}

		internal static void LateTick()
		{
			if (_chairs.Count == 0)
			{
				return;
			}
			_gone.Clear();
			foreach (KeyValuePair<IntPtr, State> chair in _chairs)
			{
				State value = chair.Value;
				if ((Object)(object)value.Lv == (Object)null)
				{
					_gone.Add(chair.Key);
					continue;
				}
				try
				{
					Tick(value);
				}
				catch (Exception ex)
				{
					Core.Log.Error("[Effects] chair net " + Ids.Of((Component)(object)value.Lv) + " failed and stops moving its parts: " + ex);
					_gone.Add(chair.Key);
				}
			}
			foreach (IntPtr item in _gone)
			{
				_chairs.Remove(item);
			}
		}

		private static void Tick(State s)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			LandVehicle lv = s.Lv;
			if (Time.time >= s.NextScan)
			{
				Scan(s);
			}
			float num = Mathf.Max(Time.deltaTime, 0.0001f);
			Vector3 position = ((Component)lv).transform.position;
			if (s.HasPos)
			{
				float num2 = Vector3.Distance(position, s.LastPos) / num * 3.6f;
				if (num2 > 300f)
				{
					num2 = s.Speed;
				}
				float num3 = Mathf.Lerp(s.Speed, num2, 1f - Mathf.Exp((0f - num) * 8f));
				s.Accel = Mathf.Lerp(s.Accel, (num3 - s.Speed) / num, 1f - Mathf.Exp((0f - num) * 6f));
				s.Speed = num3;
			}
			s.LastPos = position;
			s.HasPos = true;
			Rims(s);
			Hat(s);
			Smoke(s);
			Squeal(s);
			Lightbar(s);
			Pulse(s);
		}

		private static void Scan(State s)
		{
			s.NextScan = Time.time + 0.5f;
			Transform transform = ((Component)s.Lv).transform;
			Transform val = null;
			Transform val2 = null;
			if ((Object)(object)s.Hat != (Object)null && (Object)(object)s.Head != (Object)null && (Object)(object)s.Hat.parent == (Object)(object)s.Head)
			{
				val = s.Hat;
				val2 = s.HatHome;
			}
			s.PivotL = (((Object)(object)s.PivotL != (Object)null) ? s.PivotL : WheelchairType.Find(transform, "RimPivot_L"));
			s.PivotR = (((Object)(object)s.PivotR != (Object)null) ? s.PivotR : WheelchairType.Find(transform, "RimPivot_R"));
			s.SpinL = (s.SpinR = (s.Hat = (s.HatHome = (s.Red = (s.Blue = null)))));
			s.HatRenderers.Clear();
			s.Smokes.Clear();
			s.Pulses.Clear();
			if (s.Tyres.Count == 0)
			{
				foreach (Wheel componentsInChild in ((Component)transform).GetComponentsInChildren<Wheel>(true))
				{
					if ((Object)(object)componentsInChild != (Object)null && componentsInChild.DriftAudioEnabled)
					{
						s.Tyres.Add(componentsInChild);
					}
				}
			}
			foreach (Transform componentsInChild2 in ((Component)transform).GetComponentsInChildren<Transform>(true))
			{
				if ((Object)(object)componentsInChild2 == (Object)null)
				{
					continue;
				}
				string name = ((Object)componentsInChild2).name;
				if (name == "Chassis_Tune_neon" && (Object)(object)componentsInChild2.parent == (Object)(object)transform && (Object)(object)componentsInChild2.Find("rollin_neon") == (Object)null)
				{
					Models.FitNeon(s.Lv, componentsInChild2);
				}
				else
				{
					if (!name.StartsWith("rollin_", StringComparison.Ordinal))
					{
						continue;
					}
					switch (name)
					{
					case "rollin_spin_L":
						s.SpinL = componentsInChild2;
						break;
					case "rollin_spin_R":
						s.SpinR = componentsInChild2;
						break;
					case "rollin_hat":
						if ((Object)(object)val != (Object)null && Interop.Same((Object)(object)componentsInChild2, (Object)(object)val))
						{
							break;
						}
						s.Hat = componentsInChild2;
						s.HatHome = componentsInChild2.parent;
						foreach (Renderer componentsInChild3 in ((Component)componentsInChild2).GetComponentsInChildren<Renderer>(true))
						{
							s.HatRenderers.Add(componentsInChild3);
						}
						break;
					case "rollin_smoke":
					{
						ParticleSystem val3 = SmokeAt(s.Lv, componentsInChild2);
						if ((Object)(object)val3 != (Object)null)
						{
							s.Smokes.Add(val3);
						}
						break;
					}
					case "rollin_blink_red":
						s.Red = componentsInChild2;
						break;
					case "rollin_blink_blue":
						s.Blue = componentsInChild2;
						break;
					case "rollin_pulse":
						s.Pulses.Add(componentsInChild2);
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if ((Object)(object)s.Hat == (Object)null && (Object)(object)val2 != (Object)null && val2.IsChildOf(transform))
			{
				s.Hat = val;
				s.HatHome = val2;
				{
					foreach (Renderer componentsInChild4 in ((Component)val).GetComponentsInChildren<Renderer>(true))
					{
						s.HatRenderers.Add(componentsInChild4);
					}
					return;
				}
			}
			if ((Object)(object)val2 != (Object)null)
			{
				val.SetParent(val2, true);
				Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)s.Lv) + ": hat part replaced or removed, the old hat is taken off.");
			}
			else
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
				Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)s.Lv) + ": hat part gone, the hat is taken off the rider's head.");
			}
		}

		private static void Rims(State s)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s.SpinL != (Object)null && (Object)(object)s.PivotL != (Object)null)
			{
				s.SpinL.position = s.PivotL.position;
				s.SpinL.rotation = s.PivotL.rotation;
			}
			if ((Object)(object)s.SpinR != (Object)null && (Object)(object)s.PivotR != (Object)null)
			{
				s.SpinR.position = s.PivotR.position;
				s.SpinR.rotation = s.PivotR.rotation;
			}
		}

		private static void Hat(State s)
		{
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s.Hat == (Object)null)
			{
				return;
			}
			LandVehicle lv = s.Lv;
			Player val = null;
			Il2CppReferenceArray<VehicleSeat> seats = lv.Seats;
			if (seats != null && ((Il2CppArrayBase<VehicleSeat>)(object)seats).Length > 0 && (Object)(object)((Il2CppArrayBase<VehicleSeat>)(object)seats)[0] != (Object)null)
			{
				val = ((Il2CppArrayBase<VehicleSeat>)(object)seats)[0].Occupant;
			}
			if ((Object)(object)val == (Object)null)
			{
				if ((Object)(object)s.Head != (Object)null && (Object)(object)s.Hat.parent == (Object)(object)s.Head)
				{
					Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)lv) + ": the rider got up, the hat is back on the seat.");
				}
				HatHome(s);
				ShowHat(s, on: true);
				s.HeadOf = null;
				s.Head = null;
				return;
			}
			if ((Object)(object)s.HeadOf == (Object)null || !Interop.Same((Object)(object)s.HeadOf, (Object)(object)val))
			{
				HatHome(s);
				s.HeadOf = val;
				s.Head = HeadOf(val);
				if ((Object)(object)s.Head == (Object)null)
				{
					Core.Log.Warning("[Effects] chair net " + Ids.Of((Component)(object)lv) + ": " + ((Object)val).name + " has no head bone - the hat stays on the seat.");
				}
			}
			if (!((Object)(object)s.Head == (Object)null))
			{
				if ((Object)(object)s.Hat.parent != (Object)(object)s.Head)
				{
					PutOn(s, val);
				}
				Camera main = Camera.main;
				ShowHat(s, (Object)(object)main == (Object)null || Vector3.Distance(((Component)main).transform.position, s.Head.position) > 0.45f);
			}
		}

		private static void PutOn(State s, Player rider)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			LandVehicle lv = s.Lv;
			string by;
			float num = LiftOver(rider, s.Head, out by);
			Vector3 up = ((Component)lv).transform.up;
			s.Hat.SetParent(s.Head, true);
			s.Hat.position = s.Head.position + up * num;
			s.Hat.rotation = Quaternion.LookRotation(((Component)lv).transform.forward, up);
			Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)lv) + ": hat on " + ((Object)rider).name + "'s head, " + num.ToString("F2", CultureInfo.InvariantCulture) + " m above the head bone (" + by + ").");
		}

		private static void HatHome(State s)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)s.Hat == (Object)null) && !((Object)(object)s.HatHome == (Object)null) && !((Object)(object)s.Hat.parent == (Object)(object)s.HatHome))
			{
				s.Hat.SetParent(s.HatHome, true);
				s.Hat.localPosition = Models.HatSeat;
				s.Hat.localRotation = Quaternion.identity;
			}
		}

		private static void ShowHat(State s, bool on)
		{
			foreach (Renderer hatRenderer in s.HatRenderers)
			{
				if ((Object)(object)hatRenderer != (Object)null && hatRenderer.enabled != on)
				{
					hatRenderer.enabled = on;
				}
			}
		}

		private static float LiftOver(Player p, Transform head, out string by)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			float num = head.position.y + 0.14f;
			by = "skull";
			foreach (Renderer componentsInChild in ((Component)p.Avatar).GetComponentsInChildren<Renderer>(true))
			{
				if (!((Object)(object)componentsInChild == (Object)null) && componentsInChild.enabled && ((Component)componentsInChild).gameObject.activeInHierarchy)
				{
					Bounds bounds = componentsInChild.bounds;
					if (!(((Bounds)(ref bounds)).size.y > 0.45f) && !(Vector3.Distance(((Bounds)(ref bounds)).center, head.position) > 0.25f) && !(((Bounds)(ref bounds)).max.y <= num))
					{
						num = ((Bounds)(ref bounds)).max.y;
						by = ((Object)componentsInChild).name;
					}
				}
			}
			float num2 = num - head.position.y;
			if (num2 > 0.24f)
			{
				by = by + ", capped from " + num2.ToString("F2", CultureInfo.InvariantCulture);
				num2 = 0.24f;
			}
			return num2;
		}

		private static Transform HeadOf(Player p)
		{
			Avatar val = (((Object)(object)p != (Object)null) ? p.Avatar : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Animator val2 = (((Object)(object)val.Animation != (Object)null) ? val.Animation._animator : null);
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = ((Component)val).GetComponentInChildren<Animator>(true);
			}
			if ((Object)(object)val2 == (Object)null || !val2.isHuman)
			{
				return null;
			}
			return val2.GetBoneTransform((HumanBodyBones)10);
		}

		private static ParticleSystem SmokeAt(LandVehicle lv, Transform point)
		{
			//IL_00b5: 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)
			Transform val = point.Find("rollin_smoke_fx");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).GetComponent<ParticleSystem>();
			}
			VehicleFX componentInChildren = ((Component)lv).GetComponentInChildren<VehicleFX>(true);
			ParticleSystem val2 = (((Object)(object)componentInChildren != (Object)null && componentInChildren.exhaustFX != null && ((Il2CppArrayBase<ParticleSystem>)(object)componentInChildren.exhaustFX).Length > 0) ? ((Il2CppArrayBase<ParticleSystem>)(object)componentInChildren.exhaustFX)[0] : null);
			if ((Object)(object)val2 == (Object)null)
			{
				Core.Log.Warning("[Effects] chair net " + Ids.Of((Component)(object)lv) + " has no exhaust smoke to copy - the tailpipes stay clean.");
				((Object)((Component)point).gameObject).name = "rollin_smoke_none";
				return null;
			}
			GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, point, false);
			((Object)val3).name = "rollin_smoke_fx";
			val3.transform.localPosition = Vector3.zero;
			val3.transform.localRotation = Quaternion.identity;
			foreach (Renderer componentsInChild in val3.GetComponentsInChildren<Renderer>(true))
			{
				componentsInChild.enabled = true;
			}
			ParticleSystem component = val3.GetComponent<ParticleSystem>();
			component.Stop(true, (ParticleSystemStopBehavior)0);
			Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)lv) + ": exhaust smoke '" + ((Object)val2).name + "' on a tailpipe.");
			return component;
		}

		private static void Smoke(State s)
		{
			if (s.Smokes.Count == 0)
			{
				return;
			}
			bool isOccupied = s.Lv.IsOccupied;
			foreach (ParticleSystem smoke in s.Smokes)
			{
				if (!((Object)(object)smoke == (Object)null))
				{
					if (isOccupied && !smoke.isPlaying)
					{
						smoke.Play(true);
					}
					else if (!isOccupied && smoke.isEmitting)
					{
						smoke.Stop(true, (ParticleSystemStopBehavior)1);
					}
				}
			}
		}

		private static void Squeal(State s)
		{
			bool flag = false;
			foreach (Wheel tyre in s.Tyres)
			{
				if ((Object)(object)tyre != (Object)null && (Object)(object)tyre.DriftAudioSource != (Object)null && tyre.DriftAudioSource.IsPlaying)
				{
					flag = true;
					break;
				}
			}
			if (flag != s.Squealing)
			{
				s.Squealing = flag;
				Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)s.Lv) + ": tyres " + (flag ? "squeal" : "quiet") + " at " + s.Speed.ToString("F1") + " km/h.");
			}
		}

		private static void Lightbar(State s)
		{
			if (!((Object)(object)s.Red == (Object)null) || !((Object)(object)s.Blue == (Object)null))
			{
				bool isOccupied = s.Lv.IsOccupied;
				float num = Time.time * 3.2f;
				bool flag = num - Mathf.Floor(num) < 0.5f;
				bool flag2 = Time.time * 14f % 1f < 0.6f;
				Blink(s.Red, isOccupied && flag && flag2);
				Blink(s.Blue, isOccupied && !flag && flag2);
			}
		}

		private static void Blink(Transform t, bool on)
		{
			if (!((Object)(object)t == (Object)null))
			{
				Light componentInChildren = ((Component)t).GetComponentInChildren<Light>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.intensity = (on ? 1.2f : 0f);
				}
				Transform val = t.Find("rollin_on");
				Renderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Renderer>() : null);
				if ((Object)(object)val2 != (Object)null && val2.enabled != on)
				{
					val2.enabled = on;
				}
			}
		}

		private static void Pulse(State s)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if (s.Pulses.Count == 0)
			{
				return;
			}
			float num = (s.Lv.IsOccupied ? Mathf.Pow(Mathf.Max(0f, Mathf.Sin(Time.time * (float)Math.PI * 2f * 2.1f)), 6f) : 0f);
			Vector3 localScale = Vector3.one * (1f + 0.08f * num);
			foreach (Transform pulse in s.Pulses)
			{
				if ((Object)(object)pulse != (Object)null)
				{
					pulse.localScale = localScale;
				}
			}
		}

		private static string SmokeInfo(ParticleSystem ps)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if ((Object)(object)ps == (Object)null)
			{
				return "(gone)";
			}
			ParticleSystemRenderer component = ((Component)ps).GetComponent<ParticleSystemRenderer>();
			string[] obj = new string[7]
			{
				"(",
				ps.isPlaying ? "playing" : "stopped",
				", ",
				ps.particleCount.ToString(),
				" particles, renderer ",
				null,
				null
			};
			object obj3;
			if (!((Object)(object)component == (Object)null))
			{
				string obj2 = (((Renderer)component).enabled ? "on" : "off");
				Bounds bounds = ((Renderer)component).bounds;
				Vector3 size = ((Bounds)(ref bounds)).size;
				obj3 = obj2 + ", bounds " + ((Vector3)(ref size)).ToString("F2");
			}
			else
			{
				obj3 = "none";
			}
			obj[5] = (string)obj3;
			obj[6] = ")";
			return string.Concat(obj);
		}

		internal static string Describe()
		{
			List<string> list = new List<string>();
			foreach (State value in _chairs.Values)
			{
				if (!((Object)(object)value.Lv == (Object)null))
				{
					list.Add("net " + Ids.Of((Component)(object)value.Lv) + " " + value.Speed.ToString("F1") + " km/h" + (((Object)(object)value.SpinL != (Object)null) ? ", rims" : "") + (((Object)(object)value.Hat != (Object)null) ? (", hat" + (((Object)(object)value.Head != (Object)null && (Object)(object)value.Hat.parent == (Object)(object)value.Head) ? " on head" : " on seat")) : "") + ((value.Smokes.Count > 0) ? (", " + value.Smokes.Count + " smoking pipe(s) " + SmokeInfo(value.Smokes[0])) : "") + (((Object)(object)value.Red != (Object)null) ? ", lightbar" : "") + ((value.Pulses.Count > 0) ? ", speaker" : ""));
				}
			}
			return "effects: " + ((list.Count == 0) ? "no chairs" : string.Join("; ", list));
		}
	}
	internal static class GameMeshes
	{
		internal const string RimSport = "rim_sport";

		internal const string RimMuscle = "rim_muscle";

		internal const string Tailpipe = "tailpipe";

		internal const string Lightbar = "lightbar";

		internal const string JerryCan = "jerrycan";

		internal const string Box = "box";

		internal const string Umbrella = "umbrella";

		internal const string Radio = "radio";

		internal const string Gnome = "gnome";

		internal static readonly string[] All = new string[9] { "rim_sport", "rim_muscle", "tailpipe", "lightbar", "jerrycan", "box", "umbrella", "radio", "gnome" };

		private static readonly Dictionary<string, Transform> _found = new Dictionary<string, Transform>(StringComparer.Ordinal);

		private static readonly HashSet<string> _missing = new HashSet<string>(StringComparer.Ordinal);

		private static readonly Regex Skip = new Regex("LOD\\s*_?[1-9]|Impostor|Convex|Collider", RegexOptions.IgnoreCase);

		internal static Transform Source(string key)
		{
			if (_found.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if (_missing.Contains(key))
			{
				return null;
			}
			try
			{
				value = Find(key);
			}
			catch (Exception ex)
			{
				Core.Log.Error("[GameMeshes] looking up '" + key + "' failed: " + ex);
				value = null;
			}
			if ((Object)(object)value == (Object)null)
			{
				_missing.Add(key);
				Core.Log.Error("[GameMeshes] no game mesh for '" + key + "' - the part shows nothing.");
				return null;
			}
			_found[key] = value;
			Core.Log.Msg("[GameMeshes] '" + key + "' from " + PathOf(value) + ".");
			return value;
		}

		internal static void Reset()
		{
			_found.Clear();
			_missing.Clear();
		}

		private static Transform Find(string key)
		{
			switch (key)
			{
			case "rim_sport":
				return Vehicle("cheetah", "SportsCarWheel_FL/ModelContainer/Model/Sports car wheel/sports car wheel");
			case "rim_muscle":
				return Vehicle("hounddog", "MuscleCarWheel_FR/ModelContainer/Model/Muscle Car Wheel/muscle car wheel");
			case "tailpipe":
				return Vehicle("bruiser", "SUV/suv/TailPipe");
			case "lightbar":
				return Vehicle("bruiser_police", "SUV/Lightbar/lightbar");
			case "jerrycan":
				return Item("gasoline", "jerry can");
			case "box":
				return Named("smallbox", null, "Box");
			case "umbrella":
				return Resource("equippables/umbrella/Umbrella_TP", "Umbrella (Static)");
			case "radio":
				return Named("SM_Item_Radio_01", "SM_Item_Radio_01", null);
			case "gnome":
				return Named("gnome", null, "Beard");
			default:
				Core.Log.Error("[GameMeshes] unknown source '" + key + "'.");
				return null;
			}
		}

		internal static bool LightbarMaterials(out Material redOn, out Material redOff, out Material blueOn, out Material blueOff)
		{
			redOn = (redOff = (blueOn = (blueOff = null)));
			Transform val = Source("lightbar");
			Transform val2 = (((Object)(object)val != (Object)null) ? val.parent : null);
			PoliceLight val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<PoliceLight>() : null);
			if ((Object)(object)val3 == (Object)null)
			{
				Core.Log.Warning("[GameMeshes] no PoliceLight beside the lightbar - the lenses keep their off colour.");
				return false;
			}
			redOn = val3.RedOnMat;
			redOff = val3.RedOffMat;
			blueOn = val3.BlueOnMat;
			blueOff = val3.BlueOffMat;
			int num;
			if ((Object)(object)redOn != (Object)null)
			{
				num = (((Object)(object)blueOn != (Object)null) ? 1 : 0);
				if (num != 0)
				{
					goto IL_00a4;
				}
			}
			else
			{
				num = 0;
			}
			Core.Log.Warning("[GameMeshes] the PoliceLight has no on materials - the lenses keep their off colour.");
			goto IL_00a4;
			IL_00a4:
			return (byte)num != 0;
		}

		private static Transform Vehicle(string code, string path)
		{
			VehicleManager instance = NetworkSingleton<VehicleManager>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				Core.Log.Warning("[GameMeshes] no VehicleManager yet for '" + code + "'.");
				return null;
			}
			LandVehicle vehiclePrefab = instance.GetVehiclePrefab(code);
			if ((Object)(object)vehiclePrefab == (Object)null)
			{
				Core.Log.Warning("[GameMeshes] the game has no vehicle '" + code + "'.");
				return null;
			}
			Transform val = ((Component)vehiclePrefab).transform.Find(path);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			string name = path.Substring(path.LastIndexOf('/') + 1);
			val = Descendant(((Component)vehiclePrefab).transform, name);
			Core.Log.Warning("[GameMeshes] '" + code + "' has no '" + path + "'" + (((Object)(object)val != (Object)null) ? (", took " + PathOf(val) + " instead.") : "."));
			return val;
		}

		private static Transform Item(string id, string child)
		{
			ItemDefinition item = Registry.GetItem(id);
			if ((Object)(object)item == (Object)null)
			{
				Core.Log.Warning("[GameMeshes] the game has no item '" + id + "'.");
				return null;
			}
			StorableItemDefinition val = ((Il2CppObjectBase)item).TryCast<StorableItemDefinition>();
			StoredItem val2 = (((Object)(object)val != (Object)null) ? val.StoredItem : null);
			if ((Object)(object)val2 == (Object)null)
			{
				Core.Log.Warning("[GameMeshes] item '" + id + "' has no stored model.");
				return null;
			}
			Transform val3 = Descendant(((Component)val2).transform, child);
			if ((Object)(object)val3 == (Object)null)
			{
				Core.Log.Warning("[GameMeshes] item '" + id + "' has no '" + child + "' under " + ((Object)val2).name + ".");
			}
			return val3;
		}

		private static Transform Resource(string path, string child)
		{
			GameObject val = Resources.Load<GameObject>(path);
			if ((Object)(object)val == (Object)null)
			{
				Core.Log.Warning("[GameMeshes] no Resources prefab '" + path + "'.");
				return null;
			}
			Transform val2 = Descendant(val.transform, child);
			if ((Object)(object)val2 == (Object)null)
			{
				Core.Log.Warning("[GameMeshes] '" + path + "' has no '" + child + "'.");
			}
			return val2;
		}

		private static Transform Named(string name, string mesh, string child)
		{
			int num = 0;
			foreach (Transform item in Resources.FindObjectsOfTypeAll<Transform>())
			{
				if ((Object)(object)item == (Object)null || ((Object)item).name != name)
				{
					continue;
				}
				num++;
				if (child != null && (Object)(object)item.Find(child) == (Object)null)
				{
					continue;
				}
				if (mesh != null)
				{
					MeshFilter component = ((Component)item).GetComponent<MeshFilter>();
					if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null || ((Object)component.sharedMesh).name != mesh)
					{
						continue;
					}
				}
				if (!Batched(item))
				{
					return item;
				}
			}
			Core.Log.Warning("[GameMeshes] " + num + " object(s) named '" + name + "', none with " + (mesh ?? child) + " and its own mesh.");
			return null;
		}

		private static bool Batched(Transform t)
		{
			foreach (MeshFilter componentsInChild in ((Component)t).GetComponentsInChildren<MeshFilter>(true))
			{
				if ((Object)(object)componentsInChild.sharedMesh != (Object)null && ((Object)componentsInChild.sharedMesh).name.StartsWith("Combined Mesh", StringComparison.Ordinal))
				{
					return true;
				}
			}
			return false;
		}

		private static Transform Descendant(Transform root, string name)
		{
			foreach (Transform componentsInChild in ((Component)root).GetComponentsInChildren<Transform>(true))
			{
				if (((Object)componentsInChild).name == name)
				{
					return componentsInChild;
				}
			}
			return null;
		}

		private static string PathOf(Transform t)
		{
			string text = ((Object)t).name;
			Transform parent = t.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}

		internal static Transform Copy(string key, Transform parent, Material fallback = null)
		{
			//IL_001b: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			Transform val = Source(key);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Transform obj = CopyNode(val, parent, fallback);
			obj.localPosition = Vector3.zero;
			obj.localRotation = val.rotation;
			obj.localScale = val.lossyScale;
			return obj;
		}

		private static Transform CopyNode(Transform src, Transform parent, Material fallback)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(((Object)src).name);
			Transform transform = val.transform;
			transform.SetParent(parent, false);
			transform.localPosition = src.localPosition;
			transform.localRotation = src.localRotation;
			transform.localScale = src.localScale;
			MeshFilter component = ((Component)src).GetComponent<MeshFilter>();
			MeshRenderer component2 = ((Component)src).GetComponent<MeshRenderer>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null && (Object)(object)component2 != (Object)null)
			{
				val.AddComponent<MeshFilter>().sharedMesh = component.sharedMesh;
				MeshRenderer val2 = val.AddComponent<MeshRenderer>();
				Il2CppReferenceArray<Material> sharedMaterials = ((Renderer)component2).sharedMaterials;
				bool flag = false;
				for (int i = 0; i < ((Il2CppArrayBase<Material>)(object)sharedMaterials).Length; i++)
				{
					if ((Object)(object)((Il2CppArrayBase<Material>)(object)sharedMaterials)[i] != (Object)null)
					{
						flag = true;
					}
					else
					{
						((Il2CppArrayBase<Material>)(object)sharedMaterials)[i] = fallback;
					}
				}
				if (!flag && (Object)(object)fallback == (Object)null)
				{
					Core.Log.Warning("[GameMeshes] " + ((Object)src).name + " has no material and no fallback.");
				}
				((Renderer)val2).sharedMaterials = sharedMaterials;
			}
			for (int j = 0; j < src.childCount; j++)
			{
				Transform child = src.GetChild(j);
				if (!Skip.IsMatch(((Object)child).name) && (!((Object)(object)((Component)child).GetComponent<Light>() != (Object)null) || !((Object)(object)((Component)child).GetComponent<MeshFilter>() == (Object)null) || child.childCount != 0))
				{
					CopyNode(child, transform, fallback);
				}
			}
			return transform;
		}

		internal static Bounds Measure(Transform space, Transform root)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00d4: Unknown result type (might be due to invalid IL or missing references)
			Bounds result = default(Bounds);
			bool flag = true;
			Vector3 val = default(Vector3);
			foreach (MeshFilter componentsInChild in ((Component)root).GetComponentsInChildren<MeshFilter>(true))
			{
				if ((Object)(object)componentsInChild.sharedMesh == (Object)null)
				{
					continue;
				}
				Bounds bounds = componentsInChild.sharedMesh.bounds;
				for (int i = 0; i < 8; i++)
				{
					((Vector3)(ref val))..ctor(((i & 1) == 0) ? ((Bounds)(ref bounds)).min.x : ((Bounds)(ref bounds)).max.x, ((i & 2) == 0) ? ((Bounds)(ref bounds)).min.y : ((Bounds)(ref bounds)).max.y, ((i & 4) == 0) ? ((Bounds)(ref bounds)).min.z : ((Bounds)(ref bounds)).max.z);
					Vector3 val2 = space.InverseTransformPoint(((Component)componentsInChild).transform.TransformPoint(val));
					if (flag)
					{
						result = new Bounds(val2, Vector3.zero);
						flag = false;
					}
					else
					{
						((Bounds)(ref result)).Encapsulate(val2);
					}
				}
			}
			return result;
		}

		internal static string Describe(string key)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			Transform val = Source(key);
			if ((Object)(object)val == (Object)null)
			{
				return key + ": missing";
			}
			GameObject val2 = new GameObject("rollin_probe");
			try
			{
				Transform val3 = Copy(key, val2.transform);
				Bounds val4 = Measure(val2.transform, val3);
				int length = ((Component)val3).GetComponentsInChildren<MeshRenderer>(true).Length;
				HashSet<string> hashSet = new HashSet<string>();
				foreach (MeshRenderer componentsInChild in ((Component)val3).GetComponentsInChildren<MeshRenderer>(true))
				{
					foreach (Material item in (Il2CppArrayBase<Material>)(object)((Renderer)componentsInChild).sharedMaterials)
					{
						hashSet.Add(((Object)(object)item == (Object)null) ? "null" : (((Object)item).name + " (" + (((Object)(object)item.shader != (Object)null) ? ((Object)item.shader).name : "no shader") + ")"));
					}
				}
				string[] obj = new string[9]
				{
					key,
					": ",
					PathOf(val),
					", ",
					length.ToString(),
					" renderer(s), size ",
					null,
					null,
					null
				};
				Vector3 size = ((Bounds)(ref val4)).size;
				obj[6] = ((Vector3)(ref size)).ToString("F2");
				obj[7] = ", ";
				obj[8] = string.Join(", ", hashSet);
				return string.Concat(obj);
			}
			finally
			{
				Object.Destroy((Object)(object)val2);
			}
		}
	}
	internal static class Garage
	{
		[HarmonyPatch(typeof(SaveManager), "Save", new Type[] { typeof(string) })]
		private static class SaveHook
		{
			private static void Prefix()
			{
				if (!RollinNet.IsHost)
				{
					return;
				}
				try
				{
					EnsureLoaded();
				}
				catch (Exception ex)
				{
					Core.Log.Error("[Garage] reading Rollin.tuning before the save failed: " + ex);
				}
			}

			private static void Postfix(SaveManager __instance)
			{
				if (!RollinNet.IsHost)
				{
					return;
				}
				try
				{
					List<string> approvedBaseLevelPaths = __instance.ApprovedBaseLevelPaths;
					if (approvedBaseLevelPaths == null)
					{
						Core.Log.Warning("[Garage] the game has no list of kept files - Rollin.tuning may be deleted at the end of the save.");
					}
					else if (!approvedBaseLevelPaths.Contains("Rollin.tuning"))
					{
						approvedBaseLevelPaths.Add("Rollin.tuning");
					}
				}
				catch (Exception ex)
				{
					Core.Log.Error("[Garage] could not mark Rollin.tuning as kept: " + ex);
				}
				try
				{
					Save();
				}
				catch (Exception ex2)
				{
					Core.Log.Error("[Garage] saving the wheelchair tuning failed: " + ex2);
				}
			}
		}

		internal const string FileName = "Rollin.tuning";

		private static readonly Dictionary<string, Dictionary<string, string>> _byProp = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal);

		private static readonly Dictionary<string, Vector4> _parked = new Dictionary<string, Vector4>(StringComparer.Ordinal);

		private static readonly Dictionary<string, string> _cargo = new Dictionary<string, string>(StringComparer.Ordinal);

		private static int _applying = -1;

		private static string _loadedFrom;

		private static string _restoredFor;

		private static float _restoreAt = -1f;

		private const float RestoreDelay = 3f;

		internal static void Init()
		{
			ChassisApi.TuningChanged += OnTuningChanged;
			PropSwap.Swapped += OnSwapped;
			PropSwap.KeepsVehicle = KeepsVehicle;
			Parts.RegisterAll();
		}

		internal static void Reset()
		{
			_byProp.Clear();
			_parked.Clear();
			_cargo.Clear();
			_applying = -1;
			_loadedFrom = null;
			_restoredFor = null;
			_restoreAt = -1f;
		}

		internal static void Tick()
		{
			if (RollinNet.IsHost)
			{
				EnsureLoaded();
				RestoreParked();
			}
		}

		internal static bool IsTuned(string prop)
		{
			if (prop != null && _byProp.TryGetValue(prop, out var value))
			{
				return value.Count > 0;
			}
			return false;
		}

		private static bool KeepsVehicle(string prop)
		{
			if (!IsTuned(prop))
			{
				return Cargo.HasItems(PropSwap.VehicleOf(prop));
			}
			return true;
		}

		private static void RestoreParked()
		{
			//IL_00c0: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			if (_loadedFrom == null || _restoredFor == _loadedFrom || (Object)(object)Player.Local == (Object)null)
			{
				return;
			}
			if (_restoreAt < 0f)
			{
				_restoreAt = Time.time + 3f;
			}
			else
			{
				if (Time.time < _restoreAt)
				{
					return;
				}
				_restoredFor = _loadedFrom;
				_restoreAt = -1f;
				int num = 0;
				int num2 = 0;
				HashSet<string> hashSet = new HashSet<string>(_byProp.Keys, StringComparer.Ordinal);
				hashSet.UnionWith(_cargo.Keys);
				foreach (string item in hashSet)
				{
					num2++;
					Vector4 value;
					bool flag = _parked.TryGetValue(item, out value);
					if (PropSwap.HostPark(item, flag ? new Vector3?(new Vector3(value.x, value.y, value.z)) : ((Vector3?)null), flag ? value.w : 0f))
					{
						num++;
					}
				}
				Core.Log.Msg("[Garage] " + num + "/" + num2 + " tuned wheelchair(s) parked again as vehicles.");
			}
		}

		internal static bool Request(LandVehicle lv, string key, string value, string why)
		{
			if ((Object)(object)lv == (Object)null || !WheelchairType.Is(lv))
			{
				Core.Log.Warning("[Garage] " + why + ": no wheelchair given - " + key + " ignored.");
				return false;
			}
			value = value ?? string.Empty;
			if (RollinNet.IsHost)
			{
				return ChassisApi.SetTuning(lv, key, value);
			}
			RollinNet.ToHost("req.tune", Ids.Of((Component)(object)lv).ToString(CultureInfo.InvariantCulture), key, value);
			Core.Log.Msg("[Garage] asked the host to set " + key + " = '" + value + "' on net " + Ids.Of((Component)(object)lv) + " (" + why + ").");
			return true;
		}

		internal static void HostRequest(int vehicle, string key, string value)
		{
			LandVehicle val = Ids.Find<LandVehicle>(vehicle);
			if ((Object)(object)val == (Object)null || !WheelchairType.Is(val))
			{
				Core.Log.Warning("[Garage] tuning request for net " + vehicle + ", which is no wheelchair here - dropped.");
			}
			else if (!ChassisApi.SetTuning(val, key, value))
			{
				Core.Log.Warning("[Garage] Chassis refused " + key + " = '" + value + "' on net " + vehicle + " (reason above).");
			}
		}

		private static void OnTuningChanged(LandVehicle lv, string key)
		{
			if ((Object)(object)lv == (Object)null || !WheelchairType.Is(lv) || !RollinNet.IsHost)
			{
				return;
			}
			int num = Ids.Of((Component)(object)lv);
			if (num == _applying)
			{
				return;
			}
			string text = PropSwap.KeyOfVehicle(num);
			if (text == null)
			{
				Core.Log.Msg("[Garage] net " + num + " is no swapped prop (console spawn) - its tuning is not kept.");
				return;
			}
			Dictionary<string, string> dictionary = ChassisApi.Tuning(lv);
			if (dictionary.Count == 0)
			{
				_byProp.Remove(text);
				_parked.Remove(text);
			}
			else
			{
				_byProp[text] = dictionary;
			}
			Core.Log.Msg("[Garage] prop " + text + " keeps " + dictionary.Count + " tuning key(s).");
		}

		private static void OnSwapped(string prop, LandVehicle lv)
		{
			EnsureLoaded();
			if (_cargo.TryGetValue(prop, out var value) && !Cargo.HasItems(lv))
			{
				Cargo.LoadLater(lv, value);
				Core.Log.Msg("[Garage] prop " + prop + ": its box contents go back into net " + Ids.Of((Component)(object)lv) + ".");
			}
			if (!_byProp.TryGetValue(prop, out var value2) || value2.Count == 0)
			{
				return;
			}
			int applying = Ids.Of((Component)(object)lv);
			int num = 0;
			_applying = applying;
			try
			{
				foreach (KeyValuePair<string, string> item in new List<KeyValuePair<string, string>>(value2))
				{
					if (ChassisApi.SetTuning(lv, item.Key, item.Value))
					{
						num++;
						continue;
					}
					Core.Log.Warning("[Garage] prop " + prop + ": " + item.Key + " = '" + item.Value + "' was refused (part no longer registered?).");
				}
			}
			finally
			{
				_applying = -1;
			}
			Core.Log.Msg("[Garage] prop " + prop + " is net " + applying + " again with " + num + "/" + value2.Count + " tuning key(s).");
		}

		internal static string Describe(string prop)
		{
			if (prop == null || !_byProp.TryGetValue(prop, out var value))
			{
				return "stock";
			}
			return Encode(value);
		}

		private static string SavePath()
		{
			if (!Singleton<LoadManager>.InstanceExists)
			{
				return null;
			}
			string loadedGameFolderPath = Singleton<LoadManager>.Instance.LoadedGameFolderPath;
			if (!string.IsNullOrEmpty(loadedGameFolderPath) && Directory.Exists(loadedGameFolderPath))
			{
				return Path.Combine(loadedGameFolderPath, "Rollin.tuning");
			}
			return null;
		}

		private static void EnsureLoaded()
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			string text = SavePath();
			if (text == null || text == _loadedFrom)
			{
				return;
			}
			_loadedFrom = text;
			_byProp.Clear();
			_parked.Clear();
			_cargo.Clear();
			if (!File.Exists(text))
			{
				Core.Log.Msg("[Garage] no Rollin.tuning in this save yet.");
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(text);
				foreach (string text2 in array)
				{
					int num = text2.IndexOf('|');
					if (num <= 0)
					{
						continue;
					}
					if (text2[0] == '@')
					{
						string[] array2 = text2.Substring(num + 1).Split(';');
						if (array2.Length == 4 && TryF(array2[0], out var v) && TryF(array2[1], out var v2) && TryF(array2[2], out var v3) && TryF(array2[3], out var v4))
						{
							_parked[text2.Substring(1, num - 1)] = new Vector4(v, v2, v3, v4);
						}
						else
						{
							Core.Log.Warning("[Garage] unreadable parking line '" + text2 + "' - that chair comes back at its prop.");
						}
						continue;
					}
					if (text2[0] == '$')
					{
						try
						{
							_cargo[text2.Substring(1, num - 1)] = Encoding.UTF8.GetString(Convert.FromBase64String(text2.Substring(num + 1)));
						}
						catch (FormatException)
						{
							Core.Log.Error("[Garage] unreadable box line for " + text2.Substring(1, num - 1) + " - those items are lost.");
						}
						continue;
					}
					Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
					string[] array3 = text2.Substring(num + 1).Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
					foreach (string text3 in array3)
					{
						int num2 = text3.IndexOf('=');
						if (num2 <= 0)
						{
							Core.Log.Warning("[Garage] unreadable entry '" + text3 + "' skipped.");
						}
						else
						{
							dictionary[text3.Substring(0, num2)] = text3.Substring(num2 + 1);
						}
					}
					if (dictionary.Count > 0)
					{
						_byProp[text2.Substring(0, num)] = dictionary;
					}
				}
				Core.Log.Msg("[Garage] loaded the tuning of " + _byProp.Count + " wheelchair(s), " + _parked.Count + " parking spot(s), " + _cargo.Count + " filled box(es), from " + text + ".");
			}
			catch (Exception ex2)
			{
				Core.Log.Error("[Garage] could not read " + text + ", the wheelchairs stay stock: " + ex2.Message);
			}
		}

		private static void Save()
		{
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: 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_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			string text = SavePath();
			if (text == null)
			{
				Core.Log.Warning("[Garage] no save folder - the wheelchair tuning stays in memory.");
				return;
			}
			EnsureLoaded();
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, Dictionary<string, string>> item in _byProp)
			{
				stringBuilder.Append(item.Key).Append('|').Append(Encode(item.Value))
					.Append('\n');
			}
			foreach (string item2 in PropSwap.VehicleKeys())
			{
				string text2 = Cargo.Serialize(PropSwap.VehicleOf(item2));
				if (text2 != null)
				{
					_cargo[item2] = text2;
				}
				else
				{
					_cargo.Remove(item2);
				}
			}
			foreach (KeyValuePair<string, string> item3 in _cargo)
			{
				stringBuilder.Append('$').Append(item3.Key).Append('|')
					.Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(item3.Value)))
					.Append('\n');
			}
			HashSet<string> hashSet = new HashSet<string>(_byProp.Keys, StringComparer.Ordinal);
			hashSet.UnionWith(_cargo.Keys);
			foreach (string item4 in hashSet)
			{
				LandVehicle val = PropSwap.VehicleOf(item4);
				if ((Object)(object)val != (Object)null)
				{
					Transform transform = ((Component)val).transform;
					_parked[item4] = new Vector4(transform.position.x, transform.position.y, transform.position.z, transform.eulerAngles.y);
				}
				if (_parked.TryGetValue(item4, out var value))
				{
					stringBuilder.Append('@').Append(item4).Append('|')
						.Append(F(value.x))
						.Append(';')
						.Append(F(value.y))
						.Append(';')
						.Append(F(value.z))
						.Append(';')
						.Append(F(value.w))
						.Append('\n');
				}
			}
			File.WriteAllText(text, stringBuilder.ToString());
			Core.Log.Msg("[Garage] saved the tuning of " + _byProp.Count + " wheelchair(s), " + _parked.Count + " parking spot(s), " + _cargo.Count + " filled box(es), to " + text + ".");
		}

		private static string F(float v)
		{
			return v.ToString("R", CultureInfo.InvariantCulture);
		}

		private static bool TryF(string s, out float v)
		{
			return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out v);
		}

		private static string Encode(Dictionary<string, string> s)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, string> item in s)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(item.Key).Append('=').Append(item.Value);
			}
			return stringBuilder.ToString();
		}
	}
	internal static class Horns
	{
		internal sealed class Horn
		{
			internal string Name;

			internal string Label;

			internal Func<float[]> Make;
		}

		private const int Rate = 44100;

		internal static readonly List<Horn> All = new List<Horn>
		{
			new Horn
			{
				Name = "rollin_clown",
				Label = "Clown Horn",
				Make = Clown
			},
			new Horn
			{
				Name = "rollin_duck",
				Label = "Rubber Duck",
				Make = Duck
			},
			new Horn
			{
				Name = "rollin_train",
				Label = "Freight Train",
				Make = Train
			},
			new Horn
			{
				Name = "rollin_charge",
				Label = "Charge!",
				Make = Charge
			},
			new Horn
			{
				Name = "rollin_cucaracha",
				Label = "La Cucaracha",
				Make = Cucaracha
			}
		};

		private const float G4 = 392f;

		private const float C5 = 523.25f;

		private const float D5 = 587.33f;

		private const float E5 = 659.25f;

		private const float F5 = 698.46f;

		private const float G5 = 783.99f;

		private const float A5 = 880f;

		internal static void RegisterAll()
		{
			foreach (Horn item in All)
			{
				try
				{
					float[] array = item.Make();
					AudioClip val = AudioClip.Create(item.Name, array.Length, 1, 44100, false);
					val.SetData(Il2CppStructArray<float>.op_Implicit(array), 0);
					((Object)val).hideFlags = (HideFlags)32;
					ChassisApi.RegisterSound(item.Name, val);
					Core.Log.Msg("[Horns] '" + item.Name + "' made, " + ((float)array.Length / 44100f).ToString("F2") + " s.");
				}
				catch (Exception ex)
				{
					Core.Log.Error("[Horns] making '" + item.Name + "' failed - that horn is missing: " + ex);
				}
			}
		}

		private static float[] Buffer(float seconds)
		{
			return new float[(int)(seconds * 44100f)];
		}

		private static void Tone(float[] buf, float at, float length, float fromHz, float toHz, Func<float, float> wave, float gain)
		{
			int num = (int)(at * 44100f);
			int num2 = (int)(length * 44100f);
			double num3 = 0.0;
			for (int i = 0; i < num2 && num + i < buf.Length; i++)
			{
				float num4 = (float)i / (float)num2;
				float num5 = Mathf.Lerp(fromHz, toHz, num4);
				num3 += (double)(num5 / 44100f);
				float num6 = Mathf.Min(1f, (float)i / 441f) * Mathf.Min(1f, (float)(num2 - i) / 1323f);
				buf[num + i] += wave((float)(num3 - Math.Floor(num3))) * num6 * gain;
			}
		}

		private static float Saw(float p)
		{
			return 2f * p - 1f;
		}

		private static float Square(float p)
		{
			if (!(p < 0.5f))
			{
				return -0.8f;
			}
			return 0.8f;
		}

		private static float Sine(float p)
		{
			return Mathf.Sin(p * 2f * (float)Math.PI);
		}

		private static float[] Clip(float[] buf)
		{
			for (int i = 0; i < buf.Length; i++)
			{
				buf[i] = Mathf.Clamp(buf[i], -1f, 1f);
			}
			return buf;
		}

		private static float[] Clown()
		{
			float[] buf = Buffer(0.75f);
			Tone(buf, 0f, 0.28f, 420f, 360f, Saw, 0.45f);
			Tone(buf, 0f, 0.28f, 840f, 720f, Square, 0.12f);
			Tone(buf, 0.38f, 0.32f, 400f, 330f, Saw, 0.45f);
			Tone(buf, 0.38f, 0.32f, 800f, 660f, Square, 0.12f);
			return Clip(buf);
		}

		private static float[] Duck()
		{
			float[] buf = Buffer(0.5f);
			Tone(buf, 0f, 0.18f, 900f, 1500f, Square, 0.35f);
			Tone(buf, 0.22f, 0.22f, 1400f, 800f, Square, 0.35f);
			return Clip(buf);
		}

		private static float[] Train()
		{
			float[] buf = Buffer(1.4f);
			float[] array = new float[4] { 277f, 349f, 415f, 523f };
			foreach (float num in array)
			{
				Tone(buf, 0f, 1.4f, num, num * 0.995f, Saw, 0.16f);
				Tone(buf, 0f, 1.4f, num * 1.004f, num, Saw, 0.12f);
			}
			return Clip(buf);
		}

		private static float[] Melody(float beat, (float hz, float beats)[] notes, Func<float, float> wave, float gain)
		{
			float num = 0f;
			(float, float)[] array = notes;
			for (int i = 0; i < array.Length; i++)
			{
				(float, float) tuple = array[i];
				num += tuple.Item2 * beat;
			}
			float[] buf = Buffer(num + 0.05f);
			float num2 = 0f;
			array = notes;
			for (int i = 0; i < array.Length; i++)
			{
				(float, float) tuple2 = array[i];
				if (tuple2.Item1 > 0f)
				{
					Tone(buf, num2, tuple2.Item2 * beat * 0.9f, tuple2.Item1, tuple2.Item1, wave, gain);
				}
				num2 += tuple2.Item2 * beat;
			}
			return Clip(buf);
		}

		private static float[] Charge()
		{
			return Melody(0.13f, new(float, float)[6]
			{
				(392f, 1f),
				(523.25f, 1f),
				(659.25f, 1f),
				(783.99f, 2f),
				(659.25f, 1f),
				(783.99f, 4f)
			}, Square, 0.3f);
		}

		private static float[] Cucaracha()
		{
			return Melody(0.11f, new(float, float)[19]
			{
				(523.25f, 1f),
				(523.25f, 1f),
				(523.25f, 1f),
				(698.46f, 3f),
				(880f, 2f),
				(0f, 1f),
				(523.25f, 1f),
				(523.25f, 1f),
				(523.25f, 1f),
				(698.46f, 3f),
				(880f, 2f),
				(0f, 1f),
				(698.46f, 2f),
				(698.46f, 1f),
				(659.25f, 1f),
				(659.25f, 1f),
				(587.33f, 1f),
				(587.33f, 1f),
				(523.25f, 4f)
			}, Square, 0.28f);
		}
	}
	internal static class Menu
	{
		private sealed class Row
		{
			internal string Label;

			internal string Key;

			internal readonly List<KeyValuePair<string, string>> Options = new List<KeyValuePair<string, string>>();
		}

		private static MelonPreferences_Entry<KeyCode> _key;

		private static readonly string[] PartSlots = new string[10] { "spoiler", "booster", "exhaust", "rims", "hat", "mascot", "roof", "lights", "audio", "cargo" };

		private static readonly string[] StageSlots = new string[6] { "engine", "brakes", "suspension", "tyres", "steering", "weight" };

		private static readonly (string Label, string Value)[] Paints = new(string, string)[10]
		{
			("Stock", ""),
			("Hot Pink", "FF3EA5,metallic"),
			("Toxic Lime", "7CFF2E,classic"),
			("Gold", "FFC423,chrome"),
			("Chrome", "D9DDE3,chrome"),
			("Matte Black", "151515,matte"),
			("Candy Red", "C8102E,metallic"),
			("Baby Blue", "8FD3FF,classic"),
			("Royal Purple", "7A2BD9,metallic"),
			("Hospital Green", "8FBFA5,matte")
		};

		private static readonly (string Label, string Value)[] Neons = new(string, string)[7]
		{
			("Off", ""),
			("Pink", "FF2EC4,fblr"),
			("Cyan", "2EF2FF,fblr"),
			("Green", "39FF14,fblr"),
			("Red", "FF1A1A,fblr"),
			("Purple", "9B30FF,fblr"),
			("White", "FFFFFF,fblr")
		};

		private static List<Row> _rows;

		private static LandVehicle _lv;

		private static int _row;

		private static GameObject _canvas;

		private static TextMeshProUGUI _body;

		private static readonly Dictionary<string, (string Value, float Until)> _pending = new Dictionary<string, (string, float)>(StringComparer.OrdinalIgnoreCase);

		private static bool _orbit;

		private static bool _orbitWarned;

		internal static KeyCode Key
		{
			get
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				if (_key == null)
				{
					return (KeyCode)114;
				}
				return _key.Value;
			}
		}

		internal static bool IsOpen => (Object)(object)_lv != (Object)null;

		internal static void Init()
		{
			//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)
			_key = MelonPreferences.CreateCategory("Rollin", "Rollin").CreateEntry<KeyCode>("GarageKey", (KeyCode)114, "Garage key", "Opens and closes the tuning menu while you drive a wheelchair.", false, false, (ValueValidator)null, (string)null);
			Core.Log.Msg("[Menu] garage key: " + ((object)Key/*cast due to .constrained prefix*/).ToString() + ".");
			ChassisApi.AddKeyHint("rollin.garage", "Tuning", (Func<KeyHintContext, bool>)((KeyHintContext c) => c.Driver && WheelchairType.Is(c.Vehicle)), (Func<KeyCode>)(() => Key));
		}

		internal static void Reset()
		{
			if ((Object)(object)_lv != (Object)null)
			{
				Lock(_lv, on: false, "reset");
			}
			_lv = null;
			_orbit = false;
			if ((Object)(object)_canvas != (Object)null)
			{
				_canvas.SetActive(false);
			}
		}

		internal static void Tick()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//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)
			if ((Object)(object)_lv == (Object)null)
			{
				if (Input.GetKeyDown(Key) && !GameInput.IsTyping)
				{
					LandVehicle val = LocalChair();
					if (!((Object)(object)val == (Object)null))
					{
						Open(val, ((object)Key/*cast due to .constrained prefix*/).ToString() + " pressed");
					}
				}
			}
			else if (!Object.op_Implicit((Object)(object)_lv) || !_lv.LocalPlayerIsDriver)
			{
				Close("left the wheelchair");
			}
			else
			{
				if (GameInput.IsTyping)
				{
					return;
				}
				if (Input.GetKeyDown(Key))
				{
					Close(((object)Key/*cast due to .constrained prefix*/).ToString() + " pressed");
					return;
				}
				if (Input.GetKeyDown((KeyCode)119) || Input.GetKeyDown((KeyCode)273))
				{
					Move(-1);
				}
				if (Input.GetKeyDown((KeyCode)115) || Input.GetKeyDown((KeyCode)274))
				{
					Move(1);
				}
				if (Input.GetKeyDown((KeyCode)97))
				{
					Cycle(-1);
				}
				if (Input.GetKeyDown((KeyCode)100))
				{
					Cycle(1);
				}
				Draw();
				HoldOrbit();
			}
		}

		private static void HoldOrbit()
		{
			//IL_002b: 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_0041: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!Singleton<GameInput>.InstanceExists)
			{
				if (!_orbitWarned)
				{
					_orbitWarned = true;
					Core.Log.Warning("[Menu] no GameInput - the camera orbits only with the right button held.");
				}
				return;
			}
			GameInput instance = Singleton<GameInput>.Instance;
			ButtonCode val = (ButtonCode)1;
			if (!instance.buttonsDown.Contains(val))
			{
				instance.buttonsDown.Add(val);
				if (!instance.buttonsDownThisFrame.Contains(val))
				{
					instance.buttonsDownThisFrame.Add(val);
				}
				if (!_orbit)
				{
					Core.Log.Msg("[Menu] the camera orbits with the mouse while the menu is open.");
				}
				_orbit = true;
			}
		}

		private static void ReleaseOrbit(string why)
		{
			if (_orbit)
			{
				_orbit = false;
				if (!Singleton<GameInput>.InstanceExists)
				{
					Core.Log.Warning("[Menu] GameInput is gone - nothing to release (" + why + ").");
					return;
				}
				if (Input.GetMouseButton(1))
				{
					Core.Log.Msg("[Menu] right button is really held - the camera keeps orbiting (" + why + ").");
					return;
				}
				GameInput instance = Singleton<GameInput>.Instance;
				instance.buttonsDown.Remove((ButtonCode)1);
				instance.buttonsUpThisFrame.Add((ButtonCode)1);
				Core.Log.Msg("[Menu] camera back to right-click orbit (" + why + ").");
			}
		}

		internal static LandVehicle LocalChair()
		{
			Player local = Player.Local;
			NetworkObject val = (((Object)(object)local != (Object)null) ? local.CurrentVehicle : null);
			LandVehicle val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<LandVehicle>() : null);
			if (!((Object)(object)val2 != (Object)null) || !WheelchairType.Is(val2) || !val2.LocalPlayerIsDriver)
			{
				return null;
			}
			return val2;
		}

		internal static bool Open(LandVehicle lv, string why)
		{
			if ((Object)(object)lv == (Object)null)
			{
				Core.Log.Warning("[Menu] open (" + why + "): you are not driving a wheelchair.");
				return false;
			}
			BuildRows();
			if (!EnsureCanvas())
			{
				return false;
			}
			_lv = lv;
			Lock(lv, on: true, why);
			_row = Mathf.Clamp(_row, 0, _rows.Count - 1);
			_canvas.SetActive(true);
			Draw();
			Core.Log.Msg("[Menu] opened for net " + Ids.Of((Component)(object)lv) + " (" + why + "), " + _rows.Count + " rows.");
			return true;
		}

		internal static void Close(string why)
		{
			LandVehicle lv = _lv;
			_lv = null;
			if ((Object)(object)lv != (Object)null)
			{
				Lock(lv, on: false, why);
			}
			ReleaseOrbit(why);
			if ((Object)(object)_canvas != (Object)null)
			{
				_canvas.SetActive(false);
			}
			Core.Log.Msg("[Menu] closed (" + why + ").");
		}

		internal static void Move(int by)
		{
			if (_rows != null && _rows.Count != 0)
			{
				_row = (_row + by + _rows.Count) % _rows.Count;
			}
		}

		internal static void Cycle(int by)
		{
			if (!((Object)(object)_lv == (Object)null) && _rows != null)
			{
				Row row = _rows[_row];
				int num = IndexOf(row, Current(row.Key));
				int index = (((num >= 0) ? num : 0) + by + row.Options.Count) % row.Options.Count;
				KeyValuePair<string, string> keyValuePair = row.Options[index];
				_pending[row.Key] = (keyValuePair.Value, Time.time + 2f);
				if (!Garage.Request(_lv, row.Key, keyValuePair.Value, "menu"))
				{
					Core.Log.Warning("[Menu] " + row.Label + " -> " + keyValuePair.Key + " was refused (reason above).");
				}
				else
				{
					Core.Log.Msg("[Menu] " + row.Label + " -> " + keyValuePair.Key + " (" + row.Key + " = '" + keyValuePair.Value + "').");
				}
			}
		}

		private static string Current(string key)
		{
			if (_pending.TryGetValue(key, out (string, float) value) && Time.time < value.Item2)
			{
				return value.Item1;
			}
			return ChassisApi.GetTuning(_lv, key) ?? "";
		}

		private static int IndexOf(Row row, string value)
		{
			for (int i = 0; i < row.Options.Count; i++)
			{
				if (string.Equals(row.Options[i].Value, value ?? "", StringComparison.OrdinalIgnoreCase))
				{
					return i;
				}
			}
			return -1;
		}

		private static void BuildRows()
		{
			if (_rows != null)
			{
				return;
			}
			_rows = new List<Row>();
			Row row = new Row
			{
				Label = "Paint",
				Key = "paint"
			};
			Row row2 = new Row
			{
				Label = "Trim Paint",
				Key = "paint2"
			};
			(string, string)[] paints = Paints;
			for (int i = 0; i < paints.Length; i++)
			{
				(string, string) tuple = paints[i];
				row.Options.Add(new KeyValuePair<string, string>(tuple.Item1, tuple.Item2));
				row2.Options.Add(new KeyValuePair<string, string>(tuple.Item1, tuple.Item2));
			}
			_rows.Add(row);
			_rows.Add(row2);
			Row row3 = new Row
			{
				Label = "Neon",
				Key = "neon"
			};
			paints = Neons;
			for (int i = 0; i < paints.Length; i++)
			{
				(string, string) tuple2 = paints[i];
				row3.Options.Add(new KeyValuePair<string, string>(tuple2.Item1, tuple2.Item2));
			}
			_rows.Add(row3);
			Row row4 = new Row
			{
				Label = "Horn",
				Key = "horn"
			};
			row4.Options.Add(new KeyValuePair<string, string>("Stock", ""));
			foreach (Horns.Horn item in Horns.All)
			{
				row4.Options.Add(new KeyValuePair<string, string>(item.Label, item.Name));
			}
			row4.Options.Add(new KeyValuePair<string, string>("Bicycle Horn", "rollin_bicycle"));
			_rows.Add(row4);
			string[] partSlots = PartSlots;
			for (int i = 0; i < partSlots.Length; i++)
			{
				AddSlot(partSlots[i]);
			}
			partSlots = StageSlots;
			for (int i = 0; i < partSlots.Length; i++)
			{
				AddSlot(partSlots[i]);
			}
		}

		private static void AddSlot(string slot)
		{
			Row row = new Row
			{
				Label = Title(slot),
				Key = "part." + slot
			};
			row.Options.Add(new KeyValuePair<string, string>("Stock", ""));
			foreach (TuningPart item in Parts.All)
			{
				if (string.Equals(item.Slot, slot, StringComparison.OrdinalIgnoreCase))
				{
					row.Options.Add(new KeyValuePair<string, string>(item.Label, item.Id));
				}
			}
			if (row.Options.Count > 1)
			{
				_rows.Add(row);
			}
			else
			{
				Core.Log.Warning("[Menu] slot '" + slot + "' has no parts - no row for it.");
			}
		}

		private static string Title(string slot)
		{
			if (slot.Length != 0)
			{
				return char.ToUpperInvariant(slot[0]) + slot.Substring(1);
			}
			return slot;
		}

		private static void Draw()
		{
			//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)
			if ((Object)(object)_body == (Object)null || (Object)(object)_lv == (Object)null)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<size=130%><b>ROLLIN GARAGE</b></size>\n<color=#9AA3AD><size=80%>W/S row   A/D change   " + ((object)Key/*cast due to .constrained prefix*/).ToString() + " close   Free of charge</size></color>\n\n");
			for (int i = 0; i < _rows.Count; i++)
			{
				Row row = _rows[i];
				string text = Current(row.Key);
				int num = IndexOf(row, text);
				string value = ((num >= 0) ? row.Options[num].Key : text);
				bool flag = i == _row;
				if (i == 4 || i == 4 + PartSlotsShown())
				{
					stringBuilder.Append("<size=40%> </size>\n");
				}
				stringBuilder.Append(flag ? "<color=#FFD24A>> " : "<color=#D8DEE6>  ").Append(row.Label).Append("</color>");
				stringBuilder.Append("<pos=46%>").Append(flag ? "<color=#FFD24A>< " : "<color=#8D96A0>").Append(value)
					.Append(flag ? " ></color>" : "</color>")
					.Append('\n');
			}
			TuningStats val = ChassisApi.TuningStatsOf(_lv);
			if (val != null)
			{
				stringBuilder.Append("\n<color=#9AA3AD><size=75%>").Append(((object)val).ToString()).Append("</size></color>");
			}
			((TMP_Text)_body).text = stringBuilder.ToString();
		}

		private static int PartSlotsShown()
		{
			int num = 0;
			foreach (Row row in _rows)
			{
				string[] partSlots = PartSlots;
				foreach (string text in partSlots)
				{
					if (row.Key == "part." + text)
					{
						num++;
					}
				}
			}
			return num;
		}

		private static bool EnsureCanvas()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00a7: 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_00ad: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: 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_01c6: 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_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_canvas != (Object)null)
			{
				return true;
			}
			try
			{
				_canvas = new GameObject("RollinTuningMenu");
				Object.DontDestroyOnLoad((Object)(object)_canvas);
				Canvas obj = _canvas.AddComponent<Canvas>();
				obj.renderMode = (RenderMode)0;
				obj.sortingOrder = 400;
				CanvasScaler obj2 = _canvas.AddComponent<CanvasScaler>();
				obj2.uiScaleMode = (ScaleMode)1;
				obj2.referenceResolution = new Vector2(1920f, 1080f);
				obj2.matchWidthOrHeight = 1f;
				GameObject val = new GameObject("Panel");
				val.transform.SetParent(_canvas.transform, false);
				RectTransform obj3 = val.AddComponent<RectTransform>();
				Vector2 anchorMin = (obj3.anchorMax = new Vector2(1f, 0.5f));
				obj3.anchorMin = anchorMin;
				obj3.pivot = new Vector2(1f, 0.5f);
				obj3.anchoredPosition = new Vector2(-48f, 50f);
				obj3.sizeDelta = new Vector2(560f, 820f);
				Image obj4 = val.AddComponent<Image>();
				((Graphic)obj4).color = new Color(0.05f, 0.06f, 0.08f, 0.9f);
				((Graphic)obj4).raycastTarget = false;
				GameObject val3 = new GameObject("Accent");
				val3.transform.SetParent(val.transform, false);
				RectTransform obj5 = val3.AddComponent<RectTransform>();
				obj5.anchorMin = new Vector2(0f, 0f);
				obj5.anchorMax = new Vector2(0f, 1f);
				obj5.pivot = new Vector2(0f, 0.5f);
				obj5.sizeDelta = new Vector2(6f, 0f);
				Image obj6 = val3.AddComponent<Image>();
				((Graphic)obj6).color = new Color(1f, 0.82f, 0.29f, 1f);
				((Graphic)obj6).raycastTarget = false;
				GameObject val4 = new GameObject("Body");
				val4.transform.SetParent(val.transform, false);
				RectTransform obj7 = val4.AddComponent<RectTransform>();
				obj7.anchorMin = Vector2.zero;
				obj7.anchorMax = Vector2.one;
				obj7.offsetMin = new Vector2(30f, 22f);
				obj7.offsetMax = new Vector2(-22f, -22f);
				_body = val4.AddComponent<TextMeshProUGUI>();
				TMP_FontAsset val5 = Font();
				if ((Object)(object)val5 != (Object)null)
				{
					((TMP_Text)_body).font = val5;
				}
				else
				{
					Core.Log.Warning("[Menu] no game font found - the menu uses TextMeshPro's default.");
				}
				((TMP_Text)_body).fontSize = 21f;
				((TMP_Text)_body).richText = true;
				((TMP_Text)_body).enableWordWrapping = false;
				((TMP_Text)_body).alignment = (TextAlignmentOptions)257;
				((Graphic)_body).color = Color.white;
				((Graphic)_body).raycastTarget = false;
				_canvas.SetActive(false);
				Core.Log.Msg("[Menu] built the menu canvas, font " + (((Object)(object)val5 != (Object)null) ? ((Object)val5).name : "default") + ".");
				return true;
			}
			catch (Exception ex)
			{
				Core.Log.Error("[Menu] building the menu failed - tuning stays on the console: " + ex);
				if ((Object)(object)_canvas != (Object)null)
				{
					Object.Destroy((Object)(object)_canvas);
				}
				_canvas = null;
				_body = null;
				return false;
			}
		}

		private static TMP_FontAsset Font()
		{
			Il2CppArrayBase<TMP_FontAsset> val = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			string[] array = new string[3] { "OpenSans-SemiBold SDF", "OpenSans-Regular SDF", "LiberationSans SDF" };
			foreach (string text in array)
			{
				foreach (TMP_FontAsset item in val)
				{
					if ((Object)(object)item != (Object)null && ((Object)item).name == text)
					{
						return item;
					}
				}
			}
			if (val.Length <= 0)
			{
				return null;
			}
			return val[0];
		}

		private static void Lock(LandVehicle lv, bool on, string why)
		{
			lv.overrideControls = on;
			lv.throttleOverride = 0f;
			lv.steerOverride = 0f;
			Core.Log.Msg("[Menu] net " + Ids.Of((Component)(object)lv) + (on ? " stands still while the menu is open" : " drives again") + " (" + why + ").");
		}
	}
	internal static class Models
	{
		internal enum Anchor
		{
			Bottom,
			Top,
			Centre,
			Back,
			Front,
			BottomFront
		}

		internal enum Axis
		{
			Longest,
			Widest,
			Height
		}

		internal const string SpinLeft = "rollin_spin_L";

		internal const string SpinRight = "rollin_spin_R";

		internal const string Hat = "rollin_hat";

		internal const string SmokePoint = "rollin_smoke";

		internal const string SmokeFx = "rollin_smoke_fx";

		internal const string BlinkRed = "rollin_blink_red";

		internal const string BlinkBlue = "rollin_blink_blue";

		internal const string BlinkOn = "rollin_on";

		internal const string Pulse = "rollin_pulse";

		private static readonly string[] StockRims = new string[2] { "Wheel", "Wheel (1)" };

		private static readonly Color DarkSlate = Hex(2899535);

		private static readonly Color Steel = Hex(9807270);

		private static readonly Color PipeMetal = new Color(0.32f, 0.33f, 0.34f);

		private const float HandleY = 1.105f;

		private const float HandleX = 0.2f;

		private const float HandleFront = -0.27f;

		private const float HandleBore = 0.024f;

		private static readonly Vector3 PoleFoot = new Vector3(0f, 1.105f, -0.3f);

		private const float SeatUnderside = 0.479f;

		private const float BackPostX = 0.25f;

		private const float BackZ = -0.236f;

		private const float BackTilt = 5.5f;

		private const float BackPostFoot = 0.46f;

		private const float PipeX = 0.17f;

		private const float PipeTop = 0.454f;

		private const float PipeFront = -0.2f;

		private const float PipeLength = 0.3f;

		private const float PipeLead = -0.02f;

		private const float PipeBore = 0.04f;

		private static readonly float[] PipeHangers = new float[2] { -0.06f, -0.16f };

		private const float LightbarTop = 1.46f;

		private const float UmbrellaFoot = 1.54f;

		internal static readonly Vector3 HatSeat = new Vector3(0f, 0.5f, -0.08f);

		internal static Vector3 PipeTurn = new Vector3(0f, 180f, 0f);

		private const float TailpipeBoreRatio = 0.22222221f;

		internal const string ChassisNeon = "Chassis_Tune_neon";

		internal const string ChassisNeonLight = "Chassis_Tune_neon_light_";

		internal const string SeatNeon = "rollin_neon";

		private static readonly Dictionary<string, Material> _mats = new Dictionary<string, Material>(StringComparer.Ordinal);

		private static string _trim;

		internal static IEnumerable<TuningPart> Parts()
		{
			yield return Rims("rollin_rims_sport", "Sports Rims", 1200, "rim_sport", null);
			yield return Rims("rollin_rims_muscle", "Muscle Rims", 1600, "rim_muscle", new TuningStats
			{
				Grip = 1.1f
			});
			yield return Part("rollin_exhaust_twin", "exhaust", "Twin Tailpipes", 900, TwinExhaust, new TuningStats
			{
				EnginePitch = 0.85f
			});
			yield return Part("rollin_box", "cargo", "Moving Box", 30, delegate(Transform root)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				Transform val = Game(root, "box", new Vector3(0f, 0.479f, 0.02f), new Vector3(0f, 12f, 0f), 0.26f, Axis.Longest, Anchor.Top);
				if ((Object)(object)val == (Object)null)
				{
					Core.Log.Warning("[Models] no moving box mesh - the box cannot be opened.");
				}
				else
				{
					Cargo.AddTrigger(root, GameMeshes.Measure(root, val));
				}
			}, new TuningStats
			{
				Mass = 1.05f
			});
			yield return Part("rollin_jerrycan", "booster", "Jerry Can Rocket", 15000, JerryCanRocket, new TuningStats
			{
				Torque = 1.8f,
				Gearing = 1.8f,
				EnginePitch = 1.2f
			});
			yield return Part("rollin_wing", "spoiler", "Handle Wing", 2500, Wing, new TuningStats
			{
				Grip = 1.1f
			});
			yield return Part("rollin_lightbar", "lights", "Police Lightbar", 8000, Lightbar, null);
			yield return Part("rollin_umbrella", "roof", "Sun Umbrella", 60, delegate(Transform root)
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				Pole(root, 1.76f);
				Game(root, "umbrella", new Vector3(PoleFoot.x, 1.54f, PoleFoot.z), Vector3.zero, 0.6f, Axis.Widest, Anchor.Bottom);
			}, new TuningStats
			{
				Mass = 0.9f
			});
			yield return Part("rollin_radio", "audio", "Armrest Radio", 700, delegate(Transform root)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				Pulsing(Game(root, "radio", new Vector3(-0.29f, 0.72f, 0.15f), new Vector3(0f, -90f, 0f), 0.18f, Axis.Longest, Anchor.Bottom, null, lengthAlongZ: false, null, null, flatSideBack: false, null, ownAxes: true));
			}, null);
			yield return Part("rollin_gnome", "mascot", "Garden Gnome", 3, delegate(Transform root)
			{
				//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)
				Game(root, "gnome", new Vector3(0f, 0.52f, 0.16f), Vector3.zero, 0.24f, Axis.Height, Anchor.Bottom, null, lengthAlongZ: false, null, "Hat", flatSideBack: false, "Beard");
			}, null);
			yield return Part("rollin_hat_gnome", "hat", "Gnome Hat", 420, delegate(Transform root)
			{
				HatPiece(root, "gnome", "Hat", 0.2f, Axis.Widest, 0.02f);
			}, null);
		}

		private static TuningPart Part(string id, string slot, string label, int price, Action<Transform> build, TuningStats stats)
		{
			//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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_006b: Expected O, but got Unknown
			return new TuningPart
			{
				Id = id,
				Slot = slot,
				Label = label,
				Price = price,
				Stats = stats,
				Build = delegate(LandVehicle lv)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Expected O, but got Unknown
					_trim = ChassisApi.GetTuning(lv, "paint2");
					try
					{
						GameObject val = new GameObject("rollin_part_" + id);
						build(val.transform);
						return val;
					}
					finally
					{
						_trim = null;
					}
				},
				Fits = { ["rollin_wheelchair"] = new PartFit() }
			};
		}

		private static TuningPart Rims(string id, string label, int price, string source, TuningStats stats)
		{
			TuningPart obj = Part(id, "rims", label, price, delegate(Transform root)
			{
				//IL_000c: 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)
				Rim(root, "rollin_spin_R", source, WheelchairType.BigWheel, 0f);
				Rim(root, "rollin_spin_L", source, new Vector3(0f - WheelchairType.BigWheel.x, WheelchairType.BigWheel.y, WheelchairType.BigWheel.z), 180f);
			}, stats);
			obj.Fits["rollin_wheelchair"].Hide.AddRange(StockRims);
			return obj;
		}

		private static void Rim(Transform root, string name, string source, Vector3 at, float yaw)
		{
			//IL_0001: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: 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_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = new GameObject(name).transform;
			transform.SetParent(root, false);
			transform.localPosition = at;
			transform.localRotation = Quaternion.Euler(0f, yaw, 0f);
			Transform transform2 = new GameObject("fit").transform;
			transform2.SetParent(transform, false);
			Transform val = GameMeshes.Copy(source, transform2);
			if (!((Object)(object)val == (Object)null))
			{
				val.localRotation = Quaternion.identity;
				Bounds val2 = GameMeshes.Measure(transform2, val);
				Vector3 size = ((Bounds)(ref val2)).size;
				if (size.y < size.x && size.y < size.z)
				{
					val.localRotation = Quaternion.Euler(0f, 0f, 90f) * val.localRotation;
				}
				else if (size.z < size.x && size.z < size.y)
				{
					val.localRotation = Quaternion.Euler(0f, 90f, 0f) * val.localRotation;
				}
				val2 = GameMeshes.Measure(transform2, val);
				float num = 0.66f;
				transform2.localScale = new Vector3(0.06f / Mathf.Max(0.001f, ((Bounds)(ref val2)).size.x), num / Mathf.Max(0.001f, ((Bounds)(ref val2)).size.y), num / Mathf.Max(0.001f, ((Bounds)(ref val2)).size.z));
				val.localPosition -= ((Bounds)(ref val2)).center;
			}
		}

		private static void HatPiece(Transform root, string source, string child, float size, Axis axis, float sink)
		{
			//IL_0005: 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_0030: 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)
			Transform transform = new GameObject("rollin_hat").transform;
			transform.SetParent(root, false);
			transform.localPosition = HatSeat;
			if ((Object)(object)Game(transform, source, new Vector3(0f, 0f - sink, 0f), Vector3.zero, size, axis, Anchor.Bottom, null, lengthAlongZ: false, child) == (Object)null)
			{
				Core.Log.Warning("[Models] hat from '" + source + "' did not build.");
			}
		}

		private unsafe static void TwinExhaust(Transform root)
		{
			//IL_0000: 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_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)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing