Decompiled source of LaunchControl v1.0.5

plugins/LaunchControl/LaunchControl.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using LitJson;
using Ostranauts.Bit.Commands;
using Ostranauts.Bit.Interactions;
using Ostranauts.Bit.Items;
using Ostranauts.Bit.Items.Categories;
using Ostranauts.Bit.MegaTooltip;
using Ostranauts.Bit.PatchSystem;
using Ostranauts.Bit.Patches;
using Ostranauts.Bit.PersistentData;
using Ostranauts.Bit.Pledges;
using Ostranauts.Bit.Tasks;
using Ostranauts.Core;
using Ostranauts.Core.Models;
using Ostranauts.Tools;
using Ostranauts.UI.MegaToolTip;
using Ostranauts.UI.MegaToolTip.Interfaces;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("LaunchControl")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a10d488c79868d3728b6483db48cf54daf215dee")]
[assembly: AssemblyProduct("LaunchControl")]
[assembly: AssemblyTitle("LaunchControl")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Ostranauts.Bit
{
	public class LaunchControl : MonoBehaviour
	{
		private static LaunchControl _instance;

		private MegaTooltipManager _megaTooltipManager;

		private CommandManager _commandManager;

		private ItemManager _itemManager;

		private PersistentDataManager _persistentDataManager;

		private InteractionManager _interactionManager;

		private PledgeManager _pledgeManager;

		private TaskDataProvider _taskDataProvider;

		private PatchManager _patchManager;

		public ItemManager Items => _itemManager;

		public CommandManager Commands => _commandManager;

		public static LaunchControl Instance
		{
			get
			{
				return _instance;
			}
			private set
			{
				_instance = value;
			}
		}

		public MegaTooltipManager MegaTooltipManager => _megaTooltipManager;

		public PersistentDataManager PersistentData => _persistentDataManager;

		public InteractionManager Interactions => _interactionManager;

		public PledgeManager Pledges => _pledgeManager;

		public TaskDataProvider Tasks => _taskDataProvider;

		public PatchManager PatchManager => _patchManager;

		public static event Action OnGameReady;

		private void Awake()
		{
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Expected O, but got Unknown
			if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this)
			{
				LaunchControlPlugin.Logger.LogWarning((object)"Multiple LaunchControl instances detected! Destroying duplicate.");
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			_instance = this;
			_megaTooltipManager = new MegaTooltipManager(((Component)this).gameObject);
			_itemManager = new ItemManager();
			_commandManager = new CommandManager();
			_interactionManager = new InteractionManager();
			_pledgeManager = new PledgeManager();
			_pledgeManager.SetLogger(LaunchControlPlugin.Logger);
			try
			{
				_persistentDataManager = PersistentDataManager.Instance;
				_persistentDataManager.SetLogger(LaunchControlPlugin.Logger);
				PersistentDataPatches.InitializeLoadListener();
				LaunchControlPlugin.Logger.LogInfo((object)"PersistentData system initialized");
			}
			catch (Exception ex)
			{
				LaunchControlPlugin.Logger.LogError((object)("Failed to initialize PersistentData system: " + ex.Message));
				LaunchControlPlugin.Logger.LogError((object)ex.StackTrace);
			}
			try
			{
				_taskDataProvider = TaskDataProvider.Instance;
				TaskDataHandler taskDataHandler = new TaskDataHandler();
				taskDataHandler.Logger = LaunchControlPlugin.Logger;
				_persistentDataManager.RegisterHandler("LaunchControl.tasks", taskDataHandler);
				LaunchControlPlugin.Logger.LogInfo((object)"Task data system initialized");
			}
			catch (Exception ex2)
			{
				LaunchControlPlugin.Logger.LogError((object)("Failed to initialize Task data system: " + ex2.Message));
				LaunchControlPlugin.Logger.LogError((object)ex2.StackTrace);
			}
			try
			{
				_patchManager = new PatchManager(LaunchControlPlugin.Logger);
				LaunchControlPlugin.Logger.LogInfo((object)"Patch system initialized");
			}
			catch (Exception ex3)
			{
				LaunchControlPlugin.Logger.LogError((object)("Failed to initialize Patch system: " + ex3.Message));
				LaunchControlPlugin.Logger.LogError((object)ex3.StackTrace);
			}
			try
			{
				CrewSim.OnGameFinishedLoading.AddListener(new UnityAction(OnCrewSimGameFinishedLoading));
				LaunchControlPlugin.Logger.LogInfo((object)"Subscribed to game load complete event");
			}
			catch (Exception ex4)
			{
				LaunchControlPlugin.Logger.LogError((object)("Failed to subscribe to game load event: " + ex4.Message));
				LaunchControlPlugin.Logger.LogError((object)ex4.StackTrace);
			}
			LaunchControlPlugin.Logger.LogInfo((object)"LaunchControl instance initialized");
		}

		private void OnCrewSimGameFinishedLoading()
		{
			LaunchControlPlugin.Logger.LogInfo((object)"Game finished loading - firing OnGameReady event");
			LaunchControl.OnGameReady?.Invoke();
		}

		public static bool RegisterPledgeType(string pledgeTypeName, Type pledgeClass)
		{
			if ((Object)(object)_instance == (Object)null)
			{
				Debug.LogError((object)"LaunchControl.RegisterPledgeType called before LaunchControl was initialized!");
				return false;
			}
			return _instance._pledgeManager.RegisterPledgeType(pledgeTypeName, pledgeClass);
		}

		public static ModuleRegistration RegisterItemModule(Type moduleType, UISetupCallback setupUI)
		{
			if ((Object)(object)_instance == (Object)null)
			{
				Debug.LogError((object)"LaunchControl.RegisterItemModule called before LaunchControl was initialized!");
				return null;
			}
			return _instance._megaTooltipManager.RegisterItemModule(moduleType, setupUI);
		}

		public static ModuleRegistration RegisterPersonModule(Type moduleType, UISetupCallback setupUI)
		{
			if ((Object)(object)_instance == (Object)null)
			{
				Debug.LogError((object)"LaunchControl.RegisterPersonModule called before LaunchControl was initialized!");
				return null;
			}
			return _instance._megaTooltipManager.RegisterPersonModule(moduleType, setupUI);
		}

		private void OnDestroy()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (CrewSim.OnGameFinishedLoading != null)
			{
				CrewSim.OnGameFinishedLoading.RemoveListener(new UnityAction(OnCrewSimGameFinishedLoading));
			}
			PersistentDataPatches.CleanupLoadListener();
		}
	}
	[BepInPlugin("com.ostranauts.LaunchControl", "LaunchControl", "1.0.0")]
	public class LaunchControlPlugin : BaseUnityPlugin
	{
		private delegate void InitDelegate();

		[CompilerGenerated]
		private sealed class <WaitForDataHandlerLoad>d__6 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public LaunchControlPlugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WaitForDataHandlerLoad>d__6(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				LaunchControlPlugin launchControlPlugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!DataHandler.bLoaded)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				Logger.LogInfo((object)"DataHandler loading complete, initializing item categories...");
				launchControlPlugin.InitializeItemCategories();
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static ManualLogSource Logger;

		private Harmony _harmony;

		private GameObject _launchControlObject;

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Plugin com.ostranauts.LaunchControl v1.0.0 is loading...");
			_launchControlObject = new GameObject("LaunchControl");
			Object.DontDestroyOnLoad((Object)(object)_launchControlObject);
			_launchControlObject.AddComponent<LaunchControl>();
			Logger.LogInfo((object)"LaunchControl singleton initialized");
			_harmony = new Harmony("com.ostranauts.LaunchControl");
			_harmony.PatchAll(typeof(LaunchControlPlugin).Assembly);
			IEnumerable<MethodBase> patchedMethods = _harmony.GetPatchedMethods();
			int num = 0;
			foreach (MethodBase item in patchedMethods)
			{
				num++;
				Logger.LogInfo((object)("Patched method: " + item.DeclaringType?.Name + "." + item.Name));
			}
			Logger.LogInfo((object)$"LaunchControl patches applied successfully! ({num} methods patched)");
			RegisterBuiltInCommands();
			Logger.LogInfo((object)"LaunchControl loaded successfully!");
			Logger.LogInfo((object)"  Command registration system available");
			Logger.LogInfo((object)"  Call LaunchControl.RegisterCommand(name, callback) from your mods");
		}

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(WaitForDataHandlerLoad());
		}

		private IEnumerator WaitForDataHandlerLoad()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitForDataHandlerLoad>d__6(0)
			{
				<>4__this = this
			};
		}

		private void InitializeItemCategories()
		{
			if ((Object)(object)LaunchControl.Instance == (Object)null)
			{
				Logger.LogError((object)"Cannot initialize item categories: LaunchControl instance or ItemCategoryManager is null");
				return;
			}
			if (DataHandler.dictCOs == null || DataHandler.dictCOs.Count == 0)
			{
				Logger.LogWarning((object)"DataHandler.dictCOs is not yet available. Skipping item category initialization.");
				return;
			}
			try
			{
				Logger.LogInfo((object)"Initializing item categories after DataHandler load...");
				DefaultCategories.Initialize(LaunchControl.Instance.Items.Categories);
				LaunchControl.Instance.Items.Categories.PopulateFromPredicates();
				Logger.LogInfo((object)"Item category system initialized successfully");
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Failed to initialize item categories: " + ex.Message));
				Logger.LogError((object)ex.StackTrace);
			}
		}

		private void RegisterBuiltInCommands()
		{
			_launchControlObject.AddComponent<ListSpritesCommand>();
			Logger.LogInfo((object)"Built-in commands registered");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Logger.LogInfo((object)"LaunchControl unloaded");
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.ostranauts.LaunchControl";

		public const string PLUGIN_NAME = "LaunchControl";

		public const string PLUGIN_VERSION = "1.0.0";
	}
	public static class DevConsole
	{
		private static FieldInfo _myLogField;

		private static PropertyInfo _instanceProperty;

		private static bool _initialized;

		public static void Output(string message)
		{
			try
			{
				if (!_initialized)
				{
					Initialize();
				}
				if ((object)_instanceProperty == null || (object)_myLogField == null)
				{
					Debug.Log((object)("[LaunchControl Console] " + message));
					return;
				}
				object value = _instanceProperty.GetValue(null, null);
				if (value == null)
				{
					Debug.Log((object)("[LaunchControl Console] " + message));
					return;
				}
				string text = _myLogField.GetValue(value) as string;
				if (text == null)
				{
					text = "";
				}
				string value2 = text + "\n" + message;
				_myLogField.SetValue(value, value2);
				LaunchControlPlugin.Logger.LogInfo((object)("[Console] " + message));
			}
			catch (Exception ex)
			{
				LaunchControlPlugin.Logger.LogError((object)("Failed to output to console: " + ex.Message));
				Debug.Log((object)("[LaunchControl Console] " + message));
			}
		}

		private static void Initialize()
		{
			try
			{
				Type type = Type.GetType("ConsoleToGUI, Assembly-CSharp");
				if ((object)type == null)
				{
					LaunchControlPlugin.Logger.LogWarning((object)"Could not find ConsoleToGUI type");
					_initialized = true;
					return;
				}
				_instanceProperty = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public);
				if ((object)_instanceProperty == null)
				{
					LaunchControlPlugin.Logger.LogWarning((object)"Could not find ConsoleToGUI.instance property");
					_initialized = true;
					return;
				}
				_myLogField = type.GetField("myLog", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if ((object)_myLogField == null)
				{
					LaunchControlPlugin.Logger.LogWarning((object)"Could not find ConsoleToGUI.myLog field");
					_initialized = true;
				}
				else
				{
					LaunchControlPlugin.Logger.LogInfo((object)"DevConsole initialized successfully");
					_initialized = true;
				}
			}
			catch (Exception ex)
			{
				LaunchControlPlugin.Logger.LogError((object)("Failed to initialize DevConsole: " + ex.Message));
				_initialized = true;
			}
		}
	}
	public static class SpriteUtility
	{
		private static Dictionary<string, Sprite> _cachedSprites = new Dictionary<string, Sprite>();

		private static Dictionary<string, GameObject> _cachedPrefabs = new Dictionary<string, GameObject>();

		public static Sprite FindSprite(string prefabName, string[] keywords, string pathHint = null, bool useCache = true)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				LaunchControlPlugin.Logger.LogWarning((object)"FindSprite: prefabName is null or empty");
				return null;
			}
			if (keywords == null || keywords.Length == 0)
			{
				LaunchControlPlugin.Logger.LogWarning((object)"FindSprite: keywords is null or empty");
				return null;
			}
			string text = string.Join(",", keywords);
			string key = prefabName + "::" + text + "::" + (pathHint ?? "any");
			if (useCache && _cachedSprites.TryGetValue(key, out var value))
			{
				return value;
			}
			GameObject val = LoadPrefab(prefabName, useCache);
			if ((Object)(object)val == (Object)null)
			{
				LaunchControlPlugin.Logger.LogWarning((object)("FindSprite: Could not load prefab '" + prefabName + "'"));
				return null;
			}
			GameObject val2 = val;
			if (!string.IsNullOrEmpty(pathHint))
			{
				GameObject val3 = FindChildByPath(val, pathHint);
				if ((Object)(object)val3 != (Object)null)
				{
					val2 = val3;
				}
				else
				{
					LaunchControlPlugin.Logger.LogWarning((object)("FindSprite: Path hint '" + pathHint + "' not found in prefab '" + prefabName + "', searching entire prefab"));
				}
			}
			Image[] componentsInChildren = val2.GetComponentsInChildren<Image>(true);
			foreach (Image val4 in componentsInChildren)
			{
				if ((Object)(object)val4 == (Object)null || (Object)(object)val4.sprite == (Object)null)
				{
					continue;
				}
				string text2 = ((Object)val4.sprite).name.ToLower();
				bool flag = true;
				foreach (string text3 in keywords)
				{
					if (!text2.Contains(text3.ToLower().Trim()))
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					if (useCache)
					{
						_cachedSprites[key] = val4.sprite;
					}
					LaunchControlPlugin.Logger.LogInfo((object)("FindSprite: Found sprite '" + ((Object)val4.sprite).name + "' in prefab '" + prefabName + "' at path '" + GetGameObjectPath(((Component)val4).gameObject, val) + "'"));
					return val4.sprite;
				}
			}
			LaunchControlPlugin.Logger.LogWarning((object)("FindSprite: No sprite matching keywords '" + text + "' found in prefab '" + prefabName + "'"));
			return null;
		}

		public static Sprite GetSpriteFromPrefab(string prefabPath, string childPath = null, bool useCache = true)
		{
			if (string.IsNullOrEmpty(prefabPath))
			{
				LaunchControlPlugin.Logger.LogWarning((object)"GetSpriteFromPrefab: prefabPath is null or empty");
				return null;
			}
			string key = prefabPath + "::" + (childPath ?? "root");
			if (useCache && _cachedSprites.TryGetValue(key, out var value))
			{
				return value;
			}
			GameObject val = LoadPrefab(prefabPath, useCache);
			if ((Object)(object)val == (Object)null)
			{
				LaunchControlPlugin.Logger.LogWarning((object)("GetSpriteFromPrefab: Could not load prefab '" + prefabPath + "'"));
				return null;
			}
			GameObject val2 = (string.IsNullOrEmpty(childPath) ? val : FindChildByPath(val, childPath));
			if ((Object)(object)val2 == (Object)null)
			{
				LaunchControlPlugin.Logger.LogWarning((object)("GetSpriteFromPrefab: Could not find child at path '" + childPath + "' in prefab '" + prefabPath + "'"));
				return null;
			}
			Image component = val2.GetComponent<Image>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.sprite != (Object)null)
			{
				if (useCache)
				{
					_cachedSprites[key] = component.sprite;
				}
				LaunchControlPlugin.Logger.LogInfo((object)("GetSpriteFromPrefab: Found sprite '" + ((Object)component.sprite).name + "' at '" + prefabPath + "/" + childPath + "'"));
				return component.sprite;
			}
			LaunchControlPlugin.Logger.LogWarning((object)("GetSpriteFromPrefab: No Image component with sprite found at '" + prefabPath + "/" + childPath + "'"));
			return null;
		}

		public static GameObject FindChildByPath(GameObject parent, string path)
		{
			if ((Object)(object)parent == (Object)null || string.IsNullOrEmpty(path))
			{
				return null;
			}
			Transform val = parent.transform;
			string[] array = path.Split(new char[1] { '/' });
			foreach (string text in array)
			{
				if (!string.IsNullOrEmpty(text))
				{
					Transform val2 = val.Find(text);
					if ((Object)(object)val2 == (Object)null)
					{
						return null;
					}
					val = val2;
				}
			}
			return ((Component)val).gameObject;
		}

		public static Sprite FindSpriteByName(string spriteName, bool useCache = true)
		{
			if (string.IsNullOrEmpty(spriteName))
			{
				return null;
			}
			string key = "name::" + spriteName;
			if (useCache && _cachedSprites.TryGetValue(key, out var value))
			{
				return value;
			}
			Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
			foreach (Sprite val in array)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name == spriteName)
				{
					if (useCache)
					{
						_cachedSprites[key] = val;
					}
					return val;
				}
			}
			return null;
		}

		public static Sprite FindSpriteByKeywords(string[] keywords, bool useCache = true)
		{
			if (keywords == null || keywords.Length == 0)
			{
				return null;
			}
			string text = string.Join(",", keywords);
			string key = "global::" + text;
			if (useCache && _cachedSprites.TryGetValue(key, out var value))
			{
				return value;
			}
			Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
			foreach (Sprite val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string text2 = ((Object)val).name.ToLower();
				bool flag = true;
				foreach (string text3 in keywords)
				{
					if (!text2.Contains(text3.ToLower()))
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					if (useCache)
					{
						_cachedSprites[key] = val;
					}
					LaunchControlPlugin.Logger.LogInfo((object)("FindSpriteByKeywords: Found sprite '" + ((Object)val).name + "'"));
					return val;
				}
			}
			LaunchControlPlugin.Logger.LogWarning((object)("FindSpriteByKeywords: No sprite matching keywords '" + text + "' found"));
			return null;
		}

		public static Sprite LoadSprite(string resourcePath, bool useCache = true)
		{
			if (string.IsNullOrEmpty(resourcePath))
			{
				return null;
			}
			string key = "resource::" + resourcePath;
			if (useCache && _cachedSprites.TryGetValue(key, out var value))
			{
				return value;
			}
			Sprite val = Resources.Load<Sprite>(resourcePath);
			if ((Object)(object)val != (Object)null && useCache)
			{
				_cachedSprites[key] = val;
			}
			return val;
		}

		public static List<Sprite> GetAllSpritesInHierarchy(GameObject root, string childPath = null)
		{
			List<Sprite> list = new List<Sprite>();
			GameObject val = (string.IsNullOrEmpty(childPath) ? root : FindChildByPath(root, childPath));
			if ((Object)(object)val == (Object)null)
			{
				return list;
			}
			Image[] componentsInChildren = val.GetComponentsInChildren<Image>(true);
			foreach (Image val2 in componentsInChildren)
			{
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sprite != (Object)null)
				{
					list.Add(val2.sprite);
				}
			}
			return list;
		}

		public static void ClearCache()
		{
			_cachedSprites.Clear();
			_cachedPrefabs.Clear();
			LaunchControlPlugin.Logger.LogInfo((object)"SpriteUtility: Cache cleared");
		}

		public static string GetCacheStats()
		{
			return $"SpriteUtility Cache: {_cachedSprites.Count} sprites, {_cachedPrefabs.Count} prefabs";
		}

		public static List<string> GetAllLoadedSprites(int maxResults = 100)
		{
			List<string> list = new List<string>();
			Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
			int num = 0;
			Sprite[] array2 = array;
			foreach (Sprite val in array2)
			{
				if ((Object)(object)val != (Object)null)
				{
					list.Add(((Object)val).name);
					num++;
					if (num >= maxResults)
					{
						break;
					}
				}
			}
			return list;
		}

		public static List<string> GetAllResourcePrefabs(int maxResults = 50)
		{
			List<string> list = new List<string>();
			GameObject[] array = Resources.LoadAll<GameObject>("");
			int num = 0;
			GameObject[] array2 = array;
			foreach (GameObject val in array2)
			{
				if ((Object)(object)val != (Object)null)
				{
					list.Add(((Object)val).name);
					num++;
					if (num >= maxResults)
					{
						break;
					}
				}
			}
			return list;
		}

		private static GameObject LoadPrefab(string prefabPath, bool useCache)
		{
			if (useCache && _cachedPrefabs.TryGetValue(prefabPath, out var value))
			{
				return value;
			}
			GameObject val = Resources.Load<GameObject>(prefabPath);
			if ((Object)(object)val != (Object)null && useCache)
			{
				_cachedPrefabs[prefabPath] = val;
			}
			return val;
		}

		private static string GetGameObjectPath(GameObject obj, GameObject root)
		{
			if ((Object)(object)obj == (Object)null || (Object)(object)obj == (Object)(object)root)
			{
				return "";
			}
			string text = ((Object)obj).name;
			Transform parent = obj.transform.parent;
			while ((Object)(object)parent != (Object)null && (Object)(object)((Component)parent).gameObject != (Object)(object)root)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}
	}
	public class GameObjectPath
	{
		private List<string> _pathParts = new List<string>();

		public GameObjectPath()
		{
		}

		public GameObjectPath(string initialPath)
		{
			if (!string.IsNullOrEmpty(initialPath))
			{
				_pathParts.AddRange(initialPath.Split(new char[1] { '/' }));
			}
		}

		public GameObjectPath Child(string childName)
		{
			_pathParts.Add(childName);
			return this;
		}

		public override string ToString()
		{
			string[] array = new string[_pathParts.Count];
			for (int i = 0; i < _pathParts.Count; i++)
			{
				array[i] = _pathParts[i];
			}
			return string.Join("/", array);
		}

		public static implicit operator string(GameObjectPath path)
		{
			return path.ToString();
		}

		public static GameObjectPath Build(string root = null)
		{
			return new GameObjectPath(root);
		}
	}
}
namespace Ostranauts.Bit.Tasks
{
	public class TaskDataHandler : PersistentDataHandler
	{
		private const string DATA_FILENAME = "task_data.json";

