Decompiled source of FollowTheWay v1.0.0

BepInEx/plugins/FollowTheWay.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.CompilerServices;
using FollowTheWay.Models;
using FollowTheWay.Utilities;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("FollowTheWay")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FollowTheWay")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7aa796a6-4555-431c-9f0c-3f03bd9eca5e")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace FollowTheWay
{
	[BepInPlugin("com.followtheway.peak.mod", "FollowTheWay", "1.0.0")]
	public class FollowTheWayPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private PathVisualizer pathVisualizer;

		private PathSelectionUI pathSelectionUI;

		private PathRecorder pathRecorder;

		private float _nextNickProbeAt;

		private const float NickProbeInterval = 1f;

		private bool _nickLoggedOnce = false;

		public static FollowTheWayPlugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigHandler.Init(((BaseUnityPlugin)this).Config);
			if (!ConfigHandler.EnableRecording.Value)
			{
				LogInfo("FollowTheWay disabled via config. Exiting…");
				return;
			}
			GameObject val = new GameObject("FollowTheWay PathRecorder");
			pathRecorder = val.AddComponent<PathRecorder>();
			Object.DontDestroyOnLoad((Object)(object)val);
			PathRecorder.SetPlayerNameProvider(GetGameNicknameSafe);
			if (ConfigHandler.AllowUploads.Value)
			{
				new Harmony("com.followtheway.peak.mod").PatchAll();
				LogInfo("Harmony patches applied successfully");
			}
			JsonConvert.DefaultSettings = () => new JsonSerializerSettings
			{
				ReferenceLoopHandling = (ReferenceLoopHandling)1,
				NullValueHandling = (NullValueHandling)1
			};
			SceneManager.activeSceneChanged += OnActiveSceneChanged;
			LogInfo("FollowTheWay initialized successfully!");
		}

		private void Update()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(ConfigHandler.ToggleMenuKey.Value))
			{
				pathSelectionUI?.ToggleMenu();
			}
			if (Time.unscaledTime >= _nextNickProbeAt)
			{
				_nextNickProbeAt = Time.unscaledTime + 1f;
				string gameNicknameSafe = GetGameNicknameSafe();
				if (!string.IsNullOrEmpty(gameNicknameSafe) && !_nickLoggedOnce)
				{
					LogInfo("Detected player nickname: " + gameNicknameSafe);
					_nickLoggedOnce = true;
				}
			}
		}

		private void OnActiveSceneChanged(Scene oldScene, Scene newScene)
		{
			string text = ((Scene)(ref newScene)).name.ToLowerInvariant();
			if (text.Contains("menu") || text.Contains("title") || text.Contains("lobby") || ((Scene)(ref newScene)).name == "Pretitle" || ((Scene)(ref newScene)).name == "Airport")
			{
				PathRecorder.Instance?.StopIfRecording(PathRecorder.StopReason.LevelChange);
			}
			else if (IsGameLevel(((Scene)(ref newScene)).name))
			{
				InitializeGameComponents();
			}
		}

		private bool IsGameLevel(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				return false;
			}
			string text = sceneName.ToLowerInvariant();
			if (text.Contains("menu") || text.Contains("title") || text.Contains("lobby"))
			{
				return false;
			}
			if (sceneName == "Pretitle" || sceneName == "Airport")
			{
				return false;
			}
			return true;
		}

		private void InitializeGameComponents()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//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)
			//IL_00a3: Expected O, but got Unknown
			try
			{
				GameObject val = new GameObject("FollowTheWay Path Manager");
				pathVisualizer = val.AddComponent<PathVisualizer>();
				Object.DontDestroyOnLoad((Object)(object)val);
				Color color = default(Color);
				((Color)(ref color))..ctor(ConfigHandler.LineColorR.Value, ConfigHandler.LineColorG.Value, ConfigHandler.LineColorB.Value, 1f);
				pathVisualizer.UpdateStyleFromConfig(ConfigHandler.LineWidth.Value, color, ConfigHandler.ForceOnTop.Value, ConfigHandler.SmoothCorners.Value, ConfigHandler.DecimationStep.Value, ConfigHandler.MaxPoints.Value);
				if (ConfigHandler.ShowPathSelectionUI.Value)
				{
					GameObject val2 = new GameObject("FollowTheWay UI Manager");
					pathSelectionUI = val2.AddComponent<PathSelectionUI>();
					Object.DontDestroyOnLoad((Object)(object)val2);
					pathSelectionUI.Initialize(pathVisualizer);
					LogInfo("PathSelectionUI initialized");
				}
				_nickLoggedOnce = false;
				LogInfo("Game components initialized successfully");
			}
			catch (Exception arg)
			{
				LogError($"Failed to init game components: {arg}");
			}
		}

		private string GetGameNicknameSafe()
		{
			try
			{
				Character localCharacter = Character.localCharacter;
				if ((Object)(object)localCharacter != (Object)null && localCharacter.IsLocal)
				{
					try
					{
						PropertyInfo property = ((object)localCharacter).GetType().GetProperty("characterName");
						if (property != null)
						{
							string text = property.GetValue(localCharacter) as string;
							if (!string.IsNullOrWhiteSpace(text) && text != "Bot")
							{
								return text;
							}
						}
					}
					catch
					{
					}
					try
					{
						Component component = ((Component)localCharacter).GetComponent("PhotonView");
						if ((Object)(object)component != (Object)null)
						{
							object obj2 = ((object)component).GetType().GetProperty("Owner")?.GetValue(component, null);
							if (obj2 != null)
							{
								string text2 = obj2.GetType().GetProperty("NickName")?.GetValue(obj2, null) as string;
								if (!string.IsNullOrWhiteSpace(text2) && text2 != "Bot")
								{
									return text2;
								}
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				LogDebug("GetGameNicknameSafe error: " + ex.Message);
			}
			return null;
		}

		public PathVisualizer GetPathVisualizer()
		{
			return pathVisualizer;
		}

		public PathSelectionUI GetPathSelectionUI()
		{
			return pathSelectionUI;
		}

		public static void LogDebug(string msg)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.Log((LogLevel)32, (object)msg);
			}
		}

		public static void LogInfo(string msg)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.Log((LogLevel)16, (object)msg);
			}
		}

		public static void LogWarning(string msg)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.Log((LogLevel)4, (object)msg);
			}
		}

		public static void LogError(string msg)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.Log((LogLevel)2, (object)msg);
			}
		}

		public static void LogError(Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.Log((LogLevel)2, (object)(ex.Message + "\n" + ex.StackTrace));
			}
		}

		private void OnDestroy()
		{
			SceneManager.activeSceneChanged -= OnActiveSceneChanged;
		}
	}
	[HarmonyPatch]
	public static class GameEventPatches
	{
		[HarmonyPatch(typeof(Character), "Update")]
		[HarmonyPostfix]
		public static void OnCharacterUpdate(Character __instance)
		{
			//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)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)(object)Character.localCharacter && (Object)(object)PathRecorder.Instance != (Object)null)
			{
				Vector3 center = __instance.Center;
				PathRecorder.RecordPosition(center);
			}
		}

		[HarmonyPatch(typeof(Character), "RPCA_Die")]
		[HarmonyPostfix]
		public static void OnCharacterDie(Character __instance)
		{
			PathRecorder instance = PathRecorder.Instance;
			if (!((Object)(object)__instance != (Object)(object)Character.localCharacter) && !((Object)(object)instance == (Object)null))
			{
				instance.StopIfRecording(PathRecorder.StopReason.Death);
			}
		}

		[HarmonyPatch(typeof(Character), "RPCEndGame")]
		[HarmonyPostfix]
		public static void OnCharacterWin(Character __instance)
		{
			PathRecorder instance = PathRecorder.Instance;
			if (!((Object)(object)__instance != (Object)(object)Character.localCharacter) && !((Object)(object)instance == (Object)null))
			{
				instance.ReportVictoryEvent();
			}
		}
	}
	public static class PathDataManager
	{
		public class PathMetaLight
		{
			public string Id;

			public string Name;

			public string Author;

			public string CreatedAtLocal;

			public int PointCount;
		}

		private static string PathsDirectory => Path.Combine(Paths.ConfigPath, "FollowTheWay", "paths");

		public static string SavePath(PathData pathData)
		{
			try
			{
				Directory.CreateDirectory(PathsDirectory);
				string text = $"path_{pathData.Timestamp}.json";
				string path = Path.Combine(PathsDirectory, text);
				string contents = JsonConvert.SerializeObject((object)pathData, (Formatting)1);
				File.WriteAllText(path, contents);
				FollowTheWayPlugin.LogInfo("Path saved: " + text);
				return text;
			}
			catch (Exception ex)
			{
				FollowTheWayPlugin.LogError("Failed to save path: " + ex.Message);
				return null;
			}
		}

		public static void SavePathAs(string fileName, PathData pathData)
		{
			try
			{
				Directory.CreateDirectory(PathsDirectory);
				string path = Path.Combine(PathsDirectory, fileName);
				string contents = JsonConvert.SerializeObject((object)pathData, (Formatting)1);
				File.WriteAllText(path, contents);
				FollowTheWayPlugin.LogInfo("Path updated: " + fileName);
			}
			catch (Exception ex)
			{
				FollowTheWayPlugin.LogError("Failed to update path " + fileName + ": " + ex.Message);
			}
		}

		public static IEnumerable<string> GetAllPaths()
		{
			Directory.CreateDirectory(PathsDirectory);
			return Directory.EnumerateFiles(PathsDirectory, "*.json").Select(Path.GetFileName);
		}

		public static PathData LoadPath(string fileName)
		{
			try
			{
				string path = Path.Combine(PathsDirectory, fileName);
				if (File.Exists(path))
				{
					string text = File.ReadAllText(path);
					return JsonConvert.DeserializeObject<PathData>(text);
				}
			}
			catch (Exception ex)
			{
				FollowTheWayPlugin.LogError("Failed to load path " + fileName + ": " + ex.Message);
			}
			return null;
		}

		public static void DeletePath(string fileName)
		{
			try
			{
				string path = Path.Combine(PathsDirectory, fileName);
				if (File.Exists(path))
				{
					File.Delete(path);
					FollowTheWayPlugin.LogInfo("Deleted path: " + fileName);
				}
			}
			catch (Exception ex)
			{
				FollowTheWayPlugin.LogError("Failed to delete path " + fileName + ": " + ex.Message);
			}
		}

		public static void DeleteAll()
		{
			try
			{
				Directory.CreateDirectory(PathsDirectory);
				IEnumerable<string> enumerable = Directory.EnumerateFiles(PathsDirectory, "*.json");
				int num = 0;
				foreach (string item in enumerable)
				{
					try
					{
						File.Delete(item);
						num++;
					}
					catch
					{
					}
				}
				FollowTheWayPlugin.LogInfo($"Deleted all paths: {num} files");
			}
			catch (Exception ex)
			{
				FollowTheWayPlugin.LogError("Failed to delete all paths: " + ex.Message);
			}
		}

		public static PathMetaLight TryReadMeta(string fileName)
		{
			try
			{
				string path = Path.Combine(PathsDirectory, fileName);
				if (!File.Exists(path))
				{
					return null;
				}
				PathData pathData = LoadPath(fileName);
				if (pathData == null)
				{
					return null;
				}
				string createdAtLocal = "";
				try
				{
					createdAtLocal = DateTimeOffset.FromUnixTimeSeconds(pathData.Timestamp).ToLocalTime().DateTime.ToString("yyyy-MM-dd HH:mm:ss");
				}
				catch
				{
				}
				int pointCount = pathData.Points?.Count ?? 0;
				string name = ((!string.IsNullOrWhiteSpace(pathData.Name)) ? pathData.Name : fileName);
				string author = pathData.Author ?? "";
				return new PathMetaLight
				{
					Id = fileName,
					Name = name,
					Author = author,
					CreatedAtLocal = createdAtLocal,
					PointCount = pointCount
				};
			}
			catch
			{
				return null;
			}
		}
	}
	public class PathRecorder : MonoBehaviour
	{
		public enum StopReason
		{
			Unknown,
			Manual,
			LevelChange,
			Victory,
			Death
		}

		public readonly List<Vector3> CurrentPath = new List<Vector3>(1024);

		private float lastRecordTime;

		private float startTime;

		private const float RECORD_INTERVAL = 0.1f;

		private const float VICTORY_GRACE = 3f;

		private StopReason? _finalReason;

		private bool _savingInProgress;

		private bool pendingVictory;

		private float pendingVictoryUntil;

		private string lastSavedFileName;

		private static Func<string> _playerNameProvider;

		public static PathRecorder Instance { get; private set; }

		public bool IsRecording { get; private set; }

		public StopReason? FinalReason => _finalReason;

		private static int Priority(StopReason r)
		{
			return r switch
			{
				StopReason.Death => 100, 
				StopReason.Victory => 90, 
				StopReason.LevelChange => 70, 
				StopReason.Manual => 60, 
				_ => 0, 
			};
		}

		public static void SetPlayerNameProvider(Func<string> provider)
		{
			_playerNameProvider = provider;
		}

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
				FollowTheWayPlugin.LogInfo("PathRecorder initialized");
			}
			else
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			if (pendingVictory && Time.time >= pendingVictoryUntil)
			{
				pendingVictory = false;
				if (IsRecording)
				{
					FollowTheWayPlugin.LogDebug("[PathRecorder] Victory grace expired -> stopping as Victory");
					StopRecording(StopReason.Victory);
				}
			}
		}

		public void StartRecording()
		{
			if (IsRecording)
			{
				FollowTheWayPlugin.LogDebug("Already recording path");
				return;
			}
			CurrentPath.Clear();
			IsRecording = true;
			lastRecordTime = Time.time;
			startTime = lastRecordTime;
			_finalReason = null;
			_savingInProgress = false;
			pendingVictory = false;
			pendingVictoryUntil = 0f;
			lastSavedFileName = null;
			FollowTheWayPlugin.LogInfo("Started recording path");
		}

		public void ReportVictoryEvent()
		{
			FollowTheWayPlugin.LogDebug(string.Format("[PathRecorder] ReportVictoryEvent received. isRecording={0}, finalReason={1}, pendingVictory={2}", IsRecording, _finalReason?.ToString() ?? "null", pendingVictory));
			if (IsRecording && _finalReason.GetValueOrDefault() != StopReason.Death)
			{
				_finalReason = StopReason.Victory;
				pendingVictory = true;
				pendingVictoryUntil = Time.time + 3f;
				FollowTheWayPlugin.LogDebug($"[PathRecorder] Victory scheduled with grace {3f}s (until {pendingVictoryUntil:0.00})");
			}
		}

		public void StopRecording(StopReason reason)
		{
			FollowTheWayPlugin.LogDebug(string.Format("[PathRecorder] StopRecording called with {0}. isRecording={1}, finalReason={2}, pendingVictory={3}", reason, IsRecording, _finalReason?.ToString() ?? "null", pendingVictory));
			pendingVictory = false;
			if (_finalReason.HasValue)
			{
				if (_finalReason.Value != StopReason.Death && Priority(reason) > Priority(_finalReason.Value))
				{
					_finalReason = reason;
				}
			}
			else
			{
				_finalReason = reason;
			}
			if (IsRecording)
			{
				IsRecording = false;
				if (_savingInProgress)
				{
					FollowTheWayPlugin.LogDebug("[PathRecorder] Duplicate StopRecording ignored");
					return;
				}
				_savingInProgress = true;
				string text = SafeGetPlayerName();
				string text2 = ((!string.IsNullOrWhiteSpace(text)) ? text : "LocalPlayer");
				DateTimeOffset now = DateTimeOffset.Now;
				string name = $"Run {now:yyyy-MM-dd HH:mm:ss}";
				long timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
				float num = Mathf.Max(0f, Time.time - startTime);
				StopReason valueOrDefault = _finalReason.GetValueOrDefault(reason);
				PathData pathData = new PathData
				{
					Timestamp = timestamp,
					DurationSeconds = num,
					Reason = valueOrDefault,
					Points = new List<Vector3>(CurrentPath),
					PlayerName = text2,
					CompletionTime = num,
					PlayerDied = (valueOrDefault == StopReason.Death),
					Name = name,
					Author = text2
				};
				string text3 = (lastSavedFileName = PathDataManager.SavePath(pathData));
				FollowTheWayPlugin.LogInfo(string.Format("Stopped recording path. Reason: {0}, Points: {1}, Duration: {2:F1}s, File: {3}", valueOrDefault, CurrentPath.Count, pathData.DurationSeconds, text3 ?? "n/a"));
				_savingInProgress = false;
			}
		}

		public void StopIfRecording(StopReason reason)
		{
			FollowTheWayPlugin.LogDebug(string.Format("[PathRecorder] StopIfRecording called with {0}. isRecording={1}, finalReason={2}, pendingVictory={3}", reason, IsRecording, _finalReason?.ToString() ?? "null", pendingVictory));
			if (reason == StopReason.Victory)
			{
				ReportVictoryEvent();
				return;
			}
			if (_finalReason.HasValue)
			{
				if (_finalReason.Value != StopReason.Death && Priority(reason) > Priority(_finalReason.Value))
				{
					_finalReason = reason;
				}
			}
			else
			{
				_finalReason = reason;
			}
			if (IsRecording)
			{
				StopRecording(reason);
			}
			else if (reason == StopReason.Death)
			{
				TryFixLastSavedReasonToDeath();
			}
		}

		public static void RecordPosition(Vector3 position)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			PathRecorder instance = Instance;
			if (!((Object)(object)instance == (Object)null) && instance.IsRecording)
			{
				float time = Time.time;
				if (!(time - instance.lastRecordTime < 0.1f))
				{
					instance.CurrentPath.Add(position);
					instance.lastRecordTime = time;
				}
			}
		}

		private void TryFixLastSavedReasonToDeath()
		{
			try
			{
				if (!string.IsNullOrEmpty(lastSavedFileName))
				{
					PathData pathData = PathDataManager.LoadPath(lastSavedFileName);
					if (pathData != null && pathData.Reason != StopReason.Death)
					{
						pathData.Reason = StopReason.Death;
						pathData.PlayerDied = true;
						PathDataManager.SavePathAs(lastSavedFileName, pathData);
						FollowTheWayPlugin.LogDebug("[PathRecorder] Patched last saved file to Death: " + lastSavedFileName);
					}
				}
			}
			catch (Exception ex)
			{
				FollowTheWayPlugin.LogDebug("[PathRecorder] Failed to patch last saved file to Death: " + ex.Message);
			}
		}

		private string SafeGetPlayerName()
		{
			try
			{
				if (_playerNameProvider != null)
				{
					string text = _playerNameProvider();
					if (!string.IsNullOrWhiteSpace(text))
					{
						return text;
					}
				}
			}
			catch (Exception ex)
			{
				FollowTheWayPlugin.LogDebug("SafeGetPlayerName error: " + ex.Message);
			}
			return null;
		}
	}
	public class PathVisualizer : MonoBehaviour
	{
		private LineRenderer lineRenderer;

		private Material baseMaterial;

		private Vector3[] _tempBuffer;

		public int DecimationStep { get; set; } = 1;


		public int MaxPoints { get; set; } = 100000;


		public float LineWidth { get; set; } = 0.35f;


		public Color LineColor { get; set; } = Color.green;


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


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


		private void Awake()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			lineRenderer = ((Component)this).gameObject.AddComponent<LineRenderer>();
			Material val = null;
			string[] array = new string[4] { "Unlit/Color", "Sprites/Default", "Legacy Shaders/Unlit/Color", "Standard" };
			string[] array2 = array;
			foreach (string text in array2)
			{
				Shader val2 = Shader.Find(text);
				if ((Object)(object)val2 != (Object)null)
				{
					val = new Material(val2);
					FollowTheWayPlugin.LogDebug("[FollowTheWay] Using shader: " + text);
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = new Material(Shader.Find("Sprites/Default"));
				FollowTheWayPlugin.LogWarning("[FollowTheWay] Using fallback shader");
			}
			baseMaterial = val;
			((Renderer)lineRenderer).material = baseMaterial;
			ApplyStyle();
			lineRenderer.positionCount = 0;
			((Component)this).gameObject.SetActive(true);
		}

		private void ApplyStyle()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			lineRenderer.startWidth = LineWidth;
			lineRenderer.endWidth = LineWidth;
			if (SmoothCorners)
			{
				lineRenderer.numCapVertices = 5;
				lineRenderer.numCornerVertices = 5;
			}
			else
			{
				lineRenderer.numCapVertices = 0;
				lineRenderer.numCornerVertices = 0;
			}
			Color lineColor = LineColor;
			lineColor.a = 1f;
			lineRenderer.startColor = lineColor;
			lineRenderer.endColor = lineColor;
			if ((Object)(object)((Renderer)lineRenderer).material != (Object)null)
			{
				((Renderer)lineRenderer).material.color = lineColor;
			}
			((Renderer)lineRenderer).material.renderQueue = (ForceOnTop ? 5000 : 2000);
			lineRenderer.useWorldSpace = true;
			lineRenderer.alignment = (LineAlignment)0;
			((Renderer)lineRenderer).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)lineRenderer).receiveShadows = false;
		}

		public void UpdateStyleFromConfig(float width, Color color, bool forceOnTop, bool smooth, int decimation, int maxPoints)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			LineWidth = Mathf.Clamp(width, 0.02f, 1.5f);
			LineColor = color;
			ForceOnTop = forceOnTop;
			SmoothCorners = smooth;
			DecimationStep = Mathf.Max(1, decimation);
			MaxPoints = Mathf.Max(100, maxPoints);
			ApplyStyle();
		}

		public void ShowPath(List<Vector3> points, Color? overrideColor = null)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			if (points == null || points.Count < 2)
			{
				lineRenderer.positionCount = 0;
				FollowTheWayPlugin.LogDebug("[FollowTheWay] Path cleared - insufficient points");
				return;
			}
			if (overrideColor.HasValue)
			{
				Color value = overrideColor.Value;
				value.a = 1f;
				LineColor = value;
			}
			ApplyStyle();
			int count = points.Count;
			int num = Mathf.Min(count, MaxPoints);
			int num2 = Mathf.Max(1, DecimationStep);
			int num3 = (count + num2 - 1) / num2;
			if (num3 > num)
			{
				num2 = Mathf.CeilToInt((float)count / (float)num);
				num3 = (count + num2 - 1) / num2;
			}
			if (_tempBuffer == null || _tempBuffer.Length < num3)
			{
				_tempBuffer = (Vector3[])(object)new Vector3[Mathf.NextPowerOfTwo(num3)];
			}
			int num4 = 0;
			for (int i = 0; i < count; i += num2)
			{
				if (num4 >= num)
				{
					break;
				}
				_tempBuffer[num4++] = points[i];
			}
			if (num4 < num && count > 0 && (num4 == 0 || _tempBuffer[num4 - 1] != points[count - 1]))
			{
				_tempBuffer[num4++] = points[count - 1];
			}
			lineRenderer.positionCount = num4;
			lineRenderer.SetPositions(_tempBuffer);
			FollowTheWayPlugin.LogDebug($"[FollowTheWay] Visualized path with {count} src -> {num4} rendered (step={num2}, max={MaxPoints}), color: {LineColor}");
		}

		public void ClearPath()
		{
			lineRenderer.positionCount = 0;
			FollowTheWayPlugin.LogDebug("[FollowTheWay] Path cleared manually");
		}
	}
	public class PathSelectionUI : MonoBehaviour
	{
		private struct CachedInfo
		{
			public long Timestamp;

			public float DurationSeconds;

			public PathRecorder.StopReason Reason;

			public int PointsCount;

			public string Name;

			public string Author;
		}

		private enum FilterType
		{
			All,
			Wins,
			Deaths,
			Manual,
			LevelChange
		}

		public static PathSelectionUI Instance;

		public static ManualLogSource Log;

		private bool _showMenu;

		private Vector2 _scroll;

		private Rect _windowRect = new Rect(40f, 40f, 900f, 820f);

		private int _windowId;

		private GUIStyle _valueLineStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _headerStyle;

		private GUIStyle _statusStyle;

		private GUIStyle _greenButton;

		private GUIStyle _redButton;

		private GUIStyle _reasonStyle;

		private GUIStyle _boldLabel;

		private readonly List<string> _availablePaths = new List<string>();

		private readonly Dictionary<string, CachedInfo> _cache = new Dictionary<string, CachedInfo>();

		private string _selectedPath = "";

		private FilterType _currentFilter = FilterType.All;

		private bool _sortByTime = false;

		private bool _sortByDate = true;

		private string _search = string.Empty;

		private string _pendingName = "";

		private string _pendingAuthor = "";

		public Action ApplyVisualizerStyle = delegate
		{
		};

		public Action<string> ShowPath = delegate
		{
		};

		public Action<string> HidePath = delegate
		{
		};

		public Func<bool> IsPathShown = () => false;

		public Action<string> DeletePathById = delegate
		{
		};

		public Action DeleteAllPaths = delegate
		{
		};

		public Action<bool> ToggleRecording = delegate
		{
		};

		public Func<bool> IsRecording = () => false;

		private void Awake()
		{
			Instance = this;
			_windowId = "FTW_PathSelectionUI".GetHashCode();
			if (Log == null)
			{
				Log = Logger.CreateLogSource("FollowTheWay.UI");
			}
			Log.LogInfo((object)"[UI] PathSelectionUI initialized");
		}

		public void Initialize(PathVisualizer visualizer)
		{
			ApplyVisualizerStyle = delegate
			{
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)visualizer == (Object)null))
				{
					Color color = default(Color);
					((Color)(ref color))..ctor(ConfigHandler.LineColorR.Value, ConfigHandler.LineColorG.Value, ConfigHandler.LineColorB.Value, 1f);
					visualizer.UpdateStyleFromConfig(ConfigHandler.LineWidth.Value, color, ConfigHandler.ForceOnTop.Value, ConfigHandler.SmoothCorners.Value, Math.Max(1, ConfigHandler.DecimationStep.Value), Math.Max(100, ConfigHandler.MaxPoints.Value));
				}
			};
			ShowPath = delegate(string pathName)
			{
				PathData pathData = PathDataManager.LoadPath(pathName);
				if (pathData == null || pathData.Points == null || pathData.Points.Count < 2)
				{
					FollowTheWayPlugin.LogWarning("[FTW] ShowPath: path " + pathName + " is empty or not found");
					visualizer.ClearPath();
				}
				else
				{
					ApplyVisualizerStyle?.Invoke();
					visualizer.ShowPath(pathData.Points);
				}
			};
			HidePath = delegate
			{
				visualizer.ClearPath();
			};
			IsPathShown = delegate
			{
				LineRenderer component = ((Component)visualizer).GetComponent<LineRenderer>();
				return (Object)(object)component != (Object)null && component.positionCount > 0;
			};
			DeletePathById = delegate(string id)
			{
				PathDataManager.DeletePath(id);
			};
			DeleteAllPaths = delegate
			{
				PathDataManager.DeleteAll();
			};
			ToggleRecording = delegate(bool wantOn)
			{
				if (wantOn)
				{
					PathRecorder.Instance?.StartRecording();
				}
				else
				{
					PathRecorder.Instance?.StopRecording(PathRecorder.StopReason.Manual);
				}
			};
			IsRecording = () => PathRecorder.Instance?.IsRecording ?? false;
			RefreshPathList();
		}

		public void ToggleMenu()
		{
			_showMenu = !_showMenu;
			if (_showMenu)
			{
				RefreshPathList();
			}
		}

		private void EnsureStyles()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Expected O, but got Unknown
			if (_valueLineStyle == null)
			{
				_valueLineStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)3,
					fontSize = 12,
					fontStyle = (FontStyle)0
				};
				_valueLineStyle.normal.textColor = new Color(0.92f, 0.95f, 1f, 1f);
			}
			if (_titleStyle == null)
			{
				_titleStyle = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
			}
			if (_headerStyle == null)
			{
				_headerStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 16,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
			}
			if (_statusStyle == null)
			{
				_statusStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 13,
					fontStyle = (FontStyle)1
				};
			}
			if (_greenButton == null)
			{
				GUIStyle val = new GUIStyle(GUI.skin.button);
				val.normal.textColor = Color.white;
				val.fontStyle = (FontStyle)1;
				val.alignment = (TextAnchor)4;
				_greenButton = val;
			}
			if (_redButton == null)
			{
				GUIStyle val2 = new GUIStyle(GUI.skin.button);
				val2.normal.textColor = Color.white;
				val2.fontStyle = (FontStyle)1;
				val2.alignment = (TextAnchor)4;
				_redButton = val2;
			}
			if (_reasonStyle == null)
			{
				_reasonStyle = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
			}
			if (_boldLabel == null)
			{
				_boldLabel = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
			}
		}

		private void OnGUI()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if (_showMenu)
			{
				EnsureStyles();
				GUI.depth = 0;
				GUI.color = Color.white;
				GUI.backgroundColor = Color.white;
				_windowRect = GUI.Window(_windowId, _windowRect, new WindowFunction(DrawWindow), "FollowTheWay — Paths & Filters");
			}
		}

		private void DrawWindow(int id)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			try
			{
				DrawHeaderAndRecordBar();
				GUILayout.Space(6f);
				DrawMetaEditor();
				GUILayout.Space(6f);
				DrawFilters();
				GUILayout.Space(6f);
				DrawPathsList();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)$"[UI] DrawWindow error: {arg}");
				}
			}
			finally
			{
				GUILayout.EndVertical();
			}
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 24f));
		}

		private void DrawHeaderAndRecordBar()
		{
			//IL_0049: 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_0074: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			GUILayout.Label("FollowTheWay — Path Manager", _headerStyle, Array.Empty<GUILayoutOption>());
			bool flag = IsRecording?.Invoke() ?? false;
			GUI.color = (flag ? Color.red : Color.green);
			GUILayout.Label(flag ? "Status: Recording" : "Status: Idle", _statusStyle, Array.Empty<GUILayoutOption>());
			GUI.color = Color.white;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (!flag)
			{
				Color backgroundColor = GUI.backgroundColor;
				GUI.backgroundColor = new Color(0.15f, 0.6f, 0.15f, 1f);
				if (GUILayout.Button("Start Recording", _greenButton, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Height(28f),
					GUILayout.Width(180f)
				}))
				{
					ToggleRecording?.Invoke(obj: true);
				}
				GUI.backgroundColor = backgroundColor;
			}
			else
			{
				Color backgroundColor2 = GUI.backgroundColor;
				GUI.backgroundColor = new Color(0.75f, 0.2f, 0.2f, 1f);
				if (GUILayout.Button("Stop Recording", _redButton, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Height(28f),
					GUILayout.Width(180f)
				}))
				{
					ToggleRecording?.Invoke(obj: false);
				}
				GUI.backgroundColor = backgroundColor2;
			}
			if (GUILayout.Button("Refresh List", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(28f),
				GUILayout.Width(180f)
			}))
			{
				RefreshPathList();
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Hide Visualization", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(28f),
				GUILayout.Width(200f)
			}))
			{
				Func<bool> isPathShown = IsPathShown;
				if (isPathShown != null && isPathShown())
				{
					HidePath?.Invoke(string.Empty);
					_selectedPath = "";
				}
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
		}

		private void DrawMetaEditor()
		{
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Run Metadata", _titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Name:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
			_pendingName = GUILayout.TextField(_pendingName ?? "", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinWidth(260f),
				GUILayout.ExpandWidth(true)
			});
			GUILayout.Space(16f);
			GUILayout.Label("Author (nickname):", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			_pendingAuthor = GUILayout.TextField(_pendingAuthor ?? "", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinWidth(220f),
				GUILayout.ExpandWidth(true)
			});
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Apply to Last Saved", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(220f),
				GUILayout.Height(26f)
			}))
			{
				ApplyMetaToLastSaved(_pendingName, _pendingAuthor);
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
		}

		private void DrawFilters()
		{
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Filters", _titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(GUI.skin.box, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Search:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			string text = GUILayout.TextField(_search, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinWidth(260f),
				GUILayout.ExpandWidth(true)
			});
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(GUI.skin.box, Array.Empty<GUILayoutOption>());
			string text2 = ((((Rect)(ref _windowRect)).width < 760f) ? "Date (↓ newer)" : "Date (newer → older)");
			string text3 = ((((Rect)(ref _windowRect)).width < 760f) ? "Time (↑ faster)" : "Time (faster → slower)");
			bool flag = GUILayout.Toggle(_sortByDate, text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(260f) });
			bool flag2 = GUILayout.Toggle(_sortByTime, text3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(260f) });
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			if (text != _search || flag != _sortByDate || flag2 != _sortByTime)
			{
				_search = text;
				_sortByDate = flag;
				_sortByTime = flag2;
				if (_sortByDate)
				{
					_sortByTime = false;
				}
				if (_sortByTime)
				{
					_sortByDate = false;
				}
			}
			GUILayout.BeginHorizontal(GUI.skin.box, Array.Empty<GUILayoutOption>());
			DrawFilterButton(FilterType.All, "All", 100f);
			DrawFilterButton(FilterType.Deaths, "Deaths", 100f);
			DrawFilterButton(FilterType.Wins, "Wins", 100f);
			DrawFilterButton(FilterType.Manual, "Manual", 100f);
			DrawFilterButton(FilterType.LevelChange, "Level Change", 100f);
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
			{
				_currentFilter = FilterType.All;
				_search = "";
				_sortByDate = true;
				_sortByTime = false;
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
		}

		private void DrawFilterButton(FilterType type, string label, float width)
		{
			//IL_0015: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			bool flag = _currentFilter == type;
			GUI.color = (flag ? Color.green : Color.white);
			if (GUILayout.Button(flag ? ("[" + label + "]") : label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(width) }))
			{
				_currentFilter = type;
			}
			GUI.color = Color.white;
		}

		private void DrawPathsList()
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			List<string> list = GetFilteredPaths().ToList();
			GUILayout.Label($"Saved paths: {list.Count} of {_availablePaths.Count}", _titleStyle, Array.Empty<GUILayoutOption>());
			if (list.Count == 0)
			{
				GUILayout.Label("Nothing found.", Array.Empty<GUILayoutOption>());
				GUILayout.EndVertical();
				return;
			}
			_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(560f) });
			string text = null;
			foreach (string item in list)
			{
				if (!_cache.TryGetValue(item, out var value))
				{
					continue;
				}
				GUILayout.BeginHorizontal(GUI.skin.box, Array.Empty<GUILayoutOption>());
				bool flag = _selectedPath == item && (IsPathShown?.Invoke() ?? false);
				GUI.color = (flag ? Color.green : Color.white);
				if (GUILayout.Button(flag ? "Hide" : "Show", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
				{
					if (flag)
					{
						HidePath?.Invoke(string.Empty);
						_selectedPath = "";
					}
					else
					{
						_selectedPath = item;
						LoadAndVisualizePath(item);
					}
				}
				GUI.color = Color.white;
				GUILayout.Space(6f);
				GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				string text2 = (string.IsNullOrWhiteSpace(value.Name) ? item : value.Name);
				GUILayout.Label(text2, _boldLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				Color color = GUI.color;
				GUI.color = ReasonColor(value.Reason);
				GUILayout.Label(ReasonToText(value.Reason), _reasonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				GUI.color = color;
				string text3 = (string.IsNullOrWhiteSpace(value.Author) ? "(no author)" : value.Author);
				string text4 = TimeSpan.FromSeconds(value.DurationSeconds).ToString("mm\\:ss");
				string text5 = FormatLocalDate(value.Timestamp);
				GUILayout.Label($"Author: {text3}   •   Time: {text4}   •   Points: {value.PointsCount}   •   Date: {text5}", _valueLineStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				GUILayout.EndVertical();
				GUILayout.Space(6f);
				GUI.color = Color.red;
				if (GUILayout.Button("Delete", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
				{
					text = item;
				}
				GUI.color = Color.white;
				GUILayout.EndHorizontal();
				GUILayout.Space(2f);
			}
			GUILayout.EndScrollView();
			if (text != null)
			{
				DeletePath(text);
			}
			GUILayout.EndVertical();
		}

		private Color ReasonColor(PathRecorder.StopReason r)
		{
			//IL_006b: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(r switch
			{
				PathRecorder.StopReason.Death => new Color(0.9f, 0.2f, 0.2f, 1f), 
				PathRecorder.StopReason.Victory => new Color(0.2f, 0.8f, 0.2f, 1f), 
				PathRecorder.StopReason.Manual => new Color(0.2f, 0.4f, 1f, 1f), 
				PathRecorder.StopReason.LevelChange => new Color(0.65f, 0.65f, 0.65f, 1f), 
				_ => Color.white, 
			});
		}

		private IEnumerable<string> GetFilteredPaths()
		{
			IEnumerable<string> source = _availablePaths.Where((string n) => _cache.ContainsKey(n));
			if (!string.IsNullOrWhiteSpace(_search))
			{
				string s = _search.Trim();
				source = source.Where(delegate(string n)
				{
					CachedInfo cachedInfo2 = _cache[n];
					if (!string.IsNullOrEmpty(cachedInfo2.Name) && cachedInfo2.Name.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return true;
					}
					return (!string.IsNullOrEmpty(cachedInfo2.Author) && cachedInfo2.Author.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0) || n.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0;
				});
			}
			source = source.Where(delegate(string n)
			{
				CachedInfo cachedInfo = _cache[n];
				return _currentFilter switch
				{
					FilterType.Deaths => cachedInfo.Reason == PathRecorder.StopReason.Death, 
					FilterType.Wins => cachedInfo.Reason == PathRecorder.StopReason.Victory, 
					FilterType.Manual => cachedInfo.Reason == PathRecorder.StopReason.Manual, 
					FilterType.LevelChange => cachedInfo.Reason == PathRecorder.StopReason.LevelChange, 
					_ => true, 
				};
			});
			if (_sortByDate)
			{
				source = source.OrderByDescending((string n) => _cache[n].Timestamp);
			}
			else if (_sortByTime)
			{
				source = source.OrderBy((string n) => _cache[n].DurationSeconds);
			}
			return source;
		}

		private void LoadAndVisualizePath(string pathName)
		{
			PathData pathData = PathDataManager.LoadPath(pathName);
			if (pathData != null)
			{
				TryPullNameAuthor(pathName, pathData);
				ApplyVisualizerStyle?.Invoke();
				ShowPath?.Invoke(pathName);
				FollowTheWayPlugin.LogDebug("Visualized path " + pathName);
			}
		}

		private void DeletePath(string pathName)
		{
			DeletePathById?.Invoke(pathName);
			_cache.Remove(pathName);
			RefreshPathList();
			if (_selectedPath == pathName)
			{
				_selectedPath = "";
				HidePath?.Invoke(string.Empty);
			}
		}

		private string ReasonToText(PathRecorder.StopReason reason)
		{
			return reason switch
			{
				PathRecorder.StopReason.Death => "Reason: Death", 
				PathRecorder.StopReason.Victory => "Reason: Victory", 
				PathRecorder.StopReason.Manual => "Reason: Manual stop", 
				PathRecorder.StopReason.LevelChange => "Reason: Level change", 
				_ => "Reason: Unknown", 
			};
		}

		private string FormatLocalDate(long timestampSeconds)
		{
			try
			{
				return DateTimeOffset.FromUnixTimeSeconds(timestampSeconds).ToLocalTime().DateTime.ToString("yyyy-MM-dd HH:mm:ss");
			}
			catch
			{
				return "";
			}
		}

		private void RefreshPathList()
		{
			_availablePaths.Clear();
			_availablePaths.AddRange(PathDataManager.GetAllPaths());
			_cache.Clear();
			foreach (string availablePath in _availablePaths)
			{
				PathData pathData = PathDataManager.LoadPath(availablePath);
				if (pathData != null)
				{
					_cache[availablePath] = new CachedInfo
					{
						Timestamp = pathData.Timestamp,
						DurationSeconds = pathData.DurationSeconds,
						Reason = pathData.Reason,
						PointsCount = ((pathData.Points != null) ? pathData.Points.Count : 0),
						Name = GetField(pathData, "Name"),
						Author = GetField(pathData, "Author")
					};
				}
			}
			FollowTheWayPlugin.LogDebug($"Refreshed path list: {_availablePaths.Count} paths (cached: {_cache.Count})");
		}

		private string GetField(object data, string prop)
		{
			try
			{
				Type type = data.GetType();
				PropertyInfo property = type.GetProperty(prop);
				if (property != null)
				{
					return (property.GetValue(data) as string) ?? "";
				}
				FieldInfo field = type.GetField(prop);
				if (field != null)
				{
					return (field.GetValue(data) as string) ?? "";
				}
			}
			catch
			{
			}
			return "";
		}

		private void TryPullNameAuthor(string pathName, object pathData)
		{
			string field = GetField(pathData, "Name");
			string field2 = GetField(pathData, "Author");
			if (_cache.TryGetValue(pathName, out var value))
			{
				bool flag = false;
				if (!string.IsNullOrEmpty(field) && field != value.Name)
				{
					value.Name = field;
					flag = true;
				}
				if (!string.IsNullOrEmpty(field2) && field2 != value.Author)
				{
					value.Author = field2;
					flag = true;
				}
				if (flag)
				{
					_cache[pathName] = value;
				}
			}
		}

		private void ApplyMetaToLastSaved(string name, string author)
		{
			if (_availablePaths.Count == 0)
			{
				return;
			}
			string text = null;
			long num = long.MinValue;
			foreach (string availablePath in _availablePaths)
			{
				if (_cache.TryGetValue(availablePath, out var value) && value.Timestamp > num)
				{
					num = value.Timestamp;
					text = availablePath;
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			PathData pathData = PathDataManager.LoadPath(text);
			if (pathData == null)
			{
				return;
			}
			bool flag = false;
			flag |= TrySetField(pathData, "Name", name);
			if (flag | TrySetField(pathData, "Author", author))
			{
				PathDataManager.SavePath(pathData);
				if (_cache.TryGetValue(text, out var value2))
				{
					value2.Name = (string.IsNullOrEmpty(name) ? value2.Name : name);
					value2.Author = (string.IsNullOrEmpty(author) ? value2.Author : author);
					_cache[text] = value2;
				}
				FollowTheWayPlugin.LogInfo("Applied meta to last path: " + text + " (Name='" + name + "', Author='" + author + "')");
				RefreshPathList();
			}
		}

		private bool TrySetField(object data, string prop, string value)
		{
			try
			{
				if (value == null)
				{
					return false;
				}
				Type type = data.GetType();
				PropertyInfo property = type.GetProperty(prop);
				if (property != null && property.PropertyType == typeof(string))
				{
					property.SetValue(data, value);
					return true;
				}
				FieldInfo field = type.GetField(prop);
				if (field != null && field.FieldType == typeof(string))
				{
					field.SetValue(data, value);
					return true;
				}
			}
			catch
			{
			}
			return false;
		}
	}
}
namespace FollowTheWay.UI
{
	public class ToastController : MonoBehaviour
	{
		private static ToastController instance;

		private string currentMessage = "";

		private float messageEndTime = 0f;

		private void Awake()
		{
			if ((Object)(object)instance == (Object)null)
			{
				instance = this;
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			}
			else
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		public static void ShowToast(string message, float duration = 2f)
		{
			if ((Object)(object)instance != (Object)null)
			{
				instance.DisplayToast(message, duration);
			}
			else
			{
				FollowTheWayPlugin.LogInfo($"[TOAST] {message} (for {duration}s)");
			}
		}

		private void DisplayToast(string message, float duration)
		{
			currentMessage = message;
			messageEndTime = Time.time + duration;
			FollowTheWayPlugin.LogInfo("[ToastController] Showing toast: " + message);
		}

		private void OnGUI()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < messageEndTime && !string.IsNullOrEmpty(currentMessage))
			{
				GUIStyle val = new GUIStyle(GUI.skin.box)
				{
					fontSize = 16,
					alignment = (TextAnchor)4
				};
				GUI.Box(new Rect((float)(Screen.width / 2 - 150), 50f, 300f, 50f), currentMessage, val);
			}
		}
	}
}
namespace FollowTheWay.Models
{
	public class PathData
	{
		public long Timestamp { get; set; }

		public float DurationSeconds { get; set; }

		public PathRecorder.StopReason Reason { get; set; }

		public List<Vector3> Points { get; set; } = new List<Vector3>();


		public int MapId { get; set; }

		public string PlayerName { get; set; }

		public float CompletionTime { get; set; }

		public bool PlayerDied { get; set; }

		public string Name { get; set; }

		public string Author { get; set; }
	}
	public class PathPoint
	{
		public float X { get; set; }

		public float Y { get; set; }

		public float Z { get; set; }

		public float Timestamp { get; set; }

		public PathPoint()
		{
		}

		public PathPoint(Vector3 position, float time)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			X = position.x;
			Y = position.y;
			Z = position.z;
			Timestamp = time;
		}
	}
	public class ServerResponse<T>
	{
		public bool Success { get; set; }

		public string Message { get; set; }

		public T Paths { get; set; }
	}
}
namespace FollowTheWay.Utilities
{
	public static class ConfigHandler
	{
		public static ConfigEntry<bool> EnableRecording { get; private set; }

		public static ConfigEntry<bool> AllowUploads { get; private set; }

		public static ConfigEntry<bool> ShowToasts { get; private set; }

		public static ConfigEntry<bool> ShowPathSelectionUI { get; private set; }

		public static ConfigEntry<KeyCode> ToggleMenuKey { get; private set; }

		public static ConfigEntry<float> LineWidth { get; private set; }

		public static ConfigEntry<bool> ForceOnTop { get; private set; }

		public static ConfigEntry<bool> SmoothCorners { get; private set; }

		public static ConfigEntry<int> DecimationStep { get; private set; }

		public static ConfigEntry<int> MaxPoints { get; private set; }

		public static ConfigEntry<float> LineColorR { get; private set; }

		public static ConfigEntry<float> LineColorG { get; private set; }

		public static ConfigEntry<float> LineColorB { get; private set; }

		public static void Init(ConfigFile config)
		{
			EnableRecording = config.Bind<bool>("General", "EnableRecording", true, "Enable path recording");
			AllowUploads = config.Bind<bool>("Network", "AllowUploads", true, "Apply Harmony patches (required for automatic recording)");
			ShowToasts = config.Bind<bool>("UI", "ShowToasts", true, "Show toast notifications");
			ShowPathSelectionUI = config.Bind<bool>("UI", "ShowPathSelectionUI", true, "Enable path selection UI");
			ToggleMenuKey = config.Bind<KeyCode>("Hotkeys", "ToggleMenu", (KeyCode)287, "Open/close the mod menu");
			LineWidth = config.Bind<float>("Visual", "LineWidth", 0.35f, "Line thickness (0.02..1.5)");
			ForceOnTop = config.Bind<bool>("Visual", "ForceOnTop", false, "Render on top of geometry (higher renderQueue)");
			SmoothCorners = config.Bind<bool>("Visual", "SmoothCorners", true, "Smooth corners/caps for the line");
			LineColorR = config.Bind<float>("Visual", "LineColorR", 0f, "Line color R (0..1)");
			LineColorG = config.Bind<float>("Visual", "LineColorG", 1f, "Line color G (0..1)");
			LineColorB = config.Bind<float>("Visual", "LineColorB", 0f, "Line color B (0..1)");
			DecimationStep = config.Bind<int>("Performance", "DecimationStep", 1, "Render each Nth point (min 1)");
			MaxPoints = config.Bind<int>("Performance", "MaxPoints", 10000, "Max number of points in LineRenderer (min 100)");
		}
	}
	public static class MapHelper
	{
		public static bool IsGameLevel(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				return false;
			}
			string text = sceneName.ToLower();
			return text.Contains("level") || text.Contains("stage") || text.Contains("map") || text.Contains("game");
		}

		public static int GetCurrentMapId()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			switch (((Scene)(ref activeScene)).name.ToLower())
			{
			case "level1":
			case "stage1":
				return 1;
			case "level2":
			case "stage2":
				return 2;
			default:
				return 1;
			}
		}

		public static string GetCurrentMapName()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name;
		}
	}
	public class Vector3Converter : JsonConverter<Vector3>
	{
		public override void WriteJson(JsonWriter writer, Vector3 value, JsonSerializer serializer)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			writer.WriteStartObject();
			writer.WritePropertyName("x");
			writer.WriteValue(value.x);
			writer.WritePropertyName("y");
			writer.WriteValue(value.y);
			writer.WritePropertyName("z");
			writer.WriteValue(value.z);
			writer.WriteEndObject();
		}

		public override Vector3 ReadJson(JsonReader reader, Type objectType, Vector3 existingValue, bool hasExistingValue, JsonSerializer serializer)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			while (reader.Read() && (int)reader.TokenType != 13)
			{
				if ((int)reader.TokenType == 4)
				{
					string text = reader.Value.ToString();
					reader.Read();
					switch (text)
					{
					case "x":
						num = Convert.ToSingle(reader.Value);
						break;
					case "y":
						num2 = Convert.ToSingle(reader.Value);
						break;
					case "z":
						num3 = Convert.ToSingle(reader.Value);
						break;
					}
				}
			}
			return new Vector3(num, num2, num3);
		}
	}
}
namespace FollowTheWay.Api
{
	public static class PathClient
	{
		[CompilerGenerated]
		private sealed class <GetServerStatusAsync>d__3 : IAsyncStateMachine
		{
			public int <>1__state;

