Decompiled source of MultiDelivery v1.0.5

MultiDelivery-IL2CPP.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using Il2Cpp;
using Il2CppFishNet;
using Il2CppFishNet.Connection;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.Core.Items.Framework;
using Il2CppScheduleOne.Core.Weather;
using Il2CppScheduleOne.Delivery;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Graffiti;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Map;
using Il2CppScheduleOne.Money;
using Il2CppScheduleOne.NPCs.CharacterClasses;
using Il2CppScheduleOne.Persistence.Datas;
using Il2CppScheduleOne.Persistence.Loaders;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Phone.Delivery;
using Il2CppScheduleOne.UI.Shop;
using Il2CppScheduleOne.Vehicles;
using Il2CppScheduleOne.Vehicles.Modification;
using Il2CppSteamworks;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.IO;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using MultiDelivery;
using MultiDelivery.Builders;
using MultiDelivery.GameConsole.Commands;
using MultiDelivery.GameConsole.Commands.Help;
using MultiDelivery.GameConsole.Commands.Pool;
using MultiDelivery.GameConsole.Commands.Quest;
using MultiDelivery.GameConsole.Core;
using MultiDelivery.Helpers;
using MultiDelivery.Network;
using MultiDelivery.Persistence;
using MultiDelivery.Pool;
using MultiDelivery.Quest;
using S1API.Console;
using S1API.Dialogues;
using S1API.Entities;
using S1API.Entities.Dialogue;
using S1API.Entities.NPCs.Suburbia;
using S1API.Internal.Abstraction;
using S1API.Leveling;
using S1API.Messaging;
using S1API.Money;
using S1API.Quests;
using S1API.Quests.Constants;
using S1API.Saveables;
using S1API.Utils;
using Semver;
using SteamNetworkLib;
using SteamNetworkLib.Core;
using SteamNetworkLib.Events;
using SteamNetworkLib.Models;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(global::MultiDelivery.MultiDelivery), "MultiDelivery", "1.0.5", "k073l", null)]
[assembly: MelonColor(1, 0, 255, 0)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonPlatformDomain(/*Could not decode attribute arguments.*/)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("MultiDelivery-IL2CPP")]
[assembly: AssemblyConfiguration("IL2CPP")]
[assembly: AssemblyDescription("Add vehicles, order multiple deliveries from the same place!")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: AssemblyInformationalVersion("1.0.5+1e3711e3b7b873b5063b983a5dfae1d74542cb89")]
[assembly: AssemblyProduct("MultiDelivery-IL2CPP")]
[assembly: AssemblyTitle("MultiDelivery-IL2CPP")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.5.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 MultiDelivery
{
	public class Logger
	{
		private Instance? _melonLogger;

		private static bool _initialized;

		private static readonly object InitLock = new object();

		private static ConstructorInfo? _melonLoggerCtor;

		private static object? _defaultTextColor;

		private static Type? _defaultTextColorType;

		private static object? _melonNsColor;

		private static MethodInfo? _msgMethod;

		public string? Namesection { get; set; }

		public bool RaiseTrace { get; set; }

		public bool RaiseDebug { get; set; }

		private static string? RootNamespace => typeof(Logger).Namespace?.Split('.').FirstOrDefault();

		public Logger(string? namesection = null)
		{
			if (namesection == null)
			{
				Namesection = typeof(Logger).Namespace?.Split('.').FirstOrDefault();
			}
			else if (!string.IsNullOrEmpty(RootNamespace) && !namesection.StartsWith(RootNamespace))
			{
				Namesection = RootNamespace + "." + namesection;
			}
			else
			{
				Namesection = namesection;
			}
			SetupInstance();
		}

		public Logger(Instance melonLogger)
		{
			FieldInfo field = typeof(Instance).GetField("Name", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field != null)
			{
				Namesection = field.GetValue(melonLogger) as string;
			}
			SetupInstance();
		}

		public static implicit operator Logger(Instance melonLogger)
		{
			return new Logger(melonLogger);
		}

		public void Trace(params object[] args)
		{
			Log(LogLevel.Trace, null, args);
		}

		public void Debug(params object[] args)
		{
			Log(LogLevel.Debug, null, args);
		}

		public void T(params object[] args)
		{
			Log(LogLevel.Trace, null, args);
		}

		public void D(params object[] args)
		{
			Log(LogLevel.Debug, null, args);
		}

		public void Info(params object[] args)
		{
			Log(LogLevel.Info, null, args);
		}

		public void Msg(params object[] args)
		{
			Log(LogLevel.Info, null, args);
		}

		public void I(params object[] args)
		{
			Log(LogLevel.Info, null, args);
		}

		public void M(params object[] args)
		{
			Log(LogLevel.Info, null, args);
		}

		public void Warning(params object[] args)
		{
			Log(LogLevel.Warning, null, args);
		}

		public void Warn(params object[] args)
		{
			Log(LogLevel.Warning, null, args);
		}

		public void W(params object[] args)
		{
			Log(LogLevel.Warning, null, args);
		}

		public void Error(params object[] args)
		{
			Log(LogLevel.Error, null, args);
		}

		public void Err(params object[] args)
		{
			Log(LogLevel.Error, null, args);
		}

		public void E(params object[] args)
		{
			Log(LogLevel.Error, null, args);
		}

		public void Fatal(params object[] args)
		{
			Log(LogLevel.BigError, null, args);
		}

		public void BigError(params object[] args)
		{
			Log(LogLevel.BigError, null, args);
		}

		public void F(params object[] args)
		{
			Log(LogLevel.BigError, null, args);
		}

		public void BE(params object[] args)
		{
			Log(LogLevel.BigError, null, args);
		}

		public void InfoColored(object txtColor, params object[] args)
		{
			Log(LogLevel.Info, txtColor, args);
		}

		public void MsgColored(object txtColor, params object[] args)
		{
			Log(LogLevel.Info, txtColor, args);
		}

		public void IC(object txtColor, params object[] args)
		{
			Log(LogLevel.Info, txtColor, args);
		}

		public void MC(object txtColor, params object[] args)
		{
			Log(LogLevel.Info, txtColor, args);
		}

		public void Log(LogLevel level, string message)
		{
			Log(level, null, message);
		}

		private static void EnsureInitialized()
		{
			if (_initialized)
			{
				return;
			}
			lock (InitLock)
			{
				if (_initialized)
				{
					return;
				}
				Type typeFromHandle = typeof(MelonLogger);
				FieldInfo field = typeFromHandle.GetField("DefaultTextColor", BindingFlags.Static | BindingFlags.Public);
				_defaultTextColorType = field?.FieldType;
				if (_defaultTextColorType == null)
				{
					MelonLogger.Error("Could not determine the type of DefaultTextColor");
					return;
				}
				_defaultTextColor = field?.GetValue(null);
				Type typeFromHandle2 = typeof(Instance);
				_melonLoggerCtor = typeFromHandle2.GetConstructor(new Type[2]
				{
					typeof(string),
					_defaultTextColorType
				});
				Type melonBaseType = typeof(MelonBase);
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				Type[] source;
				try
				{
					source = executingAssembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					source = ex.Types.OfType<Type>().ToArray();
				}
				Type type = source.FirstOrDefault((Type t) => melonBaseType.IsAssignableFrom(t) && !t.IsAbstract);
				Type type2 = typeof(Melon<>).MakeGenericType(type ?? throw new InvalidOperationException("No MelonBase derived type found in the current assembly."));
				PropertyInfo property = type2.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
				if (property != null)
				{
					PropertyInfo property2 = property.PropertyType.GetProperty("ConsoleColor", BindingFlags.Instance | BindingFlags.Public);
					if (property2 != null)
					{
						_melonNsColor = property2.GetValue(property.GetValue(null));
					}
				}
				if (_melonNsColor == null)
				{
					FieldInfo field2 = typeFromHandle.GetField("DefaultMelonColor", BindingFlags.Static | BindingFlags.Public);
					if (field2 != null)
					{
						_melonNsColor = field2.GetValue(null);
					}
				}
				_msgMethod = typeFromHandle2.GetMethod("Msg", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
				{
					_defaultTextColorType,
					typeof(string)
				}, null);
				if (_melonLoggerCtor == null)
				{
					MelonLogger.Error("Could not find constructor for MelonLogger.Instance(string, <colorType>)");
				}
				if (_defaultTextColor == null)
				{
					MelonLogger.Error("Could not find DefaultTextColor");
				}
				if (_melonNsColor == null)
				{
					MelonLogger.Error("Could not find Melon<>.Instance.ConsoleColor or MelonLogger.DefaultMelonColor");
				}
				if (_msgMethod == null)
				{
					MelonLogger.Error("Could not find MelonLogger.Instance.Msg(<colorType>, string)");
				}
				_initialized = true;
			}
		}

		private static string GetCallerInfo()
		{
			StackTrace stackTrace = new StackTrace();
			for (int i = 3; i < stackTrace.FrameCount; i++)
			{
				StackFrame frame = stackTrace.GetFrame(i);
				MethodBase method = frame.GetMethod();
				if (method?.DeclaringType != null)
				{
					return method.DeclaringType.FullName + "." + method.Name;
				}
			}
			return "unknown";
		}

		private void SetupInstance()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			if (string.IsNullOrEmpty(Namesection))
			{
				Namesection = "Logger";
			}
			EnsureInitialized();
			object obj = _melonLoggerCtor?.Invoke(new object[2] { Namesection, _melonNsColor });
			if (obj == null)
			{
				throw new NullReferenceException("Could not create MelonLogger.Instance");
			}
			_melonLogger = (Instance)obj;
		}

		private void Log(LogLevel level, object? txtColor, params object[] args)
		{
			if (args.Length == 0)
			{
				return;
			}
			string text;
			if (args.Length == 1)
			{
				text = args[0]?.ToString() ?? "";
			}
			else
			{
				string format = args[0]?.ToString() ?? "";
				text = string.Format(format, args[1..]);
			}
			object obj = txtColor ?? _defaultTextColor;
			switch (level)
			{
			case LogLevel.Trace:
			{
				string text2 = "[TRACE " + GetCallerInfo() + "] " + text;
				if (RaiseTrace)
				{
					_msgMethod?.Invoke(_melonLogger, new object[2] { obj, text2 });
				}
				else
				{
					MelonDebug.Msg(text2);
				}
				break;
			}
			case LogLevel.Debug:
			{
				string text3 = "[DEBUG " + GetCallerInfo() + "] " + text;
				if (RaiseDebug)
				{
					_msgMethod?.Invoke(_melonLogger, new object[2] { obj, text3 });
				}
				else
				{
					MelonDebug.Msg(text3);
				}
				break;
			}
			default:
				_msgMethod?.Invoke(_melonLogger, new object[2] { obj, text });
				break;
			case LogLevel.Warning:
			{
				Instance? melonLogger3 = _melonLogger;
				if (melonLogger3 != null)
				{
					melonLogger3.Warning(text);
				}
				break;
			}
			case LogLevel.Error:
			{
				Instance? melonLogger2 = _melonLogger;
				if (melonLogger2 != null)
				{
					melonLogger2.Error(text);
				}
				break;
			}
			case LogLevel.BigError:
			{
				Instance? melonLogger = _melonLogger;
				if (melonLogger != null)
				{
					melonLogger.BigError(text);
				}
				break;
			}
			}
		}
	}
	public enum LogLevel
	{
		Trace,
		Debug,
		Info,
		Warning,
		Error,
		BigError
	}
	public static class BuildInfo
	{
		public const string Name = "MultiDelivery";

		public const string Description = "Add vehicles, order multiple deliveries from the same place!";

		public const string Author = "k073l";

		public const string Version = "1.0.5";
	}
	public class MultiDelivery : MelonMod
	{
		private static Logger Logger;

		private IDeliveryNetworkManager? _networkManager;

		private bool _networkManagerFailed;

		internal static MelonPreferences_Category Category = MelonPreferences.CreateCategory("MultiDeliverySettings", "MultiDelivery's Settings");

		internal static MelonPreferences_Entry<bool> NetworkLogging;

		internal static MelonPreferences_Entry<bool> PoolDebugLogging;

		internal static MelonPreferences_Entry<bool> QuestDebugLogging;

		public override void OnInitializeMelon()
		{
			Logger = ((MelonBase)this).LoggerInstance;
			Logger.Msg("MultiDelivery initialized");
			NetworkLogging = Category.CreateEntry<bool>("NetworkDebugLogs", false, "Enable Network Logs", "Display networking-related debug logs in MelonLoader console/log file (may be verbose)", false, false, (ValueValidator)null, (string)null);
			PoolDebugLogging = Category.CreateEntry<bool>("PoolDebugLogs", false, "Enable Pool Debug Logs", "Display pool-related debug logs in MelonLoader console/log file (may be verbose)", false, false, (ValueValidator)null, (string)null);
			QuestDebugLogging = Category.CreateEntry<bool>("QuestDebugLogs", false, "Enable Quest Debug Logs", "Display quest-related debug logs in MelonLoader console/log file (may be verbose)", false, false, (ValueValidator)null, (string)null);
			RegisterLoggerSettings();
			CheckDependencies();
			MelonCoroutines.Start(InitializeNetworkManager());
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			QuestSetupManager.OnSceneWasLoaded(buildIndex, sceneName);
			if (!(sceneName != "Menu"))
			{
				PoolManager.Instance.ClearAll();
			}
		}

		private IEnumerator InitializeNetworkManager()
		{
			if (SteamAPI.Init())
			{
				yield return null;
				_networkManager = NetworkLoader.Create();
				if (_networkManager == null)
				{
					Logger.Warning("NetworkManager is null, multiplayer features will be unavailable.");
				}
				else
				{
					NetworkConvenienceMethods.InitializeNetworking(_networkManager);
					_networkManager.RegisterLoggerSettings();
				}
			}
		}

		public override void OnUpdate()
		{
			if (_networkManagerFailed || _networkManager == null)
			{
				return;
			}
			try
			{
				_networkManager.Update();
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Network manager update failed: " + ex.Message + "\n\nYou can ignore this error if you plan on playing singleplayer only and don't want to install SteamNetworkLib");
				_networkManagerFailed = true;
			}
		}

		public override void OnDeinitializeMelon()
		{
			_networkManager?.Dispose();
			Logger.Msg("MultiDelivery deinitialized");
		}

		private static void CheckDependencies()
		{
			DependenciesChecker dependenciesChecker = new DependenciesChecker
			{
				ShowMenuBanner = true,
				UnloadIfMissingRequired = true
			};
			dependenciesChecker.AddDependency(new DependencyInfo
			{
				Name = "S1API (Forked)",
				AssemblyName = "S1API",
				IsRequired = true,
				Version = "3.0.1",
				Urls = new List<DependencyUrl>(3)
				{
					new DependencyUrl
					{
						SourceName = "Thunderstore",
						Url = "https://thunderstore.io/c/schedule-i/p/ifBars/S1API_Forked/"
					},
					new DependencyUrl
					{
						SourceName = "NexusMods",
						Url = "https://www.nexusmods.com/schedule1/mods/1194"
					},
					new DependencyUrl
					{
						SourceName = "Github",
						Url = "https://github.com/ifBars/S1API/releases/"
					}
				}
			});
			dependenciesChecker.AddDependency(new DependencyInfo
			{
				Name = "SteamNetworkLib",
				AssemblyName = "SteamNetworkLib",
				IsRequired = false,
				Version = "1.2.1",
				Urls = new List<DependencyUrl>(4)
				{
					new DependencyUrl
					{
						SourceName = "Thunderstore Il2Cpp",
						Url = "https://thunderstore.io/c/schedule-i/p/ifBars/SteamNetworkLib_Il2Cpp/"
					},
					new DependencyUrl
					{
						SourceName = "Thunderstore Mono",
						Url = "https://thunderstore.io/c/schedule-i/p/ifBars/SteamNetworkLib_Mono/"
					},
					new DependencyUrl
					{
						SourceName = "NexusMods",
						Url = "https://www.nexusmods.com/schedule1/mods/1396"
					},
					new DependencyUrl
					{
						SourceName = "Github",
						Url = "https://github.com/ifBars/SteamNetworkLib/releases"
					}
				}
			});
			dependenciesChecker.ProcessAndAlert();
		}

		private static void RegisterLoggerSettings()
		{
			SetAndRegister(ActiveDeliveryPatch.Logger, PoolDebugLogging);
			SetAndRegister(CapacityText.Logger, PoolDebugLogging);
			SetAndRegister(DeliveryInstancePatches.Logger, PoolDebugLogging);
			SetAndRegister(LoaderPatch.Logger, PoolDebugLogging);
			SetAndRegister(PoolManager.Logger, PoolDebugLogging);
			SetAndRegister(DropoffQuest.Logger, QuestDebugLogging);
			SetAndRegister(DropoffQuestDialogue.Logger, QuestDebugLogging);
			SetAndRegister(QuestSetupManager.Logger, QuestDebugLogging);
		}

		private static void SetAndRegister(Logger logger, MelonPreferences_Entry<bool>? entry)
		{
			logger.RaiseDebug = entry?.Value ?? false;
			((MelonEventBase<LemonAction<bool, bool>>)(object)entry?.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)delegate(bool _, bool newValue)
			{
				logger.RaiseDebug = newValue;
			}, 0, false);
		}
	}
}
namespace MultiDelivery.Quest
{
	public class DropoffQuest : Quest
	{
		internal const string Name = "Expanding the Fleet";

		private bool _vehicleAdded;

		private QuestEntry _addVehicleEntry;

		private int _startingCapacity;

		private static VehicleDropoffZone dropoffZone;

		private static Vector3 _dropoffZonePosition;

		internal static readonly Logger Logger = new Logger("DropoffQuest");

		protected override string Title => "Expanding the Fleet";

		protected override string Description => "Bring a delivery vehicle to the dropoff zone to expand your delivery capacity";

		protected override bool AutoBegin => false;

		protected override Sprite QuestIcon => IconLoader.QuestIconSprite;

		internal QuestState State => ((Quest)this).QuestState;

