Decompiled source of EasySave v1.0.0

plugins/EasySave/EasySave.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("EasySave")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+929406ebc9ced03c1253a792df2f3919052323c0")]
[assembly: AssemblyProduct("EasySave")]
[assembly: AssemblyTitle("EasySave")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace EasySave;

internal static class DeliveryStateCapture
{
	internal static DeliveryState Capture(MonoBehaviour car, ManualLogSource logger)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		DeliveryState deliveryState = new DeliveryState
		{
			timestamp = DateTime.UtcNow.ToString("o"),
			sceneBuildIndex = ((Scene)(ref activeScene)).buildIndex,
			sceneName = ((Scene)(ref activeScene)).name,
			carPosition = SavedVector3.From(((Component)car).transform.position),
			carRotation = SavedQuaternion.From(((Component)car).transform.rotation),
			packageSpawnPoint = SavedVector3.From(Vector3.zero)
		};
		MonoBehaviour val = ReflectionHelpers.FindActiveBehaviour("jobBoard");
		if ((Object)(object)val == (Object)null)
		{
			logger.LogWarning((object)"EasySave: jobBoard not found; saved car state without delivery state.");
			return deliveryState;
		}
		object obj = ReflectionHelpers.Get(val, "selectedJob");
		deliveryState.hasActiveDelivery = obj != null;
		deliveryState.progress = ReflectionHelpers.Get(val, "progress", 0);
		deliveryState.packageSpawnPoint = SavedVector3.From(ReflectionHelpers.Get<Vector3>(val, "packageSpawnPoint", Vector3.zero));
		if (!deliveryState.hasActiveDelivery || deliveryState.progress <= 0)
		{
			deliveryState.hasActiveDelivery = false;
			deliveryState.stage = DeliveryStage.None;
			logger.LogInfo((object)"EasySave: saved delivery state (no active delivery).");
			return deliveryState;
		}
		deliveryState.job = CaptureJob(obj);
		deliveryState.route = CaptureRoute(val);
		GameObject currentPayload = ReflectionHelpers.AsGameObject(ReflectionHelpers.Get(val, "currentPayload"));
		Transform payloadParent = ReflectionHelpers.Get<Transform>(val, "payloadParent");
		deliveryState.stage = ClassifyStage(car, deliveryState.progress, currentPayload, payloadParent, obj);
		deliveryState.payload = CapturePayload(val, obj);
		logger.LogInfo((object)($"EasySave: captured delivery state stage={deliveryState.stage}, progress={deliveryState.progress}, " + string.Format("payload={0}, mode={1}.", deliveryState.job.payloadIndex, deliveryState.payload?.parentMode ?? "None")));
		return deliveryState;
	}

	private static DeliveryStage ClassifyStage(MonoBehaviour car, int progress, GameObject currentPayload, Transform payloadParent, object selectedJob)
	{
		//IL_0072: 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)
		bool flag = (Object)(object)payloadParent != (Object)null && payloadParent.childCount > 0;
		string text = (((Object)(object)currentPayload != (Object)null) ? ((Object)currentPayload).name : string.Empty);
		if (progress == 1 && (Object)(object)currentPayload == (Object)null && !flag)
		{
			return DeliveryStage.AcceptedGoToPickup;
		}
		if (progress == 1 && (Object)(object)currentPayload != (Object)null && !flag)
		{
			return DeliveryStage.PayloadActiveOrInHands;
		}
		if (progress >= 2)
		{
			object obj = ReflectionHelpers.Get(selectedJob, "to");
			if (((obj != null) ? Vector3.Distance(((Component)car).transform.position, ReflectionHelpers.ObjectPosition(obj)) : float.MaxValue) <= 35f && (Object)(object)currentPayload != (Object)null)
			{
				return DeliveryStage.AtDestinationBeforeDelivery;
			}
			if (flag || text.IndexOf("Placed In Truck", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return DeliveryStage.InTruckOrDelivering;
			}
		}
		if (!((Object)(object)currentPayload != (Object)null))
		{
			return DeliveryStage.AcceptedGoToPickup;
		}
		return DeliveryStage.PayloadActiveOrInHands;
	}

	private static SavedJobState CaptureJob(object job)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		object value = ReflectionHelpers.Get(job, "from");
		object value2 = ReflectionHelpers.Get(job, "to");
		object value3 = ReflectionHelpers.Get(job, "shop");
		GameObject val = ReflectionHelpers.AsGameObject(ReflectionHelpers.Get(job, "payloadPrefab"));
		return new SavedJobState
		{
			shopName = ReflectionHelpers.ObjectName(value3),
			fromNodeName = ReflectionHelpers.ObjectName(value),
			fromNodePosition = SavedVector3.From(ReflectionHelpers.ObjectPosition(value)),
			toNodeName = ReflectionHelpers.ObjectName(value2),
			toNodePosition = SavedVector3.From(ReflectionHelpers.ObjectPosition(value2)),
			payloadIndex = ReflectionHelpers.Get(job, "payloadIndex", -1),
			payloadPrefabName = (((Object)(object)val != (Object)null) ? ((Object)val).name : null),
			price = ReflectionHelpers.Get(job, "price", 0f),
			mass = ReflectionHelpers.Get(job, "mass", 0f),
			distance = ReflectionHelpers.Get(job, "distance", 0f),
			bonusDistance = ReflectionHelpers.Get(job, "bonusDistance", 0f),
			destinationIndex = ReflectionHelpers.Get(job, "destinationIndex", -1),
			duration = ReflectionHelpers.Get(job, "duration", 0f),
			timeStart = ReflectionHelpers.Get(job, "timeStart", 0f),
			name = ReflectionHelpers.Get<string>(job, "name"),
			startingCityName = ReflectionHelpers.Get<string>(job, "startingCityName"),
			destCityName = ReflectionHelpers.Get<string>(job, "destCityName"),
			isIntercity = ReflectionHelpers.Get(job, "isIntercity", fallback: false),
			isChallenge = ReflectionHelpers.Get(job, "isChallenge", fallback: false)
		};
	}

	private static SavedRouteState CaptureRoute(MonoBehaviour board)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		object obj = ReflectionHelpers.Get(ReflectionHelpers.Get(board, "navigation") ?? ReflectionHelpers.FindActiveBehaviour("sPathFinder"), "dest");
		if (obj == null)
		{
			return null;
		}
		return new SavedRouteState
		{
			destinationNodeName = ReflectionHelpers.ObjectName(obj),
			destinationNodePosition = SavedVector3.From(ReflectionHelpers.ObjectPosition(obj))
		};
	}

	private static PayloadState CapturePayload(MonoBehaviour board, object selectedJob)
	{
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: 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_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_027c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = ReflectionHelpers.AsGameObject(ReflectionHelpers.Get(board, "currentPayload"));
		Transform val2 = ReflectionHelpers.Get<Transform>(board, "payloadParent");
		Transform val3 = FindPayloadRoot(val, val2);
		if ((Object)(object)val3 == (Object)null)
		{
			return null;
		}
		Transform val4 = null;
		string parentMode = "World";
		if ((Object)(object)val2 != (Object)null && val3.IsChildOf(val2))
		{
			parentMode = "InTruck";
			val4 = val2;
		}
		else
		{
			Transform val5 = FindAncestorByName(val3, "packagePoint") ?? FindAncestorByName(((Object)(object)val != (Object)null) ? val.transform : null, "packagePoint");
			if ((Object)(object)val5 != (Object)null)
			{
				parentMode = "InHands";
				val4 = val5;
			}
		}
		Vector3 value = (((Object)(object)val4 != (Object)null) ? val4.InverseTransformPoint(val3.position) : val3.localPosition);
		Quaternion value2 = (((Object)(object)val4 != (Object)null) ? (Quaternion.Inverse(val4.rotation) * val3.rotation) : val3.localRotation);
		PayloadState payloadState = new PayloadState
		{
			payloadIndex = ReflectionHelpers.Get(selectedJob, "payloadIndex", -1),
			currentPayloadName = (((Object)(object)val != (Object)null) ? ((Object)val).name : ((Object)val3).name),
			rootPayloadCloneName = ((Object)val3).name,
			parentMode = parentMode,
			localPosition = SavedVector3.From(value),
			localRotation = SavedQuaternion.From(value2),
			worldPosition = SavedVector3.From(val3.position),
			worldRotation = SavedQuaternion.From(val3.rotation),
			localScale = SavedVector3.From(val3.localScale),
			worldScale = SavedVector3.From(val3.lossyScale),
			currentPayloadActive = ((Object)(object)val == (Object)null || val.activeSelf),
			currentPayloadWorldPosition = SavedVector3.From(((Object)(object)val != (Object)null) ? val.transform.position : val3.position),
			currentPayloadWorldRotation = SavedQuaternion.From(((Object)(object)val != (Object)null) ? val.transform.rotation : val3.rotation)
		};
		Component[] componentsInChildren = ((Component)val3).GetComponentsInChildren<Component>(true);
		foreach (Component val6 in componentsInChildren)
		{
			if (!((Object)(object)val6 == (Object)null) && !(((object)val6).GetType().Name != "Rigidbody"))
			{
				string text = ReflectionHelpers.TransformPath(val3, val6.transform);
				if (text != null)
				{
					payloadState.rigidbodies.Add(new SavedRigidbodyState
					{
						childPath = text,
						localPosition = SavedVector3.From(val6.transform.localPosition),
						localRotation = SavedQuaternion.From(val6.transform.localRotation),
						velocity = SavedVector3.From(ReadVectorProperty(val6, "linearVelocity", "velocity")),
						angularVelocity = SavedVector3.From(ReadVectorProperty(val6, "angularVelocity")),
						isKinematic = ReadBoolProperty(val6, "isKinematic"),
						useGravity = ReadBoolProperty(val6, "useGravity")
					});
				}
			}
		}
		return payloadState;
	}

	private static Transform FindPayloadRoot(GameObject currentPayload, Transform payloadParent)
	{
		if ((Object)(object)currentPayload != (Object)null && ((Object)currentPayload).name.IndexOf("Placed In Truck", StringComparison.OrdinalIgnoreCase) >= 0 && (Object)(object)payloadParent != (Object)null && payloadParent.childCount > 0)
		{
			return payloadParent.GetChild(0);
		}
		if ((Object)(object)currentPayload != (Object)null)
		{
			return FindPayloadNamedChild(currentPayload.transform) ?? currentPayload.transform;
		}
		return null;
	}

	private static Transform FindPayloadNamedChild(Transform root)
	{
		for (int i = 0; i < root.childCount; i++)
		{
			Transform child = root.GetChild(i);
			if (((Object)child).name.StartsWith("PAYLOAD", StringComparison.OrdinalIgnoreCase))
			{
				return child;
			}
		}
		return null;
	}

	private static Transform FindAncestorByName(Transform transform, string name)
	{
		while ((Object)(object)transform != (Object)null)
		{
			if (string.Equals(((Object)transform).name, name, StringComparison.OrdinalIgnoreCase))
			{
				return transform;
			}
			transform = transform.parent;
		}
		return null;
	}

	private static Vector3 ReadVectorProperty(object target, params string[] names)
	{
		//IL_0045: 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_0038: 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)
		foreach (string name in names)
		{
			object obj = target.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target, null);
			if (obj is Vector3)
			{
				return (Vector3)obj;
			}
		}
		return Vector3.zero;
	}

	private static bool ReadBoolProperty(object target, string name)
	{
		object obj = target.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target, null);
		bool flag = default(bool);
		int num;
		if (obj is bool)
		{
			flag = (bool)obj;
			num = 1;
		}
		else
		{
			num = 0;
		}
		return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
	}
}
internal enum RestoredJobSource
{
	LiveJobs,
	LiveJobsBackup,
	ReconstructedFromSave
}
internal static class DeliveryStateRestore
{
	private sealed class JobMatch
	{
		internal object Job;