			public AsyncUniTaskMethodBuilder<ServerResponse<string>> <>t__builder;

			public string version;

			private HttpResponseMessage <response>5__1;

			private string <json>5__2;

			private HttpResponseMessage <>s__3;

			private string <>s__4;

			private Exception <ex>5__5;

			private TaskAwaiter<HttpResponseMessage> <>u__1;

			private TaskAwaiter<string> <>u__2;

			private void MoveNext()
			{
				int num = <>1__state;
				ServerResponse<string> result;
				try
				{
					if ((uint)num > 1u)
					{
					}
					try
					{
						TaskAwaiter<string> awaiter;
						TaskAwaiter<HttpResponseMessage> awaiter2;
						if (num != 0)
						{
							if (num == 1)
							{
								awaiter = <>u__2;
								<>u__2 = default(TaskAwaiter<string>);
								num = (<>1__state = -1);
								goto IL_0115;
							}
							awaiter2 = client.GetAsync("https://your-server.com/api/status?version=" + version).GetAwaiter();
							if (!awaiter2.IsCompleted)
							{
								num = (<>1__state = 0);
								<>u__1 = awaiter2;
								<GetServerStatusAsync>d__3 <GetServerStatusAsync>d__ = this;
								<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<HttpResponseMessage>, <GetServerStatusAsync>d__3>(ref awaiter2, ref <GetServerStatusAsync>d__);
								return;
							}
						}
						else
						{
							awaiter2 = <>u__1;
							<>u__1 = default(TaskAwaiter<HttpResponseMessage>);
							num = (<>1__state = -1);
						}
						<>s__3 = awaiter2.GetResult();
						<response>5__1 = <>s__3;
						<>s__3 = null;
						awaiter = <response>5__1.Content.ReadAsStringAsync().GetAwaiter();
						if (!awaiter.IsCompleted)
						{
							num = (<>1__state = 1);
							<>u__2 = awaiter;
							<GetServerStatusAsync>d__3 <GetServerStatusAsync>d__ = this;
							<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, <GetServerStatusAsync>d__3>(ref awaiter, ref <GetServerStatusAsync>d__);
							return;
						}
						goto IL_0115;
						IL_0115:
						<>s__4 = awaiter.GetResult();
						<json>5__2 = <>s__4;
						<>s__4 = null;
						result = JsonConvert.DeserializeObject<ServerResponse<string>>(<json>5__2);
					}
					catch (Exception ex)
					{
						<ex>5__5 = ex;
						FollowTheWayPlugin.LogError("[PathClient] Failed to get server status: " + <ex>5__5.Message);
						result = new ServerResponse<string>
						{
							Success = false,
							Message = <ex>5__5.Message
						};
					}
				}
				catch (Exception ex)
				{
					<>1__state = -2;
					<>t__builder.SetException(ex);
					return;
				}
				<>1__state = -2;
				<>t__builder.SetResult(result);
			}