		protected override void OnCreated()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			((Registerable)this).OnCreated();
			_startingCapacity = PoolManager.Instance.PoolCount;
			Logger.Debug($"Starting Quest with {_startingCapacity} capacity");
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(5.1f, 4.2f, 82.58f);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0.55f, 4.2f, 76.56f);
			_dropoffZonePosition = (val + val2) / 2f;
			if ((Object)(object)dropoffZone != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)dropoffZone).gameObject);
			}
			dropoffZone = VehicleDropoffZoneFactory.CreateZone(val, val2, 5f, (Color?)new Color(0f, 1f, 0f, 0.4f), showVisuals: true, this);
			Logger.Debug("Dropoff zone created. Spawning " + ((Object)dropoffZone).name);
			((Quest)this).OnComplete += Completed;
			Logger.Debug("Wired completion event");
			UpdateQuestEntries();
		}

		private void UpdateQuestEntries()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			base.QuestEntries.Clear();
			if (!_vehicleAdded)
			{
				Logger.Debug("Adding add vehicle entry");
				_addVehicleEntry = ((Quest)this).AddEntry("Purchase a " + "veeper".Capitalize() + " and drive it into the green dropoff zone (top floor of the parking garage, next to storage unit)", (Vector3?)_dropoffZonePosition);
				_addVehicleEntry.Begin();
			}
			Logger.Debug("Entries added!");
		}

		public void MarkAddVehicleEntryComplete()
		{
			Logger.Debug("Marked add vehicle entry as completed");
			_addVehicleEntry.Complete();
		}

		private void Completed()
		{
			Logger.Msg("Delivery vehicle dropoff quest completed!");
			MelonCoroutines.Start(NotifyCompletion());
		}

		private IEnumerator NotifyCompletion()
		{
			int i = 0;
			while (i < 3 && PoolManager.Instance.PoolCount <= _startingCapacity)
			{
				yield return (object)new WaitForSeconds(3f);
				int num = i + 1;
				i = num;
			}
			NPC npc = NPC.Get<JeremyWilkinson>();
			if (npc != null)
			{
				if (PoolManager.Instance.PoolCount <= _startingCapacity)
				{
					npc.SendTextMessage("Something went wrong... Vehicle got in a car crash :(", (Response[])null, 1f, true);
					yield break;
				}
				npc.SendTextMessage($"Vehicle added, you now can order {PoolManager.Instance.PoolCount} more deliver{((PoolManager.Instance.PoolCount > 1) ? "ies" : "y")} from stores.", (Response[])null, 1f, true);
				npc.SendTextMessage("If you want to add more, you know where to find me.", (Response[])null, 1f, true);
			}
		}
	}
	public class DropoffQuestDialogue
	{
		internal static readonly Logger Logger = new Logger("DropoffQuestDialogue");

		private const string ContainerName = "DeliveryExpansion";

		public static void Register()
		{
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			NPC jeremy = NPC.Get<JeremyWilkinson>();
			if (jeremy == null)
			{
				Logger.Warning("Jeremy Wilkinson not found");
				return;
			}
			jeremy.Dialogue.BuildAndRegisterContainer("DeliveryExpansion", (Action<DialogueContainerBuilder>)delegate(DialogueContainerBuilder c)
			{
				c.AddNode("OFFER_FIRST", "Yeah! I can help with that. If you bring a " + "veeper".Capitalize() + " to the dropoff zone, I'll add it to the fleet. This will let you handle multiple deliveries at once. Want to give it a shot?", (Action<ChoiceList>)delegate(ChoiceList ch)
				{
					ch.Add("BUY_NOW", "Sure! Can I buy one from you right now?", "CHECK_FUNDS");
					ch.Add("ACCEPT", "I already have one, let's do it!", "ACCEPTED");
					ch.Add("DECLINE", "Maybe later.", "DECLINED");
				});
				c.AddNode("OFFER_REPEAT", "Want to expand your fleet even more? Just bring another vehicle to the dropoff zone and I'll add it for you.", (Action<ChoiceList>)delegate(ChoiceList ch)
				{
					ch.Add("BUY_NOW", "Yeah, can I buy another one from you?", "CHECK_FUNDS");
					ch.Add("ACCEPT", "I've got one ready!", "ACCEPTED");
					ch.Add("DECLINE", "Not right now.", "DECLINED");
				});
				c.AddNode("CHECK_FUNDS", $"A {"veeper".Capitalize()} runs <color=#19BEF0>({MoneyManager.FormatAmount(GetVehiclePrice(), false, false)})</color>. Want to pick one up?", (Action<ChoiceList>)delegate(ChoiceList ch)
				{
					ch.Add("PURCHASE", "I'll take it. <color=#19BEF0>(" + MoneyManager.FormatAmount(GetVehiclePrice(), false, false) + ")</color>", "PURCHASE_COMPLETE");
					ch.Add("NEVERMIND", "Let me think about it.", "DECLINED");
				});
				c.AddNode("PURCHASE_COMPLETE", "All yours. You can customize it if you want. Now just drive it to the dropoff zone - I've marked it on your map.", (Action<ChoiceList>)null);
				c.AddNode("NOT_ENOUGH", "You don't have enough money to buy it. Come back later.", (Action<ChoiceList>)null);
				c.AddNode("IN_PROGRESS", "You already have an active delivery expansion going! Just bring the vehicle to the dropoff zone. Top floor of the parking garage, next to the storage units - check your map if you forgot where it is.", (Action<ChoiceList>)null);
				c.AddNode("ACCEPTED", "Great! I've marked the dropoff zone on your map - top floor of the parking garage, next to the storage units. Just drive the vehicle in there when you're ready.", (Action<ChoiceList>)null);
				c.AddNode("DECLINED", "No worries, just let me know if you change your mind!", (Action<ChoiceList>)null);
			});
			jeremy.Dialogue.OnChoiceSelected("ACCEPT", (Action)OnAcceptQuest);
			jeremy.Dialogue.OnChoiceSelected("BUY_NOW", (Action)OnAcceptQuest);
			jeremy.Dialogue.OnChoiceSelected("DECLINE", (Action)delegate
			{
				Logger.Debug("Player declined quest");
			});
			jeremy.Dialogue.OnChoiceSelected("NEVERMIND", (Action)delegate
			{
				Logger.Debug("Player cancelled purchase");
			});
			jeremy.Dialogue.OnChoiceSelected("PURCHASE", (Action)delegate
			{
				//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_0100: Unknown result type (might be due to invalid IL or missing references)
				float vehiclePrice = GetVehiclePrice();
				float onlineBalance = Money.GetOnlineBalance();
				if (onlineBalance >= vehiclePrice)
				{
					Money.CreateOnlineTransaction("veeper".Capitalize() + " purchase", 0f - vehiclePrice, 1f, "Bought as a part of delivery expansion");
					Logger.Msg($"Player purchased {"veeper"} for ${vehiclePrice:F2}");
					Jeremy component = jeremy.gameObject.GetComponent<Jeremy>();
					if ((Object)(object)component != (Object)null)
					{
						Dealership dealership = component.Dealership;
						if ((Object)(object)dealership != (Object)null)
						{
							dealership.SpawnVehicle("veeper");
							return;
						}
					}
					NetworkSingleton<VehicleManager>.Instance.SpawnVehicle("veeper", new Vector3(9.92f, 0.54f, -33.55f), Quaternion.identity, true);
				}
				else
				{
					jeremy.Dialogue.JumpTo("DeliveryExpansion", "NOT_ENOUGH", false);
				}
			});
			DialogueInjector.Register(new DialogueInjection(jeremy.ID, "Dealership_Salesman_Sell", "cc0d838e-2824-4fd5-907d-798dc0195c16", "OFFER_FIRST", "ASK_EXPANSION", "Can I expand my delivery capacity?", (Action)delegate
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Invalid comparison between Unknown and I4
				DropoffQuest dropoffQuest = QuestManager.GetQuestByName("Expanding the Fleet") as DropoffQuest;
				bool flag = PoolManager.Instance.PoolCount > 0;
				bool flag2 = dropoffQuest != null && (int)dropoffQuest.State == 1;
				Logger.Debug($"Quest state - Active: {flag2}, Has expanded: {flag}");
				string text = (flag2 ? "IN_PROGRESS" : (flag ? "OFFER_REPEAT" : "OFFER_FIRST"));
				Logger.Debug($"Jumping to '{"DeliveryExpansion"}', node '{text}'");
				jeremy.Dialogue.JumpTo("DeliveryExpansion", text, false);
			}));
			Logger.Msg("Registered delivery expansion dialogue");
		}

		internal static void OnAcceptQuest()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			if (!(QuestManager.GetQuestByName("Expanding the Fleet") is DropoffQuest dropoffQuest))
			{
				if (QuestManager.CreateQuest<DropoffQuest>((string)null) is DropoffQuest dropoffQuest2)
				{
					((Quest)dropoffQuest2).Begin();
				}
				Logger.Msg("Started delivery expansion quest");
			}
			else if (dropoffQuest != null && (int)dropoffQuest.State == 2)
			{
				((Quest)dropoffQuest).Begin();
				Logger.Msg("Restarted delivery expansion quest");
			}
		}

		private static float GetVehiclePrice()
		{
			LandVehicle vehiclePrefab = NetworkSingleton<VehicleManager>.Instance.GetVehiclePrefab("veeper");
			return (vehiclePrefab != null) ? vehiclePrefab.VehiclePrice : 5000f;
		}
	}
	public class QuestSetupManager
	{
		internal const string RequestedVehicleCode = "veeper";

		internal const string QuestStartMessage = "Your properties are getting busy. Want to handle more than one delivery at a time? I've got an idea. Stop by the dealership.";

		private static FullRank RequiredRank = new FullRank((Rank)5, 1);

		internal static readonly Logger Logger = new Logger("QuestSetupManager");

		public static void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (!(sceneName == "Main"))
			{
				if (sceneName == "Menu")
				{
					Player.LocalPlayerSpawned -= WirePlayerEvent;
					LevelManager.OnXPChanged -= SendMessageIfRequiredRank;
				}
			}
			else
			{
				Player.LocalPlayerSpawned += WirePlayerEvent;
			}
		}

		private static void WirePlayerEvent(Player _)
		{
			Logger.Debug("Player loaded event called");
			MelonCoroutines.Start(WireOnXpChangedDelayed());
		}

		private static IEnumerator WireOnXpChangedDelayed()
		{
			yield return (object)new WaitUntil(Func<bool>.op_Implicit((Func<bool>)(() => LevelManager.Exists)));
			if (PersistentDropoffQuestData.Instance.HasMessaged)
			{
				DropoffQuestDialogue.Register();
				yield break;
			}
			Logger.Debug("Wiring on xp changed");
			LevelManager.OnXPChanged += SendMessageIfRequiredRank;
		}

		private static void SendMessageIfRequiredRank(FullRank _, FullRank current)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			Logger.Debug($"Current rank {current}, required: {RequiredRank}");
			if (PersistentDropoffQuestData.Instance.HasMessaged)
			{
				MelonDebug.Msg("Xp changed wired, but already messaged - registering dialogue now.");
				DropoffQuestDialogue.Register();
			}
			else
			{
				if (current < RequiredRank)
				{
					return;
				}
				NPC val = NPC.Get<JeremyWilkinson>();
				if (val != null)
				{
					if (NetworkConvenienceMethods.HostOrSingleplayer)
					{
						val.SendTextMessage("Your properties are getting busy. Want to handle more than one delivery at a time? I've got an idea. Stop by the dealership.", (Response[])null, 1f, true);
					}
					PersistentDropoffQuestData.Instance.HasMessaged = true;
					DropoffQuestDialogue.Register();
					LevelManager.OnXPChanged -= SendMessageIfRequiredRank;
				}
			}
		}
	}
	[RegisterTypeInIl2Cpp]
	public class VehicleDropoffZone : MonoBehaviour
	{
		private VehicleDetector _detector;

		private Logger _logger;

		private GameObject _visualPlane;

		private Material _visualMaterial;

		private Color _baseColor;

		private DropoffQuest? _quest;

		public Vector3 Corner1 { get; private set; }

		public Vector3 Corner2 { get; private set; }

		public bool ShowVisuals { get; set; } = true;

		private void Awake()
		{
			_logger = new Logger("VehicleDropoffZone");
			_logger.RaiseDebug = MultiDelivery.QuestDebugLogging?.Value ?? false;
			((MelonEventBase<LemonAction<bool, bool>>)(object)MultiDelivery.QuestDebugLogging?.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)delegate(bool _, bool newValue)
			{
				_logger.RaiseDebug = newValue;
			}, 0, false);
		}

		private void Start()
		{
			_detector = ((Component)this).gameObject.GetComponent<VehicleDetector>();
			if ((Object)(object)_detector == (Object)null)
			{
				_detector = ((Component)this).gameObject.AddComponent<VehicleDetector>();
			}
		}

		private void Update()
		{
			if (_detector.vehicles.Count <= 0)
			{
				return;
			}
			foreach (LandVehicle item in _detector.vehicles.AsEnumerable<LandVehicle>())
			{
				OnVehicleEntered(item);
			}
		}

		private void OnVehicleEntered(LandVehicle vehicle)
		{
			_logger.Debug("Vehicle entered dropoff zone: " + vehicle.vehicleName);
			if (!IsCorrectVehicleType(vehicle))
			{
				if (Time.frameCount % 60 == 0)
				{
					_logger.Warning("Wrong vehicle type: " + vehicle.vehicleCode);
				}
				return;
			}
			if (vehicle.IsOccupied)
			{
				_logger.Msg("Ejecting player from vehicle");
				vehicle.ExitVehicle();
			}
			ProcessAndAddToPool(vehicle);
			_detector.vehicles.Remove(vehicle);
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}

		private static bool IsCorrectVehicleType(LandVehicle vehicle)
		{
			return vehicle.vehicleCode == "veeper";
		}

		private void ProcessAndAddToPool(LandVehicle vehicle)
		{
			//IL_003b: 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)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			_logger.Debug($"Adding vehicle to pool: {vehicle.GUID}");
			DeliveryVehicle val = ((Component)vehicle).GetComponent<DeliveryVehicle>();
			if ((Object)(object)val == (Object)null)
			{
				Guid gUID = vehicle.GUID;
				val = new DeliveryVehicleBuilder().WithLandVehicle(vehicle).WithGuid(gUID).Build();
			}
			vehicle.IsPlayerOwned = false;
			vehicle.SetIsPlayerOwned((NetworkConnection)null, false);
			vehicle.SetVisible(false);
			vehicle.IsPhysicallySimulated = false;
			IEnumerable<LandVehicle> source = from lv in NetworkSingleton<VehicleManager>.Instance.PlayerOwnedVehicles.AsEnumerable<LandVehicle>()
				where ((object)lv.GUID/*cast due to .constrained prefix*/).ToString() != ((object)vehicle.GUID/*cast due to .constrained prefix*/).ToString()
				select lv;
			NetworkSingleton<VehicleManager>.Instance.PlayerOwnedVehicles = source.ToIl2CppList();
			((Component)vehicle).transform.position = new Vector3(0f, -100f, 0f);
			PoolManager.Instance.AddToSaveData(val);
			PoolManager.Instance.AddToPool(val);
			_quest?.MarkAddVehicleEntryComplete();
			_logger.Msg($"Vehicle added to pool. Total vehicles: {PoolManager.Instance.PoolCount}");
		}

		public void SetupZone(Vector3 corner1, Vector3 corner2, float height = 5f, Color? visualColor = null)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			Corner1 = corner1;
			Corner2 = corner2;
			Vector3 val = (corner1 + corner2) / 2f;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(Mathf.Abs(corner2.x - corner1.x), height, Mathf.Abs(corner2.z - corner1.z));
			((Component)this).transform.position = val;
			BoxCollider val3 = ((Component)this).gameObject.GetComponent<BoxCollider>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = ((Component)this).gameObject.AddComponent<BoxCollider>();
			}
			((Collider)val3).isTrigger = true;
			val3.size = val2;
			val3.center = Vector3.zero;
			if (ShowVisuals)
			{
				_baseColor = (Color)(((??)visualColor) ?? new Color(0f, 1f, 1f, 0.3f));
				CreateVisualPlane(val2, _baseColor);
			}
			_logger.Debug($"Dropoff zone created: Center={val}, Size={val2}");
		}

		private void CreateVisualPlane(Vector3 size, Color color)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			_visualPlane = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)_visualPlane).name = "DropoffZoneVisual";
			_visualPlane.transform.SetParent(((Component)this).transform);
			_visualPlane.transform.localPosition = Vector3.zero;
			_visualPlane.transform.localScale = new Vector3(size.x, 0.1f, size.z);
			Collider component = _visualPlane.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			ApplyDebugMaterial(_visualPlane, color);
		}

		private void ApplyDebugMaterial(GameObject obj, Color color)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_006b: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			Renderer component = obj.GetComponent<Renderer>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Shader val = Shader.Find("Universal Render Pipeline/Lit");
			if (!((Object)(object)val == (Object)null))
			{
				_visualMaterial = new Material(val);
				if (_visualMaterial.HasProperty("_Surface"))
				{
					_visualMaterial.SetFloat("_Surface", 1f);
				}
				if (color.a <= 0f)
				{
					color.a = 0.3f;
				}
				if (_visualMaterial.HasProperty("_BaseColor"))
				{
					_visualMaterial.SetColor("_BaseColor", color);
				}
				if (_visualMaterial.HasProperty("_EmissionColor"))
				{
					_visualMaterial.EnableKeyword("_EMISSION");
					_visualMaterial.SetColor("_EmissionColor", new Color(color.r, color.g, color.b) * 1.5f);
				}
				_visualMaterial.SetInt("_ZWrite", 0);
				_visualMaterial.renderQueue = 3000;
				component.material = _visualMaterial;
			}
		}

		public void SetVisualsEnabled(bool enabled)
		{
			ShowVisuals = enabled;
			if ((Object)(object)_visualPlane != (Object)null)
			{
				_visualPlane.SetActive(enabled);
			}
		}

		[HideFromIl2Cpp]
		public void SetQuest(DropoffQuest quest)
		{
			_quest = quest;
		}

		private void OnDestroy()
		{
			if ((Object)(object)_visualPlane != (Object)null)
			{
				Object.Destroy((Object)(object)_visualPlane);
			}
		}
	}
	public static class VehicleDropoffZoneFactory
	{
		public static VehicleDropoffZone CreateZone(Vector3 corner1, Vector3 corner2, float height = 5f, Color? visualColor = null, bool showVisuals = true, DropoffQuest? attachedQuest = null)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("VehicleDropoffZone");
			VehicleDropoffZone vehicleDropoffZone = val.AddComponent<VehicleDropoffZone>();
			vehicleDropoffZone.ShowVisuals = showVisuals;
			vehicleDropoffZone.SetupZone(corner1, corner2, height, visualColor);
			if (attachedQuest != null)
			{
				vehicleDropoffZone.SetQuest(attachedQuest);
			}
			return vehicleDropoffZone;
		}

		public static VehicleDropoffZone CreateZoneNear(Transform reference, Vector3 offset, Vector3 size, Color? visualColor = null)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = reference.position + offset;
			Vector3 corner = val - size / 2f;
			Vector3 corner2 = val + size / 2f;
			return CreateZone(corner, corner2, size.y, visualColor);
		}
	}
}
namespace MultiDelivery.Pool
{
	[HarmonyPatch(typeof(DeliveryManager))]
	internal static class ActiveDeliveryPatch
	{
		internal static readonly Logger Logger = new Logger("ActiveDeliveryPatch");

		[HarmonyPatch("GetActiveShopDelivery")]
		[HarmonyPostfix]
		private static void AllowIfPoolAssigmentAvailable(DeliveryManager __instance, DeliveryShop shop, ref DeliveryInstance __result)
		{
			if (__result == null)
			{
				return;
			}
			lock (PoolManager.Lock)
			{
				if (PoolManager.Instance.BaseVehicleAllocationsForShop.TryGetValue(shop.MatchingShopInterfaceName, out var value))
				{
					if (Time.frameCount % 30 == 0)
					{
						Logger.Debug($"Base: {value}");
					}
					if (!value)
					{
						__result = null;
						return;
					}
					DeliveryVehicle firstFree = PoolManager.Instance.GetFirstFree();
					if (!((Object)(object)firstFree == (Object)null))
					{
						Logger.Debug("Free pool vehicle found");
						__result = null;
					}
				}
				else
				{
					DeliveryVehicle firstFree2 = PoolManager.Instance.GetFirstFree();
					if (!((Object)(object)firstFree2 == (Object)null))
					{
						Logger.Debug("Free pool vehicle found");
						__result = null;
					}
				}
			}
		}

		[HarmonyPatch("SendDelivery")]
		[HarmonyPostfix]
		private static void AllocateVehicle(DeliveryManager __instance, DeliveryInstance delivery)
		{
			lock (PoolManager.Lock)
			{
				if (PoolManager.Instance.Allocations.ContainsKey(delivery.DeliveryID))
				{
					Logger.Debug("Already allocated, skipping");
					return;
				}
				PoolManager.Instance.BaseVehicleAllocationsForShop.TryAdd(delivery.StoreName, value: false);
				Logger.Debug($"Base allocation: {PoolManager.Instance.BaseVehicleAllocationsForShop[delivery.StoreName]}");
				if (!PoolManager.Instance.BaseVehicleAllocationsForShop[delivery.StoreName])
				{
					Logger.Debug("Base vehicle allocating");
					DeliveryVehicle deliveryVehicle = NetworkSingleton<DeliveryManager>.Instance.GetShopInterface(delivery.StoreName).DeliveryVehicle;
					PoolManager.Instance.SetBaseAllocation(delivery.StoreName, allocated: true);
					PoolManager.Instance.Allocations.Add(delivery.DeliveryID, deliveryVehicle);
					VehicleSave.Instance.AddAllocation(delivery.DeliveryID, deliveryVehicle);
					NetworkConvenienceMethods.NotifyAllocation(delivery.DeliveryID, deliveryVehicle, isAllocated: true);
				}
				else
				{
					PoolManager.Instance.GetOrAllocateFirstFree(delivery.DeliveryID);
					Logger.Debug("Allocated for " + delivery.DeliveryID);
				}
			}
		}
	}
	[HarmonyPatch(typeof(DeliveryShop))]
	internal static class CapacityText
	{
		internal static readonly Logger Logger = new Logger("CapacityText");

		private static ConditionalWeakTable<DeliveryShop, Text> _capacityTexts = new ConditionalWeakTable<DeliveryShop, Text>();

		[HarmonyPatch("Initialize")]
		[HarmonyPostfix]
		private static void AddCapacityTextPostfix(DeliveryShop __instance)
		{
			Logger.Debug("Adding capacity text for " + ((Object)__instance).name);
			if (_capacityTexts.TryGetValue(__instance, out Text _))
			{
				return;
			}
			Text deliveryTimeLabel = __instance.DeliveryTimeLabel;
			GameObject val = ((deliveryTimeLabel != null) ? ((Component)((Component)deliveryTimeLabel).transform.parent).gameObject : null);
			Logger.Debug($"Adding capacity text: {deliveryTimeLabel}, templatego: {val}");
			if (val == null)
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val);
			val2.transform.SetParent(val.transform.parent, false);
			val2.transform.SetSiblingIndex(val.transform.GetSiblingIndex());
			Text component = ((Component)val2.transform.Find("Label")).GetComponent<Text>();
			component.text = "Free vehicles";
			Text component2 = ((Component)val2.transform.Find("Time")).GetComponent<Text>();
			component2.text = "1/1";
			_capacityTexts.Add(__instance, component2);
			List<Transform> list = val.transform.parent.FindAllTransforms("Spacer");
			if (list.Count > 0)
			{
				Transform val3 = list[list.Count - 1];
				if ((Object)(object)val3 != (Object)null)
				{
					((Component)val3).gameObject.SetActive(false);
				}
			}
		}

		[HarmonyPatch("RefreshCart")]
		[HarmonyPostfix]
		private static void UpdateCapacityTextPostfix(DeliveryShop __instance)
		{
			if (!((App<DeliveryApp>)(object)PlayerSingleton<DeliveryApp>.Instance).isOpen)
			{
				Logger.Debug("Delivery app is not open, skipping capacity text update for " + ((Object)__instance).name);
				return;
			}
			if (!_capacityTexts.TryGetValue(__instance, out Text value))
			{
				Logger.Debug("Capacity text for " + ((Object)__instance).name + " not found!");
				return;
			}
			var (value2, value3) = GetVehiclesForShop(__instance);
			value.text = $"{value2}/{value3}";
		}