		public override string ModuleName => "LaunchControl.tasks";

		public override bool CanSave()
		{
			return true;
		}

		public override bool CanLoad()
		{
			return true;
		}

		public override void Save(string moduleFolder)
		{
			try
			{
				Dictionary<string, Dictionary<string, object>> allData = TaskDataProvider.Instance.GetAllData();
				if (allData == null || allData.Count == 0)
				{
					base.Logger.LogInfo((object)"[TaskDataHandler] No task data to save");
					return;
				}
				Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>();
				foreach (KeyValuePair<string, Dictionary<string, object>> item in allData)
				{
					Dictionary<string, string> dictionary2 = new Dictionary<string, string>();
					foreach (KeyValuePair<string, object> item2 in item.Value)
					{
						if (item2.Value != null)
						{
							try
							{
								string value = JsonMapper.ToJson(item2.Value);
								dictionary2[item2.Key] = value;
							}
							catch (Exception ex)
							{
								base.Logger.LogWarning((object)$"[TaskDataHandler] Failed to serialize value for key '{item2.Key}': {ex.Message}");
							}
						}
					}
					if (dictionary2.Count > 0)
					{
						dictionary[item.Key] = dictionary2;
					}
				}
				string contents = JsonMapper.ToJson((object)dictionary);
				File.WriteAllText(Path.Combine(moduleFolder, "task_data.json"), contents);
				base.Logger.LogInfo((object)$"[TaskDataHandler] Saved {dictionary.Count} task data entries");
			}
			catch (Exception ex2)
			{
				base.Logger.LogError((object)$"[TaskDataHandler] Error saving task data: {ex2.Message}\n{ex2.StackTrace}");
				throw;
			}
		}