			void IAsyncStateMachine.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				this.MoveNext();
			}

			[DebuggerHidden]
			private void SetStateMachine(IAsyncStateMachine stateMachine)
			{
			}

			void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
			{
				//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
				this.SetStateMachine(stateMachine);
			}
		}

		[CompilerGenerated]
		private sealed class <RetrievePathsAsync>d__2 : IAsyncStateMachine
		{
			public int <>1__state;

			public AsyncUniTaskMethodBuilder<ServerResponse<List<PathData>>> <>t__builder;

			public int mapId;

			private HttpResponseMessage <response>5__1;

			private string <json>5__2;

			private HttpResponseMessage <>s__3;

			private string <>s__4;

			private Exception <ex>5__5;

			private TaskAwaiter<HttpResponseMessage> <>u__1;

			private TaskAwaiter<string> <>u__2;

			private void MoveNext()
			{
				int num = <>1__state;
				ServerResponse<List<PathData>> result;
				try
				{
					if ((uint)num > 1u)
					{
					}
					try
					{
						TaskAwaiter<string> awaiter;
						TaskAwaiter<HttpResponseMessage> awaiter2;
						if (num != 0)
						{
							if (num == 1)
							{
								awaiter = <>u__2;
								<>u__2 = default(TaskAwaiter<string>);
								num = (<>1__state = -1);
								goto IL_011f;
							}
							awaiter2 = client.GetAsync(string.Format("{0}/paths?map={1}", "https://your-server.com/api", mapId)).GetAwaiter();
							if (!awaiter2.IsCompleted)
							{
								num = (<>1__state = 0);
								<>u__1 = awaiter2;
								<RetrievePathsAsync>d__2 <RetrievePathsAsync>d__ = this;
								<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<HttpResponseMessage>, <RetrievePathsAsync>d__2>(ref awaiter2, ref <RetrievePathsAsync>d__);
								return;
							}
						}
						else
						{
							awaiter2 = <>u__1;
							<>u__1 = default(TaskAwaiter<HttpResponseMessage>);
							num = (<>1__state = -1);
						}
						<>s__3 = awaiter2.GetResult();
						<response>5__1 = <>s__3;
						<>s__3 = null;
						awaiter = <response>5__1.Content.ReadAsStringAsync().GetAwaiter();
						if (!awaiter.IsCompleted)
						{
							num = (<>1__state = 1);
							<>u__2 = awaiter;
							<RetrievePathsAsync>d__2 <RetrievePathsAsync>d__ = this;
							<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, <RetrievePathsAsync>d__2>(ref awaiter, ref <RetrievePathsAsync>d__);
							return;
						}
						goto IL_011f;
						IL_011f:
						<>s__4 = awaiter.GetResult();
						<json>5__2 = <>s__4;
						<>s__4 = null;
						result = JsonConvert.DeserializeObject<ServerResponse<List<PathData>>>(<json>5__2);
					}
					catch (Exception ex)
					{
						<ex>5__5 = ex;
						FollowTheWayPlugin.LogError("[PathClient] Failed to retrieve paths: " + <ex>5__5.Message);
						result = new ServerResponse<List<PathData>>
						{
							Success = false,
							Message = <ex>5__5.Message,
							Paths = new List<PathData>()
						};
					}
				}
				catch (Exception ex)
				{
					<>1__state = -2;
					<>t__builder.SetException(ex);
					return;
				}
				<>1__state = -2;
				<>t__builder.SetResult(result);
			}