		internal RestoredJobSource Source;

		internal float Score;
	}

	private const float EconomyTolerance = 0.05f;

	private const float NodePositionTolerance = 2f;

	internal static bool Restore(DeliveryState state, MonoBehaviour car, ManualLogSource logger, out bool asynchronous, Action<bool> asynchronousCompletion = null)
	{
		//IL_0461: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c2: 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)
		//IL_0436: Unknown result type (might be due to invalid IL or missing references)
		asynchronous = false;
		if (state == null || (Object)(object)car == (Object)null)
		{
			return false;
		}
		if (EasySaveSettings.EnableCarCheckpoint)
		{
			((Component)car).transform.SetPositionAndRotation(state.carPosition.ToVector3(), state.carRotation.ToQuaternion());
		}
		if (!state.hasActiveDelivery || state.stage == DeliveryStage.None || !EasySaveSettings.EnableDeliveryStateRestore)
		{
			return true;
		}
		logger.LogInfo((object)($"EasySave: restore requested stage={state.stage} payload={state.job?.payloadIndex ?? (-1)} " + string.Format("savedPrice={0:F2} from={1} ", state.job?.price ?? 0f, state.job?.fromNodeName ?? "null") + "to=" + (state.job?.toNodeName ?? "null") + "."));
		MonoBehaviour val = ReflectionHelpers.FindActiveBehaviour("jobBoard");
		MonoBehaviour val2 = ReflectionHelpers.Get<MonoBehaviour>(val, "navigation") ?? ReflectionHelpers.FindActiveBehaviour("sPathFinder");
		MonoBehaviour val3 = ReflectionHelpers.FindActiveBehaviour("PayloadManager");
		RemovePreviousModPayloads(val, logger);
		if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || state.job == null)
		{
			return Abort(logger, "required game objects or saved job are missing");
		}
		if (ReflectionHelpers.Get(val, "selectedJob") != null || ReflectionHelpers.Get(val, "progress", 0) > 0)
		{
			return Abort(logger, "the game already has a live delivery; it was left untouched");
		}
		if (state.job.isChallenge)
		{
			return Abort(logger, "challenge deliveries are not safe to reconstruct");
		}
		if (state.job.price <= 0f)
		{
			return Abort(logger, "saved job price is not positive");
		}
		if (!state.job.isIntercity && state.job.price > 20f)
		{
			return Abort(logger, $"saved local delivery price {state.job.price:F2} is outside the economy-safe range");
		}
		if (state.stage == DeliveryStage.PayloadActiveOrInHands)
		{
			return Abort(logger, "Stage 2 restore skipped safely; save before pickup or after placing cargo in truck");
		}
		if (state.stage == DeliveryStage.AtDestinationBeforeDelivery && (state.payload == null || state.payload.parentMode != "InTruck"))
		{
			return Abort(logger, "destination payload-out restore is not yet safe");
		}
		JobMatch jobMatch = FindMatchingJobRelaxed(val, state.job);
		if (jobMatch == null)
		{
			logger.LogInfo((object)"EasySave: no live matching job found, reconstructing from saved state.");
			object fromNode = FindNode(state.job.fromNodeName, state.job.fromNodePosition);
			object toNode = FindNode(state.job.toNodeName, state.job.toNodePosition);
			object obj;
			try
			{
				obj = ReconstructJobFromSave(val, state.job, fromNode, toNode, val3, val2, logger);
			}
			catch (Exception exception)
			{
				return Abort(logger, "saved job reconstruction failed: " + Unwrap(exception).Message);
			}
			if (obj == null)
			{
				return Abort(logger, "saved job could not be matched or reconstructed");
			}
			jobMatch = new JobMatch
			{
				Job = obj,
				Source = RestoredJobSource.ReconstructedFromSave,
				Score = 0f
			};
		}
		object job = jobMatch.Job;
		object fromNode2 = ReflectionHelpers.Get(job, "from");
		object toNode2 = ReflectionHelpers.Get(job, "to");
		LogMatchedJob(logger, jobMatch, state.job);
		if (jobMatch.Source != RestoredJobSource.ReconstructedFromSave)
		{
			LogNonCriticalDifferences(logger, job, state.job);
		}
		try
		{
			ValidateJobEconomy(job, state.job, jobMatch.Source);
		}
		catch (Exception exception2)
		{
			return Abort(logger, Unwrap(exception2).Message);
		}
		object previousJob = ReflectionHelpers.Get(val, "selectedJob");
		int previousProgress = ReflectionHelpers.Get(val, "progress", 0);
		object previousPayload = ReflectionHelpers.Get(val, "currentPayload");
		Vector3 previousSpawnPoint = ReflectionHelpers.Get<Vector3>(val, "packageSpawnPoint", Vector3.zero);
		object previousDestination = ReflectionHelpers.Get(val2, "dest");
		try
		{
			if (state.stage == DeliveryStage.AcceptedGoToPickup)
			{
				if (!RestoreAcceptedStage(val, val2, state, job, fromNode2))
				{
					throw new InvalidOperationException("accepted-stage invariants were not satisfied");
				}
				RestoreDeliveryResultEconomy(val, job, state.job, jobMatch.Source, logger);
				EconomyRestoreDiagnostics.RegisterRestoredJob(job, jobMatch.Source);
				LogRestoreSuccess(logger, state, jobMatch);
				return true;
			}
			if (!RestoreInTruckStage(val, val2, state, job, toNode2, jobMatch, logger, previousJob, previousProgress, previousPayload, previousSpawnPoint, previousDestination, asynchronousCompletion))
			{
				throw new InvalidOperationException("in-truck vanilla restore flow could not start");
			}
			asynchronous = true;
			return true;
		}
		catch (Exception exception3)
		{
			RollBack(val, val2, logger, previousJob, previousProgress, previousPayload, previousSpawnPoint, previousDestination);
			logger.LogWarning((object)("EasySave: delivery restore aborted and rolled back: " + Unwrap(exception3).Message));
			return false;
		}
	}

	private static bool RestoreAcceptedStage(MonoBehaviour board, MonoBehaviour pathFinder, DeliveryState state, object job, object fromNode)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: 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)
		Transform val = ReflectionHelpers.Get<Transform>(board, "payloadParent");
		if ((Object)(object)val == (Object)null || val.childCount != 0)
		{
			return false;
		}
		ReflectionHelpers.Set(board, "selectedJob", job);
		ReflectionHelpers.Set(board, "progress", 1);
		ReflectionHelpers.Set(board, "currentPayload", null);
		ReflectionHelpers.Set(board, "packageSpawnPoint", (state.packageSpawnPoint != null) ? state.packageSpawnPoint.ToVector3() : Vector3.zero);
		if (EasySaveSettings.EnableRouteRestore)
		{
			SetRoute(pathFinder, fromNode);
		}
		if (!(ReflectionHelpers.Invoke(board, "CheckJobProgress", false, Vector3.zero) is IEnumerator enumerator))
		{
			return false;
		}
		board.StartCoroutine(enumerator);
		if (ReflectionHelpers.Get(board, "selectedJob") == job && ReflectionHelpers.Get(board, "progress", 0) == 1 && (Object)(object)ReflectionHelpers.AsGameObject(ReflectionHelpers.Get(board, "currentPayload")) == (Object)null)
		{
			return val.childCount == 0;
		}
		return false;
	}

	private static bool RestoreInTruckStage(MonoBehaviour board, MonoBehaviour pathFinder, DeliveryState state, object job, object toNode, JobMatch match, ManualLogSource logger, object previousJob, int previousProgress, object previousPayload, Vector3 previousSpawnPoint, object previousDestination, Action<bool> completion)
	{
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		if (!EasySaveSettings.EnablePayloadRestore || state.payload == null || state.payload.parentMode != "InTruck" || state.progress < 2)
		{
			return false;
		}
		Transform val = ReflectionHelpers.Get<Transform>(board, "payloadParent");
		if ((Object)(object)val == (Object)null || val.childCount != 0)
		{
			return false;
		}
		ReflectionHelpers.Set(board, "selectedJob", job);
		ReflectionHelpers.Set(board, "progress", 0);
		ReflectionHelpers.Set(board, "currentPayload", null);
		ReflectionHelpers.Set(board, "packageSpawnPoint", (state.packageSpawnPoint != null) ? state.packageSpawnPoint.ToVector3() : Vector3.zero);
		if (!(ReflectionHelpers.Invoke(board, "CheckJobProgress", true, Vector3.zero) is IEnumerator enumerator))
		{
			return false;
		}
		Coroutine val2 = null;
		try
		{
			val2 = board.StartCoroutine(enumerator);
		}
		finally
		{
			MarkRestoreObjects(board, val);
		}
		if (val2 == null)
		{
			return false;
		}
		board.StartCoroutine(ValidateInTruckRestore(board, pathFinder, val, state, job, toNode, match, logger, val2, previousJob, previousProgress, previousPayload, previousSpawnPoint, previousDestination, completion));
		return true;
	}

	private static IEnumerator ValidateInTruckRestore(MonoBehaviour board, MonoBehaviour pathFinder, Transform payloadPivot, DeliveryState state, object job, object toNode, JobMatch match, ManualLogSource logger, Coroutine runningFlow, object previousJob, int previousProgress, object previousPayload, Vector3 previousSpawnPoint, object previousDestination, Action<bool> completion)
	{
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		float deadline = Time.unscaledTime + Mathf.Max(2f, EasySaveSettings.RestoreTimeoutSeconds);
		string failure = null;
		while (Time.unscaledTime < deadline)
		{
			bool flag;
			try
			{
				MarkRestoreObjects(board, payloadPivot);
				GameObject val = ReflectionHelpers.AsGameObject(ReflectionHelpers.Get(board, "currentPayload"));
				flag = ReflectionHelpers.Get(board, "selectedJob") == job && ReflectionHelpers.Get(board, "progress", 0) == 2 && (Object)(object)val != (Object)null && !val.activeSelf && ((Object)val).name == "Placed In Truck" && (Object)(object)payloadPivot != (Object)null && payloadPivot.childCount == 1;
			}
			catch (Exception exception)
			{
				failure = Unwrap(exception).Message;
				break;
			}
			if (flag)
			{
				break;
			}
			yield return null;
		}
		bool flag2 = false;
		if (failure == null)
		{
			try
			{
				GameObject val2 = ReflectionHelpers.AsGameObject(ReflectionHelpers.Get(board, "currentPayload"));
				Transform val3 = (((Object)(object)payloadPivot != (Object)null && payloadPivot.childCount == 1) ? payloadPivot.GetChild(0) : null);
				if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || val2.activeSelf || ((Object)val2).name != "Placed In Truck")
				{
					throw new InvalidOperationException("vanilla in-truck lifecycle did not reach its expected state");
				}
				((Component)val3).gameObject.SetActive(true);
				if (state.payload.localPosition != null)
				{
					val3.localPosition = state.payload.localPosition.ToVector3();
				}
				if (state.payload.localRotation != null)
				{
					val3.localRotation = state.payload.localRotation.ToQuaternion();
				}
				if (state.payload.worldScale != null)
				{
					SetWorldScale(val3, state.payload.worldScale.ToVector3());
				}
				RestoreRigidbodies(val3, state.payload.rigidbodies);
				if (EasySaveSettings.EnableRouteRestore)
				{
					SetRoute(pathFinder, toNode);
				}
				float num = ReflectionHelpers.Get(job, "price", 0f);
				if (ReflectionHelpers.Get(board, "selectedJob") != job || ReflectionHelpers.Get(board, "progress", 0) != 2 || num <= 0f || payloadPivot.childCount != 1)
				{
					throw new InvalidOperationException("post-restore economy or payload invariant failed");
				}
				ValidateJobEconomy(job, state.job, match.Source);
				RestoreDeliveryResultEconomy(board, job, state.job, match.Source, logger);
				EconomyRestoreDiagnostics.RegisterRestoredJob(job, match.Source);
				flag2 = true;
				LogRestoreSuccess(logger, state, match);
			}
			catch (Exception exception2)
			{
				failure = Unwrap(exception2).Message;
			}
		}
		if (!flag2)
		{
			if (runningFlow != null)
			{
				board.StopCoroutine(runningFlow);
			}
			RollBack(board, pathFinder, logger, previousJob, previousProgress, previousPayload, previousSpawnPoint, previousDestination);
			logger.LogWarning((object)("EasySave: delivery restore aborted and rolled back: " + (failure ?? "vanilla in-truck restore timed out") + "."));
		}
		completion?.Invoke(flag2);
	}

	private static JobMatch FindMatchingJobRelaxed(MonoBehaviour board, SavedJobState saved)
	{
		JobMatch jobMatch = null;
		RestoredJobSource[] array = new RestoredJobSource[2]
		{
			RestoredJobSource.LiveJobs,
			RestoredJobSource.LiveJobsBackup
		};
		foreach (RestoredJobSource restoredJobSource in array)
		{
			string name = ((restoredJobSource == RestoredJobSource.LiveJobs) ? "jobs" : "jobsBackup");
			if (!(ReflectionHelpers.Get(board, name) is IEnumerable enumerable))
			{
				continue;
			}
			foreach (object item in enumerable)
			{
				if (IsRelaxedJobMatch(item, saved))
				{
					float num = MatchScore(item, saved);
					if (jobMatch == null || num < jobMatch.Score)
					{
						jobMatch = new JobMatch
						{
							Job = item,
							Source = restoredJobSource,
							Score = num
						};
					}
				}
			}
		}
		return jobMatch;
	}

	private static bool IsRelaxedJobMatch(object candidate, SavedJobState saved)
	{
		if (candidate == null || saved == null)
		{
			return false;
		}
		object node = ReflectionHelpers.Get(candidate, "from");
		object node2 = ReflectionHelpers.Get(candidate, "to");
		bool flag = ReflectionHelpers.FindField(candidate.GetType(), "destinationIndex") == null || ReflectionHelpers.Get(candidate, "destinationIndex", -2) == saved.destinationIndex;
		return ReflectionHelpers.Get(candidate, "payloadIndex", -2) == saved.payloadIndex && NodeMatches(node, saved.fromNodeName, saved.fromNodePosition) && NodeMatches(node2, saved.toNodeName, saved.toNodePosition) && flag;
	}

	private static bool NodeMatches(object node, string savedName, SavedVector3 savedPosition)
	{
		//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)
		if (node == null)
		{
			return false;
		}
		bool num = !string.IsNullOrEmpty(savedName) && string.Equals(ReflectionHelpers.ObjectName(node), savedName, StringComparison.OrdinalIgnoreCase);
		int num2;
		if (savedPosition != null)
		{
			Vector3 val = ReflectionHelpers.ObjectPosition(node) - savedPosition.ToVector3();
			num2 = ((((Vector3)(ref val)).sqrMagnitude <= 4f) ? 1 : 0);
		}
		else
		{
			num2 = 0;
		}
		bool flag = (byte)num2 != 0;
		return num || flag;
	}

	private static float MatchScore(object candidate, SavedJobState saved)
	{
		float num = Mathf.Abs(ReflectionHelpers.Get(candidate, "price", 0f) - saved.price);
		float num2 = Mathf.Abs(ReflectionHelpers.Get(candidate, "mass", 0f) - saved.mass);
		float num3 = Mathf.Abs(ReflectionHelpers.Get(candidate, "distance", 0f) - saved.distance);
		float num4 = Mathf.Abs(ReflectionHelpers.Get(candidate, "bonusDistance", 0f) - saved.bonusDistance);
		return num * 100f + num2 * 10f + num3 + num4;
	}

	private static object ReconstructJobFromSave(MonoBehaviour board, SavedJobState saved, object fromNode, object toNode, MonoBehaviour payloadManager, MonoBehaviour pathFinder, ManualLogSource logger)
	{
		if (fromNode == null || toNode == null || saved == null)
		{
			return null;
		}
		Type type = ReflectionHelpers.FindField(((object)board).GetType(), "selectedJob")?.FieldType;
		if (type == null)
		{
			return null;
		}
		GameObject val = ReflectionHelpers.AsGameObject(ReflectionHelpers.Invoke(payloadManager, "GetPayload", saved.payloadIndex));
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		if (!string.IsNullOrEmpty(saved.payloadPrefabName) && !string.Equals(((Object)val).name, saved.payloadPrefabName, StringComparison.OrdinalIgnoreCase))
		{
			return null;
		}
		object uninitializedObject = FormatterServices.GetUninitializedObject(type);
		object obj = FindShop(saved.shopName, fromNode);
		if (!saved.isIntercity && obj == null)
		{
			return null;
		}
		object obj2 = ReflectionHelpers.Invoke(pathFinder, "FindPath", fromNode, toNode);
		if (obj2 == null)
		{
			FieldInfo fieldInfo = ReflectionHelpers.FindField(type, "path");
			if (fieldInfo == null)
			{
				return null;
			}
			obj2 = Activator.CreateInstance(fieldInfo.FieldType);
		}
		SetRequired(uninitializedObject, "shop", obj);
		SetRequired(uninitializedObject, "from", fromNode);
		SetRequired(uninitializedObject, "to", toNode);
		SetRequired(uninitializedObject, "payloadPrefab", val);
		SetRequired(uninitializedObject, "payloadIndex", saved.payloadIndex);
		SetRequired(uninitializedObject, "price", saved.price);
		SetRequired(uninitializedObject, "mass", saved.mass);
		SetRequired(uninitializedObject, "distance", saved.distance);
		SetRequired(uninitializedObject, "bonusDistance", saved.bonusDistance);
		SetRequired(uninitializedObject, "destinationIndex", saved.destinationIndex);
		SetRequired(uninitializedObject, "duration", saved.duration);
		SetRequired(uninitializedObject, "timeStart", saved.timeStart);
		SetRequired(uninitializedObject, "name", saved.name);
		SetRequired(uninitializedObject, "startingCityName", saved.startingCityName);
		SetRequired(uninitializedObject, "destCityName", saved.destCityName);
		SetRequired(uninitializedObject, "isIntercity", saved.isIntercity);
		SetRequired(uninitializedObject, "isChallenge", false);
		SetRequired(uninitializedObject, "challenge", null);
		SetRequired(uninitializedObject, "path", obj2);
		ValidateJobEconomy(uninitializedObject, saved, RestoredJobSource.ReconstructedFromSave);
		logger.LogInfo((object)($"EasySave: reconstructed job payload={saved.payloadIndex} price={saved.price:F2} " + $"distance={saved.distance:F3} bonusDistance={saved.bonusDistance:F3} " + $"duration={saved.duration:F2} timeStart={saved.timeStart:F2}."));
		return uninitializedObject;
	}

	private static void SetRequired(object target, string fieldName, object value)
	{
		if (!ReflectionHelpers.Set(target, fieldName, value))
		{
			throw new MissingFieldException(target.GetType().FullName, fieldName);
		}
	}

	private static void ValidateJobEconomy(object job, SavedJobState saved, RestoredJobSource source)
	{
		float num = ReflectionHelpers.Get(job, "price", -1f);
		if (num <= 0f)
		{
			throw new InvalidOperationException($"restored job price is invalid: {num:F2}");
		}
		if (!saved.isChallenge && num > 20f)
		{
			throw new InvalidOperationException($"restored job price is unsafe: {num:F2}");
		}
		if (source == RestoredJobSource.ReconstructedFromSave && Mathf.Abs(num - saved.price) > 0.1f)
		{
			throw new InvalidOperationException($"reconstructed job failed economy sanity check restoredPrice={num:F2} " + $"savedPrice={saved.price:F2}");
		}
	}

	private static void RestoreDeliveryResultEconomy(MonoBehaviour board, object job, SavedJobState saved, RestoredJobSource source, ManualLogSource logger)
	{
		float num = ((source == RestoredJobSource.ReconstructedFromSave) ? saved.distance : ReflectionHelpers.Get(job, "distance", -1f));
		float num2 = ((source == RestoredJobSource.ReconstructedFromSave) ? saved.bonusDistance : ReflectionHelpers.Get(job, "bonusDistance", -1f));
		float num3 = ((source == RestoredJobSource.ReconstructedFromSave) ? saved.mass : ReflectionHelpers.Get(job, "mass", -1f));
		float num4 = ReflectionHelpers.Get(job, "price", -1f);
		if (num < 0f || num2 < 0f || num3 < 0f)
		{
			throw new InvalidOperationException("delivery result metrics are incomplete");
		}
		object obj = ReflectionHelpers.Invoke(board, "CalculatePrice", num, num2, num3);
		if (!(obj is float num5) || num5 <= 0f || Mathf.Abs(num5 - num4) > 0.15f)
		{
			throw new InvalidOperationException(string.Format("delivery result economy mismatch calculated={0} jobPrice={1:F2}", obj ?? "null", num4));
		}
		MethodInfo? method = ((object)board).GetType().GetMethod("SaveResultsData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
		{
			typeof(float),
			typeof(float),
			typeof(float)
		}, null);
		if (method == null)
		{
			throw new MissingMethodException(((object)board).GetType().FullName, "SaveResultsData(float, float, float)");
		}
		method.Invoke(board, new object[3] { num, num2, num3 });
		logger.LogInfo((object)($"EasySave: restored payout metrics distance={num:F3} " + $"bonusDistance={num2:F3} mass={num3:F3} " + $"calculatedPrice={num5:F2}."));
	}

	private static void LogMatchedJob(ManualLogSource logger, JobMatch match, SavedJobState saved)
	{
		object job = match.Job;
		logger.LogInfo((object)($"EasySave: restore job source={match.Source} payload={saved.payloadIndex} " + string.Format("livePrice={0:F2} savedPrice={1:F2} ", ReflectionHelpers.Get(job, "price", 0f), saved.price) + string.Format("liveDistance={0:F3} ", ReflectionHelpers.Get(job, "distance", 0f)) + $"savedDistance={saved.distance:F3}."));
		float num = ReflectionHelpers.Get(job, "price", 0f);
		if (match.Source != RestoredJobSource.ReconstructedFromSave && Mathf.Abs(num - saved.price) > 0.05f)
		{
			logger.LogWarning((object)($"EasySave: matched live job with different price live={num:F2} " + $"saved={saved.price:F2}; using live job price."));
		}
	}

	private static void LogNonCriticalDifferences(ManualLogSource logger, object job, SavedJobState saved)
	{
		float num = ReflectionHelpers.Get(job, "distance", 0f);
		float num2 = ReflectionHelpers.Get(job, "bonusDistance", 0f);
		float num3 = ReflectionHelpers.Get(job, "duration", 0f);
		float num4 = ReflectionHelpers.Get(job, "timeStart", 0f);
		if (Mathf.Abs(num - saved.distance) > 0.05f || Mathf.Abs(num2 - saved.bonusDistance) > 0.05f || Mathf.Abs(num3 - saved.duration) > 1f || Mathf.Abs(num4 - saved.timeStart) > 1f)
		{
			logger.LogWarning((object)"EasySave: matched job has non-critical timing/distance differences; live economy fields were preserved.");
		}
	}

	private static void LogRestoreSuccess(ManualLogSource logger, DeliveryState state, JobMatch match)
	{
		logger.LogInfo((object)($"EasySave: restored delivery state stage={state.stage} " + string.Format("payload={0} price={1:F2} ", state.job.payloadIndex, ReflectionHelpers.Get(match.Job, "price", 0f)) + $"jobSource={match.Source} economySafe=true."));
	}

	private static object FindNode(string name, SavedVector3 savedPosition)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = savedPosition?.ToVector3() ?? Vector3.zero;
		object result = null;
		float num = float.MaxValue;
		foreach (MonoBehaviour item in ReflectionHelpers.FindBehaviours("sMapNode"))
		{
			Scene scene = ((Component)item).gameObject.scene;
			if (((Scene)(ref scene)).IsValid() && ((Component)item).gameObject.activeInHierarchy)
			{
				Vector3 val2 = ((Component)item).transform.position - val;
				float num2 = ((Vector3)(ref val2)).sqrMagnitude;
				if (!string.IsNullOrEmpty(name) && !string.Equals(((Object)item).name, name, StringComparison.OrdinalIgnoreCase))
				{
					num2 += 1000000f;
				}
				if (num2 < num)
				{
					num = num2;
					result = item;
				}
			}
		}
		return result;
	}

	private static object FindShop(string name, object fromNode)
	{
		//IL_0022: 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)
		object result = null;
		foreach (MonoBehaviour item in ReflectionHelpers.FindBehaviours("ShopInfo"))
		{
			Scene scene = ((Component)item).gameObject.scene;
			if (((Scene)(ref scene)).IsValid() && ((Component)item).gameObject.activeInHierarchy)
			{
				if (ReflectionHelpers.Get(item, "node") == fromNode)
				{
					result = item;
				}
				if (!string.IsNullOrEmpty(name) && string.Equals(((Object)item).name, name, StringComparison.OrdinalIgnoreCase))
				{
					return item;
				}
			}
		}
		return result;
	}

	private static void SetRoute(MonoBehaviour pathFinder, object destination)
	{
		if (destination == null)
		{
			throw new InvalidOperationException("route destination is missing");
		}
		ReflectionHelpers.Invoke(pathFinder, "SetDestination", destination);
		if (ReflectionHelpers.Get(pathFinder, "dest") == null)
		{
			throw new InvalidOperationException("SetDestination did not register a destination");
		}
	}

	private static void MarkRestoreObjects(MonoBehaviour board, Transform payloadPivot)
	{
		GameObject val = ReflectionHelpers.AsGameObject(ReflectionHelpers.Get(board, "currentPayload"));
		if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<EasySavePayloadMarker>() == (Object)null)
		{
			val.AddComponent<EasySavePayloadMarker>();
		}
		if ((Object)(object)payloadPivot == (Object)null)
		{
			return;
		}
		for (int i = 0; i < payloadPivot.childCount; i++)
		{
			GameObject gameObject = ((Component)payloadPivot.GetChild(i)).gameObject;
			if ((Object)(object)gameObject.GetComponent<EasySavePayloadMarker>() == (Object)null)
			{
				gameObject.AddComponent<EasySavePayloadMarker>();
			}
		}
	}

	private static void RollBack(MonoBehaviour board, MonoBehaviour pathFinder, ManualLogSource logger, object previousJob, int previousProgress, object previousPayload, Vector3 previousSpawnPoint, object previousDestination)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		RemovePreviousModPayloads(board, logger);
		ReflectionHelpers.Set(board, "selectedJob", previousJob);
		ReflectionHelpers.Set(board, "progress", previousProgress);
		ReflectionHelpers.Set(board, "currentPayload", previousPayload);
		ReflectionHelpers.Set(board, "packageSpawnPoint", previousSpawnPoint);
		try
		{
			if (previousDestination != null)
			{
				ReflectionHelpers.Invoke(pathFinder, "SetDestination", previousDestination);
			}
			else
			{
				ReflectionHelpers.Set(pathFinder, "dest", null);
			}
		}
		catch
		{
			ReflectionHelpers.Set(pathFinder, "dest", previousDestination);
		}
	}

	private static bool Abort(ManualLogSource logger, string reason)
	{
		logger.LogWarning((object)("EasySave: delivery restore aborted: " + reason + "."));
		return false;
	}

	private static Exception Unwrap(Exception exception)
	{
		if (!(exception is TargetInvocationException { InnerException: not null } ex))
		{
			return exception;
		}
		return ex.InnerException;
	}

	private static void SetWorldScale(Transform transform, Vector3 worldScale)
	{
		//IL_001b: 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_0020: 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_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = (((Object)(object)transform.parent != (Object)null) ? transform.parent.lossyScale : Vector3.one);
		transform.localScale = new Vector3((Mathf.Abs(val.x) > 0.0001f) ? (worldScale.x / val.x) : worldScale.x, (Mathf.Abs(val.y) > 0.0001f) ? (worldScale.y / val.y) : worldScale.y, (Mathf.Abs(val.z) > 0.0001f) ? (worldScale.z / val.z) : worldScale.z);
	}

	private static void RemovePreviousModPayloads(MonoBehaviour board, ManualLogSource logger)
	{
		GameObject val = ReflectionHelpers.AsGameObject(ReflectionHelpers.Get(board, "currentPayload"));
		HashSet<int> hashSet = new HashSet<int>();
		EasySavePayloadMarker[] array = Resources.FindObjectsOfTypeAll<EasySavePayloadMarker>();
		foreach (EasySavePayloadMarker easySavePayloadMarker in array)
		{
			if (!((Object)(object)easySavePayloadMarker == (Object)null))
			{
				if ((Object)(object)val == (Object)(object)((Component)easySavePayloadMarker).gameObject)
				{
					ReflectionHelpers.Set(board, "currentPayload", null);
				}
				if (hashSet.Add(((Object)((Component)easySavePayloadMarker).gameObject).GetInstanceID()))
				{
					Object.Destroy((Object)(object)((Component)easySavePayloadMarker).gameObject);
				}
			}
		}
		GameObject[] array2 = Resources.FindObjectsOfTypeAll<GameObject>();
		foreach (GameObject val2 in array2)
		{
			if (!((Object)(object)val2 == (Object)null) && ((Object)val2).name.StartsWith("EasySave_RestoredPayload", StringComparison.OrdinalIgnoreCase) && hashSet.Add(((Object)val2).GetInstanceID()))
			{
				if ((Object)(object)val == (Object)(object)val2)
				{
					ReflectionHelpers.Set(board, "currentPayload", null);
				}
				Object.Destroy((Object)(object)val2);
			}
		}
		if (hashSet.Count > 0)
		{
			logger.LogWarning((object)$"EasySave: cleaned up {hashSet.Count} mod-restored payload object(s).");
		}
	}

	private static void RestoreRigidbodies(Transform root, List<SavedRigidbodyState> bodies)
	{
		//IL_0038: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		if (bodies == null)
		{
			return;
		}
		foreach (SavedRigidbodyState body in bodies)
		{
			Transform val = ReflectionHelpers.ResolveTransformPath(root, body.childPath);
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			val.localPosition = body.localPosition.ToVector3();
			val.localRotation = body.localRotation.ToQuaternion();
			Component[] components = ((Component)val).GetComponents<Component>();
			foreach (Component val2 in components)
			{
				if (!((Object)(object)val2 == (Object)null) && !(((object)val2).GetType().Name != "Rigidbody"))
				{
					SetProperty(val2, "isKinematic", body.isKinematic);
					SetProperty(val2, "useGravity", body.useGravity);
					if (!SetProperty(val2, "linearVelocity", body.velocity.ToVector3()))
					{
						SetProperty(val2, "velocity", body.velocity.ToVector3());
					}
					SetProperty(val2, "angularVelocity", body.angularVelocity.ToVector3());
					break;
				}
			}
		}
	}

	private static bool SetProperty(object target, string name, object value)
	{
		PropertyInfo property = target.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (property == null || !property.CanWrite)
		{
			return false;
		}
		property.SetValue(target, value, null);
		return true;
	}
}
internal static class DeliveryStateStore
{
	internal static string StatePath => Path.Combine(Application.persistentDataPath, "EasySaveState.json");

