Decompiled source of CoconutMall v1.0.0

BepInEx/patchers/SlipSkid.StripFix.dll

Decompiled 6 hours ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Preloader.Core.Patching;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SlipSkid.StripFix
{
	[PatcherPluginInfo("slipskid.stripfix", "Slip & Skid - Strip Fix", "1.0.0")]
	public class StripFixPatcher : BasePatcher
	{
		private const string UnityVersion = "2022.3.62f2";

		[TargetAssembly("UnityEngine.CoreModule.dll")]
		public void PatchCoreModule(AssemblyDefinition assembly)
		{
			TypeDefinition type = assembly.MainModule.GetType("UnityEngine.Application");
			if (type == null)
			{
				((BasePatcher)this).Log.LogWarning((object)"UnityEngine.Application not found; skipping strip fix.");
				return;
			}
			RestoreUnityVersion(assembly, type);
			RestoreLogMessageReceived(assembly, type);
		}

		private void RestoreUnityVersion(AssemblyDefinition assembly, TypeDefinition application)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_006c: 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_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_00ba: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			if (application.Methods.Any((MethodDefinition m) => ((MemberReference)m).Name == "get_unityVersion"))
			{
				((BasePatcher)this).Log.LogInfo((object)"Application.get_unityVersion already present.");
				return;
			}
			TypeReference val = assembly.MainModule.TypeSystem.String;
			MethodDefinition val2 = new MethodDefinition("get_unityVersion", (MethodAttributes)2198, val);
			ILProcessor iLProcessor = val2.Body.GetILProcessor();
			iLProcessor.Append(iLProcessor.Create(OpCodes.Ldstr, "2022.3.62f2"));
			iLProcessor.Append(iLProcessor.Create(OpCodes.Ret));
			application.Methods.Add(val2);
			application.Properties.Add(new PropertyDefinition("unityVersion", (PropertyAttributes)0, val)
			{
				GetMethod = val2
			});
			ManualLogSource log = ((BasePatcher)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(40, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Restored Application.unityVersion => \"");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>("2022.3.62f2");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("\".");
			}
			log.LogInfo(val3);
		}

		private void RestoreLogMessageReceived(AssemblyDefinition assembly, TypeDefinition application)
		{
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			if (application.Events.Any((EventDefinition e) => ((MemberReference)e).Name == "logMessageReceived"))
			{
				((BasePatcher)this).Log.LogInfo((object)"Application.logMessageReceived already present.");
				return;
			}
			FieldDefinition val = application.Fields.FirstOrDefault((FieldDefinition f) => ((MemberReference)f).Name == "s_LogCallbackHandler");
			TypeDefinition val2 = application.NestedTypes.FirstOrDefault((TypeDefinition t) => ((MemberReference)t).Name == "LogCallback");
			if (val == null || val2 == null)
			{
				((BasePatcher)this).Log.LogWarning((object)"s_LogCallbackHandler or LogCallback missing — cannot restore logMessageReceived. Game log forwarding will stay disabled.");
				return;
			}
			ModuleDefinition mainModule = assembly.MainModule;
			MethodReference combineOrRemove = mainModule.ImportReference((MethodBase)typeof(Delegate).GetMethod("Combine", new Type[2]
			{
				typeof(Delegate),
				typeof(Delegate)
			}));
			MethodReference combineOrRemove2 = mainModule.ImportReference((MethodBase)typeof(Delegate).GetMethod("Remove", new Type[2]
			{
				typeof(Delegate),
				typeof(Delegate)
			}));
			MethodDefinition val3 = BuildAccessor("add_logMessageReceived", (TypeReference)(object)val2, val, combineOrRemove, mainModule);
			MethodDefinition val4 = BuildAccessor("remove_logMessageReceived", (TypeReference)(object)val2, val, combineOrRemove2, mainModule);
			application.Methods.Add(val3);
			application.Methods.Add(val4);
			application.Events.Add(new EventDefinition("logMessageReceived", (EventAttributes)0, (TypeReference)(object)val2)
			{
				AddMethod = val3,
				RemoveMethod = val4
			});
			((BasePatcher)this).Log.LogInfo((object)"Restored Application.logMessageReceived — game Debug.Log will reach BepInEx.");
		}

		private static MethodDefinition BuildAccessor(string name, TypeReference callbackType, FieldDefinition handlerField, MethodReference combineOrRemove, ModuleDefinition module)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_002e: 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_004d: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			MethodDefinition val = new MethodDefinition(name, (MethodAttributes)2198, module.TypeSystem.Void);
			((MethodReference)val).Parameters.Add(new ParameterDefinition("value", (ParameterAttributes)0, callbackType));
			ILProcessor iLProcessor = val.Body.GetILProcessor();
			iLProcessor.Append(iLProcessor.Create(OpCodes.Ldsfld, (FieldReference)(object)handlerField));
			iLProcessor.Append(iLProcessor.Create(OpCodes.Ldarg_0));
			iLProcessor.Append(iLProcessor.Create(OpCodes.Call, combineOrRemove));
			iLProcessor.Append(iLProcessor.Create(OpCodes.Castclass, callbackType));
			iLProcessor.Append(iLProcessor.Create(OpCodes.Stsfld, (FieldReference)(object)handlerField));
			iLProcessor.Append(iLProcessor.Create(OpCodes.Ret));
			return val;
		}
	}
	internal static class CecilExtensions
	{
		public static bool Any<T>(this Collection<T> collection, Func<T, bool> predicate)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Enumerator<T> enumerator = collection.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					T current = enumerator.Current;
					if (predicate(current))
					{
						return true;
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			return false;
		}

		public static T FirstOrDefault<T>(this Collection<T> collection, Func<T, bool> predicate) where T : class
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Enumerator<T> enumerator = collection.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					T current = enumerator.Current;
					if (predicate(current))
					{
						return current;
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			return null;
		}
	}
}