			void IAsyncStateMachine.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				this.MoveNext();
			}

			[DebuggerHidden]
			private void SetStateMachine(IAsyncStateMachine stateMachine)
			{
			}

			void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
			{
				//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
				this.SetStateMachine(stateMachine);
			}
		}

		[CompilerGenerated]
		private sealed class <SubmitPathAsync>d__4 : IAsyncStateMachine
		{
			public int <>1__state;

			public AsyncUniTaskMethodBuilder<ServerResponse<string>> <>t__builder;

			public PathData pathData;

			private string <json>5__1;

			private StringContent <content>5__2;

			private HttpResponseMessage <response>5__3;

			private string <responseJson>5__4;

			private HttpResponseMessage <>s__5;

			private string <>s__6;

			private Exception <ex>5__7;

			private TaskAwaiter<HttpResponseMessage> <>u__1;

			private TaskAwaiter<string> <>u__2;

			private void MoveNext()
			{
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Expected O, but got Unknown
				int num = <>1__state;
				ServerResponse<string> result;
				try
				{
					if ((uint)num > 1u)
					{
					}
					try
					{
						TaskAwaiter<string> awaiter;
						TaskAwaiter<HttpResponseMessage> awaiter2;
						if (num != 0)
						{
							if (num == 1)
							{
								awaiter = <>u__2;
								<>u__2 = default(TaskAwaiter<string>);
								num = (<>1__state = -1);
								goto IL_013c;
							}
							<json>5__1 = JsonConvert.SerializeObject((object)pathData);
							<content>5__2 = new StringContent(<json>5__1, Encoding.UTF8, "application/json");
							awaiter2 = client.PostAsync("https://your-server.com/api/paths", (HttpContent)(object)<content>5__2).GetAwaiter();
							if (!awaiter2.IsCompleted)
							{
								num = (<>1__state = 0);
								<>u__1 = awaiter2;
								<SubmitPathAsync>d__4 <SubmitPathAsync>d__ = this;
								<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<HttpResponseMessage>, <SubmitPathAsync>d__4>(ref awaiter2, ref <SubmitPathAsync>d__);
								return;
							}
						}
						else
						{
							awaiter2 = <>u__1;
							<>u__1 = default(TaskAwaiter<HttpResponseMessage>);
							num = (<>1__state = -1);
						}
						<>s__5 = awaiter2.GetResult();
						<response>5__3 = <>s__5;
						<>s__5 = null;
						awaiter = <response>5__3.Content.ReadAsStringAsync().GetAwaiter();
						if (!awaiter.IsCompleted)
						{
							num = (<>1__state = 1);
							<>u__2 = awaiter;
							<SubmitPathAsync>d__4 <SubmitPathAsync>d__ = this;
							<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, <SubmitPathAsync>d__4>(ref awaiter, ref <SubmitPathAsync>d__);
							return;
						}
						goto IL_013c;
						IL_013c:
						<>s__6 = awaiter.GetResult();
						<responseJson>5__4 = <>s__6;
						<>s__6 = null;
						result = JsonConvert.DeserializeObject<ServerResponse<string>>(<responseJson>5__4);
					}
					catch (Exception ex)
					{
						<ex>5__7 = ex;
						FollowTheWayPlugin.LogError("[PathClient] Failed to submit path: " + <ex>5__7.Message);
						result = new ServerResponse<string>
						{
							Success = false,
							Message = <ex>5__7.Message
						};
					}
				}
				catch (Exception ex)
				{
					<>1__state = -2;
					<>t__builder.SetException(ex);
					return;
				}
				<>1__state = -2;
				<>t__builder.SetResult(result);
			}

			void IAsyncStateMachine.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				this.MoveNext();
			}

			[DebuggerHidden]
			private void SetStateMachine(IAsyncStateMachine stateMachine)
			{
			}

			void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
			{
				//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
				this.SetStateMachine(stateMachine);
			}
		}

		private static readonly HttpClient client = new HttpClient();

		private const string BaseUrl = "https://your-server.com/api";

		[AsyncStateMachine(typeof(<RetrievePathsAsync>d__2))]
		[DebuggerStepThrough]
		public static UniTask<ServerResponse<List<PathData>>> RetrievePathsAsync(int mapId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			<RetrievePathsAsync>d__2 <RetrievePathsAsync>d__ = new <RetrievePathsAsync>d__2();
			<RetrievePathsAsync>d__.<>t__builder = AsyncUniTaskMethodBuilder<ServerResponse<List<PathData>>>.Create();
			<RetrievePathsAsync>d__.mapId = mapId;
			<RetrievePathsAsync>d__.<>1__state = -1;
			<RetrievePathsAsync>d__.<>t__builder.Start<<RetrievePathsAsync>d__2>(ref <RetrievePathsAsync>d__);
			return <RetrievePathsAsync>d__.<>t__builder.Task;
		}

		[AsyncStateMachine(typeof(<GetServerStatusAsync>d__3))]
		[DebuggerStepThrough]
		public static UniTask<ServerResponse<string>> GetServerStatusAsync(string version)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			<GetServerStatusAsync>d__3 <GetServerStatusAsync>d__ = new <GetServerStatusAsync>d__3();
			<GetServerStatusAsync>d__.<>t__builder = AsyncUniTaskMethodBuilder<ServerResponse<string>>.Create();
			<GetServerStatusAsync>d__.version = version;
			<GetServerStatusAsync>d__.<>1__state = -1;
			<GetServerStatusAsync>d__.<>t__builder.Start<<GetServerStatusAsync>d__3>(ref <GetServerStatusAsync>d__);
			return <GetServerStatusAsync>d__.<>t__builder.Task;
		}

		[AsyncStateMachine(typeof(<SubmitPathAsync>d__4))]
		[DebuggerStepThrough]
		public static UniTask<ServerResponse<string>> SubmitPathAsync(PathData pathData)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			<SubmitPathAsync>d__4 <SubmitPathAsync>d__ = new <SubmitPathAsync>d__4();
			<SubmitPathAsync>d__.<>t__builder = AsyncUniTaskMethodBuilder<ServerResponse<string>>.Create();
			<SubmitPathAsync>d__.pathData = pathData;
			<SubmitPathAsync>d__.<>1__state = -1;
			<SubmitPathAsync>d__.<>t__builder.Start<<SubmitPathAsync>d__4>(ref <SubmitPathAsync>d__);
			return <SubmitPathAsync>d__.<>t__builder.Task;
		}
	}
}