		public override void Load(string moduleFolder)
		{
			try
			{
				string path = Path.Combine(moduleFolder, "task_data.json");
				if (!File.Exists(path))
				{
					base.Logger.LogInfo((object)"[TaskDataHandler] No task data file found (this is normal for new saves)");
					return;
				}
				Dictionary<string, Dictionary<string, string>> dictionary = JsonMapper.ToObject<Dictionary<string, Dictionary<string, string>>>(File.ReadAllText(path));
				if (dictionary == null)
				{
					base.Logger.LogWarning((object)"[TaskDataHandler] Failed to deserialize task data");
					return;
				}
				Dictionary<string, Dictionary<string, object>> dictionary2 = new Dictionary<string, Dictionary<string, object>>();
				foreach (KeyValuePair<string, Dictionary<string, string>> item in dictionary)
				{
					Dictionary<string, object> dictionary3 = new Dictionary<string, object>();
					foreach (KeyValuePair<string, string> item2 in item.Value)
					{
						try
						{
							JsonData value = JsonMapper.ToObject(item2.Value);
							dictionary3[item2.Key] = value;
						}
						catch (Exception ex)
						{
							base.Logger.LogWarning((object)$"[TaskDataHandler] Failed to deserialize value for key '{item2.Key}': {ex.Message}");
						}
					}
					if (dictionary3.Count > 0)
					{
						dictionary2[item.Key] = dictionary3;
					}
				}
				TaskDataProvider.Instance.SetAllData(dictionary2);
				base.Logger.LogInfo((object)$"[TaskDataHandler] Loaded {dictionary2.Count} task data entries");
			}
			catch (Exception ex2)
			{
				base.Logger.LogError((object)$"[TaskDataHandler] Error loading task data: {ex2.Message}\n{ex2.StackTrace}");
				throw;
			}
		}

		public override void LoadFromMemory(string saveFolderPath, Dictionary<string, byte[]> dictFiles)
		{
			try
			{
				string value = "mods/" + ModuleName + "/task_data.json";
				byte[] array = null;
				foreach (KeyValuePair<string, byte[]> dictFile in dictFiles)
				{
					if (dictFile.Key.Equals(value, StringComparison.OrdinalIgnoreCase))
					{
						array = dictFile.Value;
						break;
					}
				}
				if (array == null)
				{
					base.Logger.LogInfo((object)"[TaskDataHandler] No task data file found in memory (this is normal for new saves)");
					return;
				}
				Dictionary<string, Dictionary<string, string>> dictionary = JsonMapper.ToObject<Dictionary<string, Dictionary<string, string>>>(Encoding.UTF8.GetString(array));
				if (dictionary == null)
				{
					base.Logger.LogWarning((object)"[TaskDataHandler] Failed to deserialize task data from memory");
					return;
				}
				Dictionary<string, Dictionary<string, object>> dictionary2 = new Dictionary<string, Dictionary<string, object>>();
				foreach (KeyValuePair<string, Dictionary<string, string>> item in dictionary)
				{
					Dictionary<string, object> dictionary3 = new Dictionary<string, object>();
					foreach (KeyValuePair<string, string> item2 in item.Value)
					{
						try
						{
							JsonData value2 = JsonMapper.ToObject(item2.Value);
							dictionary3[item2.Key] = value2;
						}
						catch (Exception ex)
						{
							base.Logger.LogWarning((object)$"[TaskDataHandler] Failed to deserialize value for key '{item2.Key}': {ex.Message}");
						}
					}
					if (dictionary3.Count > 0)
					{
						dictionary2[item.Key] = dictionary3;
					}
				}
				TaskDataProvider.Instance.SetAllData(dictionary2);
				base.Logger.LogInfo((object)$"[TaskDataHandler] Loaded {dictionary2.Count} task data entries from memory");
			}
			catch (Exception ex2)
			{
				base.Logger.LogError((object)$"[TaskDataHandler] Error loading task data from memory: {ex2.Message}\n{ex2.StackTrace}");
				throw;
			}
		}
	}
	public class TaskDataProvider
	{
		private static TaskDataProvider _instance;

		private Dictionary<string, Dictionary<string, object>> _taskData;

		public static TaskDataProvider Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new TaskDataProvider();
				}
				return _instance;
			}
		}

		private TaskDataProvider()
		{
			_taskData = new Dictionary<string, Dictionary<string, object>>();
		}

		private string GetTaskKey(Task2 task)
		{
			if (task == null)
			{
				throw new ArgumentNullException("task");
			}
			return string.Format("{0}:{1}:{2}:{3}:{4}", task.strDuty ?? "null", task.strInteraction ?? "null", task.strTargetCOID ?? "null", task.nTile, task.strTileShip ?? "null").GetHashCode().ToString();
		}

		public void SetData<T>(Task2 task, string key, T value)
		{
			if (task == null)
			{
				throw new ArgumentNullException("task");
			}
			if (string.IsNullOrEmpty(key))
			{
				throw new ArgumentException("Key cannot be null or empty", "key");
			}
			string taskKey = GetTaskKey(task);
			if (!_taskData.ContainsKey(taskKey))
			{
				_taskData[taskKey] = new Dictionary<string, object>();
			}
			_taskData[taskKey][key] = value;
		}

		public T GetData<T>(Task2 task, string key)
		{
			if (task == null || string.IsNullOrEmpty(key))
			{
				return default(T);
			}
			string taskKey = GetTaskKey(task);
			if (!_taskData.ContainsKey(taskKey))
			{
				return default(T);
			}
			if (!_taskData[taskKey].ContainsKey(key))
			{
				return default(T);
			}
			object obj = _taskData[taskKey][key];
			if (obj == null)
			{
				return default(T);
			}
			try
			{
				return (T)obj;
			}
			catch (InvalidCastException)
			{
				return default(T);
			}
		}

		public bool HasData(Task2 task, string key)
		{
			if (task == null || string.IsNullOrEmpty(key))
			{
				return false;
			}
			string taskKey = GetTaskKey(task);
			if (_taskData.ContainsKey(taskKey))
			{
				return _taskData[taskKey].ContainsKey(key);
			}
			return false;
		}

		public void RemoveData(Task2 task, string key)
		{
			if (task == null || string.IsNullOrEmpty(key))
			{
				return;
			}
			string taskKey = GetTaskKey(task);
			if (_taskData.ContainsKey(taskKey))
			{
				_taskData[taskKey].Remove(key);
				if (_taskData[taskKey].Count == 0)
				{
					_taskData.Remove(taskKey);
				}
			}
		}

		public void ClearTask(Task2 task)
		{
			if (task != null)
			{
				string taskKey = GetTaskKey(task);
				_taskData.Remove(taskKey);
			}
		}

		public void CleanupOrphanedData()
		{
			if (CrewSim.objInstance == null || CrewSim.objInstance.workManager == null)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>();
			WorkManager workManager = CrewSim.objInstance.workManager;
			FieldInfo field = typeof(WorkManager).GetField("dictTasks2", BindingFlags.Instance | BindingFlags.NonPublic);
			if ((object)field != null && field.GetValue(workManager) is Dictionary<string, List<Task2>> dictionary)
			{
				foreach (KeyValuePair<string, List<Task2>> item in dictionary)
				{
					List<Task2> value = item.Value;
					if (value == null)
					{
						continue;
					}
					for (int i = 0; i < value.Count; i++)
					{
						Task2 val = value[i];
						if (val != null)
						{
							try
							{
								string taskKey = GetTaskKey(val);
								hashSet.Add(taskKey);
							}
							catch (Exception)
							{
							}
						}
					}
				}
			}
			FieldInfo field2 = typeof(WorkManager).GetField("aTasksActive", BindingFlags.Instance | BindingFlags.NonPublic);
			if ((object)field2 != null && field2.GetValue(workManager) is List<Task2> list)
			{
				for (int j = 0; j < list.Count; j++)
				{
					Task2 val2 = list[j];
					if (val2 != null)
					{
						try
						{
							string taskKey2 = GetTaskKey(val2);
							hashSet.Add(taskKey2);
						}
						catch (Exception)
						{
						}
					}
				}
			}
			List<string> list2 = new List<string>();
			foreach (KeyValuePair<string, Dictionary<string, object>> taskDatum in _taskData)
			{
				if (!hashSet.Contains(taskDatum.Key))
				{
					list2.Add(taskDatum.Key);
				}
			}
			for (int k = 0; k < list2.Count; k++)
			{
				_taskData.Remove(list2[k]);
			}
			LaunchControlPlugin.Logger.LogInfo((object)$"[TaskDataProvider] Cleaned up {list2.Count} orphaned task data entries");
		}

		internal Dictionary<string, Dictionary<string, object>> GetAllData()
		{
			return _taskData;
		}

		internal void SetAllData(Dictionary<string, Dictionary<string, object>> data)
		{
			if (data == null)
			{
				_taskData = new Dictionary<string, Dictionary<string, object>>();
			}
			else
			{
				_taskData = data;
			}
		}
	}
}
namespace Ostranauts.Bit.Pledges
{
	public class PledgeManager
	{
		private readonly Dictionary<string, Type> _customPledgeTypes;

		private ManualLogSource _logger;

		public int RegisteredCount => _customPledgeTypes.Count;

		public PledgeManager()
		{
			_customPledgeTypes = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
		}

		public void SetLogger(ManualLogSource logger)
		{
			_logger = logger;
		}

		public bool RegisterPledgeType(string pledgeTypeName, Type pledgeClass)
		{
			if (string.IsNullOrEmpty(pledgeTypeName))
			{
				LogError("Cannot register pledge with null or empty type name");
				return false;
			}
			if ((object)pledgeClass == null)
			{
				LogError("Cannot register pledge '" + pledgeTypeName + "' with null class type");
				return false;
			}
			if (!typeof(Pledge2).IsAssignableFrom(pledgeClass))
			{
				LogError("Cannot register pledge '" + pledgeTypeName + "': Class " + pledgeClass.Name + " does not inherit from Pledge2");
				return false;
			}
			if ((object)pledgeClass.GetConstructor(Type.EmptyTypes) == null)
			{
				LogError("Cannot register pledge '" + pledgeTypeName + "': Class " + pledgeClass.Name + " does not have a parameterless constructor");
				return false;
			}
			if (_customPledgeTypes.ContainsKey(pledgeTypeName))
			{
				LogWarning("Pledge type '" + pledgeTypeName + "' already registered, overwriting with " + pledgeClass.Name);
				_customPledgeTypes[pledgeTypeName] = pledgeClass;
			}
			else
			{
				_customPledgeTypes.Add(pledgeTypeName, pledgeClass);
				LogInfo("Registered custom pledge type '" + pledgeTypeName + "' -> " + pledgeClass.Name);
			}
			return true;
		}

		public Pledge2 CreatePledge(string pledgeTypeName)
		{
			if (string.IsNullOrEmpty(pledgeTypeName))
			{
				return null;
			}
			if (!_customPledgeTypes.TryGetValue(pledgeTypeName, out var value))
			{
				return null;
			}
			try
			{
				object? obj = Activator.CreateInstance(value);
				return (Pledge2)((obj is Pledge2) ? obj : null);
			}
			catch (Exception ex)
			{
				LogError("Failed to create pledge instance for type '" + pledgeTypeName + "': " + ex.Message);
				return null;
			}
		}

		public bool IsRegistered(string pledgeTypeName)
		{
			if (!string.IsNullOrEmpty(pledgeTypeName))
			{
				return _customPledgeTypes.ContainsKey(pledgeTypeName);
			}
			return false;
		}

		public IEnumerable<string> GetRegisteredPledgeTypes()
		{
			return _customPledgeTypes.Keys;
		}

		internal void Clear()
		{
			_customPledgeTypes.Clear();
		}

		private void LogInfo(string message)
		{
			if (_logger != null)
			{
				_logger.LogInfo((object)("[PledgeManager] " + message));
			}
			else
			{
				Debug.Log((object)("[PledgeManager] " + message));
			}
		}

		private void LogWarning(string message)
		{
			if (_logger != null)
			{
				_logger.LogWarning((object)("[PledgeManager] " + message));
			}
			else
			{
				Debug.LogWarning((object)("[PledgeManager] " + message));
			}
		}

		private void LogError(string message)
		{
			if (_logger != null)
			{
				_logger.LogError((object)("[PledgeManager] " + message));
			}
			else
			{
				Debug.LogError((object)("[PledgeManager] " + message));
			}
		}
	}
}
namespace Ostranauts.Bit.PersistentData
{
	public abstract class ListPersistentDataHandler<T> : PersistentDataHandler
	{
		protected virtual string FileName => "data.json";

		protected abstract List<T> GetDataList();

		protected abstract void SetDataList(List<T> dataList);

		protected virtual void ClearData()
		{
		}

		protected virtual bool ValidateItem(T item)
		{
			return item != null;
		}

		protected virtual T ProcessLoadedItem(T item)
		{
			return item;
		}