	internal static void Save(DeliveryState state)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Expected O, but got Unknown
		string statePath = StatePath;
		string text = statePath + ".tmp";
		if (EasySaveSettings.BackupBeforeWrite && File.Exists(statePath))
		{
			File.Copy(statePath, statePath + ".bak", overwrite: true);
		}
		DataContractJsonSerializer val = new DataContractJsonSerializer(typeof(DeliveryState));
		using (MemoryStream memoryStream = new MemoryStream())
		{
			((XmlObjectSerializer)val).WriteObject((Stream)memoryStream, (object)state);
			File.WriteAllBytes(text, memoryStream.ToArray());
		}
		File.Copy(text, statePath, overwrite: true);
		File.Delete(text);
	}

	internal static bool TryLoad(out DeliveryState state, out string error)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		state = null;
		error = null;
		try
		{
			if (!File.Exists(StatePath))
			{
				return false;
			}
			DataContractJsonSerializer val = new DataContractJsonSerializer(typeof(DeliveryState));
			using (FileStream fileStream = File.OpenRead(StatePath))
			{
				state = ((XmlObjectSerializer)val).ReadObject((Stream)fileStream) as DeliveryState;
			}
			if (state == null)
			{
				return false;
			}
			if (state.version != 4)
			{
				error = $"Unsupported EasySave schema version {state.version}; expected 4.";
				state = null;
				return false;
			}
			return true;
		}
		catch (Exception ex)
		{
			error = ex.ToString();
			return false;
		}
	}

	internal static void BackupBeforeRestore()
	{
		if (File.Exists(StatePath))
		{
			string text = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss");
			File.Copy(StatePath, StatePath + ".bak-before-restore-" + text, overwrite: true);
		}
	}
}
public sealed class EasySavePayloadMarker : MonoBehaviour
{
}
internal static class EasySaveSettings
{
	internal static bool EnableNativeSave { get; private set; } = true;