		private static (int available, int total) GetVehiclesForShop(DeliveryShop shop)
		{
			lock (PoolManager.Lock)
			{
				string matchingShopInterfaceName = shop.MatchingShopInterfaceName;
				PoolManager pool = PoolManager.Instance;
				int item = 1 + pool.Pool.Count;
				int num = 0;
				if (!(pool.BaseVehicleAllocationsForShop.TryGetValue(matchingShopInterfaceName, out var value) && value))
				{
					num++;
				}
				int num2 = pool.Allocations.Values.Count((DeliveryVehicle v) => pool.Pool.Contains(v));
				int num3 = pool.Pool.Count - num2;
				num += num3;
				return (available: num, total: item);
			}
		}
	}
	[HarmonyPatch(typeof(DeliveryInstance))]
	internal static class DeliveryInstancePatches
	{
		internal static readonly Logger Logger = new Logger("DeliveryInstancePatches");

		[HarmonyPatch("SetStatus")]
		[HarmonyPrefix]
		private static bool UsePoolSetStatus(DeliveryInstance __instance, EDeliveryStatus status)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Invalid comparison between Unknown and I4
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Invalid comparison between Unknown and I4
			lock (PoolManager.Lock)
			{
				string text = $"Setting delivery status to {status} for delivery {__instance.DeliveryID}";
				Console.Log(Object.op_Implicit(text), (Object)null);
				Logger.Msg(text);
				__instance.Status = status;
				ShopInterface shopInterface = NetworkSingleton<DeliveryManager>.Instance.GetShopInterface(__instance.StoreName);
				if ((int)status != 2)
				{
					if ((int)status == 3)
					{
						if ((Object)(object)__instance.ActiveVehicle == (Object)(object)shopInterface.DeliveryVehicle)
						{
							PoolManager.Instance.SetBaseAllocation(__instance.StoreName, allocated: false);
						}
						PoolManager.Instance.FreeAllocation(__instance.DeliveryID);
						if ((Object)(object)__instance.ActiveVehicle != (Object)null)
						{
							__instance.ActiveVehicle.Deactivate();
						}
						UnityEvent onDeliveryCompleted = __instance.onDeliveryCompleted;
						if (onDeliveryCompleted != null)
						{
							onDeliveryCompleted.Invoke();
						}
					}
				}
				else
				{
					if (PoolManager.Instance.Allocations.TryGetValue(__instance.DeliveryID, out DeliveryVehicle value))
					{
						__instance.ActiveVehicle = value;
					}
					else
					{
						__instance.ActiveVehicle = shopInterface.DeliveryVehicle;
					}
					__instance.ActiveVehicle.Activate(__instance);
				}
				return false;
			}
		}

		[HarmonyPatch("AddItemsToDeliveryVehicle")]
		[HarmonyPrefix]
		private static bool UsePoolAddItemsToDeliveryVehicle(DeliveryInstance __instance)
		{
			lock (PoolManager.Lock)
			{
				ShopInterface shopInterface = NetworkSingleton<DeliveryManager>.Instance.GetShopInterface(__instance.StoreName);
				if (!PoolManager.Instance.Allocations.TryGetValue(__instance.DeliveryID, out DeliveryVehicle value))
				{
					value = ((shopInterface != null) ? shopInterface.DeliveryVehicle : null);
				}
				Il2CppReferenceArray<StringIntPair> items = __instance.Items;
				foreach (StringIntPair item2 in (Il2CppArrayBase<StringIntPair>)(object)items)
				{
					ItemDefinition item = Registry.GetItem(item2.String);
					int num = item2.Int;
					while (num > 0)
					{
						int num2 = Mathf.Min(num, ((BaseItemDefinition)item).StackLimit);
						num -= num2;
						ItemInstance defaultInstance = item.GetDefaultInstance(num2);
						value.Vehicle.Storage.InsertItem(defaultInstance, Object.op_Implicit((Object)(object)item));
					}
				}
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(DeliveryVehicle))]
	internal class DeliveryVehiclePatch
	{
		[HarmonyPatch("Deactivate")]
		[HarmonyPostfix]
		private static void NullActiveDelivery(DeliveryVehicle __instance)
		{
			DeliveryInstance activeDelivery = __instance.ActiveDelivery;
			object obj;
			if (activeDelivery == null)
			{
				obj = null;
			}
			else
			{
				LoadingDock loadingDock = activeDelivery.LoadingDock;
				obj = ((loadingDock != null) ? loadingDock.VehicleDetector : null);
			}
			if ((Object)obj != (Object)null)
			{
				__instance.ActiveDelivery.LoadingDock.SetOccupant((LandVehicle)null);
				__instance.ActiveDelivery.LoadingDock.VehicleDetector.Clear();
			}
			if (__instance.ActiveDelivery != null)
			{
				__instance.ActiveDelivery = null;
			}
		}
	}
	[HarmonyPatch(typeof(DeliveriesLoader))]
	internal static class LoaderPatch
	{
		internal static readonly Logger Logger = new Logger("LoaderPatch");

		[HarmonyPatch("Load")]
		[HarmonyPrefix]
		private static bool Load(DeliveriesLoader __instance, string mainPath)
		{
			bool flag = false;
			string text = default(string);
			if (((Loader)__instance).TryLoadFile(Path.Combine(mainPath, "Deliveries"), ref text, true) || ((Loader)__instance).TryLoadFile(mainPath, ref text, true))
			{
				DeliveriesData val = null;
				try
				{
					val = JsonUtility.FromJson<DeliveriesData>(text);
				}
				catch (Exception ex)
				{
					Debug.LogError(Object.op_Implicit("Error loading data: " + ex.Message));
					Logger.Debug("Error loading data: " + ex.Message);
				}
				if (val != null && val.ActiveDeliveries != null)
				{
					LoadDelivery(val);
					if (val.DeliveryVehicles != null)
					{
						flag = true;
						VehicleData[] array = Il2CppArrayBase<VehicleData>.op_Implicit((Il2CppArrayBase<VehicleData>)(object)val.DeliveryVehicles);
						VehicleData[] array2 = array;
						foreach (VehicleData data in array2)
						{
							LoadVehicle(data, mainPath);
						}
					}
				}
			}
			if (!flag && Directory.Exists(mainPath))
			{
				Console.Log(Object.op_Implicit("Loading legacy delivery vehicles at: " + mainPath), (Object)null);
				string text2 = Path.Combine(mainPath, "DeliveryVehicles");
				List<DirectoryInfo> directories = ((Loader)__instance).GetDirectories(text2);
				for (int j = 0; j < directories.Count; j++)
				{
					__instance.LoadVehicle(((FileSystemInfo)directories[j]).FullName);
				}
			}
			return false;
		}

		private static void LoadVehicle(VehicleData data, string path)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			Logger.Debug("Processing GUID " + data.GUID);
			LandVehicle val;
			lock (PoolManager.Lock)
			{
				DeliveryVehicle? obj = ((IEnumerable<DeliveryVehicle>)PoolManager.Instance.Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle dv) => ((object)dv.Vehicle.GUID/*cast due to .constrained prefix*/).ToString() == data.GUID));
				val = ((obj != null) ? obj.Vehicle : null);
			}
			if ((Object)(object)val == (Object)null)
			{
				Logger.Debug("GUID " + data.GUID + " not found in Pool, lookup via GUIDManager");
				val = GUIDManager.GetObject<LandVehicle>(new Guid(data.GUID));
			}
			if ((Object)(object)val == (Object)null)
			{
				Logger.Error("Vehicle not found with GUID", data.GUID);
				Console.LogError(Object.op_Implicit("LoadVehicle: Vehicle not found with GUID " + data.GUID), (Object)null);
			}
			else
			{
				LoadVehicle(val, data, path);
			}
		}

		private static void LoadVehicle(LandVehicle vehicle, VehicleData data, string containerPath)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Logger.Debug($"Processing vehicle {((Object)vehicle).name} with GUID {vehicle.GUID}");
			if ((Object)(object)vehicle.Storage != (Object)null)
			{
				if (data.VehicleContents != null && data.VehicleContents.Items != null)
				{
					DeserializedItemSet val = default(DeserializedItemSet);
					if (ItemSet.TryDeserialize(data.VehicleContents, ref val))
					{
						val.LoadTo(vehicle.Storage.ItemSlots);
					}
				}
				else if (File.Exists(Path.Combine(containerPath, "Contents.json")))
				{
					Console.LogWarning(Object.op_Implicit("Loading legacy vehicle contents."), (Object)null);
					string text = default(string);
					DeserializedItemSet val2 = default(DeserializedItemSet);
					if (vehicle.Loader.TryLoadFile(containerPath, "Contents", ref text) && ItemSet.TryDeserialize(text, ref val2))
					{
						val2.LoadTo(vehicle.Storage.ItemSlots);
					}
				}
			}
			if (data.SpraySurfaces == null)
			{
				return;
			}
			try
			{
				for (int i = 0; i < data.SpraySurfaces.Count; i++)
				{
					if (((Il2CppArrayBase<SpraySurface>)(object)vehicle._spraySurfaces).Length > i)
					{
						SpraySurface obj = ((Il2CppArrayBase<SpraySurface>)(object)vehicle._spraySurfaces)[i];
						if (obj != null)
						{
							obj.Set((NetworkConnection)null, ((Il2CppObjectBase)data.SpraySurfaces[i].Strokes.ToArray()).Cast<Il2CppReferenceArray<SprayStroke>>(), data.SpraySurfaces[i].ContainsCartelGraffiti);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Logger.Error("Exception thrown while loading saved graffities", ex);
			}
		}

		private static DeliveryVehicle? FindVehicleByGuid(string guid)
		{
			lock (PoolManager.Lock)
			{
				DeliveryVehicle val = ((IEnumerable<DeliveryVehicle>)PoolManager.Instance.Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle dv) => dv.GUID.ToString() == guid));
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			Enumerator<ShopInterface> enumerator = ShopInterface.AllShops.GetEnumerator();
			while (enumerator.MoveNext())
			{
				ShopInterface current = enumerator.Current;
				if ((Object)(object)current.DeliveryVehicle != (Object)null && current.DeliveryVehicle.GUID.ToString() == guid)
				{
					return current.DeliveryVehicle;
				}
			}
			return null;
		}

		private static void LoadDelivery(DeliveriesData data)
		{
			if (data == null)
			{
				return;
			}
			if (data.ActiveDeliveries != null)
			{
				foreach (AllocationEntry item in VehicleSave.Instance.AllocationMap.ToList())
				{
					DeliveryVehicle val = FindVehicleByGuid(item.VehicleGUID);
					if ((Object)(object)val != (Object)null)
					{
						PoolManager.Instance.AllocateDirectly(item.DeliveryID, val);
						Logger.Debug("Restored allocation: " + item.DeliveryID + " -> " + item.VehicleGUID);
					}
					else
					{
						Logger.Warning("Could not find vehicle for allocation: " + item.VehicleGUID);
					}
				}
				foreach (BaseAllocationEntry item2 in VehicleSave.Instance.BaseAllocationMap.ToList())
				{
					PoolManager.Instance.SetBaseAllocation(item2.ShopName, item2.IsAllocated);
					Logger.Debug($"Restored base allocation: {item2.ShopName} = {item2.IsAllocated}");
				}
				foreach (DeliveryInstance item3 in (Il2CppArrayBase<DeliveryInstance>)(object)data.ActiveDeliveries)
				{
					NetworkSingleton<DeliveryManager>.Instance.SendDelivery(item3);
				}
			}
			if (data.DeliveryHistory != null)
			{
				foreach (DeliveryReceipt item4 in (Il2CppArrayBase<DeliveryReceipt>)(object)data.DeliveryHistory)
				{
					NetworkSingleton<DeliveryManager>.Instance._deliveryHistory.Add(item4);
				}
			}
			if (data.DisplayedDeliveryHistory == null)
			{
				return;
			}
			foreach (DeliveryReceipt item5 in (Il2CppArrayBase<DeliveryReceipt>)(object)data.DisplayedDeliveryHistory)
			{
				NetworkSingleton<DeliveryManager>.Instance._displayedDeliveryHistory.Add(item5);
			}
		}
	}
	public class PoolManager
	{
		internal static readonly Logger Logger = new Logger("PoolManager");

		internal static readonly object Lock = new object();

		public static PoolManager Instance { get; } = new PoolManager();

		public HashSet<DeliveryVehicle> Pool { get; } = new HashSet<DeliveryVehicle>();

		internal Dictionary<string, DeliveryVehicle> Allocations { get; } = new Dictionary<string, DeliveryVehicle>();

		internal Dictionary<string, bool> BaseVehicleAllocationsForShop { get; } = new Dictionary<string, bool>();

		internal int PoolCount
		{
			get
			{
				lock (Lock)
				{
					return Pool.Count;
				}
			}
		}

		internal int AllocationCount
		{
			get
			{
				lock (Lock)
				{
					return Allocations.Count;
				}
			}
		}

		public void AddToPool(DeliveryVehicle deliveryVehicle, bool notify = true)
		{
			lock (Lock)
			{
				Pool.Add(deliveryVehicle);
				if (notify)
				{
					NetworkConvenienceMethods.NotifyVehicleAdded(deliveryVehicle);
				}
			}
		}

		public void AddToSaveData(DeliveryVehicle deliveryVehicle)
		{
			if ((Object)(object)deliveryVehicle == (Object)null)
			{
				throw new ArgumentNullException("deliveryVehicle");
			}
			VehicleSave.Instance.AddVehicle(deliveryVehicle.Vehicle);
			NetworkConvenienceMethods.NotifyVehicleCreated(deliveryVehicle);
		}

		public DeliveryVehicle? GetFirstFree()
		{
			lock (Lock)
			{
				DeliveryVehicle val = ((IEnumerable<DeliveryVehicle>)Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle dv) => dv.ActiveDelivery == null && !Allocations.ContainsValue(dv)));
				if (Time.frameCount % 30 == 0)
				{
					Logger.Debug("Pool lookup: " + (((Object)(object)val == (Object)null) ? "null" : "not null"));
				}
				return val;
			}
		}

		public DeliveryVehicle GetOrAllocateFirstFree(string deliveryId)
		{
			lock (Lock)
			{
				Logger.Debug("GetOrAllocateFirstFree called for: " + deliveryId);
				if (Allocations.TryGetValue(deliveryId, out DeliveryVehicle value))
				{
					Logger.Debug("Already allocated, returning existing");
					return value;
				}
				DeliveryVehicle firstFree = GetFirstFree();
				if ((Object)(object)firstFree == (Object)null)
				{
					Logger.Debug($"No free vehicle found! Pool count: {Pool.Count}, Allocations count: {Allocations.Count}");
					foreach (KeyValuePair<string, DeliveryVehicle> allocation in Allocations)
					{
						Logger logger = Logger;
						object[] array = new object[1];
						string key = allocation.Key;
						DeliveryInstance activeDelivery = allocation.Value.ActiveDelivery;
						array[0] = "Allocation: " + key + " -> Vehicle has ActiveDelivery: " + (((activeDelivery != null) ? activeDelivery.DeliveryID : null) ?? "null");
						logger.Debug(array);
					}
					throw new ArgumentException("Tried to allocate a non-free vehicle");
				}
				Allocations.Add(deliveryId, firstFree);
				Logger.Debug("Allocated new vehicle for " + deliveryId + ", vehicle: " + firstFree.GUID);
				VehicleSave.Instance.AddAllocation(deliveryId, firstFree);
				NetworkConvenienceMethods.NotifyAllocation(deliveryId, firstFree, isAllocated: true);
				return firstFree;
			}
		}

		internal void AllocateDirectly(string deliveryId, DeliveryVehicle deliveryVehicle)
		{
			lock (Lock)
			{
				Logger.Debug("AllocateDirectly called for: " + deliveryId);
				if (Allocations.TryGetValue(deliveryId, out DeliveryVehicle _))
				{
					Logger.Debug("Already allocated, returning");
					return;
				}
				Allocations.Add(deliveryId, deliveryVehicle);
				Logger.Debug("Directly allocated vehicle for " + deliveryId + ", vehicle: " + deliveryVehicle.GUID);
				VehicleSave.Instance.AddAllocation(deliveryId, deliveryVehicle);
				NetworkConvenienceMethods.NotifyAllocation(deliveryId, deliveryVehicle, isAllocated: true);
			}
		}

		internal void SetBaseAllocation(string shopName, bool allocated)
		{
			lock (Lock)
			{
				BaseVehicleAllocationsForShop[shopName] = allocated;
			}
			VehicleSave.Instance.SyncBaseAllocation(shopName, allocated);
			NetworkConvenienceMethods.NotifyBaseAllocation(shopName, allocated);
		}

		public void FreeAllocation(string deliveryId)
		{
			lock (Lock)
			{
				Logger.Debug("Free custom allocation: " + deliveryId);
				if (Allocations.TryGetValue(deliveryId, out DeliveryVehicle value))
				{
					Allocations.Remove(deliveryId);
					VehicleSave.Instance.RemoveAllocation(deliveryId);
					NetworkConvenienceMethods.NotifyAllocation(deliveryId, value, isAllocated: false);
				}
			}
		}

		internal void ClearAll()
		{
			lock (Lock)
			{
				Pool.Clear();
				Allocations.Clear();
				BaseVehicleAllocationsForShop.Clear();
			}
			VehicleSave instance = VehicleSave.Instance;
			instance.ClearAllocations();
			instance.ClearBaseAllocations();
		}

		internal bool RemoveFromPool(DeliveryVehicle vehicle)
		{
			lock (Lock)
			{
				List<string> list = (from x in Allocations
					where (Object)(object)x.Value == (Object)(object)vehicle
					select x.Key).ToList();
				foreach (string item in list)
				{
					Allocations.Remove(item);
					VehicleSave.Instance.RemoveAllocation(item);
				}
				VehicleSave.Instance.RemoveAllocationsForVehicle(vehicle);
				return Pool.Remove(vehicle);
			}
		}

		internal DeliveryVehicle? LastPoolVehicle()
		{
			lock (Lock)
			{
				return Pool.LastOrDefault();
			}
		}
	}
	[HarmonyPatch(typeof(Wheel))]
	internal class WheelPatch
	{
		[HarmonyPatch("OnWeatherChange")]
		[HarmonyPrefix]
		private static bool ExitIfNull(Wheel __instance, WeatherConditions newConditions)
		{
			if ((Object)(object)((__instance != null) ? __instance.vehicle : null) == (Object)null)
			{
				return false;
			}
			if (newConditions != null)
			{
				_ = newConditions.Rainy;
				if (0 == 0)
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(DeliveryVehicle))]
	internal static class DeliveryVehicleAwakePatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPrefix]
		private static bool ExitIfNull(DeliveryVehicle __instance)
		{
			Guid val = default(Guid);
			if (Guid.TryParse(__instance.GUID, ref val))
			{
				return true;
			}
			if ((Object)(object)((Component)__instance).GetComponent<LandVehicle>() == (Object)null)
			{
				return false;
			}
			__instance.Vehicle = ((Component)__instance).GetComponent<LandVehicle>();
			__instance.Deactivate();
			return false;
		}
	}
}
namespace MultiDelivery.Persistence
{
	public class PersistentDropoffQuestData : Saveable
	{
		[SaveableField("MessageData")]
		public bool HasMessaged;

		public static PersistentDropoffQuestData Instance { get; private set; } = new PersistentDropoffQuestData();

		public PersistentDropoffQuestData()
		{
			Instance = this;
		}
	}
	[Serializable]
	public class AllocationEntry
	{
		public string DeliveryID;

		public string VehicleGUID;
	}
	[Serializable]
	public class BaseAllocationEntry
	{
		public string ShopName;

		public bool IsAllocated;
	}
	public class VehicleSave : Saveable
	{
		[SaveableField("VehicleSaveData")]
		private List<VehicleSaveDto> _dtos = new List<VehicleSaveDto>();

		[SaveableField("AllocationMap")]
		private List<AllocationEntry> _allocationMap = new List<AllocationEntry>();

		[SaveableField("BaseAllocationMap")]
		private List<BaseAllocationEntry> _baseAllocationMap = new List<BaseAllocationEntry>();

		private static readonly Logger Logger = new Logger("VehicleSave");

		private static Transform _parent;

		public override SaveableLoadOrder LoadOrder => (SaveableLoadOrder)0;

		public IReadOnlyList<AllocationEntry> AllocationMap => _allocationMap;

		public IReadOnlyList<BaseAllocationEntry> BaseAllocationMap => _baseAllocationMap;

		public static VehicleSave Instance { get; set; } = new VehicleSave();

		public VehicleSave()
		{
			Instance = this;
		}

		public void AddVehicle(LandVehicle vehicle)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			VehicleSaveDto item = new VehicleSaveDto
			{
				Guid = ((object)vehicle.GUID/*cast due to .constrained prefix*/).ToString(),
				VehicleType = vehicle.VehicleCode,
				Color = vehicle.Color.displayedColor
			};
			if (!_dtos.Contains(item))
			{
				_dtos.Add(item);
			}
		}

		internal void AddAllocation(string deliveryId, DeliveryVehicle vehicle)
		{
			string vehicleGUID = vehicle.GUID.ToString();
			_allocationMap.RemoveAll((AllocationEntry e) => e.DeliveryID == deliveryId);
			_allocationMap.Add(new AllocationEntry
			{
				DeliveryID = deliveryId,
				VehicleGUID = vehicleGUID
			});
		}

		internal void RemoveAllocation(string deliveryId)
		{
			_allocationMap.RemoveAll((AllocationEntry e) => e.DeliveryID == deliveryId);
		}

		internal void RemoveAllocationsForVehicle(DeliveryVehicle vehicle)
		{
			string guid = vehicle.GUID.ToString();
			_allocationMap.RemoveAll((AllocationEntry e) => e.VehicleGUID == guid);
		}

		internal void ClearAllocations()
		{
			_allocationMap.Clear();
		}

		internal void ClearBaseAllocations()
		{
			_baseAllocationMap.Clear();
		}

		internal void SyncBaseAllocation(string shopName, bool allocated)
		{
			_baseAllocationMap.RemoveAll((BaseAllocationEntry e) => e.ShopName == shopName);
			_baseAllocationMap.Add(new BaseAllocationEntry
			{
				ShopName = shopName,
				IsAllocated = allocated
			});
		}

		internal void RemoveVehicle(DeliveryVehicle vehicle)
		{
			_dtos.RemoveAll((VehicleSaveDto dto) => dto.Guid.ToString() == vehicle.GUID.ToString());
		}

		protected override void OnLoaded()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			Logger.Msg($"OnLoaded: Loading {_dtos.Count} vehicles");
			if ((Object)(object)_parent == (Object)null)
			{
				GameObject val = GameObject.Find("VehiclePool");
				if ((Object)(object)val == (Object)null)
				{
					val = new GameObject("VehiclePool");
				}
				_parent = val.transform;
			}
			Guid guid = default(Guid);
			for (int i = 0; i < _dtos.Count; i++)
			{
				Logger.Debug($"Loading vehicle {i}: {_dtos[i].Guid}");
				((Guid)(ref guid))..ctor(_dtos[i].Guid);
				LandVehicle val2 = new LandVehicleBuilder().WithVehicleCode(_dtos[i].VehicleType).WithVehicleName($"Additional Delivery Vehicle {i + 1}").WithGuid(guid)
					.WithColor(_dtos[i].Color)
					.WithParent(_parent)
					.Build();
				MelonCoroutines.Start(DeferredSetColor(val2, _dtos[i].Color));
				Logger.Debug($"Built LandVehicle: {val2.vehicleName}, ObjectId: {((NetworkBehaviour)val2).ObjectId}");
				DeliveryVehicle val3 = new DeliveryVehicleBuilder().WithLandVehicle(val2).WithGuid(guid).Build();
				Logger.Debug("Built DeliveryVehicle: " + val3.GUID);
				PoolManager.Instance.AddToPool(val3);
				Logger.Debug($"Added to pool. Pool count now: {PoolManager.Instance.PoolCount}");
			}
			Logger.Msg($"OnLoaded complete. Final pool count: {PoolManager.Instance.PoolCount}");
		}

		private IEnumerator DeferredSetColor(LandVehicle vehicle, EVehicleColor color)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			while ((Object)(object)Player.Local == (Object)null || (Object)(object)((Component)Player.Local).gameObject == (Object)null)
			{
				yield return null;
			}
			yield return null;
			vehicle.ApplyColor(color);
		}
	}
	public record VehicleSaveDto
	{
		public string Guid { get; set; }

		public string VehicleType { get; set; }

		public EVehicleColor Color { get; set; }
	}
}
namespace MultiDelivery.Network
{
	public class DeliveryNetworkManager : IDeliveryNetworkManager, IDisposable
	{
		private SteamNetworkClient _client;

		private readonly Logger _logger;

		private const string ModDataKey = "MultiDelivery_Version";

		private const string ModVersion = "1.0.0";

		public bool IsInLobby
		{
			get
			{
				SteamNetworkClient client = _client;
				return client != null && client.IsInLobby;
			}
		}

		public bool IsHost
		{
			get
			{
				SteamNetworkClient client = _client;
				return client != null && client.IsHost;
			}
		}

		public bool IsSingleplayer => !IsInLobby;

		public bool HostOrSingleplayer => IsHost || IsSingleplayer;

		public DeliveryNetworkManager()
		{
			_logger = new Logger("Network");
		}

		public bool Initialize()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			try
			{
				NetworkRules val = new NetworkRules
				{
					EnableRelay = true,
					AcceptOnlyFriends = false
				};
				_client = new SteamNetworkClient(val);
				if (!_client.Initialize())
				{
					_logger.Error("Failed to initialize SteamNetworkClient");
					return false;
				}
				RegisterMessageHandlers();
				SubscribeToEvents();
				_logger.Msg("Network manager initialized successfully");
				return true;
			}
			catch (Exception value)
			{
				_client = null;
				_logger.Error($"Failed to initialize network manager: {value}");
				return false;
			}
		}