		public sealed override void Save(string modFolderPath)
		{
			try
			{
				List<T> dataList = GetDataList();
				string path = Path.Combine(modFolderPath, FileName);
				if (dataList == null || dataList.Count == 0)
				{
					if (File.Exists(path))
					{
						File.Delete(path);
						LogInfo("Deleted empty " + FileName);
					}
					else
					{
						LogInfo("No data to save");
					}
					return;
				}
				List<T> list = new List<T>();
				foreach (T item in dataList)
				{
					if (ValidateItem(item))
					{
						list.Add(item);
					}
				}
				if (list.Count == 0)
				{
					LogInfo("No valid items to save after filtering");
					if (File.Exists(path))
					{
						File.Delete(path);
					}
				}
				else
				{
					string contents = SerializeList(list);
					File.WriteAllText(path, contents);
					LogInfo($"Saved {list.Count} item(s) to {FileName}");
				}
			}
			catch (Exception ex)
			{
				LogError("Failed to save " + FileName + ": " + ex.Message);
				throw;
			}
		}

		public sealed override void Load(string modFolderPath)
		{
			try
			{
				ClearData();
				string path = Path.Combine(modFolderPath, FileName);
				if (!File.Exists(path))
				{
					LogInfo("No " + FileName + " found (this is normal for saves without data)");
					return;
				}
				string json = File.ReadAllText(path);
				LoadFromJson(json);
			}
			catch (Exception ex)
			{
				LogError("Failed to load " + FileName + ": " + ex.Message);
				throw;
			}
		}

		public sealed override void LoadFromMemory(string saveFolderPath, Dictionary<string, byte[]> dictFiles)
		{
			try
			{
				ClearData();
				string key = "mods/" + ModuleName + "/" + FileName;
				if (!dictFiles.ContainsKey(key))
				{
					LogInfo("No " + FileName + " found in compressed save (this is normal for saves without data)");
					return;
				}
				byte[] bytes = dictFiles[key];
				string @string = Encoding.UTF8.GetString(bytes);
				LoadFromJson(@string);
			}
			catch (Exception ex)
			{
				LogError("Failed to load " + FileName + " from memory: " + ex.Message);
				throw;
			}
		}

		private void LoadFromJson(string json)
		{
			List<T> list = DeserializeList(json);
			if (list == null || list.Count == 0)
			{
				LogWarning(FileName + " exists but contains no valid data");
				return;
			}
			List<T> list2 = new List<T>();
			foreach (T item in list)
			{
				T val = ProcessLoadedItem(item);
				if (val != null)
				{
					list2.Add(val);
				}
			}
			SetDataList(list2);
			LogInfo($"Loaded {list2.Count} item(s) from {FileName}");
		}

		protected virtual string SerializeList(List<T> list)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			StringBuilder stringBuilder = new StringBuilder();
			JsonWriter val = new JsonWriter(stringBuilder);
			val.PrettyPrint = true;
			val.IndentValue = 2;
			JsonMapper.ToJson((object)list, val);
			return stringBuilder.ToString();
		}

		protected virtual List<T> DeserializeList(string json)
		{
			try
			{
				return new List<T>(JsonMapper.ToObject<T[]>(json));
			}
			catch (Exception ex)
			{
				LogWarning("Failed to deserialize using LitJson: " + ex.Message);
				return new List<T>();
			}
		}
	}
	public abstract class PersistentDataHandler
	{
		public abstract string ModuleName { get; }

		public ManualLogSource Logger { get; set; }

		public abstract bool CanSave();

		public abstract bool CanLoad();

		public abstract void Save(string modFolderPath);

		public abstract void Load(string modFolderPath);

		public virtual void LoadFromMemory(string saveFolderPath, Dictionary<string, byte[]> dictFiles)
		{
			string text = "mods/" + ModuleName + "/";
			bool flag = false;
			foreach (KeyValuePair<string, byte[]> dictFile in dictFiles)
			{
				if (dictFile.Key.StartsWith(text, StringComparison.OrdinalIgnoreCase))
				{
					flag = true;
					string text2 = dictFile.Key.Substring(text.Length);
					string fileName = Path.GetFileName(text2);
					LogInfo("Loading file from memory: " + text2);
					string text3 = Path.Combine(Path.GetTempPath(), "Ostranauts_ModLoad_" + Guid.NewGuid());
					Directory.CreateDirectory(text3);
					string path = Path.Combine(text3, fileName);
					try
					{
						File.WriteAllBytes(path, dictFile.Value);
					}
					catch (Exception ex)
					{
						LogError("Failed to write temp file: " + ex.Message);
					}
				}
			}
			if (!flag)
			{
				LogInfo("No files found in compressed save (this is normal for saves without mod data)");
			}
			else
			{
				LogWarning("LoadFromMemory was called but handler does not override it. Consider overriding LoadFromMemory() for better compressed save support.");
			}
		}

		protected void LogInfo(string message)
		{
			ManualLogSource logger = Logger;
			if (logger != null)
			{
				logger.LogInfo((object)("[" + ModuleName + "] " + message));
			}
		}

		protected void LogWarning(string message)
		{
			ManualLogSource logger = Logger;
			if (logger != null)
			{
				logger.LogWarning((object)("[" + ModuleName + "] " + message));
			}
		}

		protected void LogError(string message)
		{
			ManualLogSource logger = Logger;
			if (logger != null)
			{
				logger.LogError((object)("[" + ModuleName + "] " + message));
			}
		}
	}
	public class PersistentDataManager
	{
		private static PersistentDataManager _instance;

		private readonly Dictionary<string, PersistentDataHandler> _handlers;

		private ManualLogSource _logger;

		public static PersistentDataManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new PersistentDataManager();
				}
				return _instance;
			}
		}

		private PersistentDataManager()
		{
			_handlers = new Dictionary<string, PersistentDataHandler>();
		}

		public void SetLogger(ManualLogSource logger)
		{
			_logger = logger;
		}

		public void RegisterHandler(string moduleName, PersistentDataHandler handler)
		{
			if (string.IsNullOrEmpty(moduleName))
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogError((object)"[PersistentData] Cannot register handler with null or empty module name");
				}
				return;
			}
			if (handler == null)
			{
				ManualLogSource logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogError((object)("[PersistentData] Cannot register null handler for module '" + moduleName + "'"));
				}
				return;
			}
			if (moduleName != handler.ModuleName)
			{
				ManualLogSource logger3 = _logger;
				if (logger3 != null)
				{
					logger3.LogError((object)("[PersistentData] Module name mismatch: parameter '" + moduleName + "' != handler.ModuleName '" + handler.ModuleName + "'"));
				}
				return;
			}
			if (_handlers.ContainsKey(moduleName))
			{
				ManualLogSource logger4 = _logger;
				if (logger4 != null)
				{
					logger4.LogWarning((object)("[PersistentData] Handler for module '" + moduleName + "' is already registered. Replacing."));
				}
			}
			_handlers[moduleName] = handler;
			ManualLogSource logger5 = _logger;
			if (logger5 != null)
			{
				logger5.LogInfo((object)("[PersistentData] Registered handler for module '" + moduleName + "'"));
			}
		}

		public void UnregisterHandler(string moduleName)
		{
			if (!string.IsNullOrEmpty(moduleName) && _handlers.Remove(moduleName))
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)("[PersistentData] Unregistered handler for module '" + moduleName + "'"));
				}
			}
		}

		public int GetHandlerCount()
		{
			return _handlers.Count;
		}

		public void SaveAll(string saveFolderPath)
		{
			if (string.IsNullOrEmpty(saveFolderPath))
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogError((object)"[PersistentData] SaveAll called with null or empty save folder path");
				}
				return;
			}
			List<PersistentDataHandler> list = new List<PersistentDataHandler>(_handlers.Values);
			if (list.Count == 0)
			{
				ManualLogSource logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)"[PersistentData] No handlers registered, skipping save");
				}
				return;
			}
			ManualLogSource logger3 = _logger;
			if (logger3 != null)
			{
				logger3.LogInfo((object)$"[PersistentData] Saving data for {list.Count} module(s)...");
			}
			string text = Path.Combine(saveFolderPath, "mods");
			try
			{
				if (!Directory.Exists(text))
				{
					Directory.CreateDirectory(text);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger4 = _logger;
				if (logger4 != null)
				{
					logger4.LogError((object)("[PersistentData] Failed to create mods folder: " + ex.Message));
				}
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (PersistentDataHandler item in list)
			{
				try
				{
					if (!item.CanSave())
					{
						ManualLogSource logger5 = _logger;
						if (logger5 != null)
						{
							logger5.LogInfo((object)("[PersistentData] Skipping save for module '" + item.ModuleName + "' (CanSave returned false)"));
						}
						num2++;
						continue;
					}
					string text2 = Path.Combine(text, item.ModuleName);
					if (!Directory.Exists(text2))
					{
						Directory.CreateDirectory(text2);
					}
					item.Save(text2);
					num++;
					ManualLogSource logger6 = _logger;
					if (logger6 != null)
					{
						logger6.LogInfo((object)("[PersistentData] Successfully saved data for module '" + item.ModuleName + "'"));
					}
				}
				catch (Exception ex2)
				{
					num3++;
					ManualLogSource logger7 = _logger;
					if (logger7 != null)
					{
						logger7.LogError((object)("[PersistentData] Error saving data for module '" + item.ModuleName + "': " + ex2.Message + "\n" + ex2.StackTrace));
					}
					ManualLogSource logger8 = item.Logger;
					if (logger8 != null)
					{
						logger8.LogError((object)("Save failed: " + ex2.Message));
					}
				}
			}
			ManualLogSource logger9 = _logger;
			if (logger9 != null)
			{
				logger9.LogInfo((object)$"[PersistentData] Save complete: {num} succeeded, {num2} skipped, {num3} errors");
			}
		}

		public void LoadAll(string saveFolderPath)
		{
			if (string.IsNullOrEmpty(saveFolderPath))
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogError((object)"[PersistentData] LoadAll called with null or empty save folder path");
				}
				return;
			}
			List<PersistentDataHandler> list = new List<PersistentDataHandler>(_handlers.Values);
			if (list.Count == 0)
			{
				ManualLogSource logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)"[PersistentData] No handlers registered, skipping load");
				}
				return;
			}
			ManualLogSource logger3 = _logger;
			if (logger3 != null)
			{
				logger3.LogInfo((object)$"[PersistentData] Loading data for {list.Count} module(s)...");
			}
			string text = Path.Combine(saveFolderPath, "mods");
			if (!Directory.Exists(text))
			{
				ManualLogSource logger4 = _logger;
				if (logger4 != null)
				{
					logger4.LogInfo((object)"[PersistentData] No mods folder found in save (this is normal for older saves)");
				}
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (PersistentDataHandler item in list)
			{
				try
				{
					if (!item.CanLoad())
					{
						ManualLogSource logger5 = _logger;
						if (logger5 != null)
						{
							logger5.LogInfo((object)("[PersistentData] Skipping load for module '" + item.ModuleName + "' (CanLoad returned false)"));
						}
						num2++;
						continue;
					}
					string text2 = Path.Combine(text, item.ModuleName);
					if (!Directory.Exists(text2))
					{
						ManualLogSource logger6 = _logger;
						if (logger6 != null)
						{
							logger6.LogInfo((object)("[PersistentData] No save data found for module '" + item.ModuleName + "' (folder doesn't exist)"));
						}
						num2++;
						continue;
					}
					item.Load(text2);
					num++;
					ManualLogSource logger7 = _logger;
					if (logger7 != null)
					{
						logger7.LogInfo((object)("[PersistentData] Successfully loaded data for module '" + item.ModuleName + "'"));
					}
				}
				catch (Exception ex)
				{
					num3++;
					ManualLogSource logger8 = _logger;
					if (logger8 != null)
					{
						logger8.LogError((object)("[PersistentData] Error loading data for module '" + item.ModuleName + "': " + ex.Message + "\n" + ex.StackTrace));
					}
					ManualLogSource logger9 = item.Logger;
					if (logger9 != null)
					{
						logger9.LogError((object)("Load failed: " + ex.Message));
					}
				}
			}
			ManualLogSource logger10 = _logger;
			if (logger10 != null)
			{
				logger10.LogInfo((object)$"[PersistentData] Load complete: {num} succeeded, {num2} skipped, {num3} errors");
			}
		}

		public void LoadAllFromMemory(string saveFolderPath, Dictionary<string, byte[]> dictFiles)
		{
			if (string.IsNullOrEmpty(saveFolderPath))
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogError((object)"[PersistentData] LoadAllFromMemory called with null or empty save folder path");
				}
				return;
			}
			if (dictFiles == null || dictFiles.Count == 0)
			{
				ManualLogSource logger2 = _logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)"[PersistentData] No files in dictFiles, skipping load from memory");
				}
				return;
			}
			List<PersistentDataHandler> list = new List<PersistentDataHandler>(_handlers.Values);
			if (list.Count == 0)
			{
				ManualLogSource logger3 = _logger;
				if (logger3 != null)
				{
					logger3.LogInfo((object)"[PersistentData] No handlers registered, skipping load from memory");
				}
				return;
			}
			ManualLogSource logger4 = _logger;
			if (logger4 != null)
			{
				logger4.LogInfo((object)$"[PersistentData] Loading data from memory for {list.Count} module(s)...");
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (PersistentDataHandler item in list)
			{
				try
				{
					if (!item.CanLoad())
					{
						ManualLogSource logger5 = _logger;
						if (logger5 != null)
						{
							logger5.LogInfo((object)("[PersistentData] Skipping load from memory for module '" + item.ModuleName + "' (CanLoad returned false)"));
						}
						num2++;
						continue;
					}
					string value = "mods/" + item.ModuleName + "/";
					bool flag = false;
					foreach (string key in dictFiles.Keys)
					{
						if (key.StartsWith(value, StringComparison.OrdinalIgnoreCase))
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						ManualLogSource logger6 = _logger;
						if (logger6 != null)
						{
							logger6.LogInfo((object)("[PersistentData] No save data found in memory for module '" + item.ModuleName + "'"));
						}
						num2++;
						continue;
					}
					item.LoadFromMemory(saveFolderPath, dictFiles);
					num++;
					ManualLogSource logger7 = _logger;
					if (logger7 != null)
					{
						logger7.LogInfo((object)("[PersistentData] Successfully loaded data from memory for module '" + item.ModuleName + "'"));
					}
				}
				catch (Exception ex)
				{
					num3++;
					ManualLogSource logger8 = _logger;
					if (logger8 != null)
					{
						logger8.LogError((object)("[PersistentData] Error loading data from memory for module '" + item.ModuleName + "': " + ex.Message + "\n" + ex.StackTrace));
					}
					ManualLogSource logger9 = item.Logger;
					if (logger9 != null)
					{
						logger9.LogError((object)("Load from memory failed: " + ex.Message));
					}
				}
			}
			ManualLogSource logger10 = _logger;
			if (logger10 != null)
			{
				logger10.LogInfo((object)$"[PersistentData] Load from memory complete: {num} succeeded, {num2} skipped, {num3} errors");
			}
		}
	}
}
namespace Ostranauts.Bit.PatchSystem
{
	public static class FieldPathResolver
	{
		public static List<string> ParsePath(string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return new List<string>();
			}
			List<string> list = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			bool flag = false;
			foreach (char c in path)
			{
				if (flag)
				{
					stringBuilder.Append(c);
					flag = false;
					continue;
				}
				switch (c)
				{
				case '\\':
					flag = true;
					break;
				case '.':
					if (stringBuilder.Length > 0)
					{
						list.Add(stringBuilder.ToString());
						stringBuilder.Length = 0;
					}
					break;
				default:
					stringBuilder.Append(c);
					break;
				}
			}
			if (stringBuilder.Length > 0)
			{
				list.Add(stringBuilder.ToString());
			}
			return list;
		}