	internal static bool EnableCarCheckpoint { get; private set; } = true;

	internal static bool EnableDeliveryStateCapture { get; private set; } = true;

	internal static bool EnableDeliveryStateRestore { get; private set; } = true;

	internal static bool EnablePayloadRestore { get; private set; } = true;

	internal static bool EnableRouteRestore { get; private set; } = true;

	internal static bool EnableDiagnosticLogging { get; private set; }

	internal static bool EnableEconomyDiagnosticLogging { get; private set; } = true;

	internal static float RestoreTimeoutSeconds { get; private set; } = 10f;

	internal static float RestoreRetryIntervalSeconds { get; private set; } = 0.25f;

	internal static bool BackupBeforeWrite { get; private set; } = true;

	internal static bool BackupBeforeRestore { get; private set; } = true;

	internal static bool DisableRestoreAfterFailure { get; private set; } = true;

	internal static void Initialize(ConfigFile config)
	{
		EnableNativeSave = config.Bind<bool>("Save", "EnableNativeSave", true, "Call the game's native SaveData method on F5.").Value;
		EnableCarCheckpoint = config.Bind<bool>("Save", "EnableCarCheckpoint", true, "Update the native scene and car checkpoint keys on F5.").Value;
		EnableDeliveryStateCapture = config.Bind<bool>("Delivery", "EnableDeliveryStateCapture", true, "Capture delivery diagnostics/state into EasySaveState.json.").Value;
		EnableDeliveryStateRestore = config.Bind<bool>("Delivery", "EnableDeliveryStateRestore", true, "Restore supported delivery stages after scene load.").Value;
		EnablePayloadRestore = config.Bind<bool>("Delivery", "EnablePayloadRestore", true, "Restore payload for supported in-truck stages.").Value;
		EnableRouteRestore = config.Bind<bool>("Delivery", "EnableRouteRestore", true, "Restore GPS destination through sPathFinder.SetDestination.").Value;
		EnableDiagnosticLogging = config.Bind<bool>("Debug", "EnableDiagnosticLogging", false, "Enable additional targeted delivery diagnostics.").Value;
		EnableEconomyDiagnosticLogging = config.Bind<bool>("Debug", "EnableEconomyDiagnosticLogging", true, "Log the selected job price/source immediately before and after CompleteJob.").Value;
		RestoreTimeoutSeconds = config.Bind<float>("Restore", "RestoreTimeoutSeconds", 10f, "Maximum time to wait for gameplay objects.").Value;
		RestoreRetryIntervalSeconds = config.Bind<float>("Restore", "RestoreRetryIntervalSeconds", 0.25f, "Delay between gameplay object lookup retries.").Value;
		BackupBeforeWrite = config.Bind<bool>("Safety", "BackupBeforeWrite", true, "Back up the previous JSON before writing a new checkpoint.").Value;
		BackupBeforeRestore = config.Bind<bool>("Safety", "BackupBeforeRestore", true, "Back up the JSON immediately before delivery restore.").Value;
		DisableRestoreAfterFailure = config.Bind<bool>("Safety", "DisableRestoreAfterFailure", true, "Disable further delivery restores for the current session after a failure.").Value;
	}
}
internal static class EconomyRestoreDiagnostics
{
	private static ManualLogSource logger;