		public void RegisterLoggerSettings()
		{
			_logger.RaiseDebug = MultiDelivery.NetworkLogging?.Value ?? false;
			((MelonEventBase<LemonAction<bool, bool>>)(object)MultiDelivery.NetworkLogging?.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)delegate(bool _, bool newValue)
			{
				_logger.RaiseDebug = newValue;
			}, 0, false);
		}

		private void RegisterMessageHandlers()
		{
			_client.RegisterMessageHandler<VehicleAddedMessage>((Action<VehicleAddedMessage, CSteamID>)OnVehicleAdded);
			_client.RegisterMessageHandler<VehicleCreatedMessage>((Action<VehicleCreatedMessage, CSteamID>)OnVehicleCreated);
			_client.RegisterMessageHandler<VehiclePoolSyncRequest>((Action<VehiclePoolSyncRequest, CSteamID>)OnPoolSyncRequest);
			_client.RegisterMessageHandler<VehiclePoolSyncResponse>((Action<VehiclePoolSyncResponse, CSteamID>)OnPoolSyncResponse);
			_client.RegisterMessageHandler<VehicleAllocationMessage>((Action<VehicleAllocationMessage, CSteamID>)OnVehicleAllocation);
			_client.RegisterMessageHandler<BaseVehicleAllocationMessage>((Action<BaseVehicleAllocationMessage, CSteamID>)OnBaseVehicleAllocation);
		}

		private void SubscribeToEvents()
		{
			_client.OnLobbyCreated += OnLobbyCreated;
			_client.OnLobbyJoined += OnLobbyJoined;
			_client.OnMemberJoined += OnMemberJoined;
			_client.OnLobbyLeft += OnLobbyLeft;
		}

		public void Update()
		{
			SteamNetworkClient client = _client;
			if (client != null)
			{
				client.ProcessIncomingMessages();
			}
		}

		public void Dispose()
		{
			SteamNetworkClient client = _client;
			if (client != null)
			{
				client.Dispose();
			}
		}

		public async void BroadcastVehicleAdded(DeliveryVehicle vehicle)
		{
			if (!IsSingleplayer)
			{
				VehicleAddedMessage message = new VehicleAddedMessage
				{
					ObjectId = ((NetworkBehaviour)vehicle.Vehicle).ObjectId,
					VehicleGuid = vehicle.GUID,
					VehicleName = vehicle.Vehicle.vehicleName,
					VehicleCode = vehicle.Vehicle.VehicleCode,
					VehicleColor = (int)vehicle.Vehicle.Color.displayedColor
				};
				_logger.D($"Broadcasting vehicle added: ObjectId={message.ObjectId}, GUID={message.VehicleGuid}");
				await _client.BroadcastMessageAsync((P2PMessage)(object)message);
			}
		}

		public async void BroadcastVehicleCreated(DeliveryVehicle vehicle)
		{
			if (!IsSingleplayer && !IsHost)
			{
				VehicleCreatedMessage message = new VehicleCreatedMessage
				{
					ObjectId = ((NetworkBehaviour)vehicle.Vehicle).ObjectId,
					VehicleGuid = vehicle.GUID
				};
				_logger.D($"Broadcasting vehicle created: ObjectId={message.ObjectId}");
				await _client.BroadcastMessageAsync((P2PMessage)(object)message);
			}
		}

		public async void BroadcastVehicleAllocation(string deliveryId, DeliveryVehicle vehicle, bool isAllocated)
		{
			if (!IsSingleplayer)
			{
				VehicleAllocationMessage message = new VehicleAllocationMessage
				{
					DeliveryId = deliveryId,
					VehicleGuid = vehicle.GUID,
					IsAllocated = isAllocated
				};
				_logger.D($"Broadcasting allocation: Delivery={deliveryId}, Vehicle={vehicle.GUID}, Allocated={isAllocated}");
				await _client.BroadcastMessageAsync((P2PMessage)(object)message);
			}
		}

		public async void BroadcastBaseVehicleAllocation(string shopName, bool isAllocated)
		{
			if (!IsSingleplayer)
			{
				BaseVehicleAllocationMessage message = new BaseVehicleAllocationMessage
				{
					ShopName = shopName,
					IsAllocated = isAllocated
				};
				_logger.D($"Broadcasting base allocation: Shop={shopName}, Allocated={isAllocated}");
				await _client.BroadcastMessageAsync((P2PMessage)(object)message);
			}
		}

		private void OnVehicleAdded(VehicleAddedMessage message, CSteamID cSteamID)
		{
			_logger.D($"Received VehicleAdded: ObjectId={message.ObjectId}, GUID={message.VehicleGuid}");
			MelonCoroutines.Start(ProcessMessage());
			IEnumerator ProcessMessage()
			{
				yield return ExponentialBackoff(delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByName = SceneManager.GetSceneByName("Main");
					return ((Scene)(ref sceneByName)).isLoaded;
				}, 1f, 30f, 60f);
				yield return ExponentialBackoff(() => (Object)(object)FindLandVehicleByObjectId(message.ObjectId) != (Object)null, 1f, 30f, 60f);
				try
				{
					LandVehicle landVehicle = FindLandVehicleByObjectId(message.ObjectId);
					if ((Object)(object)landVehicle == (Object)null)
					{
						_logger.Warning($"LandVehicle with ObjectId {message.ObjectId} not found - may not have spawned yet");
					}
					else
					{
						Guid deliveryGuid = new Guid(message.VehicleGuid);
						landVehicle.SetGUID(deliveryGuid);
						landVehicle.ApplyColor((EVehicleColor)message.VehicleColor);
						DeliveryVehicle deliveryVehicle = ((Component)landVehicle).GetComponent<DeliveryVehicle>() ?? new DeliveryVehicleBuilder().WithLandVehicle(landVehicle).WithGuid(deliveryGuid).Build();
						PoolManager.Instance.AddToPool(deliveryVehicle, notify: false);
						_logger.D($"Added vehicle to pool: ObjectId={message.ObjectId}, DeliveryGUID={message.VehicleGuid}");
					}
				}
				catch (Exception value)
				{
					_logger.Error($"Failed to add vehicle: {value}");
				}
			}
		}

		private void OnVehicleCreated(VehicleCreatedMessage message, CSteamID senderId)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (IsHost)
			{
				_logger.D($"Received vehicle created message from {senderId}");
				MelonCoroutines.Start(ProcessMessage());
			}
			IEnumerator ProcessMessage()
			{
				yield return ExponentialBackoff(delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByName = SceneManager.GetSceneByName("Main");
					return ((Scene)(ref sceneByName)).isLoaded;
				}, 1f, 30f, 60f);
				yield return ExponentialBackoff(() => (Object)(object)FindLandVehicleByObjectId(message.ObjectId) != (Object)null, 1f, 30f, 60f);
				try
				{
					LandVehicle landVehicle = FindLandVehicleByObjectId(message.ObjectId);
					if ((Object)(object)landVehicle == (Object)null)
					{
						_logger.Error($"LandVehicle with ObjectId {message.ObjectId} not found");
					}
					else
					{
						VehicleSave.Instance.AddVehicle(landVehicle);
						_logger.D($"Added created vehicle to save data: ObjectId={message.ObjectId}, GUID={message.VehicleGuid}");
					}
				}
				catch (Exception value)
				{
					_logger.Error($"Failed to create vehicle: {value}");
				}
			}
		}

		private async void OnPoolSyncRequest(VehiclePoolSyncRequest message, CSteamID senderId)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!IsHost)
			{
				return;
			}
			_logger.D($"Received pool sync request from {senderId}");
			try
			{
				VehiclePoolSyncResponse response = new VehiclePoolSyncResponse();
				lock (PoolManager.Lock)
				{
					foreach (DeliveryVehicle vehicle in PoolManager.Instance.Pool)
					{
						response.Vehicles.Add(new VehiclePoolSyncResponse.VehicleData
						{
							ObjectId = ((NetworkBehaviour)vehicle.Vehicle).ObjectId,
							Guid = vehicle.GUID,
							Name = vehicle.Vehicle.vehicleName,
							Code = vehicle.Vehicle.VehicleCode,
							Color = (int)vehicle.Vehicle.Color.displayedColor
						});
					}
				}
				_logger.D($"Sending pool sync with {response.Vehicles.Count} vehicles");
				await _client.SendMessageToPlayerAsync(senderId, (P2PMessage)(object)response);
			}
			catch (Exception value)
			{
				_logger.Error($"Failed to send pool sync: {value}");
			}
		}

		private void OnPoolSyncResponse(VehiclePoolSyncResponse message, CSteamID senderId)
		{
			if (!IsHost)
			{
				_logger.D($"Received pool sync response with {message.Vehicles.Count} vehicles");
				MelonCoroutines.Start(ProcessMessage());
			}
			IEnumerator ProcessMessage()
			{
				yield return ExponentialBackoff(delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByName = SceneManager.GetSceneByName("Main");
					return ((Scene)(ref sceneByName)).isLoaded;
				}, 1f, 30f, 60f);
				yield return ExponentialBackoff(() => message.Vehicles.All((VehiclePoolSyncResponse.VehicleData v) => (Object)(object)FindLandVehicleByObjectId(v.ObjectId) != (Object)null), 1f, 30f, 60f);
				try
				{
					foreach (VehiclePoolSyncResponse.VehicleData vehicleData in message.Vehicles)
					{
						LandVehicle landVehicle = FindLandVehicleByObjectId(vehicleData.ObjectId);
						if ((Object)(object)landVehicle == (Object)null)
						{
							_logger.Warning($"LandVehicle with ObjectId {vehicleData.ObjectId} not found - skipping");
						}
						else
						{
							Guid deliveryGuid = new Guid(vehicleData.Guid);
							landVehicle.SetGUID(deliveryGuid);
							landVehicle.ApplyColor((EVehicleColor)vehicleData.Color);
							DeliveryVehicle deliveryVehicle = ((Component)landVehicle).GetComponent<DeliveryVehicle>() ?? new DeliveryVehicleBuilder().WithLandVehicle(landVehicle).WithGuid(deliveryGuid).Build();
							PoolManager.Instance.AddToPool(deliveryVehicle, notify: false);
						}
					}
					_logger.D($"Pool synchronized: {PoolManager.Instance.Pool.Count} vehicles");
				}
				catch (Exception value)
				{
					_logger.Error($"Failed to sync pool: {value}");
				}
			}
		}

		private void OnVehicleAllocation(VehicleAllocationMessage message, CSteamID senderId)
		{
			_logger.D($"Received allocation: Delivery={message.DeliveryId}, Vehicle={message.VehicleGuid}, Allocated={message.IsAllocated}");
			MelonCoroutines.Start(ProcessMessage());
			IEnumerator ProcessMessage()
			{
				yield return ExponentialBackoff(delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByName = SceneManager.GetSceneByName("Main");
					return ((Scene)(ref sceneByName)).isLoaded;
				}, 1f, 30f, 60f);
				yield return ExponentialBackoff(delegate
				{
					lock (PoolManager.Lock)
					{
						if ((Object)(object)((IEnumerable<DeliveryVehicle>)PoolManager.Instance.Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle v) => v.GUID == message.VehicleGuid)) != (Object)null)
						{
							return true;
						}
					}
					Enumerator<ShopInterface> enumerator2 = ShopInterface.AllShops.GetEnumerator();
					while (enumerator2.MoveNext())
					{
						ShopInterface current = enumerator2.Current;
						if ((Object)(object)current.DeliveryVehicle != (Object)null && current.DeliveryVehicle.GUID == message.VehicleGuid)
						{
							return true;
						}
					}
					return false;
				}, 1f, 30f, 60f);
				try
				{
					DeliveryVehicle vehicle;
					lock (PoolManager.Lock)
					{
						vehicle = ((IEnumerable<DeliveryVehicle>)PoolManager.Instance.Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle v) => v.GUID == message.VehicleGuid));
					}
					if ((Object)(object)vehicle == (Object)null)
					{
						Enumerator<ShopInterface> enumerator = ShopInterface.AllShops.GetEnumerator();
						while (enumerator.MoveNext())
						{
							ShopInterface shop = enumerator.Current;
							if ((Object)(object)shop.DeliveryVehicle != (Object)null && shop.DeliveryVehicle.GUID == message.VehicleGuid)
							{
								vehicle = shop.DeliveryVehicle;
								break;
							}
						}
					}
					if ((Object)(object)vehicle == (Object)null)
					{
						_logger.Warning("Vehicle not found for allocation: " + message.VehicleGuid);
					}
					else
					{
						lock (PoolManager.Lock)
						{
							if (message.IsAllocated)
							{
								_logger.D("Trying to allocate " + message.VehicleGuid + " for delivery " + message.DeliveryId);
								if (!PoolManager.Instance.Allocations.ContainsKey(message.DeliveryId))
								{
									_logger.D("Allocating " + message.VehicleGuid + " for delivery " + message.DeliveryId);
									PoolManager.Instance.Allocations.Add(message.DeliveryId, vehicle);
								}
							}
							else
							{
								_logger.D("Deallocating " + message.VehicleGuid + " for delivery " + message.DeliveryId);
								PoolManager.Instance.Allocations.Remove(message.DeliveryId);
							}
						}
					}
				}
				catch (Exception value)
				{
					_logger.Error($"Failed to process allocation: {value}");
				}
			}
		}

		private void OnBaseVehicleAllocation(BaseVehicleAllocationMessage message, CSteamID senderId)
		{
			_logger.D($"Received base allocation: Shop={message.ShopName}, Allocated={message.IsAllocated}");
			lock (PoolManager.Lock)
			{
				try
				{
					PoolManager.Instance.BaseVehicleAllocationsForShop[message.ShopName] = message.IsAllocated;
				}
				catch (Exception value)
				{
					_logger.Error($"Failed to process base allocation: {value}");
				}
			}
		}

		private void OnLobbyCreated(object sender, LobbyCreatedEventArgs e)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			_logger.D($"Lobby created: {e.Lobby.LobbyId}");
			_client.SetMyData("MultiDelivery_Version", "1.0.0");
		}

		private void OnLobbyJoined(object sender, LobbyJoinedEventArgs e)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			_logger.D($"Joined lobby: {e.Lobby.LobbyId}");
			_client.SetMyData("MultiDelivery_Version", "1.0.0");
			if (!IsHost)
			{
				RequestPoolSync();
			}
		}

		private async void OnMemberJoined(object sender, MemberJoinedEventArgs e)
		{
			if (!IsHost)
			{
				return;
			}
			_logger.D("Member joined: " + e.Member.DisplayName);
			await Task.Delay(1000);
			VehiclePoolSyncResponse response = new VehiclePoolSyncResponse();
			lock (PoolManager.Lock)
			{
				foreach (DeliveryVehicle vehicle in PoolManager.Instance.Pool)
				{
					response.Vehicles.Add(new VehiclePoolSyncResponse.VehicleData
					{
						ObjectId = ((NetworkBehaviour)vehicle.Vehicle).ObjectId,
						Guid = vehicle.GUID,
						Name = vehicle.Vehicle.vehicleName,
						Code = vehicle.Vehicle.VehicleCode,
						Color = (int)vehicle.Vehicle.Color.displayedColor
					});
				}
			}
			_logger.D($"Sending pool sync to new member ({response.Vehicles.Count} vehicles)");
			await _client.SendMessageToPlayerAsync(e.Member.SteamId, (P2PMessage)(object)response);
		}

		private void OnLobbyLeft(object sender, LobbyLeftEventArgs e)
		{
			_logger.D("Left lobby: " + e.Reason);
		}

		private async void RequestPoolSync()
		{
			if (!IsSingleplayer && !IsHost)
			{
				List<MemberInfo> members = _client.GetLobbyMembers();
				MemberInfo host = ((IEnumerable<MemberInfo>)members).FirstOrDefault((Func<MemberInfo, bool>)((MemberInfo m) => m.IsOwner));
				if (host == null)
				{
					_logger.Error("Cannot request pool sync - no host found");
					return;
				}
				VehiclePoolSyncRequest message = new VehiclePoolSyncRequest
				{
					RequesterId = ((object)_client.LocalPlayerId/*cast due to .constrained prefix*/).ToString()
				};
				_logger.D("Requesting pool sync from host");
				await _client.SendMessageToPlayerAsync(host.SteamId, (P2PMessage)(object)message);
			}
		}

		private LandVehicle? FindLandVehicleByObjectId(int objectId)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Scene sceneByName = SceneManager.GetSceneByName("Main");
			if (!((Scene)(ref sceneByName)).isLoaded)
			{
				_logger.Error("Main scene is not loaded");
				return null;
			}
			Il2CppReferenceArray<GameObject> rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
			foreach (GameObject item in (Il2CppArrayBase<GameObject>)(object)rootGameObjects)
			{
				Il2CppArrayBase<LandVehicle> componentsInChildren = item.GetComponentsInChildren<LandVehicle>(true);
				foreach (LandVehicle item2 in componentsInChildren)
				{
					if (((NetworkBehaviour)item2).ObjectId == objectId)
					{
						_logger.D($"Found LandVehicle: ObjectId={objectId}, Name={item2.vehicleName}");
						return item2;
					}
				}
			}
			_logger.Warning($"LandVehicle with ObjectId {objectId} not found in Main scene");
			return null;
		}

		private static IEnumerator ExponentialBackoff(Func<bool> predicate, float initialDelay, float finalDelay, float timeout)
		{
			float delay = initialDelay;
			float elapsed = 0f;
			while (!predicate() && elapsed < timeout)
			{
				yield return (object)new WaitForSeconds(delay);
				elapsed += delay;
				delay = Mathf.Min(delay * 2f, finalDelay);
			}
		}
	}
	public interface IDeliveryNetworkManager : IDisposable
	{
		bool IsInLobby { get; }

		bool IsHost { get; }

		bool IsSingleplayer { get; }

		bool HostOrSingleplayer { get; }

		void RegisterLoggerSettings();

		bool Initialize();

		void Update();

		void BroadcastVehicleAdded(DeliveryVehicle vehicle);

		void BroadcastVehicleCreated(DeliveryVehicle vehicle);

		void BroadcastVehicleAllocation(string deliveryId, DeliveryVehicle vehicle, bool isAllocated);

		void BroadcastBaseVehicleAllocation(string shopName, bool isAllocated);
	}
	public class VehicleAddedMessage : P2PMessage
	{
		public override string MessageType => "VehicleAdded";

		public int ObjectId { get; set; }

		public string VehicleGuid { get; set; }

		public string VehicleName { get; set; }

		public string VehicleCode { get; set; }

		public int VehicleColor { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase($"\"ObjectId\":{ObjectId},\"VehicleGuid\":\"{VehicleGuid}\",\"VehicleName\":\"{VehicleName}\",\"VehicleCode\":\"{VehicleCode}\",\"VehicleColor\":{VehicleColor}");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			ObjectId = int.Parse(((P2PMessage)this).ExtractJsonValue(text, "ObjectId"));
			VehicleGuid = ((P2PMessage)this).ExtractJsonValue(text, "VehicleGuid");
			VehicleName = ((P2PMessage)this).ExtractJsonValue(text, "VehicleName");
			VehicleCode = ((P2PMessage)this).ExtractJsonValue(text, "VehicleCode");
			VehicleColor = int.Parse(((P2PMessage)this).ExtractJsonValue(text, "VehicleColor"));
		}
	}
	public class VehicleCreatedMessage : P2PMessage
	{
		public override string MessageType => "VehicleCreated";

		public int ObjectId { get; set; }

		public string VehicleGuid { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase($"\"ObjectId\":{ObjectId},\"VehicleGuid\":\"{VehicleGuid}\"");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			ObjectId = int.Parse(((P2PMessage)this).ExtractJsonValue(text, "ObjectId"));
			VehicleGuid = ((P2PMessage)this).ExtractJsonValue(text, "VehicleGuid");
		}
	}
	public class VehiclePoolSyncRequest : P2PMessage
	{
		public override string MessageType => "VehiclePoolSyncRequest";

		public string RequesterId { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase("\"RequesterId\":\"" + RequesterId + "\"");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			RequesterId = ((P2PMessage)this).ExtractJsonValue(text, "RequesterId");
		}
	}
	public class VehiclePoolSyncResponse : P2PMessage
	{
		[Serializable]
		public class VehicleData
		{
			public int ObjectId { get; set; }

			public string Guid { get; set; }

			public string Name { get; set; }

			public string Code { get; set; }

			public int Color { get; set; }
		}

		public override string MessageType => "VehiclePoolSyncResponse";

		public List<VehicleData> Vehicles { get; set; } = new List<VehicleData>();

		public override byte[] Serialize()
		{
			string text = string.Join(",", Vehicles.Select((VehicleData v) => $"{{\"ObjectId\":{v.ObjectId},\"Guid\":\"{v.Guid}\",\"Name\":\"{v.Name}\",\"Code\":\"{v.Code}\",\"Color\":{v.Color}}}"));
			string s = ((P2PMessage)this).CreateJsonBase("\"Vehicles\":[" + text + "]");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			int num = text.IndexOf("\"Vehicles\":[", StringComparison.Ordinal) + 12;
			int num2 = text.IndexOf("]", num, StringComparison.Ordinal);
			string text2 = text.Substring(num, num2 - num);
			Vehicles.Clear();
			if (string.IsNullOrWhiteSpace(text2))
			{
				return;
			}
			string[] array = text2.Split(new string[1] { "}," }, StringSplitOptions.None);
			string[] array2 = array;
			foreach (string text3 in array2)
			{
				string text4 = text3.TrimStart('{').TrimEnd('}') + "}";
				if (text4.Contains("ObjectId"))
				{
					Vehicles.Add(new VehicleData
					{
						ObjectId = int.Parse(((P2PMessage)this).ExtractJsonValue(text4, "ObjectId")),
						Guid = ((P2PMessage)this).ExtractJsonValue(text4, "Guid"),
						Name = ((P2PMessage)this).ExtractJsonValue(text4, "Name"),
						Code = ((P2PMessage)this).ExtractJsonValue(text4, "Code"),
						Color = int.Parse(((P2PMessage)this).ExtractJsonValue(text4, "Color"))
					});
				}
			}
		}
	}
	public class VehicleAllocationMessage : P2PMessage
	{
		public override string MessageType => "VehicleAllocation";

		public string DeliveryId { get; set; }

		public string VehicleGuid { get; set; }

		public bool IsAllocated { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase($"\"DeliveryId\":\"{DeliveryId}\",\"VehicleGuid\":\"{VehicleGuid}\",\"IsAllocated\":{IsAllocated.ToString().ToLower()}");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			DeliveryId = ((P2PMessage)this).ExtractJsonValue(text, "DeliveryId");
			VehicleGuid = ((P2PMessage)this).ExtractJsonValue(text, "VehicleGuid");
			IsAllocated = bool.Parse(((P2PMessage)this).ExtractJsonValue(text, "IsAllocated"));
		}
	}
	public class BaseVehicleAllocationMessage : P2PMessage
	{
		public override string MessageType => "BaseVehicleAllocation";

		public string ShopName { get; set; }

		public bool IsAllocated { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase("\"ShopName\":\"" + ShopName + "\",\"IsAllocated\":" + IsAllocated.ToString().ToLower());
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			ShopName = ((P2PMessage)this).ExtractJsonValue(text, "ShopName");
			IsAllocated = bool.Parse(((P2PMessage)this).ExtractJsonValue(text, "IsAllocated"));
		}
	}
	public static class NetworkConvenienceMethods
	{
		private static IDeliveryNetworkManager? _networkManager;

		public static bool HostOrSingleplayer => _networkManager?.HostOrSingleplayer ?? true;

		public static void InitializeNetworking(IDeliveryNetworkManager networkManager)
		{
			_networkManager = networkManager;
		}

		public static void NotifyVehicleAdded(DeliveryVehicle vehicle)
		{
			_networkManager?.BroadcastVehicleAdded(vehicle);
		}

		public static void NotifyVehicleCreated(DeliveryVehicle vehicle)
		{
			_networkManager?.BroadcastVehicleCreated(vehicle);
		}

		public static void NotifyAllocation(string deliveryId, DeliveryVehicle vehicle, bool isAllocated)
		{
			_networkManager?.BroadcastVehicleAllocation(deliveryId, vehicle, isAllocated);
		}

		public static void NotifyBaseAllocation(string shopName, bool isAllocated)
		{
			_networkManager?.BroadcastBaseVehicleAllocation(shopName, isAllocated);
		}
	}
	internal static class NetworkLoader
	{
		private static readonly Logger Logger = new Logger("NetworkLoader");

		internal static IDeliveryNetworkManager? Create()
		{
			if (AppDomain.CurrentDomain.GetAssemblies().All((Assembly a) => a.GetName().Name != "SteamNetworkLib"))
			{
				return null;
			}
			return CreateInternal();
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static IDeliveryNetworkManager? CreateInternal()
		{
			try
			{
				DeliveryNetworkManager deliveryNetworkManager = new DeliveryNetworkManager();
				deliveryNetworkManager.Initialize();
				return deliveryNetworkManager;
			}
			catch (Exception value)
			{
				Logger.Warning($"Failed to initialize network manager: {value}. If you're playing singleplayer, you may disregard this message.");
				return null;
			}
		}
	}
}
namespace MultiDelivery.Helpers
{
	public class DependenciesChecker
	{
		public class MissingDependencyInfo(string name, string version, List<DependencyUrl> urls, bool isRequired, string reason)
		{
			public string Name { get; set; } = name;

			public string Version { get; set; } = version;

			public List<DependencyUrl> Urls { get; set; } = urls;

			public bool IsRequired { get; set; } = isRequired;

			public string Reason { get; set; } = reason;
		}

		private static readonly Logger Logger = new Logger("DependenciesChecker");

		private readonly List<DependencyInfo> _dependencies = new List<DependencyInfo>();

		private List<MissingDependencyInfo> _missingDependencies = new List<MissingDependencyInfo>();

		public bool ShowMenuBanner { get; set; } = true;

		public bool ShowBannerIfOptionalOnly { get; set; } = false;

		public bool UnloadIfMissingRequired { get; set; } = false;

		public void AddDependency(DependencyInfo dependency)
		{
			_dependencies.Add(dependency);
		}

		public void ProcessAndAlert()
		{
			CheckDependencies();
			if (_missingDependencies.Count != 0)
			{
				PrintMissing();
				if (ShowMenuBanner)
				{
					ShowBanner();
				}
				MelonCoroutines.Start(DelayedUnload());
			}
		}

		private void CheckDependencies()
		{
			_missingDependencies = new List<MissingDependencyInfo>();
			foreach (DependencyInfo dependency in _dependencies)
			{
				MissingDependencyInfo missingDependencyInfo = IsPresent(dependency);
				if (missingDependencyInfo != null)
				{
					_missingDependencies.Add(missingDependencyInfo);
				}
			}
		}

		private void PrintMissing()
		{
			Logger.Msg("Missing dependencies:");
			foreach (MissingDependencyInfo missingDependency in _missingDependencies)
			{
				if (missingDependency.IsRequired)
				{
					Logger.Error($"- {missingDependency.Name} (min version {missingDependency.Version}): required - {missingDependency.Reason}");
				}
				else
				{
					Logger.Warning($"- {missingDependency.Name} (min version {missingDependency.Version}): optional - {missingDependency.Reason}");
				}
				if (missingDependency.Urls.Count == 0)
				{
					continue;
				}
				Logger.Msg("  Possible sources:");
				foreach (DependencyUrl url in missingDependency.Urls)
				{
					Logger.Msg("  - " + url.SourceName + ": " + url.Url);
				}
			}
		}

		private void ShowBanner()
		{
			((MelonEventBase<LemonAction<int, string>>)(object)MelonEvents.OnSceneWasLoaded).Subscribe((LemonAction<int, string>)delegate(int _, string name)
			{
				if (!(name != "Menu"))
				{
					MissingDepsPanelCreator.Show(this, _missingDependencies);
				}
			}, 0, false);
			((MelonEventBase<LemonAction<int, string>>)(object)MelonEvents.OnSceneWasUnloaded).Subscribe((LemonAction<int, string>)delegate(int _, string name)
			{
				if (!(name != "Menu"))
				{
					MissingDepsPanelCreator.Hide();
				}
			}, 0, false);
			MissingDepsPanelCreator.Show(this, _missingDependencies);
		}