		public static JsonData GetNestedField(JsonData root, string fieldPath)
		{
			if (root == null || string.IsNullOrEmpty(fieldPath))
			{
				return null;
			}
			List<string> list = ParsePath(fieldPath);
			if (list.Count == 0)
			{
				return null;
			}
			JsonData val = root;
			foreach (string item in list)
			{
				if (val == null || !val.IsObject)
				{
					return null;
				}
				if (!HasKey(val, item))
				{
					return null;
				}
				val = val[item];
			}
			return val;
		}

		public static bool SetNestedField(JsonData root, string fieldPath, object value, bool createIfMissing = true)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			if (root == null || !root.IsObject || string.IsNullOrEmpty(fieldPath))
			{
				return false;
			}
			List<string> list = ParsePath(fieldPath);
			if (list.Count == 0)
			{
				return false;
			}
			JsonData val = root;
			for (int i = 0; i < list.Count - 1; i++)
			{
				string text = list[i];
				if (!HasKey(val, text))
				{
					if (!createIfMissing)
					{
						return false;
					}
					val[text] = new JsonData();
					val[text].SetJsonType((JsonType)1);
				}
				val = val[text];
				if (!val.IsObject)
				{
					return false;
				}
			}
			string text2 = list[list.Count - 1];
			val[text2] = ConvertToJsonData(value);
			return true;
		}

		public static bool RemoveNestedField(JsonData root, string fieldPath)
		{
			if (root == null || !root.IsObject || string.IsNullOrEmpty(fieldPath))
			{
				return false;
			}
			List<string> list = ParsePath(fieldPath);
			if (list.Count == 0)
			{
				return false;
			}
			JsonData val = root;
			for (int i = 0; i < list.Count - 1; i++)
			{
				string text = list[i];
				if (!HasKey(val, text))
				{
					return false;
				}
				val = val[text];
				if (!val.IsObject)
				{
					return false;
				}
			}
			string key = list[list.Count - 1];
			if (!HasKey(val, key))
			{
				return false;
			}
			if (val.IsObject)
			{
				IDictionary dictionary = (IDictionary)val;
				if (dictionary != null)
				{
					dictionary.Remove(key);
					return true;
				}
			}
			return false;
		}

		public static bool GetParentAndField(JsonData root, string fieldPath, out JsonData parent, out string fieldName)
		{
			parent = null;
			fieldName = null;
			if (root == null || !root.IsObject || string.IsNullOrEmpty(fieldPath))
			{
				return false;
			}
			List<string> list = ParsePath(fieldPath);
			if (list.Count == 0)
			{
				return false;
			}
			if (list.Count == 1)
			{
				parent = root;
				fieldName = list[0];
				return true;
			}
			JsonData val = root;
			for (int i = 0; i < list.Count - 1; i++)
			{
				string text = list[i];
				if (!HasKey(val, text))
				{
					return false;
				}
				val = val[text];
				if (!val.IsObject)
				{
					return false;
				}
			}
			parent = val;
			fieldName = list[list.Count - 1];
			return true;
		}

		private static bool HasKey(JsonData jsonData, string key)
		{
			if (jsonData == null || !jsonData.IsObject)
			{
				return false;
			}
			foreach (string key2 in jsonData.Keys)
			{
				if (key2 == key)
				{
					return true;
				}
			}
			return false;
		}

		private static JsonData ConvertToJsonData(object value)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			if (value == null)
			{
				return null;
			}
			if (value is JsonData)
			{
				return (JsonData)value;
			}
			return JsonMapper.ToObject(JsonMapper.ToJson(value));
		}

		public static bool FieldExists(JsonData root, string fieldPath)
		{
			return GetNestedField(root, fieldPath) != null;
		}

		public static JsonType? GetFieldType(JsonData root, string fieldPath)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			JsonData nestedField = GetNestedField(root, fieldPath);
			if (nestedField == null)
			{
				return null;
			}
			return nestedField.GetJsonType();
		}
	}
	public class PatchTarget
	{
		public string File { get; set; }

		public string StrName { get; set; }

		public List<string> StrNames { get; set; }

		public Dictionary<string, object> AdditionalMatches { get; set; }

		public List<string> GetStrNamePatterns()
		{
			List<string> list = new List<string>();
			if (!string.IsNullOrEmpty(StrName))
			{
				list.Add(StrName);
			}
			if (StrNames != null && StrNames.Count > 0)
			{
				list.AddRange(StrNames);
			}
			return list;
		}

		public static PatchTarget FromJsonData(JsonData json)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			if (json == null || !json.IsObject)
			{
				throw new ArgumentException("Invalid target JSON");
			}
			PatchTarget patchTarget = new PatchTarget();
			if (HasKey(json, "file"))
			{
				patchTarget.File = ((object)json["file"]).ToString();
			}
			if (HasKey(json, "strName"))
			{
				if (json["strName"].IsString)
				{
					patchTarget.StrName = ((object)json["strName"]).ToString();
				}
				else if (json["strName"].IsArray)
				{
					patchTarget.StrNames = new List<string>();
					foreach (JsonData item in (IEnumerable)json["strName"])
					{
						JsonData val = item;
						patchTarget.StrNames.Add(((object)val).ToString());
					}
				}
			}
			if (HasKey(json, "strNames") && json["strNames"].IsArray)
			{
				if (patchTarget.StrNames == null)
				{
					patchTarget.StrNames = new List<string>();
				}
				foreach (JsonData item2 in (IEnumerable)json["strNames"])
				{
					JsonData val2 = item2;
					patchTarget.StrNames.Add(((object)val2).ToString());
				}
			}
			patchTarget.AdditionalMatches = new Dictionary<string, object>();
			foreach (string key in json.Keys)
			{
				if (key != "file" && key != "strName" && key != "strNames")
				{
					patchTarget.AdditionalMatches[key] = json[key];
				}
			}
			return patchTarget;
		}

		public bool Validate(out string error)
		{
			error = null;
			if (GetStrNamePatterns().Count == 0)
			{
				error = "Target must specify at least one strName pattern";
				return false;
			}
			return true;
		}

		private static bool HasKey(JsonData jsonData, string key)
		{
			if (jsonData == null || !jsonData.IsObject)
			{
				return false;
			}
			foreach (string key2 in jsonData.Keys)
			{
				if (key2 == key)
				{
					return true;
				}
			}
			return false;
		}
	}
	public class JsonPatchFile
	{
		public PatchTarget Target { get; set; }

		public List<PatchOperation> Operations { get; set; }

		public string SourceFilePath { get; set; }

		public string InferredDataType { get; set; }

		public static List<JsonPatchFile> FromJson(string jsonString, string sourceFilePath = null)
		{
			if (string.IsNullOrEmpty(jsonString))
			{
				throw new ArgumentException("JSON string cannot be null or empty");
			}
			JsonData val;
			try
			{
				val = JsonMapper.ToObject(jsonString);
			}
			catch (Exception ex)
			{
				throw new ArgumentException("Failed to parse JSON: " + ex.Message, ex);
			}
			List<JsonPatchFile> list = new List<JsonPatchFile>();
			if (val.IsArray)
			{
				for (int i = 0; i < val.Count; i++)
				{
					JsonPatchFile item = FromJsonData(val[i], sourceFilePath);
					list.Add(item);
				}
			}
			else
			{
				if (!val.IsObject)
				{
					throw new ArgumentException("Patch file must be either an object or an array of objects");
				}
				JsonPatchFile item2 = FromJsonData(val, sourceFilePath);
				list.Add(item2);
			}
			return list;
		}

		public static JsonPatchFile FromJsonData(JsonData json, string sourceFilePath = null)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			if (json == null || !json.IsObject)
			{
				throw new ArgumentException("Invalid patch file JSON");
			}
			JsonPatchFile jsonPatchFile = new JsonPatchFile
			{
				SourceFilePath = sourceFilePath
			};
			if (!HasKey(json, "target"))
			{
				throw new ArgumentException("Patch file missing required 'target' field");
			}
			jsonPatchFile.Target = PatchTarget.FromJsonData(json["target"]);
			if (!HasKey(json, "operations"))
			{
				throw new ArgumentException("Patch file missing required 'operations' field");
			}
			if (!json["operations"].IsArray)
			{
				throw new ArgumentException("'operations' field must be an array");
			}
			jsonPatchFile.Operations = new List<PatchOperation>();
			foreach (JsonData item in (IEnumerable)json["operations"])
			{
				JsonData json2 = item;
				jsonPatchFile.Operations.Add(PatchOperation.FromJsonData(json2));
			}
			if (jsonPatchFile.Operations.Count == 0)
			{
				throw new ArgumentException("Patch file must have at least one operation");
			}
			return jsonPatchFile;
		}

		public bool Validate(out List<string> errors)
		{
			errors = new List<string>();
			if (Target == null)
			{
				errors.Add("Patch file has no target");
				return false;
			}
			if (!Target.Validate(out var error))
			{
				errors.Add("Target validation failed: " + error);
			}
			if (Operations == null || Operations.Count == 0)
			{
				errors.Add("Patch file has no operations");
				return false;
			}
			for (int i = 0; i < Operations.Count; i++)
			{
				if (!Operations[i].Validate(out var error2))
				{
					errors.Add($"Operation {i} validation failed: {error2}");
				}
			}
			return errors.Count == 0;
		}

		private static bool HasKey(JsonData jsonData, string key)
		{
			if (jsonData == null || !jsonData.IsObject)
			{
				return false;
			}
			foreach (string key2 in jsonData.Keys)
			{
				if (key2 == key)
				{
					return true;
				}
			}
			return false;
		}
	}
	public class PatchApplier
	{
		private readonly ManualLogSource _logger;

		public PatchApplier(ManualLogSource logger = null)
		{
			_logger = logger;
		}

		public bool ApplyOperation(JsonData jsonObject, PatchOperation operation, string targetName)
		{
			if (jsonObject == null || !jsonObject.IsObject)
			{
				LogError("Cannot apply operation to non-object JSON for target '" + targetName + "'");
				return false;
			}
			try
			{
				switch (operation.Op)
				{
				case PatchOperationType.Append:
					return ApplyAppend(jsonObject, operation, targetName);
				case PatchOperationType.Prepend:
					return ApplyPrepend(jsonObject, operation, targetName);
				case PatchOperationType.Insert:
					return ApplyInsert(jsonObject, operation, targetName);
				case PatchOperationType.Remove:
					return ApplyRemove(jsonObject, operation, targetName);
				case PatchOperationType.Set:
					return ApplySet(jsonObject, operation, targetName);
				case PatchOperationType.Replace:
					return ApplyReplace(jsonObject, operation, targetName);
				default:
					LogError($"Unknown operation type: {operation.Op}");
					return false;
				}
			}
			catch (Exception ex)
			{
				LogError($"Exception applying {operation.Op} operation to '{targetName}' field '{operation.Field}': {ex.Message}");
				return false;
			}
		}

		public int ApplyOperations(JsonData jsonObject, List<PatchOperation> operations, string targetName)
		{
			int num = 0;
			for (int i = 0; i < operations.Count; i++)
			{
				PatchOperation patchOperation = operations[i];
				if (ApplyOperation(jsonObject, patchOperation, targetName))
				{
					num++;
				}
				else
				{
					LogWarning($"Operation {i} ({patchOperation.Op}) failed for target '{targetName}'");
				}
			}
			return num;
		}

		private bool ApplyAppend(JsonData jsonObject, PatchOperation operation, string targetName)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			JsonData nestedField = FieldPathResolver.GetNestedField(jsonObject, operation.Field);
			if (nestedField == null)
			{
				LogError("Field '" + operation.Field + "' not found in target '" + targetName + "' for append operation");
				return false;
			}
			if (!nestedField.IsArray)
			{
				LogError($"Field '{operation.Field}' in target '{targetName}' is not an array (type: {nestedField.GetJsonType()})");
				return false;
			}
			JsonData val = ConvertToJsonData(operation.Value);
			nestedField.Add((object)val);
			LogInfo("Appended value to '" + operation.Field + "' in target '" + targetName + "'");
			return true;
		}

		private bool ApplyPrepend(JsonData jsonObject, PatchOperation operation, string targetName)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			JsonData nestedField = FieldPathResolver.GetNestedField(jsonObject, operation.Field);
			if (nestedField == null)
			{
				LogError("Field '" + operation.Field + "' not found in target '" + targetName + "' for prepend operation");
				return false;
			}
			if (!nestedField.IsArray)
			{
				LogError($"Field '{operation.Field}' in target '{targetName}' is not an array (type: {nestedField.GetJsonType()})");
				return false;
			}
			JsonData val = ConvertToJsonData(operation.Value);
			JsonData val2 = new JsonData();
			val2.SetJsonType((JsonType)2);
			val2.Add((object)val);
			for (int i = 0; i < nestedField.Count; i++)
			{
				val2.Add((object)nestedField[i]);
			}
			if (!FieldPathResolver.SetNestedField(jsonObject, operation.Field, val2, createIfMissing: false))
			{
				LogError("Failed to set field '" + operation.Field + "' after prepend");
				return false;
			}
			LogInfo("Prepended value to '" + operation.Field + "' in target '" + targetName + "'");
			return true;
		}

		private bool ApplyInsert(JsonData jsonObject, PatchOperation operation, string targetName)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			if (!operation.Index.HasValue)
			{
				LogError("Insert operation requires index for field '" + operation.Field + "' in target '" + targetName + "'");
				return false;
			}
			JsonData nestedField = FieldPathResolver.GetNestedField(jsonObject, operation.Field);
			if (nestedField == null)
			{
				LogError("Field '" + operation.Field + "' not found in target '" + targetName + "' for insert operation");
				return false;
			}
			if (!nestedField.IsArray)
			{
				LogError($"Field '{operation.Field}' in target '{targetName}' is not an array (type: {nestedField.GetJsonType()})");
				return false;
			}
			int value = operation.Index.Value;
			if (value < 0 || value > nestedField.Count)
			{
				LogError($"Insert index {value} out of range for field '{operation.Field}' (length: {nestedField.Count}) in target '{targetName}'");
				return false;
			}
			JsonData val = ConvertToJsonData(operation.Value);
			JsonData val2 = new JsonData();
			val2.SetJsonType((JsonType)2);
			for (int i = 0; i < nestedField.Count; i++)
			{
				if (i == value)
				{
					val2.Add((object)val);
				}
				val2.Add((object)nestedField[i]);
			}
			if (value == nestedField.Count)
			{
				val2.Add((object)val);
			}
			if (!FieldPathResolver.SetNestedField(jsonObject, operation.Field, val2, createIfMissing: false))
			{
				LogError("Failed to set field '" + operation.Field + "' after insert");
				return false;
			}
			LogInfo($"Inserted value at index {value} in '{operation.Field}' in target '{targetName}'");
			return true;
		}

		private bool ApplyRemove(JsonData jsonObject, PatchOperation operation, string targetName)
		{
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Expected O, but got Unknown
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Expected O, but got Unknown
			JsonData nestedField = FieldPathResolver.GetNestedField(jsonObject, operation.Field);
			if (nestedField == null)
			{
				if (operation.Value == null && !operation.Index.HasValue)
				{
					LogInfo("Field '" + operation.Field + "' doesn't exist in target '" + targetName + "', nothing to remove");
					return true;
				}
				LogError("Field '" + operation.Field + "' not found in target '" + targetName + "' for remove operation");
				return false;
			}
			if (operation.Value == null && !operation.Index.HasValue)
			{
				if (FieldPathResolver.RemoveNestedField(jsonObject, operation.Field))
				{
					LogInfo("Removed field '" + operation.Field + "' from target '" + targetName + "'");
					return true;
				}
				LogError("Failed to remove field '" + operation.Field + "' from target '" + targetName + "'");
				return false;
			}
			if (!nestedField.IsArray)
			{
				LogError("Field '" + operation.Field + "' in target '" + targetName + "' is not an array for remove operation");
				return false;
			}
			if (operation.Index.HasValue)
			{
				int value = operation.Index.Value;
				if (value < 0 || value >= nestedField.Count)
				{
					LogError($"Remove index {value} out of range for field '{operation.Field}' (length: {nestedField.Count}) in target '{targetName}'");
					return false;
				}
				JsonData val = new JsonData();
				val.SetJsonType((JsonType)2);
				for (int i = 0; i < nestedField.Count; i++)
				{
					if (i != value)
					{
						val.Add((object)nestedField[i]);
					}
				}
				if (!FieldPathResolver.SetNestedField(jsonObject, operation.Field, val, createIfMissing: false))
				{
					LogError("Failed to set field '" + operation.Field + "' after remove by index");
					return false;
				}
				LogInfo($"Removed element at index {value} from '{operation.Field}' in target '{targetName}'");
				return true;
			}
			if (operation.Value != null)
			{
				string text = ConvertToString(operation.Value);
				bool flag = false;
				JsonData val2 = new JsonData();
				val2.SetJsonType((JsonType)2);
				for (int j = 0; j < nestedField.Count; j++)
				{
					if (ConvertToString(nestedField[j]) == text && !flag)
					{
						flag = true;
					}
					else
					{
						val2.Add((object)nestedField[j]);
					}
				}
				if (!flag)
				{
					LogWarning("Value '" + text + "' not found in field '" + operation.Field + "' of target '" + targetName + "'");
					return false;
				}
				if (!FieldPathResolver.SetNestedField(jsonObject, operation.Field, val2, createIfMissing: false))
				{
					LogError("Failed to set field '" + operation.Field + "' after remove by value");
					return false;
				}
				LogInfo("Removed value '" + text + "' from '" + operation.Field + "' in target '" + targetName + "'");
				return true;
			}
			LogError("Remove operation must specify either value or index");
			return false;
		}

		private bool ApplySet(JsonData jsonObject, PatchOperation operation, string targetName)
		{
			if (FieldPathResolver.SetNestedField(jsonObject, operation.Field, operation.Value))
			{
				LogInfo("Set field '" + operation.Field + "' in target '" + targetName + "'");
				return true;
			}
			LogError("Failed to set field '" + operation.Field + "' in target '" + targetName + "'");
			return false;
		}

		private bool ApplyReplace(JsonData jsonObject, PatchOperation operation, string targetName)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			JsonData nestedField = FieldPathResolver.GetNestedField(jsonObject, operation.Field);
			if (nestedField == null)
			{
				LogError("Field '" + operation.Field + "' not found in target '" + targetName + "' for replace operation");
				return false;
			}
			if (!nestedField.IsArray)
			{
				LogError("Field '" + operation.Field + "' in target '" + targetName + "' is not an array for replace operation");
				return false;
			}
			string text = ConvertToString(operation.OldValue);
			bool flag = false;
			JsonData val = new JsonData();
			val.SetJsonType((JsonType)2);
			for (int i = 0; i < nestedField.Count; i++)
			{
				if (ConvertToString(nestedField[i]) == text && !flag)
				{
					val.Add((object)ConvertToJsonData(operation.Value));
					flag = true;
				}
				else
				{
					val.Add((object)nestedField[i]);
				}
			}
			if (!flag)
			{
				LogWarning("Old value '" + text + "' not found in field '" + operation.Field + "' of target '" + targetName + "'");
				return false;
			}
			if (!FieldPathResolver.SetNestedField(jsonObject, operation.Field, val, createIfMissing: false))
			{
				LogError("Failed to set field '" + operation.Field + "' after replace");
				return false;
			}
			LogInfo("Replaced '" + text + "' with new value in '" + operation.Field + "' in target '" + targetName + "'");
			return true;
		}

		private JsonData ConvertToJsonData(object value)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			if (value == null)
			{
				return null;
			}
			if (value is JsonData)
			{
				return (JsonData)value;
			}
			return JsonMapper.ToObject(JsonMapper.ToJson(value));
		}

		private string ConvertToString(object value)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			if (value == null)
			{
				return "";
			}
			if (value is JsonData)
			{
				JsonData val = (JsonData)value;
				if (val.IsString)
				{
					return ((object)val).ToString();
				}
				return JsonMapper.ToJson((object)val);
			}
			return value.ToString();
		}

		private void LogInfo(string message)
		{
			if (_logger != null)
			{
				_logger.LogInfo((object)("[PatchApplier] " + message));
			}
		}

		private void LogWarning(string message)
		{
			if (_logger != null)
			{
				_logger.LogWarning((object)("[PatchApplier] " + message));
			}
		}

		private void LogError(string message)
		{
			if (_logger != null)
			{
				_logger.LogError((object)("[PatchApplier] " + message));
			}
		}
	}
	public class PatchLoader
	{
		private readonly ManualLogSource _logger;

		public PatchLoader(ManualLogSource logger = null)
		{
			_logger = logger;
		}

		public List<string> FindPatchFiles(string modFolderPath, string[] ignorePatterns = null)
		{
			List<string> list = new List<string>();
			string text = Path.Combine(modFolderPath, "Data");
			if (!Directory.Exists(text))
			{
				text = Path.Combine(modFolderPath, "data");
			}
			if (!Directory.Exists(text))
			{
				return list;
			}
			try
			{
				string[] files = Directory.GetFiles(text, "*.patch", SearchOption.AllDirectories);
				foreach (string text2 in files)
				{
					string text3 = text2.Replace('\\', '/');
					bool flag = false;
					if (ignorePatterns != null)
					{
						foreach (string value in ignorePatterns)
						{
							if (text3.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
							{
								flag = true;
								break;
							}
						}
					}
					if (!flag)
					{
						list.Add(text2);
					}
				}
				list.Sort(delegate(string a, string b)
				{
					string? fileName = Path.GetFileName(a);
					string fileName2 = Path.GetFileName(b);
					return string.Compare(fileName, fileName2, StringComparison.OrdinalIgnoreCase);
				});
			}
			catch (Exception ex)
			{
				LogError("Error scanning for patch files in " + text + ": " + ex.Message);
			}
			return list;
		}

		public List<JsonPatchFile> LoadPatchFile(string filePath)
		{
			List<JsonPatchFile> list = new List<JsonPatchFile>();
			if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
			{
				LogError("Patch file not found: " + filePath);
				return list;
			}
			try
			{
				foreach (JsonPatchFile item in JsonPatchFile.FromJson(File.ReadAllText(filePath), filePath))
				{
					if (string.IsNullOrEmpty(item.Target.File))
					{
						item.InferredDataType = InferDataTypeFromPath(filePath);
					}
					if (!item.Validate(out var errors))
					{
						LogError("Patch validation failed in " + Path.GetFileName(filePath));
						foreach (string item2 in errors)
						{
							LogError("  - " + item2);
						}
					}
					else
					{
						list.Add(item);
					}
				}
				return list;
			}
			catch (Exception ex)
			{
				LogError("Error loading patch file " + filePath + ": " + ex.Message);
				LogError(ex.StackTrace);
				return list;
			}
		}

		public List<JsonPatchFile> LoadAllPatchFiles(string modFolderPath, string[] ignorePatterns = null)
		{
			List<JsonPatchFile> list = new List<JsonPatchFile>();
			foreach (string item in FindPatchFiles(modFolderPath, ignorePatterns))
			{
				List<JsonPatchFile> list2 = LoadPatchFile(item);
				if (list2 != null && list2.Count > 0)
				{
					list.AddRange(list2);
				}
			}
			return list;
		}

		public string InferDataTypeFromPath(string filePath)
		{
			if (string.IsNullOrEmpty(filePath))
			{
				return null;
			}
			try
			{
				string text = filePath.Replace('\\', '/');
				int num = text.IndexOf("/data/", StringComparison.OrdinalIgnoreCase);
				if (num < 0)
				{
					num = text.IndexOf("/Data/", StringComparison.OrdinalIgnoreCase);
				}
				if (num >= 0)
				{
					string text2 = text.Substring(num + 6);
					int num2 = text2.IndexOf('/');
					if (num2 > 0)
					{
						return text2.Substring(0, num2).ToLowerInvariant();
					}
				}
			}
			catch (Exception ex)
			{
				LogWarning("Error inferring data type from path " + filePath + ": " + ex.Message);
			}
			return null;
		}

		public string MapDataTypeToDictionary(string dataType)
		{
			if (string.IsNullOrEmpty(dataType))
			{
				return null;
			}
			switch (dataType.ToLowerInvariant())
			{
			case "ads":
				return "dictAds";
			case "ai_training":
				return "dictAIPersonalities";
			case "attackmodes":
				return "dictAModes";
			case "audioemitters":
				return "dictAudioEmitters";
			case "careers":
				return "dictCareers";
			case "chargeprofiles":
				return "dictChargeProfiles";
			case "colors":
				return "dictJsonColors";
			case "conditions":
				return "dictConds";
			case "cos":
			case "condowners":
				return "dictCOs";
			case "condrules":
				return "dictCondRules";
			case "condtrigs":
				return "dictCTs";
			case "context":
				return "dictContext";
			case "cooverlays":
				return "dictCOOverlays";
			case "crime":
				return "dictCrimes";
			case "dialogue":
				return "dictDialogue";
			case "factions":
				return "dictFactions";
			case "flaws":
				return "dictFlaws";
			case "gasrespires":
				return "dictGasRespires";
			case "guipropmaps":
				return "dictGUIPropMapUnparsed";
			case "headlines":
				return "dictHeadlines";
			case "homeworlds":
				return "dictHomeworlds";
			case "info":
				return "dictInfoNodes";
			case "installables":
				return "dictInstallables";
			case "interaction_overrides":
				return "dictIAOverrides";
			case "interactions":
				return "dictInteractions";
			case "items":
				return "dictItemDefs";
			case "jobitems":
				return "dictJobitems";
			case "jobs":
				return "dictJobs";
			case "ledgerdefs":
				return "dictLedgerDefs";
			case "lifeevents":
				return "dictLifeEvents";
			case "lights":
				return "dictLights";
			case "loot":
				return "dictLoot";
			case "music":
				return "dictMusic";
			case "parallax":
				return "dictParallax";
			case "pda_apps":
				return "dictPDAAppIcons";
			case "personspecs":
				return "dictPersonSpecs";
			case "pledges":
				return "dictPledges";
			case "plot_beat_overrides":
				return "dictPlotBeatOverrides";
			case "plot_beats":
				return "dictPlotBeats";
			case "plot_manager":
				return "dictPlotManager";
			case "plots":
				return "dictPlots";
			case "powerinfos":
				return "dictPowerInfo";
			case "rooms":
				return "dictRoomSpecsTemp";
			case "ships":
				return "dictShips";
			case "shipspecs":
				return "dictShipSpecs";
			case "slot_effects":
				return "dictSlotEffects";
			case "slots":
				return "dictSlots";
			case "star_systems":
				return "dictStarSystems";
			case "strings":
				return "dictStrings";
			case "tickers":
				return "dictTickers";
			case "tips":
				return "dictTips";
			case "tokens":
				return "dictJsonTokens";
			case "transit":
				return "dictTransit";
			case "verbs":
				return "dictJsonVerbs";
			case "wounds":
				return "dictWounds";
			case "zone_triggers":
				return "dictZoneTriggers";
			default:
				return null;
			}
		}

		private void LogInfo(string message)
		{
			if (_logger != null)
			{
				_logger.LogInfo((object)("[PatchLoader] " + message));
			}
		}

		private void LogWarning(string message)
		{
			if (_logger != null)
			{
				_logger.LogWarning((object)("[PatchLoader] " + message));
			}
		}

		private void LogError(string message)
		{
			if (_logger != null)
			{
				_logger.LogError((object)("[PatchLoader] " + message));
			}
		}
	}
	public class PatchManager
	{
		private class QueuedMod
		{
			public string FolderPath;

			public string[] IgnorePatterns;
		}

		private readonly ManualLogSource _logger;

		private readonly PatchLoader _loader;

		private readonly PatchApplier _applier;

		private int _totalPatchesLoaded;

		private int _totalPatchesApplied;

		private int _totalOperationsApplied;

		private List<QueuedMod> _queuedMods = new List<QueuedMod>();

		private bool _loadCompleteHooked;

		public PatchManager(ManualLogSource logger)
		{
			_logger = logger;
			_loader = new PatchLoader(logger);
			_applier = new PatchApplier(logger);
		}

		public void QueueModForPatching(string modFolderPath, string[] ignorePatterns = null)
		{
			if (!_loadCompleteHooked)
			{
				DataHandler.LoadComplete = (Action)Delegate.Combine(DataHandler.LoadComplete, new Action(OnLoadComplete));
				_loadCompleteHooked = true;
			}
			_queuedMods.Add(new QueuedMod
			{
				FolderPath = modFolderPath,
				IgnorePatterns = ignorePatterns
			});
		}

		private void OnLoadComplete()
		{
			try
			{
				LogInfo($"JSON Patch System: Processing {_queuedMods.Count} mod(s)");
				foreach (QueuedMod queuedMod in _queuedMods)
				{
					ApplyPatchesForMod(queuedMod.FolderPath, queuedMod.IgnorePatterns);
				}
				_queuedMods.Clear();
				DataHandler.LoadComplete = (Action)Delegate.Remove(DataHandler.LoadComplete, new Action(OnLoadComplete));
				_loadCompleteHooked = false;
				if (_totalPatchesApplied > 0)
				{
					LogInfo($"JSON Patch System: Applied {_totalPatchesApplied} patch file(s) with {_totalOperationsApplied} operation(s)");
				}
			}
			catch (Exception ex)
			{
				LogError("JSON Patch System error: " + ex.Message);
				LogError(ex.StackTrace);
			}
		}

		public void ApplyPatchesForMod(string modFolderPath, string[] ignorePatterns = null)
		{
			try
			{
				List<JsonPatchFile> list = _loader.LoadAllPatchFiles(modFolderPath, ignorePatterns);
				if (list.Count == 0)
				{
					return;
				}
				_totalPatchesLoaded += list.Count;
				foreach (JsonPatchFile item in list)
				{
					ApplyPatch(item);
				}
			}
			catch (Exception ex)
			{
				LogError("Error processing patches for mod " + modFolderPath + ": " + ex.Message);
				LogError(ex.StackTrace);
			}
		}

		private void ApplyPatch(JsonPatchFile patch)
		{
			if (patch == null || patch.Target == null || patch.Operations == null)
			{
				LogError("Invalid patch file");
				return;
			}
			try
			{
				string fileName = Path.GetFileName(patch.SourceFilePath);
				string text = DetermineTargetDictionary(patch);
				if (string.IsNullOrEmpty(text))
				{
					LogError("Patch '" + fileName + "': Could not determine target dictionary");
					return;
				}
				object dataHandlerDictionary = GetDataHandlerDictionary(text);
				if (dataHandlerDictionary == null)
				{
					LogError("Patch '" + fileName + "': Could not access " + text);
					return;
				}
				List<string> list = FindMatchingTargets(dataHandlerDictionary, patch.Target);
				if (list.Count == 0)
				{
					LogWarning("Patch '" + fileName + "': No matching targets found");
					return;
				}
				int num = 0;
				foreach (string item in list)
				{
					if (ApplyPatchToTarget(dataHandlerDictionary, item, patch.Operations))
					{
						num++;
					}
				}
				if (num > 0)
				{
					_totalPatchesApplied++;
					LogInfo($"Patch '{fileName}': Applied to {num} target(s)");
				}
			}
			catch (Exception ex)
			{
				LogError("Error applying patch: " + ex.Message);
				LogError(ex.StackTrace);
			}
		}

		private string DetermineTargetDictionary(JsonPatchFile patch)
		{
			if (!string.IsNullOrEmpty(patch.Target.File))
			{
				string text = _loader.InferDataTypeFromPath(patch.Target.File);
				if (!string.IsNullOrEmpty(text))
				{
					return _loader.MapDataTypeToDictionary(text);
				}
			}
			if (!string.IsNullOrEmpty(patch.InferredDataType))
			{
				return _loader.MapDataTypeToDictionary(patch.InferredDataType);
			}
			return null;
		}

		private object GetDataHandlerDictionary(string dictionaryName)
		{
			try
			{
				FieldInfo field = typeof(DataHandler).GetField(dictionaryName, BindingFlags.Static | BindingFlags.Public);
				if ((object)field == null)
				{
					LogError("DataHandler." + dictionaryName + " field not found");
					return null;
				}
				return field.GetValue(null);
			}
			catch (Exception ex)
			{
				LogError("Error accessing DataHandler." + dictionaryName + ": " + ex.Message);
				return null;
			}
		}

		private List<string> FindMatchingTargets(object dictionary, PatchTarget target)
		{
			List<string> strNamePatterns = target.GetStrNamePatterns();
			if (dictionary is Dictionary<string, JsonData> dictionary2)
			{
				return TargetMatcher.FindMatchingKeysInJsonDict(dictionary2, strNamePatterns);
			}
			Type type = dictionary.GetType();
			if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(Dictionary<, >) && (object)type.GetGenericArguments()[0] == typeof(string))
			{
				PropertyInfo property = type.GetProperty("Keys");
				if ((object)property == null)
				{
					LogError("Keys property not found on dictionary");
					return new List<string>();
				}
				object value = property.GetValue(dictionary, null);
				if (value == null)
				{
					LogError("Keys collection is null");
					return new List<string>();
				}
				if (value is IEnumerable enumerable)
				{
					List<string> list = new List<string>();
					{
						foreach (object item in enumerable)
						{
							string text = item.ToString();
							foreach (string item2 in strNamePatterns)
							{
								if (TargetMatcher.Matches(text, item2))
								{
									list.Add(text);
									break;
								}
							}
						}
						return list;
					}
				}
				LogError("Keys is not IEnumerable");
				return new List<string>();
			}
			LogWarning("Unsupported dictionary type: " + type.Name);
			return new List<string>();
		}

		private bool ApplyPatchToTarget(object dictionary, string targetKey, List<PatchOperation> operations)
		{
			try
			{
				if (dictionary is Dictionary<string, JsonData> dictionary2)
				{
					if (!dictionary2.ContainsKey(targetKey))
					{
						LogError("Target '" + targetKey + "' not found in dictionary");
						return false;
					}
					JsonData jsonObject = dictionary2[targetKey];
					int num = _applier.ApplyOperations(jsonObject, operations, targetKey);
					_totalOperationsApplied += num;
					return num > 0;
				}
				Type type = dictionary.GetType();
				if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(Dictionary<, >) && (object)type.GetGenericArguments()[0] == typeof(string))
				{
					PropertyInfo property = type.GetProperty("Item");
					if ((object)property == null)
					{
						LogError("Cannot access dictionary indexer for typed dictionary");
						return false;
					}
					object value = property.GetValue(dictionary, new object[1] { targetKey });
					if (value == null)
					{
						LogError("Target '" + targetKey + "' not found in typed dictionary");
						return false;
					}
					int num2 = ApplyOperationsToTypedObject(value, operations, targetKey);
					_totalOperationsApplied += num2;
					return num2 > 0;
				}
				LogError("Unsupported dictionary type: " + type.Name);
				return false;
			}
			catch (Exception ex)
			{
				LogError("Error applying patch to target '" + targetKey + "': " + ex.Message);
				LogError("Stack trace: " + ex.StackTrace);
				return false;
			}
		}

		private int ApplyOperationsToTypedObject(object targetObject, List<PatchOperation> operations, string targetName)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Expected O, but got Unknown
			int num = 0;
			Type type = targetObject.GetType();
			foreach (PatchOperation operation in operations)
			{
				try
				{
					FieldInfo field = type.GetField(operation.Field, BindingFlags.Instance | BindingFlags.Public);
					PropertyInfo propertyInfo = null;
					if ((object)field == null)
					{
						propertyInfo = type.GetProperty(operation.Field, BindingFlags.Instance | BindingFlags.Public);
					}
					if ((object)field == null && (object)propertyInfo == null)
					{
						LogError("Field or property '" + operation.Field + "' not found on type " + type.Name);
						continue;
					}
					object obj = (((object)field != null) ? field.GetValue(targetObject) : propertyInfo.GetValue(targetObject, null));
					if (operation.Op == PatchOperationType.Append && obj is Array)
					{
						Array array = (Array)obj;
						Type elementType = array.GetType().GetElementType();
						object value = ConvertValue((JsonData)operation.Value, elementType);
						Array array2 = Array.CreateInstance(elementType, array.Length + 1);
						Array.Copy(array, array2, array.Length);
						array2.SetValue(value, array.Length);
						if ((object)field != null)
						{
							field.SetValue(targetObject, array2);
						}
						else
						{
							propertyInfo.SetValue(targetObject, array2, null);
						}
						num++;
					}
					else if (operation.Op == PatchOperationType.Set)
					{
						Type targetType = (((object)field != null) ? field.FieldType : propertyInfo.PropertyType);
						object value2 = ConvertValue((JsonData)operation.Value, targetType);
						if ((object)field != null)
						{
							field.SetValue(targetObject, value2);
						}
						else
						{
							propertyInfo.SetValue(targetObject, value2, null);
						}
						num++;
					}
					else
					{
						LogWarning($"Operation '{operation.Op}' not yet supported for typed objects");
					}
				}
				catch (Exception ex)
				{
					LogError("Error applying operation to typed object: " + ex.Message);
				}
			}
			return num;
		}

		private object ConvertValue(JsonData value, Type targetType)
		{
			if (value == null)
			{
				return null;
			}
			if (value.IsString)
			{
				string text = (string)value;
				if ((object)targetType == typeof(string))
				{
					return text;
				}
				return Convert.ChangeType(text, targetType);
			}
			if (value.IsInt)
			{
				return Convert.ChangeType((int)value, targetType);
			}
			if (value.IsLong)
			{
				return Convert.ChangeType((long)value, targetType);
			}
			if (value.IsDouble)
			{
				return Convert.ChangeType((double)value, targetType);
			}
			if (value.IsBoolean)
			{
				return Convert.ChangeType((bool)value, targetType);
			}
			string text2 = JsonMapper.ToJson((object)value);
			return typeof(JsonMapper).GetMethod("ToObject", new Type[1] { typeof(string) }).MakeGenericMethod(targetType).Invoke(null, new object[1] { text2 });
		}

		public void LogStatistics()
		{
			LogInfo("=== JSON Patch System Statistics ===");
			LogInfo($"Total patches loaded: {_totalPatchesLoaded}");
			LogInfo($"Total patches applied: {_totalPatchesApplied}");
			LogInfo($"Total operations applied: {_totalOperationsApplied}");
		}

		private void LogInfo(string message)
		{
			if (_logger != null)
			{
				_logger.LogInfo((object)("[PatchManager] " + message));
			}
		}

		private void LogWarning(string message)
		{
			if (_logger != null)
			{
				_logger.LogWarning((object)("[PatchManager] " + message));
			}
		}

		private void LogError(string message)
		{
			if (_logger != null)
			{
				_logger.LogError((object)("[PatchManager] " + message));
			}
		}
	}
	public enum PatchOperationType
	{
		Append,
		Prepend,
		Insert,
		Remove,
		Set,
		Replace
	}
	public class PatchOperation
	{
		public PatchOperationType Op { get; set; }

		public string Field { get; set; }

		public object Value { get; set; }

		public object OldValue { get; set; }

		public int? Index { get; set; }

		public static PatchOperationType ParseOperationType(string opString)
		{
			if (string.IsNullOrEmpty(opString))
			{
				throw new ArgumentException("Operation type cannot be null or empty");
			}
			return opString.ToLowerInvariant() switch
			{
				"append" => PatchOperationType.Append, 
				"prepend" => PatchOperationType.Prepend, 
				"insert" => PatchOperationType.Insert, 
				"remove" => PatchOperationType.Remove, 
				"set" => PatchOperationType.Set, 
				"replace" => PatchOperationType.Replace, 
				_ => throw new ArgumentException("Unknown operation type: " + opString), 
			};
		}

		public static PatchOperation FromJsonData(JsonData json)
		{
			if (json == null || !json.IsObject)
			{
				throw new ArgumentException("Invalid operation JSON");
			}
			PatchOperation patchOperation = new PatchOperation();
			if (!HasKey(json, "op"))
			{
				throw new ArgumentException("Operation missing required 'op' field");
			}
			patchOperation.Op = ParseOperationType(((object)json["op"]).ToString());
			if (HasKey(json, "field"))
			{
				patchOperation.Field = ((object)json["field"]).ToString();
			}
			if (HasKey(json, "value"))
			{
				patchOperation.Value = json["value"];
			}
			if (HasKey(json, "old_value"))
			{
				patchOperation.OldValue = json["old_value"];
			}
			if (HasKey(json, "index") && json["index"].IsInt)
			{
				patchOperation.Index = (int)json["index"];
			}
			return patchOperation;
		}

		public bool Validate(out string error)
		{
			error = null;
			if (string.IsNullOrEmpty(Field))
			{
				error = "Field path is required";
				return false;
			}
			switch (Op)
			{
			case PatchOperationType.Append:
			case PatchOperationType.Prepend:
				if (Value == null)
				{
					error = $"{Op} operation requires 'value' field";
					return false;
				}
				break;
			case PatchOperationType.Insert:
				if (Value == null)
				{
					error = "Insert operation requires 'value' field";
					return false;
				}
				if (!Index.HasValue)
				{
					error = "Insert operation requires 'index' field";
					return false;
				}
				break;
			case PatchOperationType.Set:
				if (Value == null)
				{
					error = "Set operation requires 'value' field";
					return false;
				}
				break;
			case PatchOperationType.Replace:
				if (Value == null || OldValue == null)
				{
					error = "Replace operation requires both 'value' and 'old_value' fields";
					return false;
				}
				break;
			}
			return true;
		}

		private static bool HasKey(JsonData jsonData, string key)
		{
			if (jsonData == null || !jsonData.IsObject)
			{
				return false;
			}
			foreach (string key2 in jsonData.Keys)
			{
				if (key2 == key)
				{
					return true;
				}
			}
			return false;
		}
	}
	public static class TargetMatcher
	{
		public static string WildcardToRegex(string pattern)
		{
			if (string.IsNullOrEmpty(pattern))
			{
				return "^$";
			}
			string text = Regex.Escape(pattern);
			text = text.Replace("\\*", ".*");
			return "^" + text + "$";
		}

		public static bool Matches(string value, string pattern)
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			if (string.IsNullOrEmpty(pattern))
			{
				return false;
			}
			if (pattern.IndexOf('*') == -1)
			{
				return value == pattern;
			}
			string pattern2 = WildcardToRegex(pattern);
			return Regex.IsMatch(value, pattern2);
		}

		public static List<string> FindMatchingKeys<T>(Dictionary<string, T> dictionary, string pattern)
		{
			List<string> list = new List<string>();
			if (dictionary == null || dictionary.Count == 0)
			{
				return list;
			}
			foreach (KeyValuePair<string, T> item in dictionary)
			{
				string key = item.Key;
				if (Matches(key, pattern))
				{
					list.Add(key);
				}
			}
			return list;
		}

		public static List<string> FindMatchingKeys<T>(Dictionary<string, T> dictionary, List<string> patterns)
		{
			HashSet<string> hashSet = new HashSet<string>();
			if (dictionary == null || dictionary.Count == 0 || patterns == null || patterns.Count == 0)
			{
				return new List<string>();
			}
			foreach (string pattern in patterns)
			{
				foreach (string item in FindMatchingKeys(dictionary, pattern))
				{
					hashSet.Add(item);
				}
			}
			return new List<string>(hashSet);
		}

		public static List<string> FindMatchingKeysInJsonDict(Dictionary<string, JsonData> dictionary, string pattern)
		{
			List<string> list = new List<string>();
			if (dictionary == null || dictionary.Count == 0)
			{
				return list;
			}
			foreach (KeyValuePair<string, JsonData> item in dictionary)
			{
				string key = item.Key;
				if (Matches(key, pattern))
				{
					list.Add(key);
					continue;
				}
				JsonData value = item.Value;
				if (value != null && value.IsObject && HasKey(value, "strName") && Matches(((object)value["strName"]).ToString(), pattern))
				{
					list.Add(key);
				}
			}
			return list;
		}

		public static List<string> FindMatchingKeysInJsonDict(Dictionary<string, JsonData> dictionary, List<string> patterns)
		{
			HashSet<string> hashSet = new HashSet<string>();
			if (dictionary == null || dictionary.Count == 0 || patterns == null || patterns.Count == 0)
			{
				return new List<string>();
			}
			foreach (string pattern in patterns)
			{
				foreach (string item in FindMatchingKeysInJsonDict(dictionary, pattern))
				{
					hashSet.Add(item);
				}
			}
			return new List<string>(hashSet);
		}

		public static List<string> FindMatchingKeysGeneric(object dictionary, List<string> patterns)
		{
			if (dictionary == null || patterns == null || patterns.Count == 0)
			{
				return new List<string>();
			}
			if (dictionary is Dictionary<string, JsonData> dictionary2)
			{
				return FindMatchingKeysInJsonDict(dictionary2, patterns);
			}
			HashSet<string> hashSet = new HashSet<string>();
			Type type = dictionary.GetType();
			if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == typeof(Dictionary<, >))
			{
				PropertyInfo property = type.GetProperty("Keys");
				if ((object)property != null && property.GetValue(dictionary, null) is IEnumerable enumerable)
				{
					foreach (object item in enumerable)
					{
						string text = item.ToString();
						foreach (string pattern in patterns)
						{
							if (Matches(text, pattern))
							{
								hashSet.Add(text);
								break;
							}
						}
					}
				}
			}
			return new List<string>(hashSet);
		}

		public static bool HasWildcard(string pattern)
		{
			if (!string.IsNullOrEmpty(pattern))
			{
				return pattern.Contains("*");
			}
			return false;
		}

		public static bool HasWildcards(List<string> patterns)
		{
			if (patterns == null || patterns.Count == 0)
			{
				return false;
			}
			foreach (string pattern in patterns)
			{
				if (HasWildcard(pattern))
				{
					return true;
				}
			}
			return false;
		}

		private s