Decompiled source of HireableDeliveryDriver IL2CPP port v1.0.1

HireableDeliveryDriver/HireableDeliveryDriver.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using HireableDeliveryDriver;
using Il2CppFishNet;
using Il2CppFishNet.Connection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.Delivery;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.GameTime;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Map;
using Il2CppScheduleOne.Money;
using Il2CppScheduleOne.Property;
using Il2CppScheduleOne.Storage;
using Il2CppScheduleOne.UI.Shop;
using Il2CppScheduleOne.Vehicles;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(DeliveryDriverMod), "Hireable Delivery Driver", "1.0.0", "brobb", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: AssemblyMetadata("NexusModID", "0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("HireableDeliveryDriver")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HireableDeliveryDriver")]
[assembly: AssemblyTitle("HireableDeliveryDriver")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 HireableDeliveryDriver
{
	public class DeliveryDriver
	{
		private static readonly string[] FirstNames = new string[15]
		{
			"Mike", "Dave", "Joe", "Tom", "Bill", "Sam", "Jack", "Pete", "Nick", "Steve",
			"Maria", "Lisa", "Kate", "Emma", "Anna"
		};

		private static readonly string[] LastNames = new string[10] { "Smith", "Jones", "Brown", "Wilson", "Taylor", "Clark", "Hall", "Lee", "King", "Wright" };

		public string Id { get; set; }

		public string Name { get; set; }

		public DeliveryRoute AssignedRoute { get; set; }

		public bool IsPaidToday { get; set; }

		public static DeliveryDriver CreateRandom()
		{
			Random random = new Random();
			return new DeliveryDriver
			{
				Id = Guid.NewGuid().ToString(),
				Name = FirstNames[random.Next(FirstNames.Length)] + " " + LastNames[random.Next(LastNames.Length)],
				IsPaidToday = true
			};
		}
	}
	public class DeliveryDriverManager
	{
		private int _lastPayDay = -1;

		public List<DeliveryDriver> Drivers { get; } = new List<DeliveryDriver>();


		public List<DeliveryRoute> Routes { get; } = new List<DeliveryRoute>();


		public void HireDriver()
		{
			DeliveryDriver item = DeliveryDriver.CreateRandom();
			Drivers.Add(item);
		}

		public void FireDriver(DeliveryDriver driver)
		{
			if (driver.AssignedRoute != null)
			{
				Routes.Remove(driver.AssignedRoute);
			}
			Drivers.Remove(driver);
		}

		public int GetIdleDriverCount()
		{
			int num = 0;
			for (int i = 0; i < Drivers.Count; i++)
			{
				if (Drivers[i].AssignedRoute == null)
				{
					num++;
				}
			}
			return num;
		}

		public float GetTotalDailyWage()
		{
			return (float)Drivers.Count * 100f;
		}

		public bool ShouldPayDailyWages()
		{
			if (!NetworkSingleton<TimeManager>.InstanceExists)
			{
				return false;
			}
			TimeManager instance = NetworkSingleton<TimeManager>.Instance;
			if (instance.ElapsedDays != _lastPayDay && instance.CurrentTime >= 600)
			{
				return true;
			}
			return false;
		}

		public void MarkWagesPaid()
		{
			if (NetworkSingleton<TimeManager>.InstanceExists)
			{
				_lastPayDay = NetworkSingleton<TimeManager>.Instance.ElapsedDays;
			}
			for (int i = 0; i < Drivers.Count; i++)
			{
				Drivers[i].IsPaidToday = true;
			}
		}

		public DeliveryDriver FindIdleDriver()
		{
			for (int i = 0; i < Drivers.Count; i++)
			{
				if (Drivers[i].AssignedRoute == null)
				{
					return Drivers[i];
				}
			}
			return null;
		}

		public DeliveryDriver FindDriverById(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return null;
			}
			for (int i = 0; i < Drivers.Count; i++)
			{
				if (Drivers[i].Id == id)
				{
					return Drivers[i];
				}
			}
			return null;
		}
	}
	public sealed class DeliveryDriverMod : MelonMod
	{
		private const KeyCode OpenUiKey = 290;

		private const float CheckIntervalSeconds = 2f;

		public const float SigningFee = 500f;

		public const float DailyWage = 100f;

		private const int DefaultFillThreshold = 80;

		private const int TravelTimeMinutes = 5;

		private const int EmptyDelayMinutes = 2;

		private DeliveryDriverManager _driverManager;

		private float _nextCheckTime;

		private bool _uiOpen;

		private Rect _windowRect = new Rect(100f, 100f, 600f, 500f);

		private Vector2 _scrollPosition;

		private CursorLockMode _previousCursorLockState;

		private bool _previousCursorVisible;

		private int _selectedSourcePropertyIndex;

		private int _selectedSourceDockIndex;

		private int _selectedDestPropertyIndex;

		private int _selectedDestDockIndex;

		private int _fillThreshold = 80;

		private List<Property> _cachedProperties;

		private string _deliveryVehicleCode;

		private bool _vehicleCodeSearched;

		private bool _warnedClient;

		private static bool IsServerAuthoritative
		{
			get
			{
				if (!InstanceFinder.IsServer)
				{
					return InstanceFinder.IsOffline;
				}
				return true;
			}
		}

		private static bool IsLocalPlayer
		{
			get
			{
				if (!InstanceFinder.IsClient)
				{
					return InstanceFinder.IsOffline;
				}
				return true;
			}
		}

		public override void OnInitializeMelon()
		{
			_driverManager = new DeliveryDriverManager();
			_nextCheckTime = 0f;
			((MelonBase)this).LoggerInstance.Msg("[DeliveryDriver] IL2CPP version loaded. Press F9 to open delivery route management.");
		}

		public override void OnUpdate()
		{
			if (IsLocalPlayer && Input.GetKeyDown((KeyCode)290))
			{
				if (IsServerAuthoritative)
				{
					ToggleUI();
				}
				else if (!_warnedClient)
				{
					_warnedClient = true;
					((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Route management is host-only in multiplayer.");
				}
			}
			if (IsServerAuthoritative && Time.unscaledTime >= _nextCheckTime)
			{
				_nextCheckTime = Time.unscaledTime + 2f;
				ProcessDeliveryRoutes();
			}
		}

		private void ToggleUI()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			_uiOpen = !_uiOpen;
			if (_uiOpen)
			{
				_previousCursorLockState = Cursor.lockState;
				_previousCursorVisible = Cursor.visible;
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				RefreshPropertyCache();
			}
			else
			{
				Cursor.lockState = _previousCursorLockState;
				Cursor.visible = _previousCursorVisible;
			}
		}

		public override void OnGUI()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (_uiOpen)
			{
				GUI.skin.window.fontSize = 14;
				GUI.skin.label.fontSize = 13;
				GUI.skin.button.fontSize = 13;
				_windowRect = GUI.Window(98765, _windowRect, WindowFunction.op_Implicit((Action<int>)DrawWindow), "Delivery Driver Management (F9 to close)");
			}
		}

		private void DrawWindow(int windowId)
		{
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"Active Drivers: {_driverManager.Drivers.Count}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			GUILayout.Label($"Daily Cost: ${_driverManager.GetTotalDailyWage():F0}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			float num = 0f;
			if (NetworkSingleton<MoneyManager>.InstanceExists)
			{
				num = NetworkSingleton<MoneyManager>.Instance.cashBalance;
			}
			GUILayout.Label($"Your Cash: ${num:F0}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			GUILayout.Label("--- Hire New Driver ---", Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"Signing Fee: ${500f:F0}  |  Daily Wage: ${100f:F0}", Array.Empty<GUILayoutOption>());
			GUI.enabled = IsServerAuthoritative && num >= 500f;
			if (GUILayout.Button("Hire Driver", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }) && NetworkSingleton<MoneyManager>.InstanceExists && IsServerAuthoritative)
			{
				NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance(-500f, true, false);
				_driverManager.HireDriver();
				((MelonBase)this).LoggerInstance.Msg("[DeliveryDriver] Hired new driver!");
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
			GUILayout.Space(15f);
			DrawNewRouteSection();
			GUILayout.Space(15f);
			GUILayout.Label("--- Active Delivery Routes ---", Array.Empty<GUILayoutOption>());
			_scrollPosition = GUILayout.BeginScrollView(_scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(200f) });
			if (_driverManager.Routes.Count == 0)
			{
				GUILayout.Label("No active routes. Create one above.", Array.Empty<GUILayoutOption>());
			}
			else
			{
				for (int i = 0; i < _driverManager.Routes.Count; i++)
				{
					DrawRouteEntry(_driverManager.Routes[i], i);
				}
			}
			GUILayout.EndScrollView();
			GUILayout.Space(10f);
			GUILayout.Label($"--- Idle Drivers ({_driverManager.GetIdleDriverCount()}) ---", Array.Empty<GUILayoutOption>());
			for (int j = 0; j < _driverManager.Drivers.Count; j++)
			{
				DeliveryDriver deliveryDriver = _driverManager.Drivers[j];
				if (deliveryDriver.AssignedRoute == null)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label("  " + deliveryDriver.Name + " - Idle", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
					GUI.enabled = IsServerAuthoritative;
					if (GUILayout.Button("Fire", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
					{
						_driverManager.FireDriver(deliveryDriver);
					}
					GUI.enabled = true;
					GUILayout.EndHorizontal();
				}
			}
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
		}

		private void DrawNewRouteSection()
		{
			GUILayout.Label("--- Create New Route ---", Array.Empty<GUILayoutOption>());
			if (_cachedProperties == null || _cachedProperties.Count == 0)
			{
				GUILayout.Label("No properties available. Own some properties first!", Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Refresh", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
				{
					RefreshPropertyCache();
				}
				return;
			}
			string[] array = new string[_cachedProperties.Count];
			for (int i = 0; i < _cachedProperties.Count; i++)
			{
				array[i] = _cachedProperties[i].PropertyName;
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Source Property:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			_selectedSourcePropertyIndex = Mathf.Clamp(_selectedSourcePropertyIndex, 0, array.Length - 1);
			if (GUILayout.Button("< " + array[_selectedSourcePropertyIndex] + " >", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }))
			{
				_selectedSourcePropertyIndex = (_selectedSourcePropertyIndex + 1) % array.Length;
				_selectedSourceDockIndex = 0;
			}
			Property val = _cachedProperties[_selectedSourcePropertyIndex];
			int loadingDockCount = val.LoadingDockCount;
			GUILayout.Label("Dock:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			if (loadingDockCount > 0)
			{
				_selectedSourceDockIndex = Mathf.Clamp(_selectedSourceDockIndex, 0, loadingDockCount - 1);
				if (GUILayout.Button($"< {_selectedSourceDockIndex + 1} >", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
				{
					_selectedSourceDockIndex = (_selectedSourceDockIndex + 1) % loadingDockCount;
				}
			}
			else
			{
				GUILayout.Label("None", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Dest Property:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			_selectedDestPropertyIndex = Mathf.Clamp(_selectedDestPropertyIndex, 0, array.Length - 1);
			if (GUILayout.Button("< " + array[_selectedDestPropertyIndex] + " >", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }))
			{
				_selectedDestPropertyIndex = (_selectedDestPropertyIndex + 1) % array.Length;
				_selectedDestDockIndex = 0;
			}
			Property val2 = _cachedProperties[_selectedDestPropertyIndex];
			int loadingDockCount2 = val2.LoadingDockCount;
			GUILayout.Label("Dock:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			if (loadingDockCount2 > 0)
			{
				_selectedDestDockIndex = Mathf.Clamp(_selectedDestDockIndex, 0, loadingDockCount2 - 1);
				if (GUILayout.Button($"< {_selectedDestDockIndex + 1} >", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
				{
					_selectedDestDockIndex = (_selectedDestDockIndex + 1) % loadingDockCount2;
				}
			}
			else
			{
				GUILayout.Label("None", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Fill Threshold:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			_fillThreshold = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)_fillThreshold, 10f, 100f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }));
			GUILayout.Label($"{_fillThreshold}%", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			bool flag2 = (GUI.enabled = IsServerAuthoritative && loadingDockCount > 0 && loadingDockCount2 > 0 && (_selectedSourcePropertyIndex != _selectedDestPropertyIndex || _selectedSourceDockIndex != _selectedDestDockIndex) && _driverManager.GetIdleDriverCount() > 0);
			if (GUILayout.Button("Create Route & Assign Driver", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }))
			{
				CreateRoute(val, val2);
			}
			GUI.enabled = true;
			if (!flag2)
			{
				if (_driverManager.GetIdleDriverCount() == 0)
				{
					GUILayout.Label("(Need idle driver)", Array.Empty<GUILayoutOption>());
				}
				else if (loadingDockCount == 0 || loadingDockCount2 == 0)
				{
					GUILayout.Label("(Properties need loading docks)", Array.Empty<GUILayoutOption>());
				}
				else if (!IsServerAuthoritative)
				{
					GUILayout.Label("(Host only in multiplayer)", Array.Empty<GUILayoutOption>());
				}
				else
				{
					GUILayout.Label("(Source and dest must differ)", Array.Empty<GUILayoutOption>());
				}
			}
			GUILayout.EndHorizontal();
		}

		private void CreateRoute(Property sourceProperty, Property destProperty)
		{
			if (IsServerAuthoritative)
			{
				DeliveryRoute deliveryRoute = new DeliveryRoute
				{
					SourcePropertyCode = sourceProperty.PropertyCode,
					SourceDockIndex = _selectedSourceDockIndex,
					DestinationPropertyCode = destProperty.PropertyCode,
					DestinationDockIndex = _selectedDestDockIndex,
					FillThresholdPercent = _fillThreshold
				};
				DeliveryDriver deliveryDriver = _driverManager.FindIdleDriver();
				if (deliveryDriver != null)
				{
					deliveryRoute.AssignedDriverId = deliveryDriver.Id;
					deliveryDriver.AssignedRoute = deliveryRoute;
					_driverManager.Routes.Add(deliveryRoute);
					SpawnVanAtSource(deliveryRoute);
					((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Created route: {sourceProperty.PropertyName} Dock {_selectedSourceDockIndex + 1} -> {destProperty.PropertyName} Dock {_selectedDestDockIndex + 1}");
				}
			}
		}

		private void DrawRouteEntry(DeliveryRoute route, int index)
		{
			PropertyManager instance = Singleton<PropertyManager>.Instance;
			Property val = (((Object)(object)instance != (Object)null) ? instance.GetProperty(route.SourcePropertyCode) : null);
			Property val2 = (((Object)(object)instance != (Object)null) ? instance.GetProperty(route.DestinationPropertyCode) : null);
			string value = (((Object)(object)val != (Object)null) ? val.PropertyName : route.SourcePropertyCode);
			string value2 = (((Object)(object)val2 != (Object)null) ? val2.PropertyName : route.DestinationPropertyCode);
			DeliveryDriver deliveryDriver = _driverManager.FindDriverById(route.AssignedDriverId);
			string text = deliveryDriver?.Name ?? "Unassigned";
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"{index + 1}. {value} #{route.SourceDockIndex + 1} -> {value2} #{route.DestinationDockIndex + 1}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(300f) });
			GUILayout.Label("[" + text + "]", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) });
			GUILayout.Label($"{route.FillThresholdPercent}%", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			GUILayout.Label(route.Status.ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) });
			GUI.enabled = IsServerAuthoritative;
			if (GUILayout.Button("X", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(25f) }))
			{
				RemoveRoute(route, deliveryDriver, index);
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
		}

		private void RemoveRoute(DeliveryRoute route, DeliveryDriver driver, int index)
		{
			if (!IsServerAuthoritative)
			{
				return;
			}
			if ((Object)(object)route.ActiveVehicle != (Object)null)
			{
				DeactivateVan(route);
				try
				{
					Object.Destroy((Object)(object)((Component)route.ActiveVehicle).gameObject);
				}
				catch (Exception ex)
				{
					((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Error destroying vehicle: " + ex.Message);
				}
				route.ActiveVehicle = null;
			}
			if (driver != null)
			{
				driver.AssignedRoute = null;
			}
			_driverManager.Routes.RemoveAt(index);
			((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Removed route {index + 1}");
		}

		private void RefreshPropertyCache()
		{
			_cachedProperties = new List<Property>();
			if (Property.OwnedProperties != null)
			{
				Enumerator<Property> enumerator = Property.OwnedProperties.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Property current = enumerator.Current;
					if ((Object)(object)current != (Object)null && current.LoadingDockCount > 0)
					{
						_cachedProperties.Add(current);
					}
				}
			}
			((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Found {_cachedProperties.Count} properties with loading docks");
		}

		private string GetDeliveryVehicleCode()
		{
			if (!string.IsNullOrEmpty(_deliveryVehicleCode))
			{
				return _deliveryVehicleCode;
			}
			if (_vehicleCodeSearched)
			{
				return null;
			}
			_vehicleCodeSearched = true;
			if (ShopInterface.AllShops != null)
			{
				Enumerator<ShopInterface> enumerator = ShopInterface.AllShops.GetEnumerator();
				while (enumerator.MoveNext())
				{
					ShopInterface current = enumerator.Current;
					if (!((Object)(object)current == (Object)null) && !((Object)(object)current.DeliveryVehicle == (Object)null) && !((Object)(object)current.DeliveryVehicle.Vehicle == (Object)null))
					{
						_deliveryVehicleCode = current.DeliveryVehicle.Vehicle.VehicleCode;
						((MelonBase)this).LoggerInstance.Msg("[DeliveryDriver] Found delivery vehicle code from " + current.ShopName + ": " + _deliveryVehicleCode);
						return _deliveryVehicleCode;
					}
				}
			}
			if (NetworkSingleton<VehicleManager>.InstanceExists)
			{
				VehicleManager instance = NetworkSingleton<VehicleManager>.Instance;
				for (int i = 0; i < instance.VehiclePrefabs.Count; i++)
				{
					LandVehicle val = instance.VehiclePrefabs[i];
					if (!((Object)(object)val == (Object)null))
					{
						string text = val.VehicleCode.ToLowerInvariant();
						if (text.Contains("van") || text.Contains("cargo") || text.Contains("delivery"))
						{
							_deliveryVehicleCode = val.VehicleCode;
							((MelonBase)this).LoggerInstance.Msg("[DeliveryDriver] Found van vehicle code from prefabs: " + _deliveryVehicleCode);
							return _deliveryVehicleCode;
						}
					}
				}
				if (instance.VehiclePrefabs.Count > 0 && (Object)(object)instance.VehiclePrefabs[0] != (Object)null)
				{
					_deliveryVehicleCode = instance.VehiclePrefabs[0].VehicleCode;
					((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Using fallback vehicle code: " + _deliveryVehicleCode);
					return _deliveryVehicleCode;
				}
			}
			((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Could not find any vehicle code!");
			return null;
		}

		private void SpawnVanAtSource(DeliveryRoute route)
		{
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Expected O, but got Unknown
			if (!IsServerAuthoritative)
			{
				return;
			}
			((MelonBase)this).LoggerInstance.Msg("[DeliveryDriver] Attempting to spawn van for route...");
			string deliveryVehicleCode = GetDeliveryVehicleCode();
			if (string.IsNullOrEmpty(deliveryVehicleCode))
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Cannot spawn van - no vehicle code available!");
				route.Status = RouteStatus.Error;
				return;
			}
			PropertyManager instance = Singleton<PropertyManager>.Instance;
			Property val = (((Object)(object)instance != (Object)null) ? instance.GetProperty(route.SourcePropertyCode) : null);
			if ((Object)(object)val == (Object)null)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Cannot find source property: " + route.SourcePropertyCode);
				route.Status = RouteStatus.Error;
				return;
			}
			if (route.SourceDockIndex >= val.LoadingDockCount)
			{
				((MelonBase)this).LoggerInstance.Error($"[DeliveryDriver] Invalid source dock index: {route.SourceDockIndex}");
				route.Status = RouteStatus.Error;
				return;
			}
			LoadingDock val2 = ((Il2CppArrayBase<LoadingDock>)(object)val.LoadingDocks)[route.SourceDockIndex];
			if ((Object)(object)val2 == (Object)null)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Source dock is null!");
				route.Status = RouteStatus.Error;
				return;
			}
			if (val2.IsInUse)
			{
				((MelonBase)this).LoggerInstance.Warning($"[DeliveryDriver] Source dock {route.SourceDockIndex + 1} is in use, waiting...");
				route.Status = RouteStatus.WaitingForDock;
				return;
			}
			ParkingLot parking = val2.Parking;
			if ((Object)(object)parking == (Object)null)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Source dock has no parking lot!");
				route.Status = RouteStatus.Error;
				return;
			}
			if (parking.ParkingSpots == null || parking.ParkingSpots.Count == 0)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Parking lot has no spots!");
				route.Status = RouteStatus.Error;
				return;
			}
			ParkingSpot val3 = parking.ParkingSpots[0];
			Vector3 position = ((Component)val3).transform.position;
			Quaternion rotation = ((Component)val3).transform.rotation;
			((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Spawn position: {position}, Rotation: {((Quaternion)(ref rotation)).eulerAngles}");
			if (!NetworkSingleton<VehicleManager>.InstanceExists)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] VehicleManager not available!");
				route.Status = RouteStatus.Error;
				return;
			}
			VehicleManager instance2 = NetworkSingleton<VehicleManager>.Instance;
			LandVehicle val4 = null;
			try
			{
				val4 = instance2.SpawnAndReturnVehicle(deliveryVehicleCode, position, rotation, false);
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Exception spawning vehicle: " + ex.Message);
				route.Status = RouteStatus.Error;
				return;
			}
			if ((Object)(object)val4 == (Object)null)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] SpawnAndReturnVehicle returned null for code: " + deliveryVehicleCode);
				route.Status = RouteStatus.Error;
				return;
			}
			((MelonBase)this).LoggerInstance.Msg("[DeliveryDriver] Successfully spawned vehicle: " + val4.VehicleName);
			val2.SetStaticOccupant(val4);
			try
			{
				val4.Park((NetworkConnection)null, new ParkData
				{
					lotGUID = parking.GUID,
					spotIndex = 0,
					alignment = val3.Alignment
				}, false);
			}
			catch (Exception ex2)
			{
				((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Error parking vehicle: " + ex2.Message);
			}
			val4.SetVisible(true);
			if ((Object)(object)val4.Storage != (Object)null)
			{
				val4.Storage.AccessSettings = (EAccessSettings)2;
				((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Vehicle storage has {val4.Storage.ItemSlots.Count} slots");
			}
			else
			{
				((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Vehicle has no storage!");
			}
			StorageDoorAnimation componentInChildren = ((Component)val4).GetComponentInChildren<StorageDoorAnimation>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.OverrideState(true);
				((MelonBase)this).LoggerInstance.Msg("[DeliveryDriver] Opened vehicle storage door");
			}
			route.ActiveVehicle = val4;
			route.CurrentDock = val2;
			route.Status = RouteStatus.LoadingAtSource;
			ConfigureDockForLoading(val2, val4);
			((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Van ready at {val.PropertyName} Dock {route.SourceDockIndex + 1}");
		}

		private void ConfigureDockForLoading(LoadingDock dock, LandVehicle vehicle)
		{
			if (!((Object)(object)dock == (Object)null) && !((Object)(object)((vehicle != null) ? vehicle.Storage : null) == (Object)null))
			{
				dock.InputSlots.Clear();
				List<ItemSlot> itemSlots = vehicle.Storage.ItemSlots;
				for (int i = 0; i < itemSlots.Count; i++)
				{
					dock.InputSlots.Add(itemSlots[i]);
				}
				dock.IsAcceptingItems = true;
				((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Configured dock for loading with {vehicle.Storage.ItemSlots.Count} input slots");
			}
		}

		private void ConfigureDockForUnloading(LoadingDock dock, LandVehicle vehicle)
		{
			if (!((Object)(object)dock == (Object)null) && !((Object)(object)((vehicle != null) ? vehicle.Storage : null) == (Object)null))
			{
				dock.OutputSlots.Clear();
				List<ItemSlot> itemSlots = vehicle.Storage.ItemSlots;
				for (int i = 0; i < itemSlots.Count; i++)
				{
					dock.OutputSlots.Add(itemSlots[i]);
				}
				((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Configured dock for unloading with {vehicle.Storage.ItemSlots.Count} output slots");
			}
		}

		private void ClearDockSlots(LoadingDock dock)
		{
			if (!((Object)(object)dock == (Object)null))
			{
				dock.InputSlots.Clear();
				dock.OutputSlots.Clear();
				dock.IsAcceptingItems = false;
			}
		}

		private void EnsureDockSlotsConfigured(LoadingDock dock, LandVehicle vehicle, bool isSourceDock)
		{
			if ((Object)(object)dock == (Object)null || (Object)(object)((vehicle != null) ? vehicle.Storage : null) == (Object)null)
			{
				return;
			}
			List<ItemSlot> itemSlots = vehicle.Storage.ItemSlots;
			if (isSourceDock)
			{
				if (dock.InputSlots.Count != itemSlots.Count || (dock.InputSlots.Count > 0 && dock.InputSlots[0] != itemSlots[0]))
				{
					dock.InputSlots.Clear();
					for (int i = 0; i < itemSlots.Count; i++)
					{
						dock.InputSlots.Add(itemSlots[i]);
					}
					dock.IsAcceptingItems = true;
				}
			}
			else if (dock.OutputSlots.Count != itemSlots.Count || (dock.OutputSlots.Count > 0 && dock.OutputSlots[0] != itemSlots[0]))
			{
				dock.OutputSlots.Clear();
				for (int j = 0; j < itemSlots.Count; j++)
				{
					dock.OutputSlots.Add(itemSlots[j]);
				}
			}
		}

		private void ActivateVanAtDock(DeliveryRoute route, LoadingDock dock, bool isSourceDock)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			if ((Object)(object)route.ActiveVehicle == (Object)null || (Object)(object)dock == (Object)null)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Cannot activate van - vehicle or dock is null");
				return;
			}
			LandVehicle activeVehicle = route.ActiveVehicle;
			ParkingLot parking = dock.Parking;
			if ((Object)(object)parking == (Object)null || parking.ParkingSpots == null || parking.ParkingSpots.Count == 0)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Dock has no valid parking");
				return;
			}
			ParkingSpot val = parking.ParkingSpots[0];
			dock.SetStaticOccupant(activeVehicle);
			activeVehicle.Park((NetworkConnection)null, new ParkData
			{
				lotGUID = parking.GUID,
				spotIndex = 0,
				alignment = val.Alignment
			}, false);
			activeVehicle.SetVisible(true);
			if ((Object)(object)activeVehicle.Storage != (Object)null)
			{
				activeVehicle.Storage.AccessSettings = (EAccessSettings)2;
			}
			StorageDoorAnimation componentInChildren = ((Component)activeVehicle).GetComponentInChildren<StorageDoorAnimation>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.OverrideState(true);
			}
			route.CurrentDock = dock;
			if (isSourceDock)
			{
				ConfigureDockForLoading(dock, activeVehicle);
			}
			else
			{
				ConfigureDockForUnloading(dock, activeVehicle);
			}
		}

		private void DeactivateVan(DeliveryRoute route)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)route.ActiveVehicle == (Object)null)
			{
				return;
			}
			LandVehicle activeVehicle = route.ActiveVehicle;
			try
			{
				activeVehicle.ExitPark(false);
				activeVehicle.SetVisible(false);
				activeVehicle.SetTransform(new Vector3(0f, -100f, 0f), Quaternion.identity);
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Error deactivating vehicle: " + ex.Message);
			}
			if ((Object)(object)route.CurrentDock != (Object)null)
			{
				ClearDockSlots(route.CurrentDock);
				route.CurrentDock.SetStaticOccupant((LandVehicle)null);
				if ((Object)(object)route.CurrentDock.VehicleDetector != (Object)null)
				{
					route.CurrentDock.VehicleDetector.Clear();
				}
				route.CurrentDock = null;
			}
		}

		private void ProcessDeliveryRoutes()
		{
			if (!IsServerAuthoritative)
			{
				return;
			}
			if (_driverManager.ShouldPayDailyWages())
			{
				PayDailyWages();
			}
			for (int i = 0; i < _driverManager.Routes.Count; i++)
			{
				DeliveryRoute deliveryRoute = _driverManager.Routes[i];
				if (deliveryRoute.Status != RouteStatus.Error)
				{
					ProcessRoute(deliveryRoute);
				}
			}
		}

		private void PayDailyWages()
		{
			if (NetworkSingleton<MoneyManager>.InstanceExists)
			{
				float totalDailyWage = _driverManager.GetTotalDailyWage();
				float cashBalance = NetworkSingleton<MoneyManager>.Instance.cashBalance;
				if (cashBalance >= totalDailyWage)
				{
					NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance(0f - totalDailyWage, true, false);
					_driverManager.MarkWagesPaid();
					((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Paid daily wages: ${totalDailyWage:F0}");
				}
				else
				{
					((MelonBase)this).LoggerInstance.Warning($"[DeliveryDriver] Cannot pay driver wages! Need ${totalDailyWage:F0}, have ${cashBalance:F0}");
				}
			}
		}

		private void ProcessRoute(DeliveryRoute route)
		{
			switch (route.Status)
			{
			case RouteStatus.WaitingForDock:
				SpawnVanAtSource(route);
				break;
			case RouteStatus.LoadingAtSource:
				ProcessLoadingAtSource(route);
				break;
			case RouteStatus.InTransit:
				ProcessInTransit(route);
				break;
			case RouteStatus.UnloadingAtDest:
				ProcessUnloadingAtDest(route);
				break;
			case RouteStatus.Returning:
				ProcessReturning(route);
				break;
			}
		}

		private void ProcessLoadingAtSource(DeliveryRoute route)
		{
			if ((Object)(object)route.ActiveVehicle == (Object)null)
			{
				((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Vehicle lost during loading, respawning...");
				route.Status = RouteStatus.WaitingForDock;
				return;
			}
			StorageEntity storage = route.ActiveVehicle.Storage;
			if ((Object)(object)storage == (Object)null)
			{
				((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Vehicle has no storage!");
				return;
			}
			if ((Object)(object)route.CurrentDock != (Object)null)
			{
				EnsureDockSlotsConfigured(route.CurrentDock, route.ActiveVehicle, isSourceDock: true);
			}
			int count = storage.ItemSlots.Count;
			int num = CountOccupiedSlots(storage.ItemSlots);
			if (count != 0)
			{
				float num2 = (float)num / (float)count * 100f;
				bool num3 = num2 >= (float)route.FillThresholdPercent;
				bool flag = num == count;
				if (num3 || flag)
				{
					((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Van departing from {route.SourcePropertyCode} with {num}/{count} slots filled ({num2:F0}%)");
					DeactivateVan(route);
					route.TransitStartTime = GetCurrentGameMinutes();
					route.Status = RouteStatus.InTransit;
				}
			}
		}

		private void ProcessInTransit(DeliveryRoute route)
		{
			if (GetElapsedMinutes(route.TransitStartTime) < 5)
			{
				return;
			}
			PropertyManager instance = Singleton<PropertyManager>.Instance;
			Property val = (((Object)(object)instance != (Object)null) ? instance.GetProperty(route.DestinationPropertyCode) : null);
			if ((Object)(object)val == (Object)null || route.DestinationDockIndex >= val.LoadingDockCount)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Invalid destination!");
				return;
			}
			LoadingDock val2 = ((Il2CppArrayBase<LoadingDock>)(object)val.LoadingDocks)[route.DestinationDockIndex];
			if (!val2.IsInUse)
			{
				ActivateVanAtDock(route, val2, isSourceDock: false);
				route.Status = RouteStatus.UnloadingAtDest;
				route.EmptyCheckStartTime = -1;
				((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Van arrived at {val.PropertyName} Dock {route.DestinationDockIndex + 1}");
			}
		}

		private void ProcessUnloadingAtDest(DeliveryRoute route)
		{
			if ((Object)(object)route.ActiveVehicle == (Object)null)
			{
				((MelonBase)this).LoggerInstance.Warning("[DeliveryDriver] Vehicle lost during unloading!");
				route.Status = RouteStatus.WaitingForDock;
				return;
			}
			StorageEntity storage = route.ActiveVehicle.Storage;
			if ((Object)(object)storage == (Object)null)
			{
				return;
			}
			if ((Object)(object)route.CurrentDock != (Object)null)
			{
				EnsureDockSlotsConfigured(route.CurrentDock, route.ActiveVehicle, isSourceDock: false);
			}
			if (CountOccupiedSlots(storage.ItemSlots) == 0)
			{
				if (route.EmptyCheckStartTime < 0)
				{
					route.EmptyCheckStartTime = GetCurrentGameMinutes();
				}
				else if (GetElapsedMinutes(route.EmptyCheckStartTime) >= 2)
				{
					((MelonBase)this).LoggerInstance.Msg("[DeliveryDriver] Van empty at destination, returning to source");
					DeactivateVan(route);
					route.TransitStartTime = GetCurrentGameMinutes();
					route.Status = RouteStatus.Returning;
				}
			}
			else
			{
				route.EmptyCheckStartTime = -1;
			}
		}

		private void ProcessReturning(DeliveryRoute route)
		{
			if (GetElapsedMinutes(route.TransitStartTime) < 5)
			{
				return;
			}
			PropertyManager instance = Singleton<PropertyManager>.Instance;
			Property val = (((Object)(object)instance != (Object)null) ? instance.GetProperty(route.SourcePropertyCode) : null);
			if ((Object)(object)val == (Object)null || route.SourceDockIndex >= val.LoadingDockCount)
			{
				((MelonBase)this).LoggerInstance.Error("[DeliveryDriver] Invalid source on return!");
				return;
			}
			LoadingDock val2 = ((Il2CppArrayBase<LoadingDock>)(object)val.LoadingDocks)[route.SourceDockIndex];
			if (!val2.IsInUse)
			{
				ActivateVanAtDock(route, val2, isSourceDock: true);
				route.Status = RouteStatus.LoadingAtSource;
				((MelonBase)this).LoggerInstance.Msg($"[DeliveryDriver] Van returned to {val.PropertyName} Dock {route.SourceDockIndex + 1}");
			}
		}

		private int GetCurrentGameMinutes()
		{
			if (NetworkSingleton<TimeManager>.InstanceExists)
			{
				TimeManager instance = NetworkSingleton<TimeManager>.Instance;
				int num = instance.CurrentTime / 100;
				int num2 = instance.CurrentTime % 100;
				return instance.ElapsedDays * 24 * 60 + num * 60 + num2;
			}
			return 0;
		}

		private int GetElapsedMinutes(int startTime)
		{
			return GetCurrentGameMinutes() - startTime;
		}

		private static int CountOccupiedSlots(List<ItemSlot> slots)
		{
			if (slots == null)
			{
				return 0;
			}
			int num = 0;
			for (int i = 0; i < slots.Count; i++)
			{
				ItemSlot val = slots[i];
				if (val != null && val.ItemInstance != null && val.Quantity > 0)
				{
					num++;
				}
			}
			return num;
		}
	}
	public class DeliveryRoute
	{
		public string SourcePropertyCode { get; set; }

		public int SourceDockIndex { get; set; }

		public string DestinationPropertyCode { get; set; }

		public int DestinationDockIndex { get; set; }

		public int FillThresholdPercent { get; set; } = 80;


		public string AssignedDriverId { get; set; }

		public RouteStatus Status { get; set; }

		public int TransitStartTime { get; set; }

		public int EmptyCheckStartTime { get; set; } = -1;


		public LandVehicle ActiveVehicle { get; set; }

		public LoadingDock CurrentDock { get; set; }
	}
	public enum RouteStatus
	{
		WaitingForDock,
		LoadingAtSource,
		InTransit,
		UnloadingAtDest,
		Returning,
		Error
	}
}