		private IEnumerator DelayedUnload()
		{
			yield return (object)new WaitForSeconds(5f);
			if (UnloadIfMissingRequired && _mis

MultiDelivery-Mono.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using FishNet;
using FishNet.Connection;
using FishNet.Object;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using MultiDelivery;
using MultiDelivery.Builders;
using MultiDelivery.GameConsole.Commands;
using MultiDelivery.GameConsole.Commands.Help;
using MultiDelivery.GameConsole.Commands.Pool;
using MultiDelivery.GameConsole.Commands.Quest;
using MultiDelivery.GameConsole.Core;
using MultiDelivery.Helpers;
using MultiDelivery.Network;
using MultiDelivery.Persistence;
using MultiDelivery.Pool;
using MultiDelivery.Quest;
using S1API.Console;
using S1API.Dialogues;
using S1API.Entities;
using S1API.Entities.Dialogue;
using S1API.Entities.NPCs.Suburbia;
using S1API.Internal.Abstraction;
using S1API.Leveling;
using S1API.Messaging;
using S1API.Money;
using S1API.Quests;
using S1API.Quests.Constants;
using S1API.Saveables;
using S1API.Utils;
using ScheduleOne;
using ScheduleOne.Core.Items.Framework;
using ScheduleOne.Core.Weather;
using ScheduleOne.Delivery;
using ScheduleOne.DevUtilities;
using ScheduleOne.Graffiti;
using ScheduleOne.ItemFramework;
using ScheduleOne.Map;
using ScheduleOne.Money;
using ScheduleOne.NPCs.CharacterClasses;
using ScheduleOne.Persistence.Datas;
using ScheduleOne.Persistence.Loaders;
using ScheduleOne.PlayerScripts;
using ScheduleOne.UI;
using ScheduleOne.UI.Phone.Delivery;
using ScheduleOne.UI.Shop;
using ScheduleOne.Vehicles;
using ScheduleOne.Vehicles.Modification;
using Semver;
using SteamNetworkLib;
using SteamNetworkLib.Core;
using SteamNetworkLib.Events;
using SteamNetworkLib.Models;
using Steamworks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(global::MultiDelivery.MultiDelivery), "MultiDelivery", "1.0.5", "k073l", null)]
[assembly: MelonColor(1, 0, 255, 0)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonPlatformDomain(/*Could not decode attribute arguments.*/)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("MultiDelivery-Mono")]
[assembly: AssemblyConfiguration("Mono")]
[assembly: AssemblyDescription("Add vehicles, order multiple deliveries from the same place!")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: AssemblyInformationalVersion("1.0.5+1e3711e3b7b873b5063b983a5dfae1d74542cb89")]
[assembly: AssemblyProduct("MultiDelivery-Mono")]
[assembly: AssemblyTitle("MultiDelivery-Mono")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.5.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 MultiDelivery
{
	public class Logger
	{
		private Instance? _melonLogger;

		private static bool _initialized;

		private static readonly object InitLock = new object();

		private static ConstructorInfo? _melonLoggerCtor;

		private static object? _defaultTextColor;

		private static Type? _defaultTextColorType;

		private static object? _melonNsColor;

		private static MethodInfo? _msgMethod;

		public string? Namesection { get; set; }

		public bool RaiseTrace { get; set; }

		public bool RaiseDebug { get; set; }

		private static string? RootNamespace => typeof(Logger).Namespace?.Split('.').FirstOrDefault();

		public Logger(string? namesection = null)
		{
			if (namesection == null)
			{
				Namesection = typeof(Logger).Namespace?.Split('.').FirstOrDefault();
			}
			else if (!string.IsNullOrEmpty(RootNamespace) && !namesection.StartsWith(RootNamespace))
			{
				Namesection = RootNamespace + "." + namesection;
			}
			else
			{
				Namesection = namesection;
			}
			SetupInstance();
		}

		public Logger(Instance melonLogger)
		{
			FieldInfo field = typeof(Instance).GetField("Name", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field != null)
			{
				Namesection = field.GetValue(melonLogger) as string;
			}
			SetupInstance();
		}

		public static implicit operator Logger(Instance melonLogger)
		{
			return new Logger(melonLogger);
		}

		public void Trace(params object[] args)
		{
			Log(LogLevel.Trace, null, args);
		}

		public void Debug(params object[] args)
		{
			Log(LogLevel.Debug, null, args);
		}

		public void T(params object[] args)
		{
			Log(LogLevel.Trace, null, args);
		}

		public void D(params object[] args)
		{
			Log(LogLevel.Debug, null, args);
		}

		public void Info(params object[] args)
		{
			Log(LogLevel.Info, null, args);
		}

		public void Msg(params object[] args)
		{
			Log(LogLevel.Info, null, args);
		}

		public void I(params object[] args)
		{
			Log(LogLevel.Info, null, args);
		}

		public void M(params object[] args)
		{
			Log(LogLevel.Info, null, args);
		}

		public void Warning(params object[] args)
		{
			Log(LogLevel.Warning, null, args);
		}

		public void Warn(params object[] args)
		{
			Log(LogLevel.Warning, null, args);
		}

		public void W(params object[] args)
		{
			Log(LogLevel.Warning, null, args);
		}

		public void Error(params object[] args)
		{
			Log(LogLevel.Error, null, args);
		}

		public void Err(params object[] args)
		{
			Log(LogLevel.Error, null, args);
		}

		public void E(params object[] args)
		{
			Log(LogLevel.Error, null, args);
		}

		public void Fatal(params object[] args)
		{
			Log(LogLevel.BigError, null, args);
		}

		public void BigError(params object[] args)
		{
			Log(LogLevel.BigError, null, args);
		}

		public void F(params object[] args)
		{
			Log(LogLevel.BigError, null, args);
		}

		public void BE(params object[] args)
		{
			Log(LogLevel.BigError, null, args);
		}

		public void InfoColored(object txtColor, params object[] args)
		{
			Log(LogLevel.Info, txtColor, args);
		}

		public void MsgColored(object txtColor, params object[] args)
		{
			Log(LogLevel.Info, txtColor, args);
		}

		public void IC(object txtColor, params object[] args)
		{
			Log(LogLevel.Info, txtColor, args);
		}

		public void MC(object txtColor, params object[] args)
		{
			Log(LogLevel.Info, txtColor, args);
		}

		public void Log(LogLevel level, string message)
		{
			Log(level, null, message);
		}

		private static void EnsureInitialized()
		{
			if (_initialized)
			{
				return;
			}
			lock (InitLock)
			{
				if (_initialized)
				{
					return;
				}
				Type typeFromHandle = typeof(MelonLogger);
				FieldInfo field = typeFromHandle.GetField("DefaultTextColor", BindingFlags.Static | BindingFlags.Public);
				_defaultTextColorType = field?.FieldType;
				if (_defaultTextColorType == null)
				{
					MelonLogger.Error("Could not determine the type of DefaultTextColor");
					return;
				}
				_defaultTextColor = field?.GetValue(null);
				Type typeFromHandle2 = typeof(Instance);
				_melonLoggerCtor = typeFromHandle2.GetConstructor(new Type[2]
				{
					typeof(string),
					_defaultTextColorType
				});
				Type melonBaseType = typeof(MelonBase);
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				Type[] source;
				try
				{
					source = executingAssembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					source = ex.Types.OfType<Type>().ToArray();
				}
				Type type = source.FirstOrDefault((Type t) => melonBaseType.IsAssignableFrom(t) && !t.IsAbstract);
				Type type2 = typeof(Melon<>).MakeGenericType(type ?? throw new InvalidOperationException("No MelonBase derived type found in the current assembly."));
				PropertyInfo property = type2.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
				if (property != null)
				{
					PropertyInfo property2 = property.PropertyType.GetProperty("ConsoleColor", BindingFlags.Instance | BindingFlags.Public);
					if (property2 != null)
					{
						_melonNsColor = property2.GetValue(property.GetValue(null));
					}
				}
				if (_melonNsColor == null)
				{
					FieldInfo field2 = typeFromHandle.GetField("DefaultMelonColor", BindingFlags.Static | BindingFlags.Public);
					if (field2 != null)
					{
						_melonNsColor = field2.GetValue(null);
					}
				}
				_msgMethod = typeFromHandle2.GetMethod("Msg", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
				{
					_defaultTextColorType,
					typeof(string)
				}, null);
				if (_melonLoggerCtor == null)
				{
					MelonLogger.Error("Could not find constructor for MelonLogger.Instance(string, <colorType>)");
				}
				if (_defaultTextColor == null)
				{
					MelonLogger.Error("Could not find DefaultTextColor");
				}
				if (_melonNsColor == null)
				{
					MelonLogger.Error("Could not find Melon<>.Instance.ConsoleColor or MelonLogger.DefaultMelonColor");
				}
				if (_msgMethod == null)
				{
					MelonLogger.Error("Could not find MelonLogger.Instance.Msg(<colorType>, string)");
				}
				_initialized = true;
			}
		}

		private static string GetCallerInfo()
		{
			StackTrace stackTrace = new StackTrace();
			for (int i = 3; i < stackTrace.FrameCount; i++)
			{
				StackFrame frame = stackTrace.GetFrame(i);
				MethodBase method = frame.GetMethod();
				if (method?.DeclaringType != null)
				{
					return method.DeclaringType.FullName + "." + method.Name;
				}
			}
			return "unknown";
		}

		private void SetupInstance()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			if (string.IsNullOrEmpty(Namesection))
			{
				Namesection = "Logger";
			}
			EnsureInitialized();
			object obj = _melonLoggerCtor?.Invoke(new object[2] { Namesection, _melonNsColor });
			if (obj == null)
			{
				throw new NullReferenceException("Could not create MelonLogger.Instance");
			}
			_melonLogger = (Instance)obj;
		}

		private void Log(LogLevel level, object? txtColor, params object[] args)
		{
			if (args.Length == 0)
			{
				return;
			}
			string text;
			if (args.Length == 1)
			{
				text = args[0]?.ToString() ?? "";
			}
			else
			{
				string format = args[0]?.ToString() ?? "";
				text = string.Format(format, args[1..]);
			}
			object obj = txtColor ?? _defaultTextColor;
			switch (level)
			{
			case LogLevel.Trace:
			{
				string text2 = "[TRACE " + GetCallerInfo() + "] " + text;
				if (RaiseTrace)
				{
					_msgMethod?.Invoke(_melonLogger, new object[2] { obj, text2 });
				}
				else
				{
					MelonDebug.Msg(text2);
				}
				break;
			}
			case LogLevel.Debug:
			{
				string text3 = "[DEBUG " + GetCallerInfo() + "] " + text;
				if (RaiseDebug)
				{
					_msgMethod?.Invoke(_melonLogger, new object[2] { obj, text3 });
				}
				else
				{
					MelonDebug.Msg(text3);
				}
				break;
			}
			default:
				_msgMethod?.Invoke(_melonLogger, new object[2] { obj, text });
				break;
			case LogLevel.Warning:
			{
				Instance? melonLogger3 = _melonLogger;
				if (melonLogger3 != null)
				{
					melonLogger3.Warning(text);
				}
				break;
			}
			case LogLevel.Error:
			{
				Instance? melonLogger2 = _melonLogger;
				if (melonLogger2 != null)
				{
					melonLogger2.Error(text);
				}
				break;
			}
			case LogLevel.BigError:
			{
				Instance? melonLogger = _melonLogger;
				if (melonLogger != null)
				{
					melonLogger.BigError(text);
				}
				break;
			}
			}
		}
	}
	public enum LogLevel
	{
		Trace,
		Debug,
		Info,
		Warning,
		Error,
		BigError
	}
	public static class BuildInfo
	{
		public const string Name = "MultiDelivery";

		public const string Description = "Add vehicles, order multiple deliveries from the same place!";

		public const string Author = "k073l";

		public const string Version = "1.0.5";
	}
	public class MultiDelivery : MelonMod
	{
		private static Logger Logger;

		private IDeliveryNetworkManager? _networkManager;

		private bool _networkManagerFailed;

		internal static MelonPreferences_Category Category = MelonPreferences.CreateCategory("MultiDeliverySettings", "MultiDelivery's Settings");

		internal static MelonPreferences_Entry<bool> NetworkLogging;

		internal static MelonPreferences_Entry<bool> PoolDebugLogging;

		internal static MelonPreferences_Entry<bool> QuestDebugLogging;

		public override void OnInitializeMelon()
		{
			Logger = ((MelonBase)this).LoggerInstance;
			Logger.Msg("MultiDelivery initialized");
			NetworkLogging = Category.CreateEntry<bool>("NetworkDebugLogs", false, "Enable Network Logs", "Display networking-related debug logs in MelonLoader console/log file (may be verbose)", false, false, (ValueValidator)null, (string)null);
			PoolDebugLogging = Category.CreateEntry<bool>("PoolDebugLogs", false, "Enable Pool Debug Logs", "Display pool-related debug logs in MelonLoader console/log file (may be verbose)", false, false, (ValueValidator)null, (string)null);
			QuestDebugLogging = Category.CreateEntry<bool>("QuestDebugLogs", false, "Enable Quest Debug Logs", "Display quest-related debug logs in MelonLoader console/log file (may be verbose)", false, false, (ValueValidator)null, (string)null);
			RegisterLoggerSettings();
			CheckDependencies();
			MelonCoroutines.Start(InitializeNetworkManager());
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			QuestSetupManager.OnSceneWasLoaded(buildIndex, sceneName);
			if (!(sceneName != "Menu"))
			{
				PoolManager.Instance.ClearAll();
			}
		}

		private IEnumerator InitializeNetworkManager()
		{
			if (SteamAPI.Init())
			{
				yield return null;
				_networkManager = NetworkLoader.Create();
				if (_networkManager == null)
				{
					Logger.Warning("NetworkManager is null, multiplayer features will be unavailable.");
				}
				else
				{
					NetworkConvenienceMethods.InitializeNetworking(_networkManager);
					_networkManager.RegisterLoggerSettings();
				}
			}
		}

		public override void OnUpdate()
		{
			if (_networkManagerFailed || _networkManager == null)
			{
				return;
			}
			try
			{
				_networkManager.Update();
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Network manager update failed: " + ex.Message + "\n\nYou can ignore this error if you plan on playing singleplayer only and don't want to install SteamNetworkLib");
				_networkManagerFailed = true;
			}
		}

		public override void OnDeinitializeMelon()
		{
			_networkManager?.Dispose();
			Logger.Msg("MultiDelivery deinitialized");
		}

		private static void CheckDependencies()
		{
			DependenciesChecker dependenciesChecker = new DependenciesChecker
			{
				ShowMenuBanner = true,
				UnloadIfMissingRequired = true
			};
			dependenciesChecker.AddDependency(new DependencyInfo
			{
				Name = "S1API (Forked)",
				AssemblyName = "S1API",
				IsRequired = true,
				Version = "3.0.1",
				Urls = new List<DependencyUrl>(3)
				{
					new DependencyUrl
					{
						SourceName = "Thunderstore",
						Url = "https://thunderstore.io/c/schedule-i/p/ifBars/S1API_Forked/"
					},
					new DependencyUrl
					{
						SourceName = "NexusMods",
						Url = "https://www.nexusmods.com/schedule1/mods/1194"
					},
					new DependencyUrl
					{
						SourceName = "Github",
						Url = "https://github.com/ifBars/S1API/releases/"
					}
				}
			});
			dependenciesChecker.AddDependency(new DependencyInfo
			{
				Name = "SteamNetworkLib",
				AssemblyName = "SteamNetworkLib",
				IsRequired = false,
				Version = "1.2.1",
				Urls = new List<DependencyUrl>(4)
				{
					new DependencyUrl
					{
						SourceName = "Thunderstore Il2Cpp",
						Url = "https://thunderstore.io/c/schedule-i/p/ifBars/SteamNetworkLib_Il2Cpp/"
					},
					new DependencyUrl
					{
						SourceName = "Thunderstore Mono",
						Url = "https://thunderstore.io/c/schedule-i/p/ifBars/SteamNetworkLib_Mono/"
					},
					new DependencyUrl
					{
						SourceName = "NexusMods",
						Url = "https://www.nexusmods.com/schedule1/mods/1396"
					},
					new DependencyUrl
					{
						SourceName = "Github",
						Url = "https://github.com/ifBars/SteamNetworkLib/releases"
					}
				}
			});
			dependenciesChecker.ProcessAndAlert();
		}

		private static void RegisterLoggerSettings()
		{
			SetAndRegister(ActiveDeliveryPatch.Logger, PoolDebugLogging);
			SetAndRegister(CapacityText.Logger, PoolDebugLogging);
			SetAndRegister(DeliveryInstancePatches.Logger, PoolDebugLogging);
			SetAndRegister(LoaderPatch.Logger, PoolDebugLogging);
			SetAndRegister(PoolManager.Logger, PoolDebugLogging);
			SetAndRegister(DropoffQuest.Logger, QuestDebugLogging);
			SetAndRegister(DropoffQuestDialogue.Logger, QuestDebugLogging);
			SetAndRegister(QuestSetupManager.Logger, QuestDebugLogging);
		}

		private static void SetAndRegister(Logger logger, MelonPreferences_Entry<bool>? entry)
		{
			logger.RaiseDebug = entry?.Value ?? false;
			((MelonEventBase<LemonAction<bool, bool>>)(object)entry?.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)delegate(bool _, bool newValue)
			{
				logger.RaiseDebug = newValue;
			}, 0, false);
		}
	}
}
namespace MultiDelivery.Quest
{
	public class DropoffQuest : Quest
	{
		internal const string Name = "Expanding the Fleet";

		private bool _vehicleAdded;

		private QuestEntry _addVehicleEntry;

		private int _startingCapacity;

		private static VehicleDropoffZone dropoffZone;

		private static Vector3 _dropoffZonePosition;

		internal static readonly Logger Logger = new Logger("DropoffQuest");

		protected override string Title => "Expanding the Fleet";

		protected override string Description => "Bring a delivery vehicle to the dropoff zone to expand your delivery capacity";

		protected override bool AutoBegin => false;

		protected override Sprite QuestIcon => IconLoader.QuestIconSprite;

		internal QuestState State => ((Quest)this).QuestState;