BepInEx/plugins/SlipSkid.MapLoader/SlipSkid.MapLoader.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.Mono;
using CameraUtils;
using Game;
using Game.Levels;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Obstacles;
using Player;
using SlipSkid.MapSDK;
using Sounds;
using Sounds.SplitScreenAudio;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using Utils;
using Utils.Networking;
using World;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SlipSkid.MapLoader
{
	internal class BoostPadZone : MonoBehaviour
	{
		public float boostSpeed = 15f;

		private const float Cooldown = 0.5f;

		private float _lastBoostTime = -999f;

		private void OnTriggerEnter(Collider other)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time - _lastBoostTime < 0.5f)
			{
				return;
			}
			Rigidbody attachedRigidbody = other.attachedRigidbody;
			if (!((Object)(object)attachedRigidbody == (Object)null))
			{
				SphereCarController componentInParent = ((Component)attachedRigidbody).GetComponentInParent<SphereCarController>();
				if (!((Object)(object)componentInParent == (Object)null))
				{
					Vector3 val = (((Object)(object)componentInParent.car != (Object)null) ? componentInParent.car.forward : ((Component)attachedRigidbody).transform.forward);
					attachedRigidbody.AddForce(val * boostSpeed, (ForceMode)2);
					_lastBoostTime = Time.time;
				}
			}
		}
	}
	public class CustomMap
	{
		public MapManifest Manifest { get; }

		public string Directory { get; }

		public AssetBundle Bundle { get; internal set; }

		public Level Level { get; internal set; }

		public string ScenePath { get; internal set; }

		public bool Loaded
		{
			get
			{
				if ((Object)(object)Bundle != (Object)null)
				{
					return (Object)(object)Level != (Object)null;
				}
				return false;
			}
		}

		public CustomMap(MapManifest manifest, string directory)
		{
			Manifest = manifest;
			Directory = directory;
		}

		public string ResolvePath(string relative)
		{
			if (!string.IsNullOrEmpty(relative))
			{
				return Path.Combine(Directory, relative);
			}
			return null;
		}

		public override string ToString()
		{
			return Manifest.DisplayName + " (" + Manifest.Id + ")";
		}
	}
	public static class CustomMapLoader
	{
		private static readonly List<CustomMap> Maps = new List<CustomMap>();

		private static bool _discovered;

		public static IReadOnlyList<CustomMap> All => Maps;

		public static bool BundlesReady { get; private set; }

		public static string MapsDirectory => Path.GetFullPath(Path.Combine(Paths.BepInExRootPath, "CustomMaps"));

		public static bool IsCustomMap(string levelName)
		{
			if (string.IsNullOrEmpty(levelName))
			{
				return false;
			}
			foreach (CustomMap map in Maps)
			{
				if ((Object)(object)map.Level != (Object)null && string.Equals(map.Level.name, levelName, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				if (string.Equals(map.Manifest.SceneName, levelName, StringComparison.OrdinalIgnoreCase) || string.Equals(map.Manifest.DisplayName, levelName, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static List<string> FindMapFolders(string root)
		{
			List<string> found = new List<string>();
			HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			Collect(root, 2);
			Collect(Paths.PluginPath, 4);
			found.Sort(StringComparer.OrdinalIgnoreCase);
			return found;
			void Collect(string directory, int depth)
			{
				if (depth >= 0 && Directory.Exists(directory))
				{
					string[] directories = Directory.GetDirectories(directory);
					foreach (string text in directories)
					{
						if (File.Exists(Path.Combine(text, "map.json")))
						{
							string fileName = Path.GetFileName(text);
							if (seen.Add(fileName))
							{
								found.Add(text);
							}
						}
						else
						{
							Collect(text, depth - 1);
						}
					}
				}
			}
		}

		public static void Discover()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			if (_discovered)
			{
				return;
			}
			_discovered = true;
			string mapsDirectory = MapsDirectory;
			if (!Directory.Exists(mapsDirectory))
			{
				Directory.CreateDirectory(mapsDirectory);
			}
			List<string> list = FindMapFolders(mapsDirectory);
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (list.Count == 0)
			{
				ManualLogSource log = Plugin.Log;
				val = new BepInExInfoLogInterpolatedStringHandler(41, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No custom maps found. Put map folders in ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(mapsDirectory);
				}
				log.LogInfo(val);
				return;
			}
			foreach (string item in list)
			{
				string path = Path.Combine(item, "map.json");
				MapManifest mapManifest;
				try
				{
					mapManifest = JsonConvert.DeserializeObject<MapManifest>(File.ReadAllText(path));
				}
				catch (Exception ex)
				{
					ManualLogSource log2 = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(33, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Skipping '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Path.GetFileName(item));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': malformed map.json: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					log2.LogError(val2);
					continue;
				}
				if (mapManifest == null)
				{
					ManualLogSource log3 = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(39, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Skipping '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Path.GetFileName(item));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': map.json parsed to nothing");
					}
					log3.LogError(val2);
					continue;
				}
				if (!mapManifest.Validate(out var error))
				{
					ManualLogSource log4 = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(13, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Skipping '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Path.GetFileName(item));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(error);
					}
					log4.LogError(val2);
					continue;
				}
				Maps.Add(new CustomMap(mapManifest, item));
				ManualLogSource log5 = Plugin.Log;
				val = new BepInExInfoLogInterpolatedStringHandler(19, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Discovered map: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(mapManifest.DisplayName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" [");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(mapManifest.Id);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]");
				}
				log5.LogInfo(val);
			}
			ManualLogSource log6 = Plugin.Log;
			val = new BepInExInfoLogInterpolatedStringHandler(29, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Maps.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" custom map(s) discovered in ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(mapsDirectory);
			}
			log6.LogInfo(val);
		}

		public static IEnumerator LoadBundlesRoutine()
		{
			Discover();
			if (Maps.Count == 0)
			{
				BundlesReady = true;
				yield break;
			}
			bool flag = default(bool);
			foreach (CustomMap map in Maps)
			{
				if ((Object)(object)map.Bundle != (Object)null)
				{
					continue;
				}
				string bundlePath = ResolveBundlePath(map);
				if (bundlePath == null)
				{
					ManualLogSource log = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(29, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<CustomMap>(map);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': no .bundle file found in ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(map.Directory);
					}
					log.LogError(val);
					continue;
				}
				AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundlePath);
				yield return request;
				if ((Object)(object)request.assetBundle == (Object)null)
				{
					ManualLogSource log2 = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(148, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<CustomMap>(map);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': AssetBundle failed to load. Most likely built with a Unity version other than ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("2022.3.62f2, or for a different platform than StandaloneWindows64.");
					}
					log2.LogError(val);
					continue;
				}
				map.Bundle = request.assetBundle;
				ManualLogSource log3 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(23, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Bundle loaded for '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<CustomMap>(map);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' (");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Path.GetFileName(bundlePath));
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(")");
				}
				log3.LogInfo(val2);
			}
			BundlesReady = true;
		}

		public static void BuildLevels(LevelManager levelManager)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			if (Maps.Count == 0)
			{
				return;
			}
			Level val = PickTemplate(levelManager, null);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"No shipped level to use as a template; cannot register custom maps.");
				return;
			}
			bool flag = default(bool);
			foreach (CustomMap map in Maps)
			{
				if ((Object)(object)map.Level != (Object)null || (Object)(object)map.Bundle == (Object)null)
				{
					continue;
				}
				try
				{
					Level template = PickTemplate(levelManager, map.Manifest.TemplateLevel) ?? val;
					map.Level = BuildLevel(map, template);
					ManualLogSource log = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(25, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Registered '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<CustomMap>(map);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' -> scene '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(map.Manifest.SceneName);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'");
					}
					log.LogInfo(val2);
				}
				catch (Exception ex)
				{
					ManualLogSource log2 = Plugin.Log;
					BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(30, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Failed to build level for '");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<CustomMap>(map);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("': ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
					}
					log2.LogError(val3);
				}
			}
		}

		private static Level BuildLevel(CustomMap map, Level template)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			Level val = Object.Instantiate<Level>(template);
			((Object)val).hideFlags = (HideFlags)61;
			val.name = map.Manifest.DisplayName;
			((Object)val).name = map.Manifest.DisplayName;
			val.sceneName = map.Manifest.SceneName;
			val.difficulty = Mathf.Max(1, map.Manifest.Difficulty);
			LevelInGameStats inGameStats = val.inGameStats;
			inGameStats.isReversible = map.Manifest.IsReversible;
			val.inGameStats = inGameStats;
			val.ghostUnlockableContent = default(GhostUnlockableContent);
			Texture2D val2 = LoadTexture(map.ResolvePath(map.Manifest.Thumbnail));
			if ((Object)(object)val2 != (Object)null)
			{
				val.thumbnailImage = val2;
			}
			Texture2D val3 = LoadTexture(map.ResolvePath(map.Manifest.Preview));
			if ((Object)(object)val3 != (Object)null)
			{
				val.previewImage = val3;
			}
			return val;
		}

		private static string ResolveBundlePath(CustomMap map)
		{
			if (!string.IsNullOrEmpty(map.Manifest.Bundle))
			{
				string text = map.ResolvePath(map.Manifest.Bundle);
				if (!File.Exists(text))
				{
					return null;
				}
				return text;
			}
			string[] files = Directory.GetFiles(map.Directory, "*.bundle");
			if (files.Length == 0)
			{
				return null;
			}
			return files[0];
		}

		private static Level PickTemplate(LevelManager levelManager, string preferredName)
		{
			Level[] array = levelManager?.levels;
			if (array == null || array.Length == 0)
			{
				return null;
			}
			Level[] array2;
			if (!string.IsNullOrEmpty(preferredName))
			{
				array2 = array;
				foreach (Level val in array2)
				{
					if ((Object)(object)val != (Object)null && val.name == preferredName)
					{
						return val;
					}
				}
			}
			array2 = array;
			foreach (Level val2 in array2)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			return null;
		}

		private static Texture2D LoadTexture(string path)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			if (string.IsNullOrEmpty(path) || !File.Exists(path))
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
			{
				((Object)val).hideFlags = (HideFlags)61;
				return val;
			}
			Object.Destroy((Object)(object)val);
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(24, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Could not decode image: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(path);
			}
			log.LogWarning(val2);
			return null;
		}
	}
	[HarmonyPatch]
	internal static class GameLogForwarder
	{
		private static ManualLogSource _log;

		internal static void Install(Harmony harmony)
		{
			_log = Logger.CreateLogSource("Game");
			harmony.PatchAll(typeof(GameLogForwarder));
			_log.LogInfo((object)"Game log forwarding active.");
		}

		private static void Write(LogLevel level, object message)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.Log(level, message ?? "null");
				}
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(Debug), "Log", new Type[] { typeof(object) })]
		[HarmonyPostfix]
		private static void OnLog(object message)
		{
			Write((LogLevel)16, message);
		}

		[HarmonyPatch(typeof(Debug), "Log", new Type[]
		{
			typeof(object),
			typeof(Object)
		})]
		[HarmonyPostfix]
		private static void OnLogContext(object message)
		{
			Write((LogLevel)16, message);
		}

		[HarmonyPatch(typeof(Debug), "LogWarning", new Type[] { typeof(object) })]
		[HarmonyPostfix]
		private static void OnWarning(object message)
		{
			Write((LogLevel)4, message);
		}

		[HarmonyPatch(typeof(Debug), "LogWarning", new Type[]
		{
			typeof(object),
			typeof(Object)
		})]
		[HarmonyPostfix]
		private static void OnWarningContext(object message)
		{
			Write((LogLevel)4, message);
		}

		[HarmonyPatch(typeof(Debug), "LogError", new Type[] { typeof(object) })]
		[HarmonyPostfix]
		private static void OnError(object message)
		{
			Write((LogLevel)2, message);
		}

		[HarmonyPatch(typeof(Debug), "LogError", new Type[]
		{
			typeof(object),
			typeof(Object)
		})]
		[HarmonyPostfix]
		private static void OnErrorContext(object message)
		{
			Write((LogLevel)2, message);
		}

		[HarmonyPatch(typeof(Debug), "LogException", new Type[] { typeof(Exception) })]
		[HarmonyPostfix]
		private static void OnException(Exception exception)
		{
			Write((LogLevel)2, exception);
		}
	}
	internal static class LevelRigHarvester
	{
		private static GameObject _cachedRig;

		private static GameObject _cachedStartLine;

		private static GameObject _cachedFinishLine;

		private static GameObject _cachedEndGamePlatform;

		private static GameObject _cachedCheckpoint;

		public static bool HasRig => (Object)(object)_cachedRig != (Object)null;

		public static GameObject StartLinePrefab => _cachedStartLine;

		public static GameObject FinishLinePrefab => _cachedFinishLine;

		public static GameObject EndGamePlatformPrefab => _cachedEndGamePlatform;

		public static GameObject CheckpointPrefab => _cachedCheckpoint;

		public static int RoadTileLayer { get; private set; } = -1;

		public static List<LevelEnvironmentBiome> StockBiomes { get; private set; }

		public static LevelEnvironmentBiome StockRushBiome { get; private set; }

		public static Material StockFogMaterial { get; private set; }

		public static Material[] StockRoadMaterials { get; private set; }

		public static GameObject RoadPiecePrefab { get; private set; }

		public static List<GameObject> RoadPiecePrefabs { get; private set; }

		public static bool HasRoadPieces
		{
			get
			{
				if (RoadPiecePrefabs != null)
				{
					return RoadPiecePrefabs.Count > 0;
				}
				return false;
			}
		}

		public static Vector3 RoadPieceSize { get; private set; }

		public static Mesh RoadPieceMesh { get; private set; }

		public static Material BorderMaterial { get; private set; }

		public static bool HasEnvironment
		{
			get
			{
				if (StockBiomes != null)
				{
					return StockBiomes.Count > 0;
				}
				return false;
			}
		}

		public static float StockGravity { get; private set; } = 40f;

		private static void HarvestRoadPieces(Scene scene, LevelTileObject sample)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Expected O, but got Unknown
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: 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)
			//IL_0297: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Expected O, but got Unknown
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Expected O, but got Unknown
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			//IL_046c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b8: Expected O, but got Unknown
			//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)sample).transform;
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("--- Stock road tile '");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)transform).name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' structure ---");
			}
			log.LogInfo(val);
			DumpHierarchy(transform, 0);
			RoadPiecePrefab = CloneInactive(((Component)transform).gameObject, "SlipSkid_CachedRoadPiece");
			RoadPiecePrefabs = new List<GameObject>();
			HashSet<string> hashSet = new HashSet<string>();
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			Bounds bounds;
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				LevelTileObject[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<LevelTileObject>(true);
				foreach (LevelTileObject val2 in componentsInChildren)
				{
					if (RoadPiecePrefabs.Count >= 24)
					{
						break;
					}
					MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
					MeshRenderer component2 = ((Component)val2).GetComponent<MeshRenderer>();
					if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null || (Object)(object)component2 == (Object)null)
					{
						continue;
					}
					string name = ((Object)component.sharedMesh).name;
					bounds = ((Renderer)component2).bounds;
					string item = $"{name}|{((Bounds)(ref bounds)).size}";
					if (hashSet.Add(item))
					{
						GameObject val3 = CloneInactive(((Component)val2).gameObject, $"SlipSkid_RoadPiece_{RoadPiecePrefabs.Count:00}");
						if (!((Object)(object)val3 == (Object)null))
						{
							RoadPiecePrefabs.Add(val3);
						}
					}
				}
			}
			ManualLogSource log2 = Plugin.Log;
			val = new BepInExInfoLogInterpolatedStringHandler(44, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Cached ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(RoadPiecePrefabs.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" real road piece prefab(s) for reuse.");
			}
			log2.LogInfo(val);
			MeshRenderer component3 = ((Component)sample).GetComponent<MeshRenderer>();
			if ((Object)(object)component3 != (Object)null)
			{
				bounds = ((Renderer)component3).bounds;
				RoadPieceSize = ((Bounds)(ref bounds)).size;
				ManualLogSource log3 = Plugin.Log;
				val = new BepInExInfoLogInterpolatedStringHandler(73, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("REAL ROAD PIECE SIZE (world): ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(RoadPieceSize);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("-> generate path segments ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(RoadPieceSize.z, "F1");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" long and ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(RoadPieceSize.x, "F1");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" wide.");
				}
				log3.LogInfo(val);
			}
			foreach (Transform item2 in transform)
			{
				Transform val4 = item2;
				if (((Object)val4).name.IndexOf("Border", StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				MeshRenderer component4 = ((Component)val4).GetComponent<MeshRenderer>();
				if (!((Object)(object)component4 == (Object)null))
				{
					BorderMaterial = ((Renderer)component4).sharedMaterial;
					Bounds bounds2 = ((Renderer)component4).bounds;
					ManualLogSource log4 = Plugin.Log;
					val = new BepInExInfoLogInterpolatedStringHandler(39, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Border piece '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)val4).name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': material='");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)(object)BorderMaterial != (Object)null) ? ((Object)BorderMaterial).name : "none");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("worldSize=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(((Bounds)(ref bounds2)).size);
					}
					log4.LogInfo(val);
					break;
				}
			}
			MeshFilter component5 = ((Component)sample).GetComponent<MeshFilter>();
			if ((Object)(object)component5 != (Object)null && (Object)(object)component5.sharedMesh != (Object)null)
			{
				RoadPieceMesh = component5.sharedMesh;
				Bounds bounds3 = RoadPieceMesh.bounds;
				ManualLogSource log5 = Plugin.Log;
				val = new BepInExInfoLogInterpolatedStringHandler(63, 6, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Road piece mesh '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)RoadPieceMesh).name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': verts=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(RoadPieceMesh.vertexCount);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("subMeshes=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(RoadPieceMesh.subMeshCount);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" size=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(((Bounds)(ref bounds3)).size);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" center=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(((Bounds)(ref bounds3)).center);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("lossyScale=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(transform.lossyScale);
				}
				log5.LogInfo(val);
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				LevelTileObject[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<LevelTileObject>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					MeshFilter component6 = ((Component)componentsInChildren[j]).GetComponent<MeshFilter>();
					string key = (((Object)(object)component6 != (Object)null && (Object)(object)component6.sharedMesh != (Object)null) ? ((Object)component6.sharedMesh).name : "(no mesh)");
					dictionary[key] = ((!dictionary.TryGetValue(key, out var value)) ? 1 : (value + 1));
				}
			}
			List<string> list = new List<string>();
			int num = 0;
			foreach (KeyValuePair<string, int> item3 in dictionary)
			{
				if (num++ >= 12)
				{
					break;
				}
				list.Add($"{item3.Key} x{item3.Value}");
			}
			ManualLogSource log6 = Plugin.Log;
			val = new BepInExInfoLogInterpolatedStringHandler(58, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Stock level uses ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(dictionary.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" distinct road mesh(es) across ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(CountTiles(scene));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" tiles: [");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", list));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]");
			}
			log6.LogInfo(val);
		}

		private static int CountTiles(Scene scene)
		{
			int num = 0;
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				num += val.GetComponentsInChildren<LevelTileObject>(true).Length;
			}
			return num;
		}

		private static void DumpHierarchy(Transform t, int depth)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			if (depth > 3)
			{
				return;
			}
			string text = new string(' ', depth * 2);
			MeshFilter component = ((Component)t).GetComponent<MeshFilter>();
			MeshRenderer component2 = ((Component)t).GetComponent<MeshRenderer>();
			Collider component3 = ((Component)t).GetComponent<Collider>();
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(38, 6, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)t).name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("mesh=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) ? ((Object)component.sharedMesh).name : "-");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("renderer=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)(object)component2 != (Object)null) ? "yes" : "-");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("collider=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)(object)component3 != (Object)null) ? ((object)component3).GetType().Name : "-");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("localScale=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(t.localScale);
			}
			log.LogInfo(val);
			foreach (Transform item in t)
			{
				DumpHierarchy(item, depth + 1);
			}
		}

		private static void HarvestEnvironment(Scene scene)
		{
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			LevelDefinition val = null;
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				val = rootGameObjects[i].GetComponentInChildren<LevelDefinition>(true);
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No LevelDefinition in the stock level; custom maps will have no scenery.");
				return;
			}
			if (val.environmentBiomes != null && val.environmentBiomes.Count > 0)
			{
				StockBiomes = new List<LevelEnvironmentBiome>();
				foreach (LevelEnvironmentBiome environmentBiome in val.environmentBiomes)
				{
					if ((Object)(object)environmentBiome != (Object)null)
					{
						StockBiomes.Add(environmentBiome);
					}
				}
			}
			StockRushBiome = val.rushModeEnvironmentBiome;
			if ((Object)(object)val.fogPlane != (Object)null)
			{
				StockFogMaterial = ((Renderer)val.fogPlane).sharedMaterial;
			}
			List<string> list = new List<string>();
			if (StockBiomes != null)
			{
				foreach (LevelEnvironmentBiome stockBiome in StockBiomes)
				{
					list.Add(((Object)stockBiome).name + "->" + (((Object)(object)stockBiome.prefabToInstantiate != (Object)null) ? ((Object)stockBiome.prefabToInstantiate).name : "NO PREFAB"));
				}
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(56, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Harvested ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>((StockBiomes != null) ? StockBiomes.Count : 0);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" environment biome(s): ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(string.Join(", ", list));
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("]; rush=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)(object)StockRushBiome != (Object)null) ? ((Object)StockRushBiome).name : "none");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("fogMaterial=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)(object)StockFogMaterial != (Object)null) ? ((Object)StockFogMaterial).name : "none");
			}
			log.LogInfo(val2);
		}

		private static void StripLevelComponents(GameObject rig)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			int num = 0;
			num += DestroyAll<RandomPositionPlayerSpawner>(rig);
			num += DestroyAll<LevelDefinition>(rig);
			num += DestroyAll<ObstacleLevelDefinition>(rig);
			num += DestroyAll<StartLine>(rig);
			num += DestroyAll<FinishLine>(rig);
			num += DestroyAll<EndGamePlatform>(rig);
			num += DestroyAll<CheckPoint>(rig);
			num += DestroyAll<LevelTileObject>(rig);
			if (num > 0)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(52, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Stripped ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" level component(s) from the harvested rig.");
				}
				log.LogInfo(val);
			}
		}

		private static int DestroyAll<T>(GameObject root) where T : Component
		{
			T[] componentsInChildren = root.GetComponentsInChildren<T>(true);
			T[] array = componentsInChildren;
			for (int i = 0; i < array.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)array[i]);
			}
			return componentsInChildren.Length;
		}

		private static GameObject CloneInactive(GameObject source, string name)
		{
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			bool activeSelf = source.activeSelf;
			source.SetActive(false);
			GameObject obj = Object.Instantiate<GameObject>(source);
			((Object)obj).name = name;
			Object.DontDestroyOnLoad((Object)(object)obj);
			source.SetActive(activeSelf);
			return obj;
		}

		public static IEnumerator HarvestRoutine()
		{
			if ((Object)(object)_cachedRig != (Object)null)
			{
				yield break;
			}
			while ((Object)(object)LevelManager.instance == (Object)null)
			{
				yield return null;
			}
			Level[] levels = LevelManager.instance.levels;
			if (levels == null || levels.Length == 0)
			{
				Plugin.Log.LogWarning((object)"No shipped levels to harvest a camera rig from.");
				yield break;
			}
			string sceneName = null;
			Level[] array = levels;
			foreach (Level val in array)
			{
				if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(val.sceneName))
				{
					sceneName = val.sceneName;
					break;
				}
			}
			if (sceneName == null)
			{
				yield break;
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(44, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Harvesting camera rig from stock level '");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(sceneName);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'...");
			}
			log.LogInfo(val2);
			AsyncOperation load;
			try
			{
				load = SceneManager.LoadSceneAsync(sceneName, (LoadSceneMode)1);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(30, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Could not additively load '");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(sceneName);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("': ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				log2.LogError(val3);
				yield break;
			}
			if (load == null)
			{
				yield break;
			}
			while (!load.isDone)
			{
				yield return null;
			}
			Scene sceneByName = SceneManager.GetSceneByName(sceneName);
			CameraManager val4 = null;
			if (((Scene)(ref sceneByName)).IsValid())
			{
				GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
				for (int i = 0; i < rootGameObjects.Length; i++)
				{
					val4 = rootGameObjects[i].GetComponentInChildren<CameraManager>(true);
					if ((Object)(object)val4 != (Object)null)
					{
						break;
					}
				}
			}
			if ((Object)(object)val4 != (Object)null)
			{
				_cachedRig = CloneInactive(((Component)((Component)val4).transform.root).gameObject, "SlipSkid_CachedCameraRig");
				StripLevelComponents(_cachedRig);
				ManualLogSource log3 = Plugin.Log;
				val2 = new BepInExInfoLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Camera rig cached from '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(sceneName);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'.");
				}
				log3.LogInfo(val2);
			}
			else
			{
				ManualLogSource log4 = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val5 = new BepInExWarningLogInterpolatedStringHandler(29, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("No CameraManager found in '");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<string>(sceneName);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("'.");
				}
				log4.LogWarning(val5);
			}
			if (((Scene)(ref sceneByName)).IsValid())
			{
				StartLine val6 = null;
				FinishLine val7 = null;
				EndGamePlatform val8 = null;
				GravityShapeInfinitePlane val9 = null;
				CheckPoint val10 = null;
				GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
				foreach (GameObject val11 in rootGameObjects)
				{
					if ((Object)(object)val6 == (Object)null)
					{
						val6 = val11.GetComponentInChildren<StartLine>(true);
					}
					if ((Object)(object)val7 == (Object)null)
					{
						val7 = val11.GetComponentInChildren<FinishLine>(true);
					}
					if ((Object)(object)val8 == (Object)null)
					{
						val8 = val11.GetComponentInChildren<EndGamePlatform>(true);
					}
					if ((Object)(object)val10 == (Object)null)
					{
						val10 = val11.GetComponentInChildren<CheckPoint>(true);
					}
					if ((Object)(object)val9 == (Object)null)
					{
						val9 = val11.GetComponentInChildren<GravityShapeInfinitePlane>(true);
					}
				}
				if ((Object)(object)val9 != (Object)null)
				{
					StockGravity = val9.gravity;
					ManualLogSource log5 = Plugin.Log;
					val2 = new BepInExInfoLogInterpolatedStringHandler(24, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Stock gravity sampled: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(StockGravity);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
					}
					log5.LogInfo(val2);
				}
				rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
				for (int i = 0; i < rootGameObjects.Length; i++)
				{
					LevelTileObject componentInChildren = rootGameObjects[i].GetComponentInChildren<LevelTileObject>(true);
					if ((Object)(object)componentInChildren == (Object)null)
					{
						continue;
					}
					Collider componentInChildren2 = ((Component)componentInChildren).GetComponentInChildren<Collider>(true);
					int layer = ((Component)componentInChildren).gameObject.layer;
					RoadTileLayer = (((Object)(object)componentInChildren2 != (Object)null) ? ((Component)componentInChildren2).gameObject.layer : layer);
					MeshRenderer component = ((Component)componentInChildren).GetComponent<MeshRenderer>();
					if ((Object)(object)component != (Object)null)
					{
						StockRoadMaterials = ((Renderer)component).sharedMaterials;
						List<string> list = new List<string>();
						Material[] stockRoadMaterials = StockRoadMaterials;
						foreach (Material val12 in stockRoadMaterials)
						{
							list.Add(((Object)(object)val12 != (Object)null) ? ((Object)val12).name : "null");
						}
						ManualLogSource log6 = Plugin.Log;
						val2 = new BepInExInfoLogInterpolatedStringHandler(27, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Stock tile materials (");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(StockRoadMaterials.Length);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("): [");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(string.Join(", ", list));
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("]");
						}
						log6.LogInfo(val2);
					}
					HarvestRoadPieces(sceneByName, componentInChildren);
					ManualLogSource log7 = Plugin.Log;
					val2 = new BepInExInfoLogInterpolatedStringHandler(111, 5, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Stock road: LevelTileObject layer ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(layer);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ('");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(LayerMask.LayerToName(layer));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'), ");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("collider layer ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(RoadTileLayer);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ('");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(LayerMask.LayerToName(RoadTileLayer));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("') ");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("on '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)(object)componentInChildren2 != (Object)null) ? ((Object)componentInChildren2).name : "no collider");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' — custom tiles will use the collider layer.");
					}
					log7.LogInfo(val2);
					break;
				}
				if (RoadTileLayer < 0)
				{
					Plugin.Log.LogWarning((object)"Could not sample the stock road layer; custom tiles stay on Default and the car's floor raycast may not see them.");
				}
				HarvestEnvironment(sceneByName);
				if ((Object)(object)val6 != (Object)null)
				{
					_cachedStartLine = CloneInactive(((Component)val6).gameObject, "SlipSkid_CachedStartLine");
				}
				if ((Object)(object)val7 != (Object)null)
				{
					_cachedFinishLine = CloneInactive(((Component)val7).gameObject, "SlipSkid_CachedFinishLine");
				}
				if ((Object)(object)val8 != (Object)null)
				{
					_cachedEndGamePlatform = CloneInactive(((Component)val8).gameObject, "SlipSkid_CachedEndGamePlatform");
				}
				if ((Object)(object)val10 != (Object)null)
				{
					_cachedCheckpoint = CloneInactive(((Component)val10).gameObject, "SlipSkid_CachedCheckpoint");
				}
				ManualLogSource log8 = Plugin.Log;
				val2 = new BepInExInfoLogInterpolatedStringHandler(64, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Cached level pieces — startLine:");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>((Object)(object)_cachedStartLine != (Object)null);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("finishLine:");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>((Object)(object)_cachedFinishLine != (Object)null);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" podium:");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>((Object)(object)_cachedEndGamePlatform != (Object)null);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("checkpoint:");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>((Object)(object)_cachedCheckpoint != (Object)null);
				}
				log8.LogInfo(val2);
			}
			AsyncOperation unload = SceneManager.UnloadSceneAsync(sceneByName);
			if (unload != null)
			{
				while (!unload.isDone)
				{
					yield return null;
				}
			}
			Plugin.Log.LogInfo((object)"Stock level unloaded; rig harvest complete.");
		}

		public static void EnsurePresent()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)CameraManager.instance != (Object)null))
			{
				if ((Object)(object)_cachedRig == (Object)null)
				{
					Plugin.Log.LogError((object)"No camera rig cached and none in the scene — the level will fail to initialise (CameraManager.SetGlobalVolume null-refs).");
					return;
				}
				GameObject obj = Object.Instantiate<GameObject>(_cachedRig);
				((Object)obj).name = "SlipSkid_CameraRig";
				obj.SetActive(true);
				SceneManager.MoveGameObjectToScene(obj, SceneManager.GetActiveScene());
				Plugin.Log.LogInfo((object)"Camera rig instantiated into custom map.");
			}
		}
	}
	internal static class MapBuilder
	{
		private static Material _fogMaterial;

		internal static readonly HashSet<string> SwappableMaterialNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static int _shadersRebound;

		private static int _shadersUnresolved;

		private static int _surfaceSkinned;

		private static int _stockPiecesPlaced;

		private static int _loggedFlags;

		private static Shader _fallbackShader;

		private const string RoadCombinedLayerName = "RoadCombined";

		private const string GeneratedCollisionName = "SlipSkid_GeneratedCollision";

		private const string CheckpointLayerName = "CheckPoint";

		private static Shader FallbackShader
		{
			get
			{
				if ((Object)(object)_fallbackShader != (Object)null)
				{
					return _fallbackShader;
				}
				_fallbackShader = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Universal Render Pipeline/Simple Lit") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Standard");
				if ((Object)(object)_fallbackShader == (Object)null)
				{
					Plugin.Log.LogError((object)"No usable fallback shader found — imported models will be invisible.");
				}
				return _fallbackShader;
			}
		}

		internal static bool SuppressStockMusic { get; private set; }

		public static bool TryBuild()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Expected O, but got Unknown
			MapRoot val = Object.FindObjectOfType<MapRoot>();
			if ((Object)(object)val == (Object)null)
			{
				SwappableMaterialNames.Clear();
				Scene activeScene = SceneManager.GetActiveScene();
				GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
				for (int i = 0; i < rootGameObjects.Length; i++)
				{
					if (!((Object)(object)rootGameObjects[i].GetComponentInChildren<MeshRenderer>(true) == (Object)null))
					{
						Plugin.Log.LogWarning((object)("Scene '" + ((Scene)(ref activeScene)).name + "' has geometry but no MapRoot. If this is a custom map, its marker scripts failed to resolve — check that SlipSkid.MapSDK.dll sits next to SlipSkid.MapLoader.dll and that the bundle was built against the same version."));
						break;
					}
				}
				return false;
			}
			if ((Object)(object)Object.FindObjectOfType<LevelDefinition>() != (Object)null)
			{
				Plugin.Log.LogInfo((object)"Custom map already has a LevelDefinition; skipping build.");
				return true;
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(42, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Building custom map '");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(val.mapName);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' from SDK markers...");
			}
			log.LogInfo(val2);
			SwappableMaterialNames.Clear();
			LevelRigHarvester.EnsurePresent();
			GameObject gameObject = ((Component)val).gameObject;
			LevelDefinition val3 = gameObject.AddComponent<LevelDefinition>();
			Surface val4 = ResolveSurface(val.defaultSurfaceIndex);
			if ((Object)(object)val4 == (Object)null)
			{
				Plugin.Log.LogError((object)"No Surface available from SurfaceManager; cannot build map.");
				return false;
			}
			BuildTiles(val, val4, val3);
			BuildCollisionMeshes(val);
			BuildBoostPads(val);
			BuildMusic(val);
			BuildLighting(gameObject, val3);
			BuildEnvironment(gameObject, val3, val4);
			BuildStartFinish(val, val3);
			BuildEndGamePlatform(val, val3);
			BuildSpawner(val);
			BuildGravity(val);
			BuildCheckpoints(val, val3);
			val3.surfaceToIgnoreDuringCount = (Surface[])(object)new Surface[0];
			val3.defaultSurfaceTileCount = val4;
			BuildObstacleLevelDefinition(gameObject);
			ManualLogSource log2 = Plugin.Log;
			val2 = new BepInExInfoLogInterpolatedStringHandler(39, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Custom map built: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(val3.tiles.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" tiles, ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(val3.checkpoints.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" checkpoints.");
			}
			log2.LogInfo(val2);
			ValidateMap(val3);
			ReportCollision(val);
			return true;
		}

		private static void ReportCollision(MapRoot root)
		{
			int num = LayerMask.NameToLayer("RoadCombined");
			int num2 = 0;
			int num3 = 0;
			Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!val.isTrigger && val.enabled && ((Component)val).gameObject.activeInHierarchy)
				{
					if (((Component)val).gameObject.layer == num)
					{
						num2++;
					}
					else
					{
						num3++;
					}
				}
			}
			if (num2 == 0)
			{
				Plugin.Log.LogError((object)"No collider on the 'RoadCombined' layer — the car will fall through this map. Every collidable mesh needs a MapCollisionMesh child.");
			}
			if (num3 == 0)
			{
				Plugin.Log.LogWarning((object)"No colliders off the RoadCombined layer — the car's floor raycast has nothing to hit, so it will never count as grounded.");
			}
		}

		private static void ValidateMap(LevelDefinition def)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (def.tiles.Count == 0)
			{
				Plugin.Log.LogError((object)"Map has no road tiles — add MapRoadTile components to your track.");
				return;
			}
			RandomPositionPlayerSpawner spawner = GameManager.Spawner;
			if ((Object)(object)spawner == (Object)null || spawner.SpawnCount == 0)
			{
				Plugin.Log.LogError((object)"Map has no spawn points — add a MapSpawnPoints marker.");
				return;
			}
			Transform spawnPoint = spawner.GetSpawnPoint(0);
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(spawnPoint.position + Vector3.up * 5f, Vector3.down, ref val, 200f, -1, (QueryTriggerInteraction)1))
			{
				Plugin.Log.LogError((object)($"No track under the first spawn point ({spawnPoint.position}) — the car will fall. " + "Move the MapSpawnPoints marker onto the road."));
			}
		}

		private static void BuildObstacleLevelDefinition(GameObject parent)
		{
			if (!((Object)(object)Object.FindObjectOfType<ObstacleLevelDefinition>() != (Object)null))
			{
				ObstacleLevelDefinition component = parent.GetComponent<ObstacleLevelDefinition>();
				(((Object)(object)component != (Object)null) ? component : parent.AddComponent<ObstacleLevelDefinition>()).forbiddenObstacleZones = (BoxCollider[])(object)new BoxCollider[0];
				Plugin.Log.LogInfo((object)"Added ObstacleLevelDefinition (required by ObstacleManager.InitLevel).");
			}
		}

		private static Surface ResolveSurface(int index)
		{
			Surface[] array = SurfaceManager.Surfaces;
			if (array == null || array.Length == 0)
			{
				SurfaceManager val = Object.FindObjectOfType<SurfaceManager>();
				array = (((Object)(object)val != (Object)null) ? val.surfaces : null);
			}
			if (array == null || array.Length == 0)
			{
				return null;
			}
			if (index < 0 || index >= array.Length)
			{
				index = 0;
			}
			return array[index];
		}

		private static void BuildTiles(MapRoot root, Surface defaultSurface, LevelDefinition def)
		{
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Expected O, but got Unknown
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			MapRoadTile[] componentsInChildren = ((Component)root).GetComponentsInChildren<MapRoadTile>(true);
			def.tiles = new List<LevelTileObject>();
			int num = 0;
			_shadersRebound = 0;
			_shadersUnresolved = 0;
			_surfaceSkinned = 0;
			_stockPiecesPlaced = 0;
			_loggedFlags = 0;
			MapRoadTile[] array = componentsInChildren;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2;
			foreach (MapRoadTile val in array)
			{
				Surface surface = ((val.surfaceIndex >= 0) ? (ResolveSurface(val.surfaceIndex) ?? defaultSurface) : defaultSurface);
				if (_loggedFlags < 3)
				{
					ManualLogSource log = Plugin.Log;
					val2 = new BepInExInfoLogInterpolatedStringHandler(51, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Tile '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)val).name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': useStockRoadPiece=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(val.useStockRoadPiece);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("useGameSurfaceMaterial=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(val.useGameSurfaceMaterial);
					}
					log.LogInfo(val2);
					_loggedFlags++;
				}
				if (val.useStockRoadPiece && LevelRigHarvester.HasRoadPieces && PlaceStockRoadPiece(val, def, surface))
				{
					continue;
				}
				Collider[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<Collider>(true);
				if (componentsInChildren2.Length == 0)
				{
					num++;
					continue;
				}
				Collider[] array2 = componentsInChildren2;
				foreach (Collider val3 in array2)
				{
					if (!val3.isTrigger && !((Object)(object)((Component)val3).GetComponentInParent<MapRoadBorder>() != (Object)null) && !((Object)(object)((Component)val3).GetComponent<MapCollisionMesh>() != (Object)null))
					{
						GameObject gameObject = ((Component)val3).gameObject;
						if (LevelRigHarvester.RoadTileLayer >= 0)
						{
							gameObject.layer = LevelRigHarvester.RoadTileLayer;
						}
						(gameObject.GetComponent<SurfaceInfo>() ?? gameObject.AddComponent<SurfaceInfo>()).surface = surface;
						if (val.useGameSurfaceMaterial)
						{
							ApplySurfaceMaterial(gameObject, surface);
						}
						else
						{
							RebindShaders(gameObject);
						}
						RegisterSwappableMaterials(gameObject);
						LevelTileObject val4 = gameObject.GetComponent<LevelTileObject>() ?? gameObject.AddComponent<LevelTileObject>();
						val4.id = MakeGuid(val, gameObject);
						MeshFilter component = gameObject.GetComponent<MeshFilter>();
						if ((Object)(object)component != (Object)null)
						{
							val4.nonBatchedMesh = component.sharedMesh;
						}
						ForceStart((MonoBehaviour)(object)val4);
						def.tiles.Add(val4);
					}
				}
			}
			if (num > 0)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val5 = new BepInExWarningLogInterpolatedStringHandler(80, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" MapRoadTile(s) had no collider and were skipped — cars would fall through them.");
				}
				log2.LogWarning(val5);
			}
			SkinBorders(root);
			RebindAllImportedShaders(root);
			ManualLogSource log3 = Plugin.Log;
			val2 = new BepInExInfoLogInterpolatedStringHandler(58, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Surface swap: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(SwappableMaterialNames.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" material name(s) registered as repaintable.");
			}
			log3.LogInfo(val2);
			ManualLogSource log4 = Plugin.Log;
			val2 = new BepInExInfoLogInterpolatedStringHandler(135, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Road: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_stockPiecesPlaced);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" real shipped piece(s) placed; ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_surfaceSkinned);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" renderer(s) given the game's surface material; ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_shadersRebound);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" authored material(s) shader-rebound, ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_shadersUnresolved);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" unresolved.");
			}
			log4.LogInfo(val2);
		}

		private static void RegisterSwappableMaterials(GameObject host)
		{
			MeshRenderer component = host.GetComponent<MeshRenderer>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Material[] sharedMaterials = ((Renderer)component).sharedMaterials;
			foreach (Material val in sharedMaterials)
			{
				if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name))
				{
					SwappableMaterialNames.Add(((Object)val).name);
				}
			}
		}

		private static SerializableGuid MakeGuid(MapRoadTile marker, GameObject host)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			string text = (string.IsNullOrEmpty(marker.tileGuid) ? BuildPath(((Component)marker).transform) : marker.tileGuid);
			if ((Object)(object)host != (Object)(object)((Component)marker).gameObject)
			{
				text = text + "/" + BuildPath(host.transform);
			}
			return new SerializableGuid(DeterministicGuid(text));
		}

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

		private static void RebindAllImportedShaders(MapRoot root)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Expected O, but got Unknown
			//IL_00c2: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			int num2 = 0;
			List<MeshRenderer> list = new List<MeshRenderer>();
			Scene scene = ((Component)root).gameObject.scene;
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				list.AddRange(val.GetComponentsInChildren<MeshRenderer>(true));
			}
			foreach (MeshRenderer item in list)
			{
				Material[] materials = ((Renderer)item).materials;
				bool flag = false;
				foreach (Material val2 in materials)
				{
					if ((Object)(object)val2 == (Object)null || (Object)(object)val2.shader == (Object)null)
					{
						continue;
					}
					if ((Object)(object)Shader.Find(((Object)val2.shader).name) != (Object)null)
					{
						num2++;
						continue;
					}
					Texture val3 = FirstTexture(val2);
					Color val4 = FirstColor(val2);
					Shader fallbackShader = FallbackShader;
					if ((Object)(object)fallbackShader == (Object)null)
					{
						continue;
					}
					val2.shader = fallbackShader;
					if ((Object)(object)val3 != (Object)null)
					{
						if (val2.HasProperty("_BaseMap"))
						{
							val2.SetTexture("_BaseMap", val3);
						}
						if (val2.HasProperty("_MainTex"))
						{
							val2.SetTexture("_MainTex", val3);
						}
					}
					if (((Color)(ref val4)).maxColorComponent < 0.05f)
					{
						val4 = Color.white;
					}
					if (val2.HasProperty("_BaseColor"))
					{
						val2.SetColor("_BaseColor", val4);
					}
					if (val2.HasProperty("_Color"))
					{
						val2.SetColor("_Color", val4);
					}
					flag = true;
					num++;
				}
				if (flag)
				{
					((Renderer)item).materials = materials;
				}
			}
			if (num > 0)
			{
				ManualLogSource log = Plugin.Log;
				bool flag2 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val5 = new BepInExInfoLogInterpolatedStringHandler(62, 3, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("Imported shaders: ");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" material(s) remapped to '");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<string>(((Object)FallbackShader).name);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("', ");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(num2);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" already valid.");
				}
				log.LogInfo(val5);
			}
		}

		private static Texture FirstTexture(Material mat)
		{
			string[] array = new string[5] { "_BaseMap", "_MainTex", "baseColorTexture", "_BaseColorTexture", "_albedoTexture" };
			foreach (string text in array)
			{
				if (mat.HasProperty(text))
				{
					Texture texture = mat.GetTexture(text);
					if ((Object)(object)texture != (Object)null)
					{
						return texture;
					}
				}
			}
			return null;
		}

		private static Color FirstColor(Material mat)
		{
			//IL_004a: 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)
			string[] array = new string[4] { "_BaseColor", "_Color", "baseColorFactor", "_BaseColorFactor" };
			foreach (string text in array)
			{
				if (mat.HasProperty(text))
				{
					return mat.GetColor(text);
				}
			}
			return Color.white;
		}

		private static bool PlaceStockRoadPiece(MapRoadTile marker, LevelDefinition def, Surface surface)
		{
			//IL_004c: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = LevelRigHarvester.RoadPiecePrefabs[0];
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val);
			((Object)val2).name = "StockRoadPiece_" + ((Object)marker).name;
			val2.transform.SetParent(((Component)marker).transform, false);
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.identity;
			MeshRenderer component = ((Component)marker).GetComponent<MeshRenderer>();
			float num;
			Bounds bounds;
			if (!((Object)(object)component != (Object)null))
			{
				num = 0f;
			}
			else
			{
				bounds = ((Renderer)component).bounds;
				num = ((Bounds)(ref bounds)).size.z;
			}
			float num2 = num;
			MeshRenderer componentInChildren = val2.GetComponentInChildren<MeshRenderer>(true);
			if ((Object)(object)componentInChildren != (Object)null && num2 > 0.01f)
			{
				bounds = ((Renderer)componentInChildren).bounds;
				float z = ((Bounds)(ref bounds)).size.z;
				if (z > 0.01f)
				{
					Vector3 localScale = val2.transform.localScale;
					localScale.z *= num2 / z;
					val2.transform.localScale = localScale;
				}
			}
			MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer obj in componentsInChildren)
			{
				((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
				((Renderer)obj).receiveShadows = true;
			}
			val2.SetActive(true);
			componentsInChildren = ((Component)marker).GetComponents<MeshRenderer>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Renderer)componentsInChildren[i]).enabled = false;
			}
			Collider[] componentsInChildren2 = val2.GetComponentsInChildren<Collider>(true);
			foreach (Collider val3 in componentsInChildren2)
			{
				if (!val3.isTrigger && !((Object)(object)((Component)val3).GetComponentInParent<MapRoadBorder>() != (Object)null))
				{
					GameObject gameObject = ((Component)val3).gameObject;
					if (LevelRigHarvester.RoadTileLayer >= 0)
					{
						gameObject.layer = LevelRigHarvester.RoadTileLayer;
					}
					(gameObject.GetComponent<SurfaceInfo>() ?? gameObject.AddComponent<SurfaceInfo>()).surface = surface;
					LevelTileObject val4 = gameObject.GetComponent<LevelTileObject>() ?? gameObject.AddComponent<LevelTileObject>();
					val4.id = MakeGuid(marker, gameObject);
					MeshFilter component2 = gameObject.GetComponent<MeshFilter>();
					if ((Object)(object)component2 != (Object)null)
					{
						val4.nonBatchedMesh = component2.sharedMesh;
					}
					ForceStart((MonoBehaviour)(object)val4);
					def.tiles.Add(val4);
				}
			}
			_stockPiecesPlaced++;
			return true;
		}

		private static void SkinBorders(MapRoot root)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			MapRoadBorder[] componentsInChildren = ((Component)root).GetComponentsInChildren<MapRoadBorder>(true);
			if (componentsInChildren.Length == 0)
			{
				return;
			}
			Material borderMaterial = LevelRigHarvester.BorderMaterial;
			int num = 0;
			MapRoadBorder[] array = componentsInChildren;
			for (int i = 0; i < array.Length; i++)
			{
				MeshRenderer[] componentsInChildren2 = ((Component)array[i]).GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val in componentsInChildren2)
				{
					if ((Object)(object)borderMaterial != (Object)null)
					{
						Material[] materials = ((Renderer)val).materials;
						for (int k = 0; k < materials.Length; k++)
						{
							materials[k] = borderMaterial;
						}
						((Renderer)val).materials = materials;
					}
					else
					{
						RebindShaders(((Component)val).gameObject);
					}
					if (LevelRigHarvester.RoadTileLayer >= 0)
					{
						((Component)val).gameObject.layer = LevelRigHarvester.RoadTileLayer;
					}
					num++;
				}
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(38, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Borders: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" renderer(s) skinned with ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)(object)borderMaterial != (Object)null) ? ((Object)borderMaterial).name : "authored material");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'.");
			}
			log.LogInfo(val2);
		}

		private static void ApplySurfaceMaterial(GameObject host, Surface surface)
		{
			Material val = (((Object)(object)surface != (Object)null && surface.effects != null) ? surface.effects.material : null);
			if ((Object)(object)val == (Object)null)
			{
				RebindShaders(host);
				return;
			}
			Material[] stockRoadMaterials = LevelRigHarvester.StockRoadMaterials;
			MeshRenderer[] components = host.GetComponents<MeshRenderer>();
			foreach (MeshRenderer val2 in components)
			{
				Material[] sharedMaterials = ((Renderer)val2).sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (j == 0 || stockRoadMaterials == null || j >= stockRoadMaterials.Length)
					{
						sharedMaterials[j] = val;
					}
					else
					{
						sharedMaterials[j] = stockRoadMaterials[j] ?? val;
					}
				}
				((Renderer)val2).materials = sharedMaterials;
				_surfaceSkinned++;
			}
		}

		private static void RebindShaders(GameObject host)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer[] components = host.GetComponents<MeshRenderer>();
			foreach (MeshRenderer val in components)
			{
				Material[] materials = ((Renderer)val).materials;
				Material[] array = materials;
				foreach (Material val2 in array)
				{
					if ((Object)(object)val2 == (Object)null || (Object)(object)val2.shader == (Object)null)
					{
						continue;
					}
					Shader val3 = Shader.Find(((Object)val2.shader).name);
					if ((Object)(object)val3 == (Object)null)
					{
						val3 = FallbackShader;
						if ((Object)(object)val3 == (Object)null)
						{
							_shadersUnresolved++;
							continue;
						}
						Texture val4 = FirstTexture(val2);
						Color val5 = FirstColor(val2);
						val2.shader = val3;
						if ((Object)(object)val4 != (Object)null)
						{
							if (val2.HasProperty("_BaseMap"))
							{
								val2.SetTexture("_BaseMap", val4);
							}
							if (val2.HasProperty("_MainTex"))
							{
								val2.SetTexture("_MainTex", val4);
							}
						}
						if (val2.HasProperty("_BaseColor"))
						{
							val2.SetColor("_BaseColor", val5);
						}
						if (val2.HasProperty("_Color"))
						{
							val2.SetColor("_Color", val5);
						}
						_shadersRebound++;
					}
					else if (!((Object)(object)val3 == (Object)(object)val2.shader))
					{
						val2.shader = val3;
						_shadersRebound++;
					}
				}
				((Renderer)val).materials = materials;
			}
		}

		private static void ForceStart(MonoBehaviour behaviour)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			MethodInfo method = ((object)behaviour).GetType().GetMethod("Start", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return;
			}
			try
			{
				method.Invoke(behaviour, null);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(28, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Forcing Start() on ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((object)behaviour).GetType().Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
		}

		private static Guid DeterministicGuid(string seed)
		{
			using MD5 mD = MD5.Create();
			return new Guid(mD.ComputeHash(Encoding.UTF8.GetBytes(seed)));
		}

		private static void BuildLighting(GameObject parent, LevelDefinition def)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			LevelLighting componentInChildren = parent.GetComponentInChildren<LevelLighting>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				def.levelLighting = componentInChildren;
				return;
			}
			Light[] array = Object.FindObjectsOfType<Light>();
			List<Light> list = new List<Light>();
			Light[] array2 = array;
			foreach (Light val in array2)
			{
				if ((Object)(object)val != (Object)null && (int)val.type == 1)
				{
					list.Add(val);
				}
			}
			GameObject val2 = new GameObject("LevelLighting");
			val2.transform.SetParent(parent.transform, false);
			LevelLighting val3 = val2.AddComponent<LevelLighting>();
			if (list.Count >= 3)
			{
				val3.mainLight = list[0];
				val3.secondaryLight = list[1];
				val3.thirdLight = list[2];
			}
			else
			{
				Plugin.Log.LogWarning((object)($"Map authored {list.Count} directional light(s); 3 are required. " + "Falling back to generated lights — these cannot be made directional because Light.type is stripped from this build, so lighting will look wrong."));
				val3.mainLight = FallbackLight(val2.transform, "MainLight", list, 0);
				val3.secondaryLight = FallbackLight(val2.transform, "SecondaryLight", list, 1);
				val3.thirdLight = FallbackLight(val2.transform, "ThirdLight", list, 2);
			}
			def.levelLighting = val3;
		}

		private static Light FallbackLight(Transform parent, string name, List<Light> authored, int index)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (index < authored.Count)
			{
				return authored[index];
			}
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			return val.AddComponent<Light>();
		}

		private static void BuildEnvironment(GameObject parent, LevelDefinition def, Surface surface)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			GameObject val = new GameObject("EnvironmentVisualRoot");
			val.transform.SetParent(parent.transform, false);
			def.environmentVisualRoot = val.transform;
			def.fogPlane = BuildFogPlane(parent.transform);
			if (LevelRigHarvester.HasEnvironment)
			{
				LevelEnvironmentBiome val2 = ResolveForcedBiome(parent, surface);
				def.environmentBiomes = (((Object)(object)val2 != (Object)null) ? new List<LevelEnvironmentBiome> { val2 } : new List<LevelEnvironmentBiome>(LevelRigHarvester.StockBiomes));
				def.rushModeEnvironmentBiome = LevelRigHarvester.StockRushBiome ?? MakeBiome(surface, rush: true);
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(48, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Using ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(def.environmentBiomes.Count);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" shipped environment biome(s) for scenery.");
				}
				log.LogInfo(val3);
			}
			else
			{
				Plugin.Log.LogWarning((object)"No shipped biomes harvested — falling back to empty scenery. The map will render against a bare background.");
				def.environmentBiomes = new List<LevelEnvironmentBiome> { MakeBiome(surface, rush: false) };
				def.rushModeEnvironmentBiome = MakeBiome(surface, rush: true);
			}
		}

		private static LevelEnvironmentBiome ResolveForcedBiome(GameObject parent, Surface surface)
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			MapRoot component = parent.GetComponent<MapRoot>();
			string text = (((Object)(object)component != (Object)null) ? component.forceEnvironmentBiome : null);
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			LevelEnvironmentBiome val = null;
			foreach (LevelEnvironmentBiome stockBiome in LevelRigHarvester.StockBiomes)
			{
				if (!((Object)(object)stockBiome == (Object)null) && ((Object)stockBiome).name != null && ((Object)stockBiome).name.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					val = stockBiome;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				List<string> list = new List<string>();
				foreach (LevelEnvironmentBiome stockBiome2 in LevelRigHarvester.StockBiomes)
				{
					if ((Object)(object)stockBiome2 != (Object)null)
					{
						list.Add(((Object)stockBiome2).name);
					}
				}
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(100, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("forceEnvironmentBiome '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' matched no shipped biome. ");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Available: [");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(string.Join(", ", list));
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("]. Falling back to automatic scenery.");
				}
				log.LogWarning(val2);
				return null;
			}
			LevelEnvironmentBiome val3 = Object.Instantiate<LevelEnvironmentBiome>(val);
			((Object)val3).name = ((Object)val).name + " (forced)";
			val3.matchingSurface = surface;
			Plugin.Log.LogInfo((object)("Forcing scenery to '" + ((Object)val).name + "' on surface '" + ((Object)surface).name + "' (handling unchanged)."));
			return val3;
		}

		private static MeshRenderer BuildFogPlane(Transform parent)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5);
			((Object)obj).name = "FogPlane";
			obj.transform.SetParent(parent, false);
			obj.transform.localPosition = new Vector3(0f, -60f, 0f);
			obj.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
			obj.transform.localScale = Vector3.one * 2000f;
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
			Material stockFogMaterial = LevelRigHarvester.StockFogMaterial;
			if ((Object)(object)stockFogMaterial != (Object)null)
			{
				((Renderer)component2).sharedMaterial = stockFogMaterial;
				((Renderer)component2).enabled = true;
			}
			else
			{
				((Renderer)component2).enabled = false;
			}
			return component2;
		}

		private static LevelEnvironmentBiome MakeBiome(Surface surface, bool rush)
		{
			//IL_003e: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_00bb: Expected O, but got Unknown
			LevelEnvironmentBiome val = ScriptableObject.CreateInstance<LevelEnvironmentBiome>();
			((Object)val).hideFlags = (HideFlags)61;
			val.matchingSurface = surface;
			val.fogColor = (rush ? new Color(0.85f, 0.35f, 0.45f) : new Color(0.45f, 0.55f, 0.85f));
			val.fogStartDistance = 120f;
			val.fogEndDistance = 700f;
			val.fogPlaneMaterial = GetFogMaterial();
			GameObject val2 = new GameObject(rush ? "RushBiomeVisuals" : "BiomeVisuals");
			val2.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val2);
			if (rush)
			{
				RushModeEnvironmentBiome val3 = val2.AddComponent<RushModeEnvironmentBiome>();
				val3.subEnvironmentBiomes = (SubEnvironmentBiomes[])(object)new SubEnvironmentBiomes[1]
				{
					new SubEnvironmentBiomes
					{
						surface = surface,
						gameObject = new GameObject("SubBiome")
					}
				};
				val3.subEnvironmentBiomes[0].gameObject.transform.SetParent(val2.transform, false);
			}
			val.prefabToInstantiate = val2;
			return val;
		}

		private static Material GetFogMaterial()
		{
			//IL_002b: 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_003d: Expected O, but got Unknown
			if ((Object)(object)_fogMaterial != (Object)null)
			{
				return _fogMaterial;
			}
			_fogMaterial = new Material(Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Unlit/Color"))
			{
				hideFlags = (HideFlags)61
			};
			return _fogMaterial;
		}

		private static void BuildStartFinish(MapRoot root, LevelDefinition def)
		{
			MapStartLine componentInChildren = ((Component)root).GetComponentInChildren<MapStartLine>(true);
			MapFinishLine componentInChildren2 = ((Component)root).GetComponentInChildren<MapFinishLine>(true);
			def.startLine = PlaceCloned<StartLine>(LevelRigHarvester.StartLinePrefab, ((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).transform : ((Component)root).transform, ((Component)root).transform, "StartLine");
			def.finishLine = PlaceCloned<FinishLine>(LevelRigHarvester.FinishLinePrefab, ((Object)(object)componentInChildren2 != (Object)null) ? ((Component)componentInChildren2).transform : ((Component)root).transform, ((Component)root).transform, "FinishLine");
			if ((Object)(object)def.startLine == (Object)null || (Object)(object)def.finishLine == (Object)null)
			{
				Plugin.Log.LogError((object)"Start or finish line could not be cloned from a shipped level — the level will not initialise correctly.");
			}
		}

		private static T PlaceCloned<T>(GameObject prefab, Transform at, Transform parent, string name) where T : Component
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			if ((Object)(object)prefab == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(32, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No cached prefab available for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogError(val);
				return default(T);
			}
			GameObject obj = Object.Instantiate<GameObject>(prefab);
			((Object)obj).name = name;
			obj.transform.SetParent(parent, false);
			obj.transform.position = at.position;
			obj.transform.rotation = at.rotation;
			obj.SetActive(true);
			return obj.GetComponentInChildren<T>(true);
		}

		private static void BuildEndGamePlatform(MapRoot root, LevelDefinition def)
		{
			MapEndGamePlatform componentInChildren = ((Component)root).GetComponentInChildren<MapEndGamePlatform>(true);
			Transform at = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).transform : ((Component)root).transform);
			def.endGamePlatform = PlaceCloned<EndGamePlatform>(LevelRigHarvester.EndGamePlatformPrefab, at, ((Component)root).transform, "EndGamePlatform");
			if ((Object)(object)def.endGamePlatform == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No end-game platform available; finishing a race may fail.");
			}
		}

		private static void BuildSpawner(MapRoot root)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			MapSpawnPoints componentInChildren = ((Component)root).GetComponentInChildren<MapSpawnPoints>(true);
			GameObject val = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject : NewChild(((Component)root).transform, "PlayerSpawner"));
			RandomPositionPlayerSpawner val2 = val.GetComponent<RandomPositionPlayerSpawner>() ?? val.AddComponent<RandomPositionPlayerSpawner>();
			List<Transform> list = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.Resolve() : new List<Transform>());
			if (list.Count == 0)
			{
				Plugin.Log.LogWarning((object)"Map has no spawn points; generating a default row of 4.");
				for (int i = 0; i < 4; i++)
				{
					GameObject val3 = NewChild(val.transform, $"SpawnPoint_{i}");
					val3.transform.localPosition = new Vector3(((float)i - 1.5f) * 4f, 1f, 0f);
					list.Add(val3.transform);
				}
			}
			SetPrivateList(val2, "spawnPositions", list);
			if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.timeTrialSpawn != (Object)null)
			{
				val2.timeTrialSpawn = componentInChildren.timeTrialSpawn;
			}
			else if (list.Count > 0)
			{
				val2.timeTrialSpawn = list[0];
			}
		}

		private static void BuildCollisionMeshes(MapRoot root)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			List<MapCollisionMesh> list = new List<MapCollisionMesh>();
			Scene scene = ((Component)root).gameObject.scene;
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				list.AddRange(val.GetComponentsInChildren<MapCollisionMesh>(true));
			}
			int num = LayerMask.NameToLayer("RoadCombined");
			if (num < 0)
			{
				Plugin.Log.LogError((object)"No 'RoadCombined' layer in this build — the car will fall through this map. Collision geometry left on its authored layer.");
				return;
			}
			foreach (MapCollisionMesh item in list)
			{
				((Component)item).gameObject.layer = num;
			}
			int num2 = GenerateMissingCollision(root, num);
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(76, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Collision: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(list.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" authored mesh(es) moved to layer ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("('");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("RoadCombined");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'), ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num2);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" generated at load time.");
			}
			log.LogInfo(val2);
		}

		private static int GenerateMissingCollision(MapRoot root, int layer)
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			if (layer < 0)
			{
				return 0;
			}
			List<Collider> list = new List<Collider>();
			Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!val.isTrigger && val.enabled && ((Component)val).gameObject.activeInHierarchy && ((Component)val).gameObject.layer != layer && !((Object)(object)((Component)val).GetComponent<MapCollisionMesh>() != (Object)null) && !HasCollisionChild(((Component)val).transform, layer))
				{
					list.Add(val);
				}
			}
			int num = 0;
			foreach (Collider item in list)
			{
				GameObject val2 = Object.Instantiate<GameObject>(((Component)item).gameObject, ((Component)item).transform);
				((Object)val2).name = "SlipSkid_GeneratedCollision";
				val2.layer = layer;
				for (int num2 = val2.transform.childCount - 1; num2 >= 0; num2--)
				{
					Object.Destroy((Object)(object)((Component)val2.transform.GetChild(num2)).gameObject);
				}
				Component[] components = val2.GetComponents<Component>();
				foreach (Component val3 in components)
				{
					if (!(val3 is Transform) && !(val3 is Collider))
					{
						Object.Destroy((Object)(object)val3);
					}
				}
				val2.transform.localPosition = Vector3.zero;
				val2.transform.localRotation = Quaternion.identity;
				val2.transform.localScale = Vector3.one;
				num++;
			}
			return num;
		}

		private static bool HasCollisionChild(Transform parent, int layer)
		{
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if ((Object)(object)((Component)child).GetComponent<MapCollisionMesh>() != (Object)null)
				{
					return true;
				}
				if (((Component)child).gameObject.layer == layer && (Object)(object)((Component)child).GetComponent<Collider>() != (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		private static void BuildBoostPads(MapRoot root)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: 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_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			List<MapBoostPad> list = new List<MapBoostPad>();
			Scene scene = ((Component)root).gameObject.scene;
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				list.AddRange(val.GetComponentsInChildren<MapBoostPad>(true));
			}
			if (list.Count == 0)
			{
				return;
			}
			int num = LayerMask.NameToLayer("RoadCombined");
			int num2 = 0;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2;
			foreach (MapBoostPad item in list)
			{
				BoxCollider component = ((Component)item).GetComponent<BoxCollider>();
				if ((Object)(object)component == (Object)null)
				{
					Plugin.Log.LogWarning((object)("Boost pad '" + ((Object)item).name + "' has no BoxCollider; skipping. AccelerationZone needs a box trigger to measure itself against."));
					continue;
				}
				((Collider)component).isTrigger = true;
				if (num >= 0)
				{
					((Component)item).gameObject.layer = num;
				}
				if (item.capAtBoostSpeed)
				{
					AccelerationZone obj = ((Component)item).GetComponent<AccelerationZone>() ?? ((Component)item).gameObject.AddComponent<AccelerationZone>();
					obj.trigger = component;
					obj.setVelocityOnEnter = true;
					obj.velocityOnEnter = item.boostSpeed;
					obj.acceleration = item.continuousAcceleration;
					obj.dynamicResize = false;
				}
				else
				{
					(((Component)item).GetComponent<BoostPadZone>() ?? ((Component)item).gameObject.AddComponent<BoostPadZone>()).boostSpeed = item.boostSpeed;
				}
				Bounds bounds = ((Collider)component).bounds;
				ManualLogSource log = Plugin.Log;
				val2 = new BepInExInfoLogInterpolatedStringHandler(44, 9, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("  boost pad '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)item).name);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' at (");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(((Bounds)(ref bounds)).center.x, "0.0");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(((Bounds)(ref bounds)).center.y, "0.0");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(((Bounds)(ref bounds)).center.z, "0.0");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(") ");
					((BepInExLogInterpolatedStringHan

BepInEx/plugins/SlipSkid.MapLoader/SlipSkid.MapSDK.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Microsoft.CodeAnalysis;
using UnityEngine;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SlipSkid.MapSDK
{
	[AddComponentMenu("Slip & Skid/Map Root")]
	public class MapRoot : MonoBehaviour
	{
		[Header("Identity")]
		public string mapName = "My Map";

		public string author = "";

		[Range(1f, 5f)]
		public int difficulty = 1;

		[Tooltip("Lets the Random level picker run this map in reverse.")]
		public bool isReversible;

		[Header("Environment")]
		[Tooltip("Index into the game's SurfaceManager.surfaces, used when a road tile doesn't pick its own. Surfaces are global and networked by index, so maps have to reuse the game's rather than ship their own.")]
		public int defaultSurfaceIndex;

		[Tooltip("Copy biome and lighting from this stock level. Empty = the first one.")]
		public string biomeFromLevel = "";

		[Tooltip("Force the backdrop scenery regardless of what the track is made of. Matched loosely against the stock biome names: Asphalt, Dirt, Ice, Magma, Mud, Sand. Empty = picked from the dominant surface.\n\nThis is how you get desert scenery on an asphalt track. Choosing it through the surface instead would also change how the car handles.")]
		public string forceEnvironmentBiome = "";
	}
	[AddComponentMenu("Slip & Skid/Road Tile")]
	public class MapRoadTile : MonoBehaviour
	{
		[Tooltip("-1 = use the map's default. Otherwise an index into SurfaceManager.surfaces.")]
		public int surfaceIndex = -1;

		[Tooltip("Stable unique id, filled in automatically. Surface swaps are networked by this GUID, so changing it between builds desyncs clients.")]
		public string tileGuid = "";

		[Tooltip("Swap this tile's geometry for a real road piece taken from a stock level. The tile's own mesh becomes placement data only; the piece brings the game's mesh, borders and materials with it.")]
		public bool useStockRoadPiece = true;

		[Tooltip("Skin this tile with the game's own surface material. Recommended: the surface-swap mechanic matches materials by name, so a tile that keeps a custom material never changes surface with the rest of the track. Uncheck for decorative geometry.")]
		public bool useGameSurfaceMaterial = true;

		private void Reset()
		{
			if (string.IsNullOrEmpty(tileGuid))
			{
				tileGuid = Guid.NewGuid().ToString();
			}
		}
	}
	[AddComponentMenu("Slip & Skid/Road Border")]
	public class MapRoadBorder : MonoBehaviour
	{
	}
	[AddComponentMenu("Slip & Skid/Boost Pad")]
	public class MapBoostPad : MonoBehaviour
	{
		[Tooltip("Speed added along the car's forward when you drive onto the pad.")]
		public float boostSpeed = 15f;

		[Tooltip("ON: the game's own behaviour, where Boost Speed is a TARGET and nothing happens if you're already faster. Values below cruising speed do nothing.\n\nOFF (default): Boost Speed is always added, so small values give a small nudge and the pad still helps at top speed.")]
		public bool capAtBoostSpeed;

		[Tooltip("Continuous push while the car is on the pad, along the PAD's forward. Zero by default: imported meshes rarely face down the track, and a non-zero value here shoves cars sideways.")]
		public float continuousAcceleration;
	}
	[AddComponentMenu("Slip & Skid/Map Music")]
	[RequireComponent(typeof(AudioSource))]
	public class MapMusic : MonoBehaviour
	{
		[Tooltip("Play instead of the game's racing track while this map is loaded.")]
		public bool replaceStockMusic = true;

		[Tooltip("Route through the game's music mixer so the volume setting applies. Off = full volume regardless of settings.")]
		public bool useGameMusicVolume = true;

		[Tooltip("Fade this music out while the game plays one of its own tracks, such as the obstacle picker or the scoreboard, and fade back in for the race. Off = both play at once.")]
		public bool duckForGameMusic = true;

		[Tooltip("How long the fade takes, in seconds.")]
		public float fadeSeconds = 1.5f;
	}
	[AddComponentMenu("Slip & Skid/Collision Mesh")]
	public class MapCollisionMesh : MonoBehaviour
	{
	}
	[AddComponentMenu("Slip & Skid/Start Line")]
	public class MapStartLine : MonoBehaviour
	{
	}
	[AddComponentMenu("Slip & Skid/Finish Line")]
	public class MapFinishLine : MonoBehaviour
	{
		public float width = 14f;

		public float height = 8f;
	}
	[AddComponentMenu("Slip & Skid/Checkpoint")]
	public class MapCheckpoint : MonoBehaviour
	{
		[Tooltip("Pass order, ascending. Ties break by sibling index.")]
		public int order;

		public float width = 14f;

		public float height = 8f;
	}
	[AddComponentMenu("Slip & Skid/Spawn Points")]
	public class MapSpawnPoints : MonoBehaviour
	{
		[Tooltip("In grid order. Children are used automatically when this is empty.")]
		public List<Transform> points = new List<Transform>();

		[Tooltip("Optional dedicated time-trial spawn. Falls back to the first point.")]
		public Transform timeTrialSpawn;

		public List<Transform> Resolve()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (points != null && points.Count > 0)
			{
				return points;
			}
			List<Transform> list = new List<Transform>();
			foreach (Transform item2 in ((Component)this).transform)
			{
				Transform item = item2;
				list.Add(item);
			}
			return list;
		}
	}
	[AddComponentMenu("Slip & Skid/End Game Platform")]
	public class MapEndGamePlatform : MonoBehaviour
	{
		public List<Transform> finishOrderSpawns = new List<Transform>();
	}
	[AddComponentMenu("Slip & Skid/Gravity Sphere")]
	public class MapGravitySphere : MonoBehaviour
	{
		public float gravity = 40f;

		public float innerRadius = 2.5f;

		public float outerRadius = 10f;

		public bool useObjectScale = true;
	}
}