	private static object restoredJob;

	private static RestoredJobSource restoredSource;

	internal static void Initialize(ManualLogSource pluginLogger)
	{
		logger = pluginLogger;
	}

	internal static void RegisterRestoredJob(object job, RestoredJobSource source)
	{
		restoredJob = job;
		restoredSource = source;
	}

	internal static void CompleteJobPrefix(object board)
	{
		if (EasySaveSettings.EnableEconomyDiagnosticLogging && logger != null)
		{
			object obj = ReflectionHelpers.Get(board, "selectedJob");
			string text = ((obj == restoredJob) ? restoredSource.ToString() : "Untracked");
			logger.LogInfo((object)("EasySave: CompleteJob prefix selectedJob payload=" + string.Format("{0} ", ReflectionHelpers.Get(obj, "payloadIndex", -1)) + string.Format("price={0:F2} ", ReflectionHelpers.Get(obj, "price", 0f)) + "from=" + (ReflectionHelpers.ObjectName(ReflectionHelpers.Get(obj, "from")) ?? "null") + " to=" + (ReflectionHelpers.ObjectName(ReflectionHelpers.Get(obj, "to")) ?? "null") + " source=" + text + "."));
		}
	}

	internal static void CompleteJobPostfix()
	{
		if (EasySaveSettings.EnableEconomyDiagnosticLogging && logger != null)
		{
			logger.LogInfo((object)"EasySave: CompleteJob postfix done.");
		}
		restoredJob = null;
	}
}
[HarmonyPatch]
internal static class CompleteJobDiagnosticPatch
{
	private static MethodBase TargetMethod()
	{
		return Type.GetType("jobBoard, Assembly-CSharp", throwOnError: false)?.GetMethod("CompleteJob", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
	}

	[HarmonyPrefix]
	private static void Prefix(object __instance)
	{
		EconomyRestoreDiagnostics.CompleteJobPrefix(__instance);
	}

	[HarmonyPostfix]
	private static void Postfix()
	{
		EconomyRestoreDiagnostics.CompleteJobPostfix();
	}
}
[BepInPlugin("com.easydeliveryco.easysave", "EasySave", "1.0.0")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.easydeliveryco.easysave";

	public const string PluginName = "EasySave";

	public const string PluginVersion = "1.0.0";

	private const string SaveSystemTypeName = "sSaveSystem";

	private const string CarControllerTypeName = "sCarController";

	private const string SceneIndexKey = "deliveryCurrentLastMapBuildIndex";

	private const string CheckpointPositionKey = "deliveryCurrentCheckpointPosition";

	private const float CheckpointYOffset = 1f;

	private const float NotificationDuration = 2.5f;

	private const float NotificationFadeInDuration = 0.18f;

	private const float NotificationFadeOutDuration = 0.3f;

	private const float NotificationWidth = 460f;

	private const float WeatherHudSideMargin = 264f;

	private const float WeatherHudIconCenterOffset = 64f;

	private const float WeatherHudTopMargin = 44f;

	private string notificationText;

	private float notificationStartedAt;

	private float notificationExpiresAt;

	private GameObject notificationRoot;

	private RectTransform notificationPanel;

	private CanvasGroup notificationCanvasGroup;

	private Text notificationLabel;

	private RawImage notificationIcon;

	private Texture2D fallbackIconTexture;

	private MonoBehaviour cachedGameplayCar;

	private MonoBehaviour cachedHud;

	private MonoBehaviour cachedMainMenuHud;

	private MonoBehaviour cachedPauseMenu;

	private MonoBehaviour cachedCameraPause;

	private FieldInfo pauseSystemPausedField;

	private FieldInfo sceneTransitionLoadingField;

	private FieldInfo cameraPausePausedField;

	private int cachedHudSceneHandle = int.MinValue;

	private float nextHudObjectRefreshAt;

	private Coroutine restoreCoroutine;

	private string lastRestoredTimestamp;

	private int lastRestoredSceneHandle = int.MinValue;

	private DeliveryState trackedDeliveryState;

	private MonoBehaviour trackedJobBoard;

	private float nextDeliveryStateCheckAt;

	private bool isRestoringDelivery;

	private bool deliveryRestoreDisabledForSession;

	private Harmony harmony;

	private void Awake()
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		EasySaveSettings.Initialize(((BaseUnityPlugin)this).Config);
		EconomyRestoreDiagnostics.Initialize(((BaseUnityPlugin)this).Logger);
		try
		{
			harmony = new Harmony("com.easydeliveryco.easysave");
			harmony.PatchAll(typeof(Plugin).Assembly);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("EasySave: economy diagnostic patch could not be installed: " + ex.Message));
		}
		ResolveHudStateFields();
		SceneManager.sceneLoaded += OnSceneLoaded;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"EasySave 1.0.0 loaded. Press F5 to save the current checkpoint.");
	}

	private void Start()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		QueueStateRestore(SceneManager.GetActiveScene());
	}

	private void Update()
	{
		if (!ShouldShowHudToast())
		{
			HideNotificationImmediately();
		}
		if (Input.GetKeyDown((KeyCode)286))
		{
			SaveCurrentCheckpoint();
		}
		UpdateNotification();
		MonitorTrackedDeliveryState();
	}

	private void LateUpdate()
	{
		if (!ShouldShowHudToast())
		{
			HideNotificationImmediately();
		}
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		cachedHudSceneHandle = int.MinValue;
		trackedJobBoard = null;
		QueueStateRestore(scene);
	}

	private void QueueStateRestore(Scene scene)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded)
		{
			if (restoreCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(restoreCoroutine);
			}
			restoreCoroutine = ((MonoBehaviour)this).StartCoroutine(RestoreSavedStateWhenReady(scene));
		}
	}

	private IEnumerator RestoreSavedStateWhenReady(Scene scene)
	{
		//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)
		restoreCoroutine = null;
		yield return null;
		yield return null;
		if (!DeliveryStateStore.TryLoad(out var state, out var error))
		{
			if (!string.IsNullOrEmpty(error))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("EasySave: state file could not be loaded: " + error));
			}
		}
		else
		{
			if (state.sceneBuildIndex != ((Scene)(ref scene)).buildIndex || (state.timestamp == lastRestoredTimestamp && ((Scene)(ref scene)).handle == lastRestoredSceneHandle))
			{
				yield break;
			}
			float deadline = Time.unscaledTime + Mathf.Max(1f, EasySaveSettings.RestoreTimeoutSeconds);
			MonoBehaviour car = null;
			MonoBehaviour board = null;
			Scene activeScene;
			while (Time.unscaledTime < deadline)
			{
				activeScene = SceneManager.GetActiveScene();
				if (((Scene)(ref activeScene)).handle != ((Scene)(ref scene)).handle)
				{
					yield break;
				}
				MonoBehaviour[] behaviours = Resources.FindObjectsOfTypeAll<MonoBehaviour>();
				car = FindActiveBehaviour(behaviours, "sCarController");
				board = FindActiveBehaviour(behaviours, "jobBoard");
				bool flag = !state.hasActiveDelivery || !EasySaveSettings.EnableDeliveryStateRestore || deliveryRestoreDisabledForSession || ((Object)(object)board != (Object)null && (Object)(object)FindActiveBehaviour(behaviours, "sPathFinder") != (Object)null && (Object)(object)FindActiveBehaviour(behaviours, "PayloadManager") != (Object)null && (state.payload == null || state.payload.parentMode != "InTruck" || (Object)(object)ReflectionHelpers.Get<Transform>(board, "payloadParent") != (Object)null));
				if ((Object)(object)car != (Object)null && flag)
				{
					break;
				}
				yield return (object)new WaitForSecondsRealtime(Mathf.Max(0.05f, EasySaveSettings.RestoreRetryIntervalSeconds));
			}
			if ((Object)(object)car == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"EasySave: restore timed out waiting for the gameplay car.");
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(Mathf.Max(0.05f, EasySaveSettings.RestoreRetryIntervalSeconds));
			car = ReflectionHelpers.FindActiveBehaviour("sCarController");
			if ((Object)(object)car == (Object)null)
			{
				yield break;
			}
			activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).handle != ((Scene)(ref scene)).handle)
			{
				yield break;
			}
			bool asynchronous = false;
			try
			{
				if (EasySaveSettings.BackupBeforeRestore && state.hasActiveDelivery && EasySaveSettings.EnableDeliveryStateRestore && !deliveryRestoreDisabledForSession)
				{
					DeliveryStateStore.BackupBeforeRestore();
				}
				isRestoringDelivery = true;
				if (!DeliveryStateRestore.Restore(state, car, ((BaseUnityPlugin)this).Logger, out asynchronous, delegate(bool success)
				{
					isRestoringDelivery = false;
					if (!success)
					{
						trackedDeliveryState = null;
						trackedJobBoard = null;
						if (EasySaveSettings.DisableRestoreAfterFailure)
						{
							deliveryRestoreDisabledForSession = true;
						}
					}
				}))
				{
					if (EasySaveSettings.DisableRestoreAfterFailure)
					{
						deliveryRestoreDisabledForSession = true;
					}
				}
				else
				{
					lastRestoredTimestamp = state.timestamp;
					lastRestoredSceneHandle = ((Scene)(ref scene)).handle;
					trackedDeliveryState = state;
					trackedJobBoard = board;
				}
			}
			catch (Exception arg)
			{
				if (EasySaveSettings.DisableRestoreAfterFailure)
				{
					deliveryRestoreDisabledForSession = true;
				}
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"EasySave: delivery restore failed safely: {arg}");
			}
			finally
			{
				if (!asynchronous)
				{
					isRestoringDelivery = false;
				}
			}
		}
	}

	private void MonitorTrackedDeliveryState()
	{
		if (isRestoringDelivery || trackedDeliveryState == null || !trackedDeliveryState.hasActiveDelivery || Time.unscaledTime < nextDeliveryStateCheckAt)
		{
			return;
		}
		nextDeliveryStateCheckAt = Time.unscaledTime + 0.5f;
		MonoBehaviour val = trackedJobBoard;
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		object obj = ReflectionHelpers.Get(val, "selectedJob");
		bool num = obj == null && ReflectionHelpers.Get(val, "progress", 0) == 0;
		bool flag = obj != null && trackedDeliveryState.job != null && (ReflectionHelpers.Get(obj, "payloadIndex", -1) != trackedDeliveryState.job.payloadIndex || !string.Equals(ReflectionHelpers.ObjectName(ReflectionHelpers.Get(obj, "from")), trackedDeliveryState.job.fromNodeName, StringComparison.OrdinalIgnoreCase) || !string.Equals(ReflectionHelpers.ObjectName(ReflectionHelpers.Get(obj, "to")), trackedDeliveryState.job.toNodeName, StringComparison.OrdinalIgnoreCase));
		if (!num && !flag)
		{
			return;
		}
		trackedDeliveryState.hasActiveDelivery = false;
		trackedDeliveryState.progress = 0;
		trackedDeliveryState.job = null;
		trackedDeliveryState.route = null;
		trackedDeliveryState.payload = null;
		trackedDeliveryState.timestamp = DateTime.UtcNow.ToString("o");
		try
		{
			DeliveryStateStore.Save(trackedDeliveryState);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"EasySave: cleared stale delivery checkpoint after the live job ended or changed.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("EasySave: could not clear stale delivery checkpoint: " + ex.Message));
		}
	}

	private void SaveCurrentCheckpoint()
	{
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: 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_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		MonoBehaviour[] behaviours;
		try
		{
			behaviours = Resources.FindObjectsOfTypeAll<MonoBehaviour>();
		}
		catch (Exception arg)
		{
			ShowNotification("Save failed");
			((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to scan game objects: {arg}");
			return;
		}
		MonoBehaviour val = FindSaveSystem(behaviours);
		if ((Object)(object)val == (Object)null)
		{
			ShowNotification("Save system not found");
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Manual save skipped: sSaveSystem was not found.");
			return;
		}
		MonoBehaviour val2 = FindActiveCar(behaviours);
		if ((Object)(object)val2 == (Object)null)
		{
			ShowNotification("Car not found");
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Manual save skipped: no active sCarController was found.");
			return;
		}
		Vector3 val3 = ((Component)val2).transform.position + Vector3.up * 1f;
		Scene activeScene = SceneManager.GetActiveScene();
		int buildIndex = ((Scene)(ref activeScene)).buildIndex;
		try
		{
			InvokeNativeSave(val, buildIndex, val3);
			if (EasySaveSettings.EnableDeliveryStateCapture)
			{
				try
				{
					DeliveryState state = DeliveryStateCapture.Capture(val2, ((BaseUnityPlugin)this).Logger);
					DeliveryStateStore.Save(state);
					trackedDeliveryState = state;
					trackedJobBoard = FindActiveBehaviour(behaviours, "jobBoard");
					((BaseUnityPlugin)this).Logger.LogInfo((object)("EasySave: wrote state file " + DeliveryStateStore.StatePath + "."));
				}
				catch (Exception arg2)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)$"EasySave: native save succeeded, but mod state could not be saved: {arg2}");
				}
			}
			ShowNotification("Game saved");
			((BaseUnityPlugin)this).Logger.LogInfo((object)($"Saved checkpoint: scene={buildIndex}, " + $"pos=({val3.x:F2}, {val3.y:F2}, {val3.z:F2})"));
		}
		catch (Exception ex)
		{
			Exception arg3 = ((ex is TargetInvocationException { InnerException: not null } ex2) ? ex2.InnerException : ex);
			ShowNotification("Save failed");
			((BaseUnityPlugin)this).Logger.LogError((object)$"Manual save failed: {arg3}");
		}
	}

	private MonoBehaviour FindSaveSystem(MonoBehaviour[] behaviours)
	{
		MonoBehaviour val = null;
		MonoBehaviour val2 = null;
		foreach (MonoBehaviour val3 in behaviours)
		{
			if (!((Object)(object)val3 == (Object)null) && !(((object)val3).GetType().Name != "sSaveSystem"))
			{
				if ((Object)(object)val == (Object)null)
				{
					val = val3;
				}
				if (IsSingletonInstance(val3))
				{
					return val3;
				}
				if ((Object)(object)val2 == (Object)null && IsActiveInHierarchy(val3))
				{
					val2 = val3;
				}
			}
		}
		if (!((Object)(object)val2 != (Object)null))
		{
			return val;
		}
		return val2;
	}

	private static MonoBehaviour FindActiveCar(MonoBehaviour[] behaviours)
	{
		return FindActiveBehaviour(behaviours, "sCarController");
	}

	private static MonoBehaviour FindActiveBehaviour(MonoBehaviour[] behaviours, string typeName)
	{
		foreach (MonoBehaviour val in behaviours)
		{
			if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == typeName && IsActiveInHierarchy(val))
			{
				return val;
			}
		}
		return null;
	}

	private static bool IsActiveInHierarchy(MonoBehaviour behaviour)
	{
		try
		{
			return (Object)(object)((Component)behaviour).gameObject != (Object)null && ((Component)behaviour).gameObject.activeInHierarchy;
		}
		catch (MissingReferenceException)
		{
			return false;
		}
	}

	private bool IsSingletonInstance(MonoBehaviour candidate)
	{
		try
		{
			FieldInfo field = ((object)candidate).GetType().GetField("instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return false;
			}
			object value = field.GetValue(field.IsStatic ? null : candidate);
			int result;
			if (value != candidate)
			{
				Object val = (Object)((value is Object) ? value : null);
				result = ((val != null && val == (Object)(object)candidate) ? 1 : 0);
			}
			else
			{
				result = 1;
			}
			return (byte)result != 0;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogDebug((object)("Could not inspect sSaveSystem.instance: " + ex.Message));
			return false;
		}
	}

	private static void InvokeNativeSave(MonoBehaviour saveSystem, int sceneIndex, Vector3 position)
	{
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		Type type = ((object)saveSystem).GetType();
		MethodInfo method = type.GetMethod("SetInt", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
		{
			typeof(string),
			typeof(int)
		}, null);
		MethodInfo method2 = type.GetMethod("SetVector3", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
		{
			typeof(string),
			typeof(Vector3)
		}, null);
		MethodInfo method3 = type.GetMethod("SaveData", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
		if (method == null)
		{
			throw new MissingMethodException(type.FullName, "SetInt(string, int)");
		}
		if (method2 == null)
		{
			throw new MissingMethodException(type.FullName, "SetVector3(string, Vector3)");
		}
		if (method3 == null)
		{
			throw new MissingMethodException(type.FullName, "SaveData()");
		}
		if (EasySaveSettings.EnableCarCheckpoint)
		{
			method.Invoke(method.IsStatic ? null : saveSystem, new object[2] { "deliveryCurrentLastMapBuildIndex", sceneIndex });
			method2.Invoke(method2.IsStatic ? null : saveSystem, new object[2] { "deliveryCurrentCheckpointPosition", position });
		}
		if (EasySaveSettings.EnableNativeSave)
		{
			method3.Invoke(method3.IsStatic ? null : saveSystem, null);
		}
	}

	private void ResolveHudStateFields()
	{
		Type type = Type.GetType("PauseSystem, Assembly-CSharp", throwOnError: false);
		Type type2 = Type.GetType("SceneTransition, Assembly-CSharp", throwOnError: false);
		Type type3 = Type.GetType("CameraPause, Assembly-CSharp", throwOnError: false);
		pauseSystemPausedField = type?.GetField("paused", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		sceneTransitionLoadingField = type2?.GetField("loadingScene", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		cameraPausePausedField = type3?.GetField("paused", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
	}

	private bool ShouldShowHudToast()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		if (!((Scene)(ref activeScene)).IsValid() || !((Scene)(ref activeScene)).isLoaded || IsMenuOnlyScene(((Scene)(ref activeScene)).name))
		{
			return false;
		}
		RefreshHudStateObjectsIfNeeded(((Scene)(ref activeScene)).handle);
		if (!IsEnabledInHierarchy(cachedGameplayCar) || !IsEnabledInHierarchy(cachedHud))
		{
			return false;
		}
		if (ReadBoolField(pauseSystemPausedField, null) || ReadBoolField(sceneTransitionLoadingField, null) || ReadBoolField(cameraPausePausedField, cachedCameraPause))
		{
			return false;
		}
		if (IsEnabledInHierarchy(cachedMainMenuHud) || IsEnabledInHierarchy(cachedPauseMenu))
		{
			return false;
		}
		return Time.timeScale > 0.0001f;
	}

	private void RefreshHudStateObjectsIfNeeded(int activeSceneHandle)
	{
		float unscaledTime = Time.unscaledTime;
		if (cachedHudSceneHandle == activeSceneHandle && unscaledTime < nextHudObjectRefreshAt)
		{
			return;
		}
		cachedHudSceneHandle = activeSceneHandle;
		nextHudObjectRefreshAt = unscaledTime + 0.5f;
		cachedGameplayCar = null;
		cachedHud = null;
		cachedMainMenuHud = null;
		cachedPauseMenu = null;
		cachedCameraPause = null;
		try
		{
			MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>();
			foreach (MonoBehaviour val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Type type = ((object)val).GetType();
				switch (type.Name)
				{
				case "sCarController":
					if ((Object)(object)cachedGameplayCar == (Object)null && IsEnabledInHierarchy(val))
					{
						cachedGameplayCar = val;
					}
					break;
				case "sHUD":
					if ((Object)(object)cachedHud == (Object)null && IsEnabledInHierarchy(val))
					{
						cachedHud = val;
					}
					break;
				case "MainMenuHUD":
					cachedMainMenuHud = cachedMainMenuHud ?? val;
					break;
				case "PauseMenuURP":
					cachedPauseMenu = cachedPauseMenu ?? val;
					break;
				case "CameraPause":
					cachedCameraPause = cachedCameraPause ?? val;
					cameraPausePausedField = cameraPausePausedField ?? type.GetField("paused", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					break;
				case "PauseSystem":
					pauseSystemPausedField = pauseSystemPausedField ?? type.GetField("paused", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					break;
				case "SceneTransition":
					sceneTransitionLoadingField = sceneTransitionLoadingField ?? type.GetField("loadingScene", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					break;
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogDebug((object)("Could not refresh gameplay HUD state: " + ex.Message));
		}
	}

	private static bool IsMenuOnlyScene(string sceneName)
	{
		if (string.IsNullOrEmpty(sceneName))
		{
			return true;
		}
		if (sceneName.IndexOf("menu", StringComparison.OrdinalIgnoreCase) < 0 && sceneName.IndexOf("title", StringComparison.OrdinalIgnoreCase) < 0)
		{
			return sceneName.IndexOf("loading", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return true;
	}

	private static bool IsEnabledInHierarchy(MonoBehaviour behaviour)
	{
		try
		{
			return (Object)(object)behaviour != (Object)null && ((Behaviour)behaviour).enabled && (Object)(object)((Component)behaviour).gameObject != (Object)null && ((Component)behaviour).gameObject.activeInHierarchy;
		}
		catch (MissingReferenceException)
		{
			return false;
		}
	}

	private static bool ReadBoolField(FieldInfo field, object target)
	{
		try
		{
			bool flag = default(bool);
			int num;
			if (field != null)
			{
				object value = field.GetValue(field.IsStatic ? null : target);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}
		catch (Exception)
		{
			return false;
		}
	}

	private void HideNotificationImmediately()
	{
		notificationText = null;
		if ((Object)(object)notificationCanvasGroup != (Object)null)
		{
			notificationCanvasGroup.alpha = 0f;
		}
		if ((Object)(object)notificationPanel != (Object)null && ((Component)notificationPanel).gameObject.activeSelf)
		{
			((Component)notificationPanel).gameObject.SetActive(false);
		}
	}

	private void ShowNotification(string message)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		if (!ShouldShowHudToast())
		{
			HideNotificationImmediately();
			return;
		}
		EnsureNotificationUi();
		notificationText = message;
		notificationStartedAt = Time.unscaledTime;
		notificationExpiresAt = Time.unscaledTime + 2.5f;
		notificationLabel.text = notificationText;
		ApplyNotificationIcon();
		notificationCanvasGroup.alpha = 0f;
		((Transform)notificationPanel).localScale = new Vector3(0.94f, 0.94f, 1f);
		((Component)notificationPanel).gameObject.SetActive(true);
	}

	private void UpdateNotification()
	{
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		if (!ShouldShowHudToast())
		{
			HideNotificationImmediately();
		}
		else
		{
			if ((Object)(object)notificationPanel == (Object)null || !((Component)notificationPanel).gameObject.activeSelf)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime >= notificationExpiresAt)
			{
				((Component)notificationPanel).gameObject.SetActive(false);
				notificationText = null;
				return;
			}
			float num = unscaledTime - notificationStartedAt;
			float num2 = notificationExpiresAt - unscaledTime;
			float num3 = 1f;
			float num4 = 1f;
			if (num < 0.18f)
			{
				float num5 = Mathf.Clamp01(num / 0.18f);
				num5 = Mathf.SmoothStep(0f, 1f, num5);
				num3 = num5;
				num4 = Mathf.Lerp(0.94f, 1f, num5);
			}
			else if (num2 < 0.3f)
			{
				float num6 = Mathf.Clamp01(num2 / 0.3f);
				num3 = Mathf.SmoothStep(0f, 1f, num6);
				num4 = Mathf.Lerp(0.97f, 1f, num3);
			}
			notificationCanvasGroup.alpha = num3;
			((Transform)notificationPanel).localScale = new Vector3(num4, num4, 1f);
		}
	}

	private void EnsureNotificationUi()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0223: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0262: Unknown result type (might be due to invalid IL or missing references)
		//IL_0276: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0302: Unknown result type (might be due to invalid IL or missing references)
		//IL_0307: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)notificationRoot != (Object)null))
		{
			notificationRoot = new GameObject("EasySave Notification");
			notificationRoot.transform.SetParent(((Component)this).transform, false);
			Canvas obj = notificationRoot.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32000;
			CanvasScaler obj2 = notificationRoot.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.screenMatchMode = (ScreenMatchMode)0;
			obj2.matchWidthOrHeight = 0f;
			GameObject val = CreateUiObject("Panel", notificationRoot.transform);
			notificationPanel = val.GetComponent<RectTransform>();
			notificationPanel.anchorMin = new Vector2(0f, 1f);
			notificationPanel.anchorMax = new Vector2(0f, 1f);
			notificationPanel.pivot = new Vector2(0.5f, 1f);
			notificationPanel.anchoredPosition = new Vector2(328f, -44f);
			notificationPanel.sizeDelta = new Vector2(460f, 164f);
			notificationCanvasGroup = val.AddComponent<CanvasGroup>();
			notificationCanvasGroup.interactable = false;
			notificationCanvasGroup.blocksRaycasts = false;
			notificationIcon = CreateUiObject("Floppy disk", (Transform)(object)notificationPanel).AddComponent<RawImage>();
			RectTransform rectTransform = ((Graphic)notificationIcon).rectTransform;
			rectTransform.anchorMin = new Vector2(0.5f, 1f);
			rectTransform.anchorMax = new Vector2(0.5f, 1f);
			rectTransform.pivot = new Vector2(0.5f, 1f);
			rectTransform.anchoredPosition = Vector2.zero;
			rectTransform.sizeDelta = new Vector2(96f, 96f);
			((Graphic)notificationIcon).color = Color.white;
			((Graphic)notificationIcon).raycastTarget = false;
			notificationLabel = CreateUiObject("Text", (Transform)(object)notificationPanel).AddComponent<Text>();
			RectTransform rectTransform2 = ((Graphic)notificationLabel).rectTransform;
			rectTransform2.anchorMin = new Vector2(0f, 1f);
			rectTransform2.anchorMax = new Vector2(1f, 1f);
			rectTransform2.pivot = new Vector2(0.5f, 1f);
			rectTransform2.anchoredPosition = new Vector2(0f, -108f);
			rectTransform2.sizeDelta = new Vector2(0f, 48f);
			notificationLabel.font = FindBestFont();
			notificationLabel.fontSize = 30;
			notificationLabel.fontStyle = (FontStyle)0;
			notificationLabel.alignment = (TextAnchor)4;
			notificationLabel.horizontalOverflow = (HorizontalWrapMode)1;
			notificationLabel.verticalOverflow = (VerticalWrapMode)0;
			((Graphic)notificationLabel).color = Color.white;
			((Graphic)notificationLabel).raycastTarget = false;
			Shadow obj3 = ((Component)notificationLabel).gameObject.AddComponent<Shadow>();
			obj3.effectColor = Color32.op_Implicit(new Color32((byte)0, (byte)0, (byte)0, (byte)180));
			obj3.effectDistance = new Vector2(2f, -2f);
			((Component)notificationPanel).gameObject.SetActive(false);
		}
	}

	private static GameObject CreateUiObject(string name, Transform parent)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected O, but got Unknown
		GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
		val.transform.SetParent(parent, false);
		return val;
	}

	private void ApplyNotificationIcon()
	{
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		Texture val = FindGameSpriteSheet();
		if ((Object)(object)val != (Object)null && val.width >= 32 && val.height >= 192)
		{
			notificationIcon.texture = val;
			notificationIcon.uvRect = new Rect(16f / (float)val.width, 1f - 192f / (float)val.height, 16f / (float)val.width, 16f / (float)val.height);
		}
		else
		{
			notificationIcon.texture = (Texture)(object)CreateFallbackIcon();
			notificationIcon.uvRect = new Rect(0f, 0f, 1f, 1f);
		}
	}

	private Texture FindGameSpriteSheet()
	{
		try
		{
			MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>();
			MonoBehaviour[] array2 = array;
			foreach (MonoBehaviour val in array2)
			{
				if (!((Object)(object)val == (Object)null) && !(((object)val).GetType().Name != "DesktopDotExe"))
				{
					object? obj = ((object)val).GetType().GetField("spriteSheet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val);
					Texture val2 = (Texture)((obj is Texture) ? obj : null);
					if (val2 != null)
					{
						return val2;
					}
				}
			}
			array2 = array;
			foreach (MonoBehaviour val3 in array2)
			{
				if (!((Object)(object)val3 == (Object)null) && !(((object)val3).GetType().Name != "sHUD"))
				{
					object obj2 = ((object)val3).GetType().GetField("R", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val3);
					object? obj3 = (obj2?.GetType().GetField("spriteSheet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(obj2);
					Texture val4 = (Texture)((obj3 is Texture) ? obj3 : null);
					if (val4 != null)
					{
						return val4;
					}
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogDebug((object)("Could not reuse the game UI sprite sheet: " + ex.Message));
		}
		return null;
	}

	private Texture2D CreateFallbackIcon()
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Expected O, but got Unknown
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: 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_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)fallbackIconTexture != (Object)null)
		{
			return fallbackIconTexture;
		}
		Color32 val = default(Color32);
		((Color32)(ref val))..ctor((byte)0, (byte)0, (byte)0, (byte)0);
		Color32 val2 = default(Color32);
		((Color32)(ref val2))..ctor((byte)239, (byte)235, (byte)215, byte.MaxValue);
		Color32 val3 = default(Color32);
		((Color32)(ref val3))..ctor((byte)31, (byte)43, (byte)45, byte.MaxValue);
		fallbackIconTexture = new Texture2D(16, 16, (TextureFormat)4, false);
		((Object)fallbackIconTexture).name = "EasySave fallback floppy disk";
		((Texture)fallbackIconTexture).filterMode = (FilterMode)0;
		((Texture)fallbackIconTexture).wrapMode = (TextureWrapMode)1;
		for (int i = 0; i < 16; i++)
		{
			for (int j = 0; j < 16; j++)
			{
				bool flag = j >= 2 && j <= 13 && i >= 1 && i <= 14;
				fallbackIconTexture.SetPixel(j, i, Color32.op_Implicit(flag ? val2 : val));
			}
		}
		for (int k = 9; k <= 13; k++)
		{
			for (int l = 4; l <= 11; l++)
			{
				fallbackIconTexture.SetPixel(l, k, Color32.op_Implicit(val3));
			}
		}
		for (int m = 10; m <= 12; m++)
		{
			for (int n = 5; n <= 9; n++)
			{
				fallbackIconTexture.SetPixel(n, m, Color32.op_Implicit(val2));
			}
		}
		for (int num = 3; num <= 6; num++)
		{
			for (int num2 = 4; num2 <= 11; num2++)
			{
				fallbackIconTexture.SetPixel(num2, num, Color32.op_Implicit(val3));
			}
		}
		fallbackIconTexture.SetPixel(10, 4, Color32.op_Implicit(val2));
		fallbackIconTexture.SetPixel(10, 5, Color32.op_Implicit(val2));
		fallbackIconTexture.Apply(false, true);
		return fallbackIconTexture;
	}

	private static Font FindBestFont()
	{
		Font val = null;
		int num = int.MinValue;
		Font[] array = Resources.FindObjectsOfTypeAll<Font>();
		foreach (Font val2 in array)
		{
			if (!((Object)(object)val2 == (Object)null) && SupportsEnglish(val2))
			{
				string text = ((Object)val2).name.ToLowerInvariant().Replace(" ", string.Empty);
				int num2 = 0;
				if (text.Contains("lanapixel"))
				{
					num2 += 1000;
				}
				if (text.Contains("perfectdosvga"))
				{
					num2 += 900;
				}
				if (text.Contains("pixel"))
				{
					num2 += 500;
				}
				if (text.Contains("mono"))
				{
					num2 += 50;
				}
				if (text.Contains("console") || text.Contains("terminal"))
				{
					num2 += 40;
				}
				if (text.Contains("font"))
				{
					num2 += 10;
				}
				if (num2 > num)
				{
					num = num2;
					val = val2;
				}
			}
		}
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		try
		{
			return Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
		}
		catch
		{
			return Resources.GetBuiltinResource<Font>("Arial.ttf");
		}
	}

	private static bool SupportsEnglish(Font font)
	{
		try
		{
			return font.HasCharacter('G') && font.HasCharacter('a') && font.HasCharacter('e');
		}
		catch
		{
			return false;
		}
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		if (restoreCoroutine != null)
		{
			((MonoBehaviour)this).StopCoroutine(restoreCoroutine);
		}
		if ((Object)(object)notificationRoot != (Object)null)
		{
			Object.Destroy((Object)(object)notificationRoot);
		}
		if ((Object)(object)fallbackIconTexture != (Object)null)
		{
			Object.Destroy((Object)(object)fallbackIconTexture);
		}
	}
}
internal static class ReflectionHelpers
{
	internal const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	internal static FieldInfo FindField(Type type, string name)
	{
		while (type != null)
		{
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field;
			}
			type = type.BaseType;
		}
		return null;
	}

	internal static object Get(object target, string name)
	{
		if (target == null)
		{
			return null;
		}
		FieldInfo fieldInfo = FindField(target.GetType(), name);
		return fieldInfo?.GetValue(fieldInfo.IsStatic ? null : target);
	}

	internal static T Get<T>(object target, string name, T fallback = default(T))
	{
		object obj = Get(target, name);
		if (obj is T)
		{
			return (T)obj;
		}
		if (obj == null)
		{
			return fallback;
		}
		try
		{
			return (T)Convert.ChangeType(obj, typeof(T), CultureInfo.InvariantCulture);
		}
		catch
		{
			return fallback;
		}
	}

	internal static bool Set(object target, string name, object value)
	{
		if (target == null)
		{
			return false;
		}
		FieldInfo fieldInfo = FindField(target.GetType(), name);
		if (fieldInfo == null)
		{
			return false;
		}
		fieldInfo.SetValue(fieldInfo.IsStatic ? null : target, value);
		return true;
	}

	internal static object Invoke(object target, string name, params object[] args)
	{
		if (target == null)
		{
			return null;
		}
		MethodInfo[] methods = target.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo in methods)
		{
			if (methodInfo.Name != name)
			{
				continue;
			}
			ParameterInfo[] parameters = methodInfo.GetParameters();
			if (parameters.Length != args.Length)
			{
				continue;
			}
			bool flag = true;
			for (int j = 0; j < args.Length; j++)
			{
				if (args[j] != null && !parameters[j].ParameterType.IsInstanceOfType(args[j]))
				{
					flag = false;
					break;
				}
			}
			if (flag)
			{
				return methodInfo.Invoke(target, args);
			}
		}
		return null;
	}

	internal static MonoBehaviour FindActiveBehaviour(string typeName)
	{
		MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>();
		foreach (MonoBehaviour val in array)
		{
			if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == typeName && ((Behaviour)val).enabled && ((Component)val).gameObject.activeInHierarchy)
			{
				return val;
			}
		}
		return null;
	}

	internal static List<MonoBehaviour> FindBehaviours(string typeName)
	{
		List<MonoBehaviour> list = new List<MonoBehaviour>();
		MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>();
		foreach (MonoBehaviour val in array)
		{
			if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == typeName)
			{
				list.Add(val);
			}
		}
		return list;
	}

	internal static GameObject AsGameObject(object value)
	{
		GameObject val = (GameObject)((value is GameObject) ? value : null);
		if (val != null)
		{
			return val;
		}
		Component val2 = (Component)((value is Component) ? value : null);
		if (val2 != null)
		{
			return val2.gameObject;
		}
		return null;
	}

	internal static Vector3 ObjectPosition(object value)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = AsGameObject(value);
		if (!((Object)(object)val != (Object)null))
		{
			return Vector3.zero;
		}
		return val.transform.position;
	}

	internal static string ObjectName(object value)
	{
		Object val = (Object)((value is Object) ? value : null);
		if (val == null)
		{
			return null;
		}
		return val.name;
	}

	internal static string TransformPath(Transform root, Transform child)
	{
		if ((Object)(object)root == (Object)(object)child)
		{
			return string.Empty;
		}
		List<string> list = new List<string>();
		Transform val = child;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
		{
			list.Add(val.GetSiblingIndex().ToString(CultureInfo.InvariantCulture));
			val = val.parent;
		}
		if ((Object)(object)val != (Object)(object)root)
		{
			return null;
		}
		list.Reverse();
		return string.Join("/", list.ToArray());
	}

	internal static Transform ResolveTransformPath(Transform root, string path)
	{
		if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(path))
		{
			return root;
		}
		Transform val = root;
		string[] array = path.Split(new char[1] { '/' });
		for (int i = 0; i < array.Length; i++)
		{
			if (!int.TryParse(array[i], out var result) || result < 0 || result >= val.childCount)
			{
				return null;
			}
			val = val.GetChild(result);
		}
		return val;
	}

	internal static Transform FindChildRecursive(Transform root, string name)
	{
		if ((Object)(object)root == (Object)null)
		{
			return null;
		}
		if (string.Equals(((Object)root).name, name, StringComparison.OrdinalIgnoreCase))
		{
			return root;
		}
		for (int i = 0; i < root.childCount; i++)
		{
			Transform val = FindChildRecursive(root.GetChild(i), name);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		return null;
	}
}
internal enum DeliveryStage
{
	None,
	AcceptedGoToPickup,
	PayloadActiveOrInHands,
	InTruckOrDelivering,
	AtDestinationBeforeDelivery
}
[DataContract]
internal sealed class DeliveryState
{
	[DataMember(Order = 1)]
	public int version = 4;

	[DataMember(Order = 2)]
	public string timestamp;

	[DataMember(Order = 3)]
	public int sceneBuildIndex;

	[DataMember(Order = 4)]
	public string sceneName;

	[DataMember(Order = 5)]
	public SavedVector3 carPosition;

	[DataMember(Order = 6)]
	public SavedQuaternion carRotation;

	[DataMember(Order = 7)]
	public bool hasActiveDelivery;

	[DataMember(Order = 8)]
	public DeliveryStage stage;

	[DataMember(Order = 9)]
	public int progress;

	[DataMember(Order = 10)]
	public SavedVector3 packageSpawnPoint;

	[DataMember(Order = 11)]
	public SavedJobState job;

	[DataMember(Order = 12)]
	public SavedRouteState route;

	[DataMember(Order = 13)]
	public PayloadState payload;

	[DataMember(Order = 14)]
	public List<string> warnings = new List<string>();
}
[DataContract]
internal sealed class SavedJobState
{
	[DataMember(Order = 1)]
	public string shopName;

	[DataMember(Order = 2)]
	public string fromNodeName;

	[DataMember(Order = 3)]
	public SavedVector3 fromNodePosition;

	[DataMember(Order = 4)]
	public string toNodeName;

	[DataMember(Order = 5)]
	public SavedVector3 toNodePosition;

	[DataMember(Order = 6)]
	public int payloadIndex;

	[DataMember(Order = 7)]
	public string payloadPrefabName;

	[DataMember(Order = 8)]
	public float price;

	[DataMember(Order = 9)]
	public float mass;

	[DataMember(Order = 10)]
	public float distance;

	[DataMember(Order = 11)]
	public float bonusDistance;

	[DataMember(Order = 12)]
	public int destinationIndex;

	[DataMember(Order = 13)]
	public float duration;

	[DataMember(Order = 14)]
	public float timeStart;

	[DataMember(Order = 15)]
	public string name;

	[DataMember(Order = 16)]
	public string startingCityName;

	[DataMember(Order = 17)]
	public string destCityName;

	[DataMember(Order = 18)]
	public bool isIntercity;

	[DataMember(Order = 19)]
	public bool isChallenge;
}
[DataContract]
internal sealed class SavedRouteState
{
	[DataMember(Order = 1)]
	public string destinationNodeName;

	[DataMember(Order = 2)]
	public SavedVector3 destinationNodePosition;
}
[DataContract]
internal sealed class PayloadState
{
	[DataMember(Order = 1)]
	public int payloadIndex;

	[DataMember(Order = 2)]
	public string currentPayloadName;

	[DataMember(Order = 3)]
	public string rootPayloadCloneName;

	[DataMember(Order = 4)]
	public string parentMode;

	[DataMember(Order = 5)]
	public SavedVector3 localPosition;

	[DataMember(Order = 6)]
	public SavedQuaternion localRotation;

	[DataMember(Order = 7)]
	public SavedVector3 worldPosition;

	[DataMember(Order = 8)]
	public SavedQuaternion worldRotation;

	[DataMember(Order = 9)]
	public SavedVector3 localScale;

	[DataMember(Order = 10)]
	public SavedVector3 worldScale;

	[DataMember(Order = 11)]
	public bool currentPayloadActive;

	[DataMember(Order = 12)]
	public SavedVector3 currentPayloadWorldPosition;

	[DataMember(Order = 13)]
	public SavedQuaternion currentPayloadWorldRotation;

	[DataMember(Order = 14)]
	public List<SavedRigidbodyState> rigidbodies = new List<SavedRigidbodyState>();
}
[DataContract]
internal sealed class SavedRigidbodyState
{
	[DataMember(Order = 1)]
	public string childPath;

	[DataMember(Order = 2)]
	public SavedVector3 localPosition;

	[DataMember(Order = 3)]
	public SavedQuaternion localRotation;

	[DataMember(Order = 4)]
	public SavedVector3 velocity;

	[DataMember(Order = 5)]
	public SavedVector3 angularVelocity;

	[DataMember(Order = 6)]
	public bool isKinematic;

	[DataMember(Order = 7)]
	public bool useGravity;
}
[DataContract]
internal sealed class SavedVector3
{
	[DataMember(Order = 1)]
	public float x;

	[DataMember(Order = 2)]
	public float y;

	[DataMember(Order = 3)]
	public float z;

	public static SavedVector3 From(Vector3 value)
	{
		//IL_0006: 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_001e: Unknown result type (might be due to invalid IL or missing references)
		return new SavedVector3
		{
			x = value.x,
			y = value.y,
			z = value.z
		};
	}

	public Vector3 ToVector3()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		return new Vector3(x, y, z);
	}
}
[DataContract]
internal sealed class SavedQuaternion
{
	[DataMember(Order = 1)]
	public float x;

	[DataMember(Order = 2)]
	public float y;

	[DataMember(Order = 3)]
	public float z;

	[DataMember(Order = 4)]
	public float w;

	public static SavedQuaternion From(Quaternion value)
	{
		//IL_0006: 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_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		return new SavedQuaternion
		{
			x = value.x,
			y = value.y,
			z = value.z,
			w = value.w
		};
	}

	public Quaternion ToQuaternion()
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		return new Quaternion(x, y, z, w);
	}
}