		protected override void OnCreated()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			((Registerable)this).OnCreated();
			_startingCapacity = PoolManager.Instance.PoolCount;
			Logger.Debug($"Starting Quest with {_startingCapacity} capacity");
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(5.1f, 4.2f, 82.58f);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0.55f, 4.2f, 76.56f);
			_dropoffZonePosition = (val + val2) / 2f;
			if ((Object)(object)dropoffZone != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)dropoffZone).gameObject);
			}
			dropoffZone = VehicleDropoffZoneFactory.CreateZone(val, val2, 5f, (Color?)new Color(0f, 1f, 0f, 0.4f), showVisuals: true, this);
			Logger.Debug("Dropoff zone created. Spawning " + ((Object)dropoffZone).name);
			((Quest)this).OnComplete += Completed;
			Logger.Debug("Wired completion event");
			UpdateQuestEntries();
		}

		private void UpdateQuestEntries()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			base.QuestEntries.Clear();
			if (!_vehicleAdded)
			{
				Logger.Debug("Adding add vehicle entry");
				_addVehicleEntry = ((Quest)this).AddEntry("Purchase a " + "veeper".Capitalize() + " and drive it into the green dropoff zone (top floor of the parking garage, next to storage unit)", (Vector3?)_dropoffZonePosition);
				_addVehicleEntry.Begin();
			}
			Logger.Debug("Entries added!");
		}

		public void MarkAddVehicleEntryComplete()
		{
			Logger.Debug("Marked add vehicle entry as completed");
			_addVehicleEntry.Complete();
		}

		private void Completed()
		{
			Logger.Msg("Delivery vehicle dropoff quest completed!");
			MelonCoroutines.Start(NotifyCompletion());
		}

		private IEnumerator NotifyCompletion()
		{
			int i = 0;
			while (i < 3 && PoolManager.Instance.PoolCount <= _startingCapacity)
			{
				yield return (object)new WaitForSeconds(3f);
				int num = i + 1;
				i = num;
			}
			NPC npc = NPC.Get<JeremyWilkinson>();
			if (npc != null)
			{
				if (PoolManager.Instance.PoolCount <= _startingCapacity)
				{
					npc.SendTextMessage("Something went wrong... Vehicle got in a car crash :(", (Response[])null, 1f, true);
					yield break;
				}
				npc.SendTextMessage($"Vehicle added, you now can order {PoolManager.Instance.PoolCount} more " + "deliver" + ((PoolManager.Instance.PoolCount > 1) ? "ies" : "y") + " from stores.", (Response[])null, 1f, true);
				npc.SendTextMessage("If you want to add more, you know where to find me.", (Response[])null, 1f, true);
			}
		}
	}
	public class DropoffQuestDialogue
	{
		internal static readonly Logger Logger = new Logger("DropoffQuestDialogue");

		private const string ContainerName = "DeliveryExpansion";

		public static void Register()
		{
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			NPC jeremy = NPC.Get<JeremyWilkinson>();
			if (jeremy == null)
			{
				Logger.Warning("Jeremy Wilkinson not found");
				return;
			}
			jeremy.Dialogue.BuildAndRegisterContainer("DeliveryExpansion", (Action<DialogueContainerBuilder>)delegate(DialogueContainerBuilder c)
			{
				c.AddNode("OFFER_FIRST", "Yeah! I can help with that. If you bring a " + "veeper".Capitalize() + " to the dropoff zone, I'll add it to the fleet. This will let you handle multiple deliveries at once. Want to give it a shot?", (Action<ChoiceList>)delegate(ChoiceList ch)
				{
					ch.Add("BUY_NOW", "Sure! Can I buy one from you right now?", "CHECK_FUNDS");
					ch.Add("ACCEPT", "I already have one, let's do it!", "ACCEPTED");
					ch.Add("DECLINE", "Maybe later.", "DECLINED");
				});
				c.AddNode("OFFER_REPEAT", "Want to expand your fleet even more? Just bring another vehicle to the dropoff zone and I'll add it for you.", (Action<ChoiceList>)delegate(ChoiceList ch)
				{
					ch.Add("BUY_NOW", "Yeah, can I buy another one from you?", "CHECK_FUNDS");
					ch.Add("ACCEPT", "I've got one ready!", "ACCEPTED");
					ch.Add("DECLINE", "Not right now.", "DECLINED");
				});
				c.AddNode("CHECK_FUNDS", "A " + "veeper".Capitalize() + " runs <color=#19BEF0>(" + MoneyManager.FormatAmount(GetVehiclePrice(), false, false) + ")</color>. Want to pick one up?", (Action<ChoiceList>)delegate(ChoiceList ch)
				{
					ch.Add("PURCHASE", "I'll take it. <color=#19BEF0>(" + MoneyManager.FormatAmount(GetVehiclePrice(), false, false) + ")</color>", "PURCHASE_COMPLETE");
					ch.Add("NEVERMIND", "Let me think about it.", "DECLINED");
				});
				c.AddNode("PURCHASE_COMPLETE", "All yours. You can customize it if you want. Now just drive it to the dropoff zone - I've marked it on your map.", (Action<ChoiceList>)null);
				c.AddNode("NOT_ENOUGH", "You don't have enough money to buy it. Come back later.", (Action<ChoiceList>)null);
				c.AddNode("IN_PROGRESS", "You already have an active delivery expansion going! Just bring the vehicle to the dropoff zone. Top floor of the parking garage, next to the storage units - check your map if you forgot where it is.", (Action<ChoiceList>)null);
				c.AddNode("ACCEPTED", "Great! I've marked the dropoff zone on your map - top floor of the parking garage, next to the storage units. Just drive the vehicle in there when you're ready.", (Action<ChoiceList>)null);
				c.AddNode("DECLINED", "No worries, just let me know if you change your mind!", (Action<ChoiceList>)null);
			});
			jeremy.Dialogue.OnChoiceSelected("ACCEPT", (Action)OnAcceptQuest);
			jeremy.Dialogue.OnChoiceSelected("BUY_NOW", (Action)OnAcceptQuest);
			jeremy.Dialogue.OnChoiceSelected("DECLINE", (Action)delegate
			{
				Logger.Debug("Player declined quest");
			});
			jeremy.Dialogue.OnChoiceSelected("NEVERMIND", (Action)delegate
			{
				Logger.Debug("Player cancelled purchase");
			});
			jeremy.Dialogue.OnChoiceSelected("PURCHASE", (Action)delegate
			{
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
				float vehiclePrice = GetVehiclePrice();
				float onlineBalance = Money.GetOnlineBalance();
				if (onlineBalance >= vehiclePrice)
				{
					Money.CreateOnlineTransaction("veeper".Capitalize() + " purchase", 0f - vehiclePrice, 1f, "Bought as a part of delivery expansion");
					Logger.Msg(string.Format("Player purchased {0} for ${1:F2}", "veeper", vehiclePrice));
					Jeremy component = jeremy.gameObject.GetComponent<Jeremy>();
					if ((Object)(object)component != (Object)null)
					{
						Dealership dealership = component.Dealership;
						if ((Object)(object)dealership != (Object)null)
						{
							dealership.SpawnVehicle("veeper");
							return;
						}
					}
					NetworkSingleton<VehicleManager>.Instance.SpawnVehicle("veeper", new Vector3(9.92f, 0.54f, -33.55f), Quaternion.identity, true);
				}
				else
				{
					jeremy.Dialogue.JumpTo("DeliveryExpansion", "NOT_ENOUGH", false);
				}
			});
			DialogueInjector.Register(new DialogueInjection(jeremy.ID, "Dealership_Salesman_Sell", "cc0d838e-2824-4fd5-907d-798dc0195c16", "OFFER_FIRST", "ASK_EXPANSION", "Can I expand my delivery capacity?", (Action)delegate
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Invalid comparison between Unknown and I4
				DropoffQuest dropoffQuest = QuestManager.GetQuestByName("Expanding the Fleet") as DropoffQuest;
				bool flag = PoolManager.Instance.PoolCount > 0;
				bool flag2 = dropoffQuest != null && (int)dropoffQuest.State == 1;
				Logger.Debug($"Quest state - Active: {flag2}, Has expanded: {flag}");
				string text = (flag2 ? "IN_PROGRESS" : (flag ? "OFFER_REPEAT" : "OFFER_FIRST"));
				Logger.Debug("Jumping to 'DeliveryExpansion', node '" + text + "'");
				jeremy.Dialogue.JumpTo("DeliveryExpansion", text, false);
			}));
			Logger.Msg("Registered delivery expansion dialogue");
		}

		internal static void OnAcceptQuest()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			if (!(QuestManager.GetQuestByName("Expanding the Fleet") is DropoffQuest dropoffQuest))
			{
				if (QuestManager.CreateQuest<DropoffQuest>((string)null) is DropoffQuest dropoffQuest2)
				{
					((Quest)dropoffQuest2).Begin();
				}
				Logger.Msg("Started delivery expansion quest");
			}
			else if (dropoffQuest != null && (int)dropoffQuest.State == 2)
			{
				((Quest)dropoffQuest).Begin();
				Logger.Msg("Restarted delivery expansion quest");
			}
		}

		private static float GetVehiclePrice()
		{
			LandVehicle vehiclePrefab = NetworkSingleton<VehicleManager>.Instance.GetVehiclePrefab("veeper");
			return (vehiclePrefab != null) ? vehiclePrefab.VehiclePrice : 5000f;
		}
	}
	public class QuestSetupManager
	{
		internal const string RequestedVehicleCode = "veeper";

		internal const string QuestStartMessage = "Your properties are getting busy. Want to handle more than one delivery at a time? I've got an idea. Stop by the dealership.";

		private static FullRank RequiredRank = new FullRank((Rank)5, 1);

		internal static readonly Logger Logger = new Logger("QuestSetupManager");

		public static void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (!(sceneName == "Main"))
			{
				if (sceneName == "Menu")
				{
					Player.LocalPlayerSpawned -= WirePlayerEvent;
					LevelManager.OnXPChanged -= SendMessageIfRequiredRank;
				}
			}
			else
			{
				Player.LocalPlayerSpawned += WirePlayerEvent;
			}
		}

		private static void WirePlayerEvent(Player _)
		{
			Logger.Debug("Player loaded event called");
			MelonCoroutines.Start(WireOnXpChangedDelayed());
		}

		private static IEnumerator WireOnXpChangedDelayed()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => LevelManager.Exists));
			if (PersistentDropoffQuestData.Instance.HasMessaged)
			{
				DropoffQuestDialogue.Register();
				yield break;
			}
			Logger.Debug("Wiring on xp changed");
			LevelManager.OnXPChanged += SendMessageIfRequiredRank;
		}

		private static void SendMessageIfRequiredRank(FullRank _, FullRank current)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			Logger.Debug($"Current rank {current}, required: {RequiredRank}");
			if (PersistentDropoffQuestData.Instance.HasMessaged)
			{
				MelonDebug.Msg("Xp changed wired, but already messaged - registering dialogue now.");
				DropoffQuestDialogue.Register();
			}
			else
			{
				if (current < RequiredRank)
				{
					return;
				}
				NPC val = NPC.Get<JeremyWilkinson>();
				if (val != null)
				{
					if (NetworkConvenienceMethods.HostOrSingleplayer)
					{
						val.SendTextMessage("Your properties are getting busy. Want to handle more than one delivery at a time? I've got an idea. Stop by the dealership.", (Response[])null, 1f, true);
					}
					PersistentDropoffQuestData.Instance.HasMessaged = true;
					DropoffQuestDialogue.Register();
					LevelManager.OnXPChanged -= SendMessageIfRequiredRank;
				}
			}
		}
	}
	[RegisterTypeInIl2Cpp]
	public class VehicleDropoffZone : MonoBehaviour
	{
		private VehicleDetector _detector;

		private Logger _logger;

		private GameObject _visualPlane;

		private Material _visualMaterial;

		private Color _baseColor;

		private DropoffQuest? _quest;

		public Vector3 Corner1 { get; private set; }

		public Vector3 Corner2 { get; private set; }

		public bool ShowVisuals { get; set; } = true;

		private void Awake()
		{
			_logger = new Logger("VehicleDropoffZone");
			_logger.RaiseDebug = MultiDelivery.QuestDebugLogging?.Value ?? false;
			((MelonEventBase<LemonAction<bool, bool>>)(object)MultiDelivery.QuestDebugLogging?.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)delegate(bool _, bool newValue)
			{
				_logger.RaiseDebug = newValue;
			}, 0, false);
		}

		private void Start()
		{
			_detector = ((Component)this).gameObject.GetComponent<VehicleDetector>();
			if ((Object)(object)_detector == (Object)null)
			{
				_detector = ((Component)this).gameObject.AddComponent<VehicleDetector>();
			}
		}

		private void Update()
		{
			if (_detector.vehicles.Count <= 0)
			{
				return;
			}
			foreach (LandVehicle item in _detector.vehicles.AsEnumerable())
			{
				OnVehicleEntered(item);
			}
		}

		private void OnVehicleEntered(LandVehicle vehicle)
		{
			_logger.Debug("Vehicle entered dropoff zone: " + vehicle.vehicleName);
			if (!IsCorrectVehicleType(vehicle))
			{
				if (Time.frameCount % 60 == 0)
				{
					_logger.Warning("Wrong vehicle type: " + vehicle.vehicleCode);
				}
				return;
			}
			if (vehicle.IsOccupied)
			{
				_logger.Msg("Ejecting player from vehicle");
				vehicle.ExitVehicle();
			}
			ProcessAndAddToPool(vehicle);
			_detector.vehicles.Remove(vehicle);
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}

		private static bool IsCorrectVehicleType(LandVehicle vehicle)
		{
			return vehicle.vehicleCode == "veeper";
		}

		private void ProcessAndAddToPool(LandVehicle vehicle)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			_logger.Debug($"Adding vehicle to pool: {vehicle.GUID}");
			DeliveryVehicle val = ((Component)vehicle).GetComponent<DeliveryVehicle>();
			if ((Object)(object)val == (Object)null)
			{
				Guid gUID = vehicle.GUID;
				val = new DeliveryVehicleBuilder().WithLandVehicle(vehicle).WithGuid(gUID).Build();
			}
			vehicle.IsPlayerOwned = false;
			vehicle.SetIsPlayerOwned((NetworkConnection)null, false);
			vehicle.SetVisible(false);
			vehicle.IsPhysicallySimulated = false;
			IEnumerable<LandVehicle> source = from lv in NetworkSingleton<VehicleManager>.Instance.PlayerOwnedVehicles.AsEnumerable()
				where lv.GUID.ToString() != vehicle.GUID.ToString()
				select lv;
			NetworkSingleton<VehicleManager>.Instance.PlayerOwnedVehicles = source.ToList();
			((Component)vehicle).transform.position = new Vector3(0f, -100f, 0f);
			PoolManager.Instance.AddToSaveData(val);
			PoolManager.Instance.AddToPool(val);
			_quest?.MarkAddVehicleEntryComplete();
			_logger.Msg($"Vehicle added to pool. Total vehicles: {PoolManager.Instance.PoolCount}");
		}

		public void SetupZone(Vector3 corner1, Vector3 corner2, float height = 5f, Color? visualColor = null)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			Corner1 = corner1;
			Corner2 = corner2;
			Vector3 val = (corner1 + corner2) / 2f;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(Mathf.Abs(corner2.x - corner1.x), height, Mathf.Abs(corner2.z - corner1.z));
			((Component)this).transform.position = val;
			BoxCollider val3 = ((Component)this).gameObject.GetComponent<BoxCollider>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = ((Component)this).gameObject.AddComponent<BoxCollider>();
			}
			((Collider)val3).isTrigger = true;
			val3.size = val2;
			val3.center = Vector3.zero;
			if (ShowVisuals)
			{
				_baseColor = (Color)(((??)visualColor) ?? new Color(0f, 1f, 1f, 0.3f));
				CreateVisualPlane(val2, _baseColor);
			}
			_logger.Debug($"Dropoff zone created: Center={val}, Size={val2}");
		}

		private void CreateVisualPlane(Vector3 size, Color color)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			_visualPlane = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)_visualPlane).name = "DropoffZoneVisual";
			_visualPlane.transform.SetParent(((Component)this).transform);
			_visualPlane.transform.localPosition = Vector3.zero;
			_visualPlane.transform.localScale = new Vector3(size.x, 0.1f, size.z);
			Collider component = _visualPlane.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			ApplyDebugMaterial(_visualPlane, color);
		}

		private void ApplyDebugMaterial(GameObject obj, Color color)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_006b: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			Renderer component = obj.GetComponent<Renderer>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Shader val = Shader.Find("Universal Render Pipeline/Lit");
			if (!((Object)(object)val == (Object)null))
			{
				_visualMaterial = new Material(val);
				if (_visualMaterial.HasProperty("_Surface"))
				{
					_visualMaterial.SetFloat("_Surface", 1f);
				}
				if (color.a <= 0f)
				{
					color.a = 0.3f;
				}
				if (_visualMaterial.HasProperty("_BaseColor"))
				{
					_visualMaterial.SetColor("_BaseColor", color);
				}
				if (_visualMaterial.HasProperty("_EmissionColor"))
				{
					_visualMaterial.EnableKeyword("_EMISSION");
					_visualMaterial.SetColor("_EmissionColor", new Color(color.r, color.g, color.b) * 1.5f);
				}
				_visualMaterial.SetInt("_ZWrite", 0);
				_visualMaterial.renderQueue = 3000;
				component.material = _visualMaterial;
			}
		}

		public void SetVisualsEnabled(bool enabled)
		{
			ShowVisuals = enabled;
			if ((Object)(object)_visualPlane != (Object)null)
			{
				_visualPlane.SetActive(enabled);
			}
		}

		public void SetQuest(DropoffQuest quest)
		{
			_quest = quest;
		}

		private void OnDestroy()
		{
			if ((Object)(object)_visualPlane != (Object)null)
			{
				Object.Destroy((Object)(object)_visualPlane);
			}
		}
	}
	public static class VehicleDropoffZoneFactory
	{
		public static VehicleDropoffZone CreateZone(Vector3 corner1, Vector3 corner2, float height = 5f, Color? visualColor = null, bool showVisuals = true, DropoffQuest? attachedQuest = null)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("VehicleDropoffZone");
			VehicleDropoffZone vehicleDropoffZone = val.AddComponent<VehicleDropoffZone>();
			vehicleDropoffZone.ShowVisuals = showVisuals;
			vehicleDropoffZone.SetupZone(corner1, corner2, height, visualColor);
			if (attachedQuest != null)
			{
				vehicleDropoffZone.SetQuest(attachedQuest);
			}
			return vehicleDropoffZone;
		}

		public static VehicleDropoffZone CreateZoneNear(Transform reference, Vector3 offset, Vector3 size, Color? visualColor = null)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = reference.position + offset;
			Vector3 corner = val - size / 2f;
			Vector3 corner2 = val + size / 2f;
			return CreateZone(corner, corner2, size.y, visualColor);
		}
	}
}
namespace MultiDelivery.Pool
{
	[HarmonyPatch(typeof(DeliveryManager))]
	internal static class ActiveDeliveryPatch
	{
		internal static readonly Logger Logger = new Logger("ActiveDeliveryPatch");

		[HarmonyPatch("GetActiveShopDelivery")]
		[HarmonyPostfix]
		private static void AllowIfPoolAssigmentAvailable(DeliveryManager __instance, DeliveryShop shop, ref DeliveryInstance __result)
		{
			if (__result == null)
			{
				return;
			}
			lock (PoolManager.Lock)
			{
				if (PoolManager.Instance.BaseVehicleAllocationsForShop.TryGetValue(shop.MatchingShopInterfaceName, out var value))
				{
					if (Time.frameCount % 30 == 0)
					{
						Logger.Debug($"Base: {value}");
					}
					if (!value)
					{
						__result = null;
						return;
					}
					DeliveryVehicle firstFree = PoolManager.Instance.GetFirstFree();
					if (!((Object)(object)firstFree == (Object)null))
					{
						Logger.Debug("Free pool vehicle found");
						__result = null;
					}
				}
				else
				{
					DeliveryVehicle firstFree2 = PoolManager.Instance.GetFirstFree();
					if (!((Object)(object)firstFree2 == (Object)null))
					{
						Logger.Debug("Free pool vehicle found");
						__result = null;
					}
				}
			}
		}

		[HarmonyPatch("SendDelivery")]
		[HarmonyPostfix]
		private static void AllocateVehicle(DeliveryManager __instance, DeliveryInstance delivery)
		{
			lock (PoolManager.Lock)
			{
				if (PoolManager.Instance.Allocations.ContainsKey(delivery.DeliveryID))
				{
					Logger.Debug("Already allocated, skipping");
					return;
				}
				PoolManager.Instance.BaseVehicleAllocationsForShop.TryAdd(delivery.StoreName, value: false);
				Logger.Debug($"Base allocation: {PoolManager.Instance.BaseVehicleAllocationsForShop[delivery.StoreName]}");
				if (!PoolManager.Instance.BaseVehicleAllocationsForShop[delivery.StoreName])
				{
					Logger.Debug("Base vehicle allocating");
					DeliveryVehicle deliveryVehicle = NetworkSingleton<DeliveryManager>.Instance.GetShopInterface(delivery.StoreName).DeliveryVehicle;
					PoolManager.Instance.SetBaseAllocation(delivery.StoreName, allocated: true);
					PoolManager.Instance.Allocations.Add(delivery.DeliveryID, deliveryVehicle);
					VehicleSave.Instance.AddAllocation(delivery.DeliveryID, deliveryVehicle);
					NetworkConvenienceMethods.NotifyAllocation(delivery.DeliveryID, deliveryVehicle, isAllocated: true);
				}
				else
				{
					PoolManager.Instance.GetOrAllocateFirstFree(delivery.DeliveryID);
					Logger.Debug("Allocated for " + delivery.DeliveryID);
				}
			}
		}
	}
	[HarmonyPatch(typeof(DeliveryShop))]
	internal static class CapacityText
	{
		internal static readonly Logger Logger = new Logger("CapacityText");

		private static ConditionalWeakTable<DeliveryShop, Text> _capacityTexts = new ConditionalWeakTable<DeliveryShop, Text>();

		[HarmonyPatch("Initialize")]
		[HarmonyPostfix]
		private static void AddCapacityTextPostfix(DeliveryShop __instance)
		{
			Logger.Debug("Adding capacity text for " + ((Object)__instance).name);
			if (_capacityTexts.TryGetValue(__instance, out Text _))
			{
				return;
			}
			Text deliveryTimeLabel = __instance.DeliveryTimeLabel;
			GameObject val = ((deliveryTimeLabel != null) ? ((Component)((Component)deliveryTimeLabel).transform.parent).gameObject : null);
			Logger.Debug($"Adding capacity text: {deliveryTimeLabel}, templatego: {val}");
			if (val == null)
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val);
			val2.transform.SetParent(val.transform.parent, false);
			val2.transform.SetSiblingIndex(val.transform.GetSiblingIndex());
			Text component = ((Component)val2.transform.Find("Label")).GetComponent<Text>();
			component.text = "Free vehicles";
			Text component2 = ((Component)val2.transform.Find("Time")).GetComponent<Text>();
			component2.text = "1/1";
			_capacityTexts.Add(__instance, component2);
			List<Transform> list = val.transform.parent.FindAllTransforms("Spacer");
			if (list.Count > 0)
			{
				Transform val3 = list[list.Count - 1];
				if ((Object)(object)val3 != (Object)null)
				{
					((Component)val3).gameObject.SetActive(false);
				}
			}
		}

		[HarmonyPatch("RefreshCart")]
		[HarmonyPostfix]
		private static void UpdateCapacityTextPostfix(DeliveryShop __instance)
		{
			Text value;
			if (!((App<DeliveryApp>)(object)PlayerSingleton<DeliveryApp>.Instance).isOpen)
			{
				Logger.Debug("Delivery app is not open, skipping capacity text update for " + ((Object)__instance).name);
			}
			else if (!_capacityTexts.TryGetValue(__instance, out value))
			{
				Logger.Debug("Capacity text for " + ((Object)__instance).name + " not found!");
			}
			else
			{
				var (num, num2) = GetVehiclesForShop(__instance);
				value.text = $"{num}/{num2}";
			}
		}

		private static (int available, int total) GetVehiclesForShop(DeliveryShop shop)
		{
			lock (PoolManager.Lock)
			{
				string matchingShopInterfaceName = shop.MatchingShopInterfaceName;
				PoolManager pool = PoolManager.Instance;
				int item = 1 + pool.Pool.Count;
				int num = 0;
				if (!(pool.BaseVehicleAllocationsForShop.TryGetValue(matchingShopInterfaceName, out var value) && value))
				{
					num++;
				}
				int num2 = pool.Allocations.Values.Count((DeliveryVehicle v) => pool.Pool.Contains(v));
				int num3 = pool.Pool.Count - num2;
				num += num3;
				return (available: num, total: item);
			}
		}
	}
	[HarmonyPatch(typeof(DeliveryInstance))]
	internal static class DeliveryInstancePatches
	{
		internal static readonly Logger Logger = new Logger("DeliveryInstancePatches");

		[HarmonyPatch("SetStatus")]
		[HarmonyPrefix]
		private static bool UsePoolSetStatus(DeliveryInstance __instance, EDeliveryStatus status)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_0060: 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_0064: 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_0069: Invalid comparison between Unknown and I4
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Invalid comparison between Unknown and I4
			lock (PoolManager.Lock)
			{
				string text = $"Setting delivery status to {status} for delivery {__instance.DeliveryID}";
				Console.Log((object)text, (Object)null);
				Logger.Msg(text);
				__instance.Status = status;
				ShopInterface shopInterface = NetworkSingleton<DeliveryManager>.Instance.GetShopInterface(__instance.StoreName);
				if ((int)status != 2)
				{
					if ((int)status == 3)
					{
						if ((Object)(object)__instance.ActiveVehicle == (Object)(object)shopInterface.DeliveryVehicle)
						{
							PoolManager.Instance.SetBaseAllocation(__instance.StoreName, allocated: false);
						}
						PoolManager.Instance.FreeAllocation(__instance.DeliveryID);
						if ((Object)(object)__instance.ActiveVehicle != (Object)null)
						{
							__instance.ActiveVehicle.Deactivate();
						}
						UnityEvent onDeliveryCompleted = __instance.onDeliveryCompleted;
						if (onDeliveryCompleted != null)
						{
							onDeliveryCompleted.Invoke();
						}
					}
				}
				else
				{
					if (PoolManager.Instance.Allocations.TryGetValue(__instance.DeliveryID, out DeliveryVehicle value))
					{
						__instance.ActiveVehicle = value;
					}
					else
					{
						__instance.ActiveVehicle = shopInterface.DeliveryVehicle;
					}
					__instance.ActiveVehicle.Activate(__instance);
				}
				return false;
			}
		}

		[HarmonyPatch("AddItemsToDeliveryVehicle")]
		[HarmonyPrefix]
		private static bool UsePoolAddItemsToDeliveryVehicle(DeliveryInstance __instance)
		{
			lock (PoolManager.Lock)
			{
				ShopInterface shopInterface = NetworkSingleton<DeliveryManager>.Instance.GetShopInterface(__instance.StoreName);
				if (!PoolManager.Instance.Allocations.TryGetValue(__instance.DeliveryID, out DeliveryVehicle value))
				{
					value = shopInterface?.DeliveryVehicle;
				}
				StringIntPair[] items = __instance.Items;
				StringIntPair[] array = items;
				foreach (StringIntPair val in array)
				{
					ItemDefinition item = Registry.GetItem(val.String);
					int num = val.Int;
					while (num > 0)
					{
						int num2 = Mathf.Min(num, ((BaseItemDefinition)item).StackLimit);
						num -= num2;
						ItemInstance defaultInstance = item.GetDefaultInstance(num2);
						value.Vehicle.Storage.InsertItem(defaultInstance, Object.op_Implicit((Object)(object)item));
					}
				}
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(DeliveryVehicle))]
	internal class DeliveryVehiclePatch
	{
		[HarmonyPatch("Deactivate")]
		[HarmonyPostfix]
		private static void NullActiveDelivery(DeliveryVehicle __instance)
		{
			DeliveryInstance activeDelivery = __instance.ActiveDelivery;
			if ((Object)(object)((activeDelivery == null) ? null : activeDelivery.LoadingDock?.VehicleDetector) != (Object)null)
			{
				__instance.ActiveDelivery.LoadingDock.SetOccupant((LandVehicle)null);
				__instance.ActiveDelivery.LoadingDock.VehicleDetector.Clear();
			}
			if (__instance.ActiveDelivery != null)
			{
				__instance.ActiveDelivery = null;
			}
		}
	}
	[HarmonyPatch(typeof(DeliveriesLoader))]
	internal static class LoaderPatch
	{
		internal static readonly Logger Logger = new Logger("LoaderPatch");

		[HarmonyPatch("Load")]
		[HarmonyPrefix]
		private static bool Load(DeliveriesLoader __instance, string mainPath)
		{
			bool flag = false;
			string text = default(string);
			if (((Loader)__instance).TryLoadFile(Path.Combine(mainPath, "Deliveries"), ref text, true) || ((Loader)__instance).TryLoadFile(mainPath, ref text, true))
			{
				DeliveriesData val = null;
				try
				{
					val = JsonUtility.FromJson<DeliveriesData>(text);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("Error loading data: " + ex.Message));
					Logger.Debug("Error loading data: " + ex.Message);
				}
				if (val != null && val.ActiveDeliveries != null)
				{
					LoadDelivery(val);
					if (val.DeliveryVehicles != null)
					{
						flag = true;
						VehicleData[] deliveryVehicles = val.DeliveryVehicles;
						VehicleData[] array = deliveryVehicles;
						foreach (VehicleData data in array)
						{
							LoadVehicle(data, mainPath);
						}
					}
				}
			}
			if (!flag && Directory.Exists(mainPath))
			{
				Console.Log((object)("Loading legacy delivery vehicles at: " + mainPath), (Object)null);
				string text2 = Path.Combine(mainPath, "DeliveryVehicles");
				List<DirectoryInfo> directories = ((Loader)__instance).GetDirectories(text2);
				for (int j = 0; j < directories.Count; j++)
				{
					__instance.LoadVehicle(directories[j].FullName);
				}
			}
			return false;
		}

		private static void LoadVehicle(VehicleData data, string path)
		{
			Logger.Debug("Processing GUID " + data.GUID);
			LandVehicle val;
			lock (PoolManager.Lock)
			{
				DeliveryVehicle? obj = ((IEnumerable<DeliveryVehicle>)PoolManager.Instance.Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle dv) => dv.Vehicle.GUID.ToString() == data.GUID));
				val = ((obj != null) ? obj.Vehicle : null);
			}
			if ((Object)(object)val == (Object)null)
			{
				Logger.Debug("GUID " + data.GUID + " not found in Pool, lookup via GUIDManager");
				val = GUIDManager.GetObject<LandVehicle>(new Guid(data.GUID));
			}
			if ((Object)(object)val == (Object)null)
			{
				Logger.Error("Vehicle not found with GUID", data.GUID);
				Console.LogError((object)("LoadVehicle: Vehicle not found with GUID " + data.GUID), (Object)null);
			}
			else
			{
				LoadVehicle(val, data, path);
			}
		}

		private static void LoadVehicle(LandVehicle vehicle, VehicleData data, string containerPath)
		{
			Logger.Debug($"Processing vehicle {((Object)vehicle).name} with GUID {vehicle.GUID}");
			if ((Object)(object)vehicle.Storage != (Object)null)
			{
				if (data.VehicleContents != null && data.VehicleContents.Items != null)
				{
					DeserializedItemSet val = default(DeserializedItemSet);
					if (ItemSet.TryDeserialize(data.VehicleContents, ref val))
					{
						val.LoadTo(vehicle.Storage.ItemSlots);
					}
				}
				else if (File.Exists(Path.Combine(containerPath, "Contents.json")))
				{
					Console.LogWarning((object)"Loading legacy vehicle contents.", (Object)null);
					string text = default(string);
					DeserializedItemSet val2 = default(DeserializedItemSet);
					if (vehicle.Loader.TryLoadFile(containerPath, "Contents", ref text) && ItemSet.TryDeserialize(text, ref val2))
					{
						val2.LoadTo(vehicle.Storage.ItemSlots);
					}
				}
			}
			if (data.SpraySurfaces == null)
			{
				return;
			}
			try
			{
				for (int i = 0; i < data.SpraySurfaces.Count; i++)
				{
					if (vehicle._spraySurfaces.Length > i)
					{
						SpraySurface obj = vehicle._spraySurfaces[i];
						if (obj != null)
						{
							obj.Set((NetworkConnection)null, data.SpraySurfaces[i].Strokes.ToArray(), data.SpraySurfaces[i].ContainsCartelGraffiti);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Logger.Error("Exception thrown while loading saved graffities", ex);
			}
		}

		private static DeliveryVehicle? FindVehicleByGuid(string guid)
		{
			lock (PoolManager.Lock)
			{
				DeliveryVehicle val = ((IEnumerable<DeliveryVehicle>)PoolManager.Instance.Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle dv) => dv.GUID.ToString() == guid));
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			foreach (ShopInterface allShop in ShopInterface.AllShops)
			{
				if ((Object)(object)allShop.DeliveryVehicle != (Object)null && allShop.DeliveryVehicle.GUID.ToString() == guid)
				{
					return allShop.DeliveryVehicle;
				}
			}
			return null;
		}

		private static void LoadDelivery(DeliveriesData data)
		{
			if (data == null)
			{
				return;
			}
			if (data.ActiveDeliveries != null)
			{
				foreach (AllocationEntry item in VehicleSave.Instance.AllocationMap.ToList())
				{
					DeliveryVehicle val = FindVehicleByGuid(item.VehicleGUID);
					if ((Object)(object)val != (Object)null)
					{
						PoolManager.Instance.AllocateDirectly(item.DeliveryID, val);
						Logger.Debug("Restored allocation: " + item.DeliveryID + " -> " + item.VehicleGUID);
					}
					else
					{
						Logger.Warning("Could not find vehicle for allocation: " + item.VehicleGUID);
					}
				}
				foreach (BaseAllocationEntry item2 in VehicleSave.Instance.BaseAllocationMap.ToList())
				{
					PoolManager.Instance.SetBaseAllocation(item2.ShopName, item2.IsAllocated);
					Logger.Debug($"Restored base allocation: {item2.ShopName} = {item2.IsAllocated}");
				}
				DeliveryInstance[] activeDeliveries = data.ActiveDeliveries;
				foreach (DeliveryInstance val2 in activeDeliveries)
				{
					NetworkSingleton<DeliveryManager>.Instance.SendDelivery(val2);
				}
			}
			if (data.DeliveryHistory != null)
			{
				DeliveryReceipt[] deliveryHistory = data.DeliveryHistory;
				foreach (DeliveryReceipt val3 in deliveryHistory)
				{
					NetworkSingleton<DeliveryManager>.Instance._deliveryHistory.Add(val3);
				}
			}
			if (data.DisplayedDeliveryHistory != null)
			{
				DeliveryReceipt[] displayedDeliveryHistory = data.DisplayedDeliveryHistory;
				foreach (DeliveryReceipt val4 in displayedDeliveryHistory)
				{
					NetworkSingleton<DeliveryManager>.Instance._displayedDeliveryHistory.Add(val4);
				}
			}
		}
	}
	public class PoolManager
	{
		internal static readonly Logger Logger = new Logger("PoolManager");

		internal static readonly object Lock = new object();

		public static PoolManager Instance { get; } = new PoolManager();

		public HashSet<DeliveryVehicle> Pool { get; } = new HashSet<DeliveryVehicle>();

		internal Dictionary<string, DeliveryVehicle> Allocations { get; } = new Dictionary<string, DeliveryVehicle>();

		internal Dictionary<string, bool> BaseVehicleAllocationsForShop { get; } = new Dictionary<string, bool>();

		internal int PoolCount
		{
			get
			{
				lock (Lock)
				{
					return Pool.Count;
				}
			}
		}

		internal int AllocationCount
		{
			get
			{
				lock (Lock)
				{
					return Allocations.Count;
				}
			}
		}

		public void AddToPool(DeliveryVehicle deliveryVehicle, bool notify = true)
		{
			lock (Lock)
			{
				Pool.Add(deliveryVehicle);
				if (notify)
				{
					NetworkConvenienceMethods.NotifyVehicleAdded(deliveryVehicle);
				}
			}
		}

		public void AddToSaveData(DeliveryVehicle deliveryVehicle)
		{
			if ((Object)(object)deliveryVehicle == (Object)null)
			{
				throw new ArgumentNullException("deliveryVehicle");
			}
			VehicleSave.Instance.AddVehicle(deliveryVehicle.Vehicle);
			NetworkConvenienceMethods.NotifyVehicleCreated(deliveryVehicle);
		}

		public DeliveryVehicle? GetFirstFree()
		{
			lock (Lock)
			{
				DeliveryVehicle val = ((IEnumerable<DeliveryVehicle>)Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle dv) => dv.ActiveDelivery == null && !Allocations.ContainsValue(dv)));
				if (Time.frameCount % 30 == 0)
				{
					Logger.Debug("Pool lookup: " + (((Object)(object)val == (Object)null) ? "null" : "not null"));
				}
				return val;
			}
		}

		public DeliveryVehicle GetOrAllocateFirstFree(string deliveryId)
		{
			lock (Lock)
			{
				Logger.Debug("GetOrAllocateFirstFree called for: " + deliveryId);
				if (Allocations.TryGetValue(deliveryId, out DeliveryVehicle value))
				{
					Logger.Debug("Already allocated, returning existing");
					return value;
				}
				DeliveryVehicle firstFree = GetFirstFree();
				if ((Object)(object)firstFree == (Object)null)
				{
					Logger.Debug($"No free vehicle found! Pool count: {Pool.Count}, Allocations count: {Allocations.Count}");
					foreach (KeyValuePair<string, DeliveryVehicle> allocation in Allocations)
					{
						Logger.Debug("Allocation: " + allocation.Key + " -> Vehicle has ActiveDelivery: " + (allocation.Value.ActiveDelivery?.DeliveryID ?? "null"));
					}
					throw new ArgumentException("Tried to allocate a non-free vehicle");
				}
				Allocations.Add(deliveryId, firstFree);
				Logger.Debug("Allocated new vehicle for " + deliveryId + ", vehicle: " + firstFree.GUID);
				VehicleSave.Instance.AddAllocation(deliveryId, firstFree);
				NetworkConvenienceMethods.NotifyAllocation(deliveryId, firstFree, isAllocated: true);
				return firstFree;
			}
		}

		internal void AllocateDirectly(string deliveryId, DeliveryVehicle deliveryVehicle)
		{
			lock (Lock)
			{
				Logger.Debug("AllocateDirectly called for: " + deliveryId);
				if (Allocations.TryGetValue(deliveryId, out DeliveryVehicle _))
				{
					Logger.Debug("Already allocated, returning");
					return;
				}
				Allocations.Add(deliveryId, deliveryVehicle);
				Logger.Debug("Directly allocated vehicle for " + deliveryId + ", vehicle: " + deliveryVehicle.GUID);
				VehicleSave.Instance.AddAllocation(deliveryId, deliveryVehicle);
				NetworkConvenienceMethods.NotifyAllocation(deliveryId, deliveryVehicle, isAllocated: true);
			}
		}

		internal void SetBaseAllocation(string shopName, bool allocated)
		{
			lock (Lock)
			{
				BaseVehicleAllocationsForShop[shopName] = allocated;
			}
			VehicleSave.Instance.SyncBaseAllocation(shopName, allocated);
			NetworkConvenienceMethods.NotifyBaseAllocation(shopName, allocated);
		}

		public void FreeAllocation(string deliveryId)
		{
			lock (Lock)
			{
				Logger.Debug("Free custom allocation: " + deliveryId);
				if (Allocations.TryGetValue(deliveryId, out DeliveryVehicle value))
				{
					Allocations.Remove(deliveryId);
					VehicleSave.Instance.RemoveAllocation(deliveryId);
					NetworkConvenienceMethods.NotifyAllocation(deliveryId, value, isAllocated: false);
				}
			}
		}

		internal void ClearAll()
		{
			lock (Lock)
			{
				Pool.Clear();
				Allocations.Clear();
				BaseVehicleAllocationsForShop.Clear();
			}
			VehicleSave instance = VehicleSave.Instance;
			instance.ClearAllocations();
			instance.ClearBaseAllocations();
		}

		internal bool RemoveFromPool(DeliveryVehicle vehicle)
		{
			lock (Lock)
			{
				List<string> list = (from x in Allocations
					where (Object)(object)x.Value == (Object)(object)vehicle
					select x.Key).ToList();
				foreach (string item in list)
				{
					Allocations.Remove(item);
					VehicleSave.Instance.RemoveAllocation(item);
				}
				VehicleSave.Instance.RemoveAllocationsForVehicle(vehicle);
				return Pool.Remove(vehicle);
			}
		}

		internal DeliveryVehicle? LastPoolVehicle()
		{
			lock (Lock)
			{
				return Pool.LastOrDefault();
			}
		}
	}
	[HarmonyPatch(typeof(Wheel))]
	internal class WheelPatch
	{
		[HarmonyPatch("OnWeatherChange")]
		[HarmonyPrefix]
		private static bool ExitIfNull(Wheel __instance, WeatherConditions newConditions)
		{
			if ((Object)(object)__instance?.vehicle == (Object)null)
			{
				return false;
			}
			if (newConditions != null)
			{
				_ = newConditions.Rainy;
				if (0 == 0)
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(DeliveryVehicle))]
	internal static class DeliveryVehicleAwakePatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPrefix]
		private static bool ExitIfNull(DeliveryVehicle __instance)
		{
			if (Guid.TryParse(__instance.GUID, out var _))
			{
				return true;
			}
			if ((Object)(object)((Component)__instance).GetComponent<LandVehicle>() == (Object)null)
			{
				return false;
			}
			__instance.Vehicle = ((Component)__instance).GetComponent<LandVehicle>();
			__instance.Deactivate();
			return false;
		}
	}
}
namespace MultiDelivery.Persistence
{
	public class PersistentDropoffQuestData : Saveable
	{
		[SaveableField("MessageData")]
		public bool HasMessaged;

		public static PersistentDropoffQuestData Instance { get; private set; } = new PersistentDropoffQuestData();

		public PersistentDropoffQuestData()
		{
			Instance = this;
		}
	}
	[Serializable]
	public class AllocationEntry
	{
		public string DeliveryID;

		public string VehicleGUID;
	}
	[Serializable]
	public class BaseAllocationEntry
	{
		public string ShopName;

		public bool IsAllocated;
	}
	public class VehicleSave : Saveable
	{
		[SaveableField("VehicleSaveData")]
		private List<VehicleSaveDto> _dtos = new List<VehicleSaveDto>();

		[SaveableField("AllocationMap")]
		private List<AllocationEntry> _allocationMap = new List<AllocationEntry>();

		[SaveableField("BaseAllocationMap")]
		private List<BaseAllocationEntry> _baseAllocationMap = new List<BaseAllocationEntry>();

		private static readonly Logger Logger = new Logger("VehicleSave");

		private static Transform _parent;

		public override SaveableLoadOrder LoadOrder => (SaveableLoadOrder)0;

		public IReadOnlyList<AllocationEntry> AllocationMap => _allocationMap;

		public IReadOnlyList<BaseAllocationEntry> BaseAllocationMap => _baseAllocationMap;

		public static VehicleSave Instance { get; set; } = new VehicleSave();

		public VehicleSave()
		{
			Instance = this;
		}

		public void AddVehicle(LandVehicle vehicle)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			VehicleSaveDto item = new VehicleSaveDto
			{
				Guid = vehicle.GUID.ToString(),
				VehicleType = vehicle.VehicleCode,
				Color = vehicle.Color.displayedColor
			};
			if (!_dtos.Contains(item))
			{
				_dtos.Add(item);
			}
		}

		internal void AddAllocation(string deliveryId, DeliveryVehicle vehicle)
		{
			string vehicleGUID = vehicle.GUID.ToString();
			_allocationMap.RemoveAll((AllocationEntry e) => e.DeliveryID == deliveryId);
			_allocationMap.Add(new AllocationEntry
			{
				DeliveryID = deliveryId,
				VehicleGUID = vehicleGUID
			});
		}

		internal void RemoveAllocation(string deliveryId)
		{
			_allocationMap.RemoveAll((AllocationEntry e) => e.DeliveryID == deliveryId);
		}

		internal void RemoveAllocationsForVehicle(DeliveryVehicle vehicle)
		{
			string guid = vehicle.GUID.ToString();
			_allocationMap.RemoveAll((AllocationEntry e) => e.VehicleGUID == guid);
		}

		internal void ClearAllocations()
		{
			_allocationMap.Clear();
		}

		internal void ClearBaseAllocations()
		{
			_baseAllocationMap.Clear();
		}

		internal void SyncBaseAllocation(string shopName, bool allocated)
		{
			_baseAllocationMap.RemoveAll((BaseAllocationEntry e) => e.ShopName == shopName);
			_baseAllocationMap.Add(new BaseAllocationEntry
			{
				ShopName = shopName,
				IsAllocated = allocated
			});
		}

		internal void RemoveVehicle(DeliveryVehicle vehicle)
		{
			_dtos.RemoveAll((VehicleSaveDto dto) => dto.Guid.ToString() == vehicle.GUID.ToString());
		}

		protected override void OnLoaded()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			Logger.Msg($"OnLoaded: Loading {_dtos.Count} vehicles");
			if ((Object)(object)_parent == (Object)null)
			{
				GameObject val = GameObject.Find("VehiclePool");
				if ((Object)(object)val == (Object)null)
				{
					val = new GameObject("VehiclePool");
				}
				_parent = val.transform;
			}
			for (int i = 0; i < _dtos.Count; i++)
			{
				Logger.Debug($"Loading vehicle {i}: {_dtos[i].Guid}");
				Guid guid = new Guid(_dtos[i].Guid);
				LandVehicle val2 = new LandVehicleBuilder().WithVehicleCode(_dtos[i].VehicleType).WithVehicleName($"Additional Delivery Vehicle {i + 1}").WithGuid(guid)
					.WithColor(_dtos[i].Color)
					.WithParent(_parent)
					.Build();
				MelonCoroutines.Start(DeferredSetColor(val2, _dtos[i].Color));
				Logger.Debug($"Built LandVehicle: {val2.vehicleName}, ObjectId: {((NetworkBehaviour)val2).ObjectId}");
				DeliveryVehicle val3 = new DeliveryVehicleBuilder().WithLandVehicle(val2).WithGuid(guid).Build();
				Logger.Debug("Built DeliveryVehicle: " + val3.GUID);
				PoolManager.Instance.AddToPool(val3);
				Logger.Debug($"Added to pool. Pool count now: {PoolManager.Instance.PoolCount}");
			}
			Logger.Msg($"OnLoaded complete. Final pool count: {PoolManager.Instance.PoolCount}");
		}

		private IEnumerator DeferredSetColor(LandVehicle vehicle, EVehicleColor color)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			while ((Object)(object)Player.Local == (Object)null || (Object)(object)((Component)Player.Local).gameObject == (Object)null)
			{
				yield return null;
			}
			yield return null;
			vehicle.ApplyColor(color);
		}
	}
	public record VehicleSaveDto
	{
		public string Guid { get; set; }

		public string VehicleType { get; set; }

		public EVehicleColor Color { get; set; }
	}
}
namespace MultiDelivery.Network
{
	public class DeliveryNetworkManager : IDeliveryNetworkManager, IDisposable
	{
		private SteamNetworkClient _client;

		private readonly Logger _logger;

		private const string ModDataKey = "MultiDelivery_Version";

		private const string ModVersion = "1.0.0";

		public bool IsInLobby
		{
			get
			{
				SteamNetworkClient client = _client;
				return client != null && client.IsInLobby;
			}
		}

		public bool IsHost
		{
			get
			{
				SteamNetworkClient client = _client;
				return client != null && client.IsHost;
			}
		}

		public bool IsSingleplayer => !IsInLobby;

		public bool HostOrSingleplayer => IsHost || IsSingleplayer;

		public DeliveryNetworkManager()
		{
			_logger = new Logger("Network");
		}

		public bool Initialize()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			try
			{
				NetworkRules val = new NetworkRules
				{
					EnableRelay = true,
					AcceptOnlyFriends = false
				};
				_client = new SteamNetworkClient(val);
				if (!_client.Initialize())
				{
					_logger.Error("Failed to initialize SteamNetworkClient");
					return false;
				}
				RegisterMessageHandlers();
				SubscribeToEvents();
				_logger.Msg("Network manager initialized successfully");
				return true;
			}
			catch (Exception arg)
			{
				_client = null;
				_logger.Error($"Failed to initialize network manager: {arg}");
				return false;
			}
		}

		public void RegisterLoggerSettings()
		{
			_logger.RaiseDebug = MultiDelivery.NetworkLogging?.Value ?? false;
			((MelonEventBase<LemonAction<bool, bool>>)(object)MultiDelivery.NetworkLogging?.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)delegate(bool _, bool newValue)
			{
				_logger.RaiseDebug = newValue;
			}, 0, false);
		}

		private void RegisterMessageHandlers()
		{
			_client.RegisterMessageHandler<VehicleAddedMessage>((Action<VehicleAddedMessage, CSteamID>)OnVehicleAdded);
			_client.RegisterMessageHandler<VehicleCreatedMessage>((Action<VehicleCreatedMessage, CSteamID>)OnVehicleCreated);
			_client.RegisterMessageHandler<VehiclePoolSyncRequest>((Action<VehiclePoolSyncRequest, CSteamID>)OnPoolSyncRequest);
			_client.RegisterMessageHandler<VehiclePoolSyncResponse>((Action<VehiclePoolSyncResponse, CSteamID>)OnPoolSyncResponse);
			_client.RegisterMessageHandler<VehicleAllocationMessage>((Action<VehicleAllocationMessage, CSteamID>)OnVehicleAllocation);
			_client.RegisterMessageHandler<BaseVehicleAllocationMessage>((Action<BaseVehicleAllocationMessage, CSteamID>)OnBaseVehicleAllocation);
		}

		private void SubscribeToEvents()
		{
			_client.OnLobbyCreated += OnLobbyCreated;
			_client.OnLobbyJoined += OnLobbyJoined;
			_client.OnMemberJoined += OnMemberJoined;
			_client.OnLobbyLeft += OnLobbyLeft;
		}

		public void Update()
		{
			SteamNetworkClient client = _client;
			if (client != null)
			{
				client.ProcessIncomingMessages();
			}
		}

		public void Dispose()
		{
			SteamNetworkClient client = _client;
			if (client != null)
			{
				client.Dispose();
			}
		}

		public async void BroadcastVehicleAdded(DeliveryVehicle vehicle)
		{
			if (!IsSingleplayer)
			{
				VehicleAddedMessage message = new VehicleAddedMessage
				{
					ObjectId = ((NetworkBehaviour)vehicle.Vehicle).ObjectId,
					VehicleGuid = vehicle.GUID,
					VehicleName = vehicle.Vehicle.vehicleName,
					VehicleCode = vehicle.Vehicle.VehicleCode,
					VehicleColor = (int)vehicle.Vehicle.Color.displayedColor
				};
				_logger.D($"Broadcasting vehicle added: ObjectId={message.ObjectId}, GUID={message.VehicleGuid}");
				await _client.BroadcastMessageAsync((P2PMessage)(object)message);
			}
		}

		public async void BroadcastVehicleCreated(DeliveryVehicle vehicle)
		{
			if (!IsSingleplayer && !IsHost)
			{
				VehicleCreatedMessage message = new VehicleCreatedMessage
				{
					ObjectId = ((NetworkBehaviour)vehicle.Vehicle).ObjectId,
					VehicleGuid = vehicle.GUID
				};
				_logger.D($"Broadcasting vehicle created: ObjectId={message.ObjectId}");
				await _client.BroadcastMessageAsync((P2PMessage)(object)message);
			}
		}

		public async void BroadcastVehicleAllocation(string deliveryId, DeliveryVehicle vehicle, bool isAllocated)
		{
			if (!IsSingleplayer)
			{
				VehicleAllocationMessage message = new VehicleAllocationMessage
				{
					DeliveryId = deliveryId,
					VehicleGuid = vehicle.GUID,
					IsAllocated = isAllocated
				};
				_logger.D($"Broadcasting allocation: Delivery={deliveryId}, Vehicle={vehicle.GUID}, Allocated={isAllocated}");
				await _client.BroadcastMessageAsync((P2PMessage)(object)message);
			}
		}

		public async void BroadcastBaseVehicleAllocation(string shopName, bool isAllocated)
		{
			if (!IsSingleplayer)
			{
				BaseVehicleAllocationMessage message = new BaseVehicleAllocationMessage
				{
					ShopName = shopName,
					IsAllocated = isAllocated
				};
				_logger.D($"Broadcasting base allocation: Shop={shopName}, Allocated={isAllocated}");
				await _client.BroadcastMessageAsync((P2PMessage)(object)message);
			}
		}

		private void OnVehicleAdded(VehicleAddedMessage message, CSteamID cSteamID)
		{
			_logger.D($"Received VehicleAdded: ObjectId={message.ObjectId}, GUID={message.VehicleGuid}");
			MelonCoroutines.Start(ProcessMessage());
			IEnumerator ProcessMessage()
			{
				yield return ExponentialBackoff(delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByName = SceneManager.GetSceneByName("Main");
					return ((Scene)(ref sceneByName)).isLoaded;
				}, 1f, 30f, 60f);
				yield return ExponentialBackoff(() => (Object)(object)FindLandVehicleByObjectId(message.ObjectId) != (Object)null, 1f, 30f, 60f);
				try
				{
					LandVehicle landVehicle = FindLandVehicleByObjectId(message.ObjectId);
					if ((Object)(object)landVehicle == (Object)null)
					{
						_logger.Warning($"LandVehicle with ObjectId {message.ObjectId} not found - may not have spawned yet");
					}
					else
					{
						Guid deliveryGuid = new Guid(message.VehicleGuid);
						landVehicle.SetGUID(deliveryGuid);
						landVehicle.ApplyColor((EVehicleColor)message.VehicleColor);
						DeliveryVehicle deliveryVehicle = ((Component)landVehicle).GetComponent<DeliveryVehicle>() ?? new DeliveryVehicleBuilder().WithLandVehicle(landVehicle).WithGuid(deliveryGuid).Build();
						PoolManager.Instance.AddToPool(deliveryVehicle, notify: false);
						_logger.D($"Added vehicle to pool: ObjectId={message.ObjectId}, DeliveryGUID={message.VehicleGuid}");
					}
				}
				catch (Exception arg)
				{
					_logger.Error($"Failed to add vehicle: {arg}");
				}
			}
		}

		private void OnVehicleCreated(VehicleCreatedMessage message, CSteamID senderId)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (IsHost)
			{
				_logger.D($"Received vehicle created message from {senderId}");
				MelonCoroutines.Start(ProcessMessage());
			}
			IEnumerator ProcessMessage()
			{
				yield return ExponentialBackoff(delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByName = SceneManager.GetSceneByName("Main");
					return ((Scene)(ref sceneByName)).isLoaded;
				}, 1f, 30f, 60f);
				yield return ExponentialBackoff(() => (Object)(object)FindLandVehicleByObjectId(message.ObjectId) != (Object)null, 1f, 30f, 60f);
				try
				{
					LandVehicle landVehicle = FindLandVehicleByObjectId(message.ObjectId);
					if ((Object)(object)landVehicle == (Object)null)
					{
						_logger.Error($"LandVehicle with ObjectId {message.ObjectId} not found");
					}
					else
					{
						VehicleSave.Instance.AddVehicle(landVehicle);
						_logger.D($"Added created vehicle to save data: ObjectId={message.ObjectId}, GUID={message.VehicleGuid}");
					}
				}
				catch (Exception arg)
				{
					_logger.Error($"Failed to create vehicle: {arg}");
				}
			}
		}

		private async void OnPoolSyncRequest(VehiclePoolSyncRequest message, CSteamID senderId)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!IsHost)
			{
				return;
			}
			_logger.D($"Received pool sync request from {senderId}");
			try
			{
				VehiclePoolSyncResponse response = new VehiclePoolSyncResponse();
				lock (PoolManager.Lock)
				{
					foreach (DeliveryVehicle vehicle in PoolManager.Instance.Pool)
					{
						response.Vehicles.Add(new VehiclePoolSyncResponse.VehicleData
						{
							ObjectId = ((NetworkBehaviour)vehicle.Vehicle).ObjectId,
							Guid = vehicle.GUID,
							Name = vehicle.Vehicle.vehicleName,
							Code = vehicle.Vehicle.VehicleCode,
							Color = (int)vehicle.Vehicle.Color.displayedColor
						});
					}
				}
				_logger.D($"Sending pool sync with {response.Vehicles.Count} vehicles");
				await _client.SendMessageToPlayerAsync(senderId, (P2PMessage)(object)response);
			}
			catch (Exception arg)
			{
				_logger.Error($"Failed to send pool sync: {arg}");
			}
		}

		private void OnPoolSyncResponse(VehiclePoolSyncResponse message, CSteamID senderId)
		{
			if (!IsHost)
			{
				_logger.D($"Received pool sync response with {message.Vehicles.Count} vehicles");
				MelonCoroutines.Start(ProcessMessage());
			}
			IEnumerator ProcessMessage()
			{
				yield return ExponentialBackoff(delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByName = SceneManager.GetSceneByName("Main");
					return ((Scene)(ref sceneByName)).isLoaded;
				}, 1f, 30f, 60f);
				yield return ExponentialBackoff(() => message.Vehicles.All((VehiclePoolSyncResponse.VehicleData v) => (Object)(object)FindLandVehicleByObjectId(v.ObjectId) != (Object)null), 1f, 30f, 60f);
				try
				{
					foreach (VehiclePoolSyncResponse.VehicleData vehicleData in message.Vehicles)
					{
						LandVehicle landVehicle = FindLandVehicleByObjectId(vehicleData.ObjectId);
						if ((Object)(object)landVehicle == (Object)null)
						{
							_logger.Warning($"LandVehicle with ObjectId {vehicleData.ObjectId} not found - skipping");
						}
						else
						{
							Guid deliveryGuid = new Guid(vehicleData.Guid);
							landVehicle.SetGUID(deliveryGuid);
							landVehicle.ApplyColor((EVehicleColor)vehicleData.Color);
							DeliveryVehicle deliveryVehicle = ((Component)landVehicle).GetComponent<DeliveryVehicle>() ?? new DeliveryVehicleBuilder().WithLandVehicle(landVehicle).WithGuid(deliveryGuid).Build();
							PoolManager.Instance.AddToPool(deliveryVehicle, notify: false);
						}
					}
					_logger.D($"Pool synchronized: {PoolManager.Instance.Pool.Count} vehicles");
				}
				catch (Exception arg)
				{
					_logger.Error($"Failed to sync pool: {arg}");
				}
			}
		}

		private void OnVehicleAllocation(VehicleAllocationMessage message, CSteamID senderId)
		{
			_logger.D($"Received allocation: Delivery={message.DeliveryId}, Vehicle={message.VehicleGuid}, Allocated={message.IsAllocated}");
			MelonCoroutines.Start(ProcessMessage());
			IEnumerator ProcessMessage()
			{
				yield return ExponentialBackoff(delegate
				{
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByName = SceneManager.GetSceneByName("Main");
					return ((Scene)(ref sceneByName)).isLoaded;
				}, 1f, 30f, 60f);
				yield return ExponentialBackoff(delegate
				{
					lock (PoolManager.Lock)
					{
						if ((Object)(object)((IEnumerable<DeliveryVehicle>)PoolManager.Instance.Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle v) => v.GUID == message.VehicleGuid)) != (Object)null)
						{
							return true;
						}
					}
					foreach (ShopInterface allShop in ShopInterface.AllShops)
					{
						if ((Object)(object)allShop.DeliveryVehicle != (Object)null && allShop.DeliveryVehicle.GUID == message.VehicleGuid)
						{
							return true;
						}
					}
					return false;
				}, 1f, 30f, 60f);
				try
				{
					DeliveryVehicle vehicle;
					lock (PoolManager.Lock)
					{
						vehicle = ((IEnumerable<DeliveryVehicle>)PoolManager.Instance.Pool).FirstOrDefault((Func<DeliveryVehicle, bool>)((DeliveryVehicle v) => v.GUID == message.VehicleGuid));
					}
					if ((Object)(object)vehicle == (Object)null)
					{
						foreach (ShopInterface shop in ShopInterface.AllShops)
						{
							if ((Object)(object)shop.DeliveryVehicle != (Object)null && shop.DeliveryVehicle.GUID == message.VehicleGuid)
							{
								vehicle = shop.DeliveryVehicle;
								break;
							}
						}
					}
					if ((Object)(object)vehicle == (Object)null)
					{
						_logger.Warning("Vehicle not found for allocation: " + message.VehicleGuid);
					}
					else
					{
						lock (PoolManager.Lock)
						{
							if (message.IsAllocated)
							{
								_logger.D("Trying to allocate " + message.VehicleGuid + " for delivery " + message.DeliveryId);
								if (!PoolManager.Instance.Allocations.ContainsKey(message.DeliveryId))
								{
									_logger.D("Allocating " + message.VehicleGuid + " for delivery " + message.DeliveryId);
									PoolManager.Instance.Allocations.Add(message.DeliveryId, vehicle);
								}
							}
							else
							{
								_logger.D("Deallocating " + message.VehicleGuid + " for delivery " + message.DeliveryId);
								PoolManager.Instance.Allocations.Remove(message.DeliveryId);
							}
						}
					}
				}
				catch (Exception arg)
				{
					_logger.Error($"Failed to process allocation: {arg}");
				}
			}
		}

		private void OnBaseVehicleAllocation(BaseVehicleAllocationMessage message, CSteamID senderId)
		{
			_logger.D($"Received base allocation: Shop={message.ShopName}, Allocated={message.IsAllocated}");
			lock (PoolManager.Lock)
			{
				try
				{
					PoolManager.Instance.BaseVehicleAllocationsForShop[message.ShopName] = message.IsAllocated;
				}
				catch (Exception arg)
				{
					_logger.Error($"Failed to process base allocation: {arg}");
				}
			}
		}

		private void OnLobbyCreated(object sender, LobbyCreatedEventArgs e)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			_logger.D($"Lobby created: {e.Lobby.LobbyId}");
			_client.SetMyData("MultiDelivery_Version", "1.0.0");
		}

		private void OnLobbyJoined(object sender, LobbyJoinedEventArgs e)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			_logger.D($"Joined lobby: {e.Lobby.LobbyId}");
			_client.SetMyData("MultiDelivery_Version", "1.0.0");
			if (!IsHost)
			{
				RequestPoolSync();
			}
		}

		private async void OnMemberJoined(object sender, MemberJoinedEventArgs e)
		{
			if (!IsHost)
			{
				return;
			}
			_logger.D("Member joined: " + e.Member.DisplayName);
			await Task.Delay(1000);
			VehiclePoolSyncResponse response = new VehiclePoolSyncResponse();
			lock (PoolManager.Lock)
			{
				foreach (DeliveryVehicle vehicle in PoolManager.Instance.Pool)
				{
					response.Vehicles.Add(new VehiclePoolSyncResponse.VehicleData
					{
						ObjectId = ((NetworkBehaviour)vehicle.Vehicle).ObjectId,
						Guid = vehicle.GUID,
						Name = vehicle.Vehicle.vehicleName,
						Code = vehicle.Vehicle.VehicleCode,
						Color = (int)vehicle.Vehicle.Color.displayedColor
					});
				}
			}
			_logger.D($"Sending pool sync to new member ({response.Vehicles.Count} vehicles)");
			await _client.SendMessageToPlayerAsync(e.Member.SteamId, (P2PMessage)(object)response);
		}

		private void OnLobbyLeft(object sender, LobbyLeftEventArgs e)
		{
			_logger.D("Left lobby: " + e.Reason);
		}

		private async void RequestPoolSync()
		{
			if (!IsSingleplayer && !IsHost)
			{
				List<MemberInfo> members = _client.GetLobbyMembers();
				MemberInfo host = ((IEnumerable<MemberInfo>)members).FirstOrDefault((Func<MemberInfo, bool>)((MemberInfo m) => m.IsOwner));
				if (host == null)
				{
					_logger.Error("Cannot request pool sync - no host found");
					return;
				}
				VehiclePoolSyncRequest message = new VehiclePoolSyncRequest
				{
					RequesterId = ((object)_client.LocalPlayerId/*cast due to .constrained prefix*/).ToString()
				};
				_logger.D("Requesting pool sync from host");
				await _client.SendMessageToPlayerAsync(host.SteamId, (P2PMessage)(object)message);
			}
		}

		private LandVehicle? FindLandVehicleByObjectId(int objectId)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Scene sceneByName = SceneManager.GetSceneByName("Main");
			if (!((Scene)(ref sceneByName)).isLoaded)
			{
				_logger.Error("Main scene is not loaded");
				return null;
			}
			GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
			GameObject[] array = rootGameObjects;
			foreach (GameObject val in array)
			{
				LandVehicle[] componentsInChildren = val.GetComponentsInChildren<LandVehicle>(true);
				LandVehicle[] array2 = componentsInChildren;
				foreach (LandVehicle val2 in array2)
				{
					if (((NetworkBehaviour)val2).ObjectId == objectId)
					{
						_logger.D($"Found LandVehicle: ObjectId={objectId}, Name={val2.vehicleName}");
						return val2;
					}
				}
			}
			_logger.Warning($"LandVehicle with ObjectId {objectId} not found in Main scene");
			return null;
		}

		private static IEnumerator ExponentialBackoff(Func<bool> predicate, float initialDelay, float finalDelay, float timeout)
		{
			float delay = initialDelay;
			float elapsed = 0f;
			while (!predicate() && elapsed < timeout)
			{
				yield return (object)new WaitForSeconds(delay);
				elapsed += delay;
				delay = Mathf.Min(delay * 2f, finalDelay);
			}
		}
	}
	public interface IDeliveryNetworkManager : IDisposable
	{
		bool IsInLobby { get; }

		bool IsHost { get; }

		bool IsSingleplayer { get; }

		bool HostOrSingleplayer { get; }

		void RegisterLoggerSettings();

		bool Initialize();

		void Update();

		void BroadcastVehicleAdded(DeliveryVehicle vehicle);

		void BroadcastVehicleCreated(DeliveryVehicle vehicle);

		void BroadcastVehicleAllocation(string deliveryId, DeliveryVehicle vehicle, bool isAllocated);

		void BroadcastBaseVehicleAllocation(string shopName, bool isAllocated);
	}
	public class VehicleAddedMessage : P2PMessage
	{
		public override string MessageType => "VehicleAdded";

		public int ObjectId { get; set; }

		public string VehicleGuid { get; set; }

		public string VehicleName { get; set; }

		public string VehicleCode { get; set; }

		public int VehicleColor { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase($"\"ObjectId\":{ObjectId},\"VehicleGuid\":\"{VehicleGuid}\",\"VehicleName\":\"{VehicleName}\",\"VehicleCode\":\"{VehicleCode}\",\"VehicleColor\":{VehicleColor}");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			ObjectId = int.Parse(((P2PMessage)this).ExtractJsonValue(text, "ObjectId"));
			VehicleGuid = ((P2PMessage)this).ExtractJsonValue(text, "VehicleGuid");
			VehicleName = ((P2PMessage)this).ExtractJsonValue(text, "VehicleName");
			VehicleCode = ((P2PMessage)this).ExtractJsonValue(text, "VehicleCode");
			VehicleColor = int.Parse(((P2PMessage)this).ExtractJsonValue(text, "VehicleColor"));
		}
	}
	public class VehicleCreatedMessage : P2PMessage
	{
		public override string MessageType => "VehicleCreated";

		public int ObjectId { get; set; }

		public string VehicleGuid { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase($"\"ObjectId\":{ObjectId},\"VehicleGuid\":\"{VehicleGuid}\"");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			ObjectId = int.Parse(((P2PMessage)this).ExtractJsonValue(text, "ObjectId"));
			VehicleGuid = ((P2PMessage)this).ExtractJsonValue(text, "VehicleGuid");
		}
	}
	public class VehiclePoolSyncRequest : P2PMessage
	{
		public override string MessageType => "VehiclePoolSyncRequest";

		public string RequesterId { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase("\"RequesterId\":\"" + RequesterId + "\"");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			RequesterId = ((P2PMessage)this).ExtractJsonValue(text, "RequesterId");
		}
	}
	public class VehiclePoolSyncResponse : P2PMessage
	{
		[Serializable]
		public class VehicleData
		{
			public int ObjectId { get; set; }

			public string Guid { get; set; }

			public string Name { get; set; }

			public string Code { get; set; }

			public int Color { get; set; }
		}

		public override string MessageType => "VehiclePoolSyncResponse";

		public List<VehicleData> Vehicles { get; set; } = new List<VehicleData>();

		public override byte[] Serialize()
		{
			string text = string.Join(",", Vehicles.Select((VehicleData v) => $"{{\"ObjectId\":{v.ObjectId},\"Guid\":\"{v.Guid}\",\"Name\":\"{v.Name}\",\"Code\":\"{v.Code}\",\"Color\":{v.Color}}}"));
			string s = ((P2PMessage)this).CreateJsonBase("\"Vehicles\":[" + text + "]");
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			int num = text.IndexOf("\"Vehicles\":[", StringComparison.Ordinal) + 12;
			int num2 = text.IndexOf("]", num, StringComparison.Ordinal);
			string text2 = text.Substring(num, num2 - num);
			Vehicles.Clear();
			if (string.IsNullOrWhiteSpace(text2))
			{
				return;
			}
			string[] array = text2.Split(new string[1] { "}," }, StringSplitOptions.None);
			string[] array2 = array;
			foreach (string text3 in array2)
			{
				string text4 = text3.TrimStart('{').TrimEnd('}') + "}";
				if (text4.Contains("ObjectId"))
				{
					Vehicles.Add(new VehicleData
					{
						ObjectId = int.Parse(((P2PMessage)this).ExtractJsonValue(text4, "ObjectId")),
						Guid = ((P2PMessage)this).ExtractJsonValue(text4, "Guid"),
						Name = ((P2PMessage)this).ExtractJsonValue(text4, "Name"),
						Code = ((P2PMessage)this).ExtractJsonValue(text4, "Code"),
						Color = int.Parse(((P2PMessage)this).ExtractJsonValue(text4, "Color"))
					});
				}
			}
		}
	}
	public class VehicleAllocationMessage : P2PMessage
	{
		public override string MessageType => "VehicleAllocation";

		public string DeliveryId { get; set; }

		public string VehicleGuid { get; set; }

		public bool IsAllocated { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase("\"DeliveryId\":\"" + DeliveryId + "\",\"VehicleGuid\":\"" + VehicleGuid + "\",\"IsAllocated\":" + IsAllocated.ToString().ToLower());
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			DeliveryId = ((P2PMessage)this).ExtractJsonValue(text, "DeliveryId");
			VehicleGuid = ((P2PMessage)this).ExtractJsonValue(text, "VehicleGuid");
			IsAllocated = bool.Parse(((P2PMessage)this).ExtractJsonValue(text, "IsAllocated"));
		}
	}
	public class BaseVehicleAllocationMessage : P2PMessage
	{
		public override string MessageType => "BaseVehicleAllocation";

		public string ShopName { get; set; }

		public bool IsAllocated { get; set; }

		public override byte[] Serialize()
		{
			string s = ((P2PMessage)this).CreateJsonBase("\"ShopName\":\"" + ShopName + "\",\"IsAllocated\":" + IsAllocated.ToString().ToLower());
			return Encoding.UTF8.GetBytes(s);
		}

		public override void Deserialize(byte[] data)
		{
			string text = Encoding.UTF8.GetString(data);
			((P2PMessage)this).ParseJsonBase(text);
			ShopName = ((P2PMessage)this).ExtractJsonValue(text, "ShopName");
			IsAllocated = bool.Parse(((P2PMessage)this).ExtractJsonValue(text, "IsAllocated"));
		}
	}
	public static class NetworkConvenienceMethods
	{
		private static IDeliveryNetworkManager? _networkManager;

		public static bool HostOrSingleplayer => _networkManager?.HostOrSingleplayer ?? true;

		public static void InitializeNetworking(IDeliveryNetworkManager networkManager)
		{
			_networkManager = networkManager;
		}

		public static void NotifyVehicleAdded(DeliveryVehicle vehicle)
		{
			_networkManager?.BroadcastVehicleAdded(vehicle);
		}

		public static void NotifyVehicleCreated(DeliveryVehicle vehicle)
		{
			_networkManager?.BroadcastVehicleCreated(vehicle);
		}

		public static void NotifyAllocation(string deliveryId, DeliveryVehicle vehicle, bool isAllocated)
		{
			_networkManager?.BroadcastVehicleAllocation(deliveryId, vehicle, isAllocated);
		}

		public static void NotifyBaseAllocation(string shopName, bool isAllocated)
		{
			_networkManager?.BroadcastBaseVehicleAllocation(shopName, isAllocated);
		}
	}
	internal static class NetworkLoader
	{
		private static readonly Logger Logger = new Logger("NetworkLoader");

		internal static IDeliveryNetworkManager? Create()
		{
			if (AppDomain.CurrentDomain.GetAssemblies().All((Assembly a) => a.GetName().Name != "SteamNetworkLib"))
			{
				return null;
			}
			return CreateInternal();
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static IDeliveryNetworkManager? CreateInternal()
		{
			try
			{
				DeliveryNetworkManager deliveryNetworkManager = new DeliveryNetworkManager();
				deliveryNetworkManager.Initialize();
				return deliveryNetworkManager;
			}
			catch (Exception arg)
			{
				Logger.Warning($"Failed to initialize network manager: {arg}. If you're playing singleplayer, you may disregard this message.");
				return null;
			}
		}
	}
}
namespace MultiDelivery.Helpers
{
	public class DependenciesChecker
	{
		public class MissingDependencyInfo(string name, string version, List<DependencyUrl> urls, bool isRequired, string reason)
		{
			public string Name { get; set; } = name;

			public string Version { get; set; } = version;

			public List<DependencyUrl> Urls { get; set; } = urls;

			public bool IsRequired { get; set; } = isRequired;

			public string Reason { get; set; } = reason;
		}

		private static readonly Logger Logger = new Logger("DependenciesChecker");

		private readonly List<DependencyInfo> _dependencies = new List<DependencyInfo>();

		private List<MissingDependencyInfo> _missingDependencies = new List<MissingDependencyInfo>();

		public bool ShowMenuBanner { get; set; } = true;

		public bool ShowBannerIfOptionalOnly { get; set; } = false;

		public bool UnloadIfMissingRequired { get; set; } = false;

		public void AddDependency(DependencyInfo dependency)
		{
			_dependencies.Add(dependency);
		}

		public void ProcessAndAlert()
		{
			CheckDependencies();
			if (_missingDependencies.Count != 0)
			{
				PrintMissing();
				if (ShowMenuBanner)
				{
					ShowBanner();
				}
				MelonCoroutines.Start(DelayedUnload());
			}
		}

		private void CheckDependencies()
		{
			_missingDependencies = new List<MissingDependencyInfo>();
			foreach (DependencyInfo dependency in _dependencies)
			{
				MissingDependencyInfo missingDependencyInfo = IsPresent(dependency);
				if (missingDependencyInfo != null)
				{
					_missingDependencies.Add(missingDependencyInfo);
				}
			}
		}

		private void PrintMissing()
		{
			Logger.Msg("Missing dependencies:");
			foreach (MissingDependencyInfo missingDependency in _missingDependencies)
			{
				if (missingDependency.IsRequired)
				{
					Logger.Error("- " + missingDependency.Name + " (min version " + missingDependency.Version + "): required - " + missingDependency.Reason);
				}
				else
				{
					Logger.Warning("- " + missingDependency.Name + " (min version " + missingDependency.Version + "): optional - " + missingDependency.Reason);
				}
				if (missingDependency.Urls.Count == 0)
				{
					continue;
				}
				Logger.Msg("  Possible sources:");
				foreach (DependencyUrl url in missingDependency.Urls)
				{
					Logger.Msg("  - " + url.SourceName + ": " + url.Url);
				}
			}
		}

		private void ShowBanner()
		{
			((MelonEventBase<LemonAction<int, string>>)(object)MelonEvents.OnSceneWasLoaded).Subscribe((LemonAction<int, string>)delegate(int _, string name)
			{
				if (!(name != "Menu"))
				{
					MissingDepsPanelCreator.Show(this, _missingDependencies);
				}
			}, 0, false);
			((MelonEventBase<LemonAction<int, string>>)(object)MelonEvents.OnSceneWasUnloaded).Subscribe((LemonAction<int, string>)delegate(int _, string name)
			{
				if (!(name != "Menu"))
				{
					MissingDepsPanelCreator.Hide();
				}
			}, 0, false);
			MissingDepsPanelCreator.Show(this, _missingDependencies);
		}

		private IEnumerator DelayedUnload()
		{
			yield return (object)new WaitForSeconds(5f);
			if (UnloadIfMissingRequired && _missingDependencies.Any((MissingDependencyInfo d) => d.IsRequired))
			{
				Logger.Warning("Missing required dependencies detected and UnloadIfMissingRequired is true, unloading mod.");
				((MelonBase)Melon<MultiDelivery>.Instance).Unregister("Missing required dependencies", false);
			}
		}

		private static MissingDependencyInfo? IsPresent(DependencyInfo dependency)
		{
			Assembly foundInDomain = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly assembly) => assembly.GetName().Name == dependency.AssemblyName);
			if (foundInDomain == null)
			{
				Logger.Debug(dependency.AssemblyName + " not found in AppDomain, marking as missing.");
				return new MissingDependencyInfo(dependency.Name, dependency.Version, dependency.Urls, dependency.IsRequired, "Assembly not found");
			}
			MelonMod val = ((IEnumerable<MelonMod>)MelonTypeBase<MelonMod>.RegisteredMelons).FirstOrDefault((Func<MelonMod, bool>)((MelonMod m) => ((MelonBase)m).MelonAssembly.Assembly == foundInDomain));
			if (val == null)
			{
				Logger.Debug(foundInDomain.GetName().Name + " wasn't found in RegisteredMelons.");
				Version version = foundInDomain.GetName().Version;
				if (version == null)
				{
					Logger.Debug(dependency.AssemblyName + " version is not available.");
					return new MissingDependencyInfo(dependency.Name, dependency.Version, dependency.Urls, dependency.IsRequired, "Cannot verify version");
				}
				if (!Version.TryParse(dependency.Version, out Version result))
				{
					Logger.Debug(dependency.AssemblyName + " version is not a valid version.");
					return new MissingDependencyInfo(dependency.Name, dependency.Version, dependency.Urls, dependency.IsRequired, "Invalid version format");
				}
				if (version < result)
				{
					Logger.Debug(dependency.AssemblyName + " version is too old.");
					return new MissingDependencyInfo(dependency.Name, dependency.Version, dependency.Urls, dependency.IsRequired, $"Version {version} found, but {dependency.Version} required");
				}
				return null;
			}
			SemVersion semanticVersion = ((MelonBase)val).Info.SemanticVersion;
			if (semanticVersion == (SemVersion)null)
			{
				Logger.Debug($"{foundInDomain.GetName().Name}'s version {semanticVersion} is not SemVer.");
				if (!Version.TryParse(dependency.Version, out Version result2))
				{
					Logger.Debug(dependency.AssemblyName +