Decompiled source of WKLib v0.0.2

plugins/WKLib.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using DarkMachine.UI;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using WKLib.Core;
using WKLib.UI.Components;
using WKLib.UI.Settings;
using WKLib.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WKLib")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.0.2.0")]
[assembly: AssemblyInformationalVersion("0.0.2+d49d720d92a1e2524ad24c037d0e9aabe712bee4")]
[assembly: AssemblyProduct("WKLib")]
[assembly: AssemblyTitle("WKLib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace WKLib
{
	[BepInPlugin("WKLib", "WKLib", "0.0.2")]
	public class WkLib : BaseUnityPlugin
	{
		private void Awake()
		{
			WKLog.Initialize(((BaseUnityPlugin)this).Logger);
			WKLog.Info("Plugin WKLib v0.0.2 is loaded!");
			UIManager.TryInitialize();
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (!(((Scene)(ref scene)).name != "Main-Menu"))
			{
				TextMeshProUGUI component = GameObject.Find("Canvas - Main Menu/Main Menu/Version Text").GetComponent<TextMeshProUGUI>();
				if (component != null)
				{
					((TMP_Text)component).text = ((TMP_Text)component).text + string.Format(" (wklib-{0}) ({1} Mods)", "0.0.2", Chainloader.PluginInfos.Count);
				}
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "WKLib";

		public const string PLUGIN_NAME = "WKLib";

		public const string PLUGIN_VERSION = "0.0.2";
	}
}
namespace WKLib.Utilities
{
	public static class WKLog
	{
		private static ManualLogSource _log;

		internal static void Initialize(ManualLogSource logSource)
		{
			_log = logSource;
		}

		public static void Info(object msg)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[WKLib] {msg}");
			}
		}

		public static void Warn(object msg)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogWarning((object)$"[WKLib] {msg}");
			}
		}

		public static void Error(object msg)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogError((object)$"[WKLib] {msg}");
			}
		}

		public static void Debug(object msg)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogDebug((object)$"[WKLib] {msg}");
			}
		}
	}
}
namespace WKLib.UI
{
	public static class UIBuilder
	{
		public static WKSlider CreateSlider(UIColumn parentColumn, string settingName, string displayName, float defaultValue = 0f, float minValue = 0f, float maxValue = 1f)
		{
			return new WKSlider(parentColumn, settingName, displayName, defaultValue, minValue, maxValue);
		}

		public static WKToggle CreateToggle(UIColumn parentColumn, string settingName, string displayName, bool defaultValue = false)
		{
			return new WKToggle(parentColumn, settingName, displayName, defaultValue);
		}

		public static WKDropdown CreateDropdown(UIColumn parentColumn, string settingName, string displayName, List<string> options, int defaultValue = 0)
		{
			return new WKDropdown(parentColumn, settingName, displayName, options, defaultValue);
		}
	}
}
namespace WKLib.UI.Settings
{
	public static class WKSettings
	{
		public class SettingInfo
		{
			public string Name;

			public Type Type;

			public object DefaultValue;

			public object CurrentValue;
		}

		[Serializable]
		private class SaveData
		{
			public List<SettingEntry> settings = new List<SettingEntry>();
		}

		[Serializable]
		private class SettingEntry
		{
			public string key = "";

			public string value = "";

			public string type = "";
		}

		private static Dictionary<string, SettingInfo> _customSettings = new Dictionary<string, SettingInfo>();

		private static Dictionary<string, object> _runtimeValues = new Dictionary<string, object>();

		private static bool _isInitialized = false;

		public static void Initialize()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			if (_isInitialized)
			{
				return;
			}
			try
			{
				Harmony harmony = new Harmony("wklib.settings");
				ApplyHarmonyPatches(harmony);
				LoadCustomSettings();
				_isInitialized = true;
				WKLog.Info("WKSettings: Initialized successfully");
			}
			catch (Exception ex)
			{
				WKLog.Error("WKSettings: Failed to initialize: " + ex.Message);
			}
		}

		public static void RegisterSetting<T>(string settingName, T defaultValue)
		{
			if (_customSettings.ContainsKey(settingName))
			{
				WKLog.Warn("WKSettings: Setting '" + settingName + "' already registered");
				return;
			}
			SettingInfo settingInfo = new SettingInfo();
			settingInfo.Name = settingName;
			settingInfo.Type = typeof(T);
			settingInfo.DefaultValue = defaultValue;
			settingInfo.CurrentValue = defaultValue;
			SettingInfo settingInfo2 = settingInfo;
			_customSettings[settingName] = settingInfo2;
			if (_runtimeValues.ContainsKey(settingName))
			{
				try
				{
					object obj = _runtimeValues[settingName];
					T val2 = ((!(obj is T val) || 1 == 0) ? ((T)ConvertValueToType(obj.ToString(), typeof(T))) : val);
					settingInfo2.CurrentValue = val2;
					_runtimeValues[settingName] = val2;
					WKLog.Info($"WKSettings: Loaded saved value '{val2}' for setting '{settingName}'");
				}
				catch (Exception ex)
				{
					WKLog.Warn("WKSettings: Failed to load saved value for '" + settingName + "': " + ex.Message + ", using default");
					_runtimeValues[settingName] = defaultValue;
					settingInfo2.CurrentValue = defaultValue;
				}
			}
			else
			{
				_runtimeValues[settingName] = defaultValue;
			}
			WKLog.Info($"WKSettings: Registered setting '{settingName}' with value '{settingInfo2.CurrentValue}'");
		}

		public static T GetSetting<T>(string settingName, T fallback = default(T))
		{
			if (_runtimeValues.TryGetValue(settingName, out var value))
			{
				try
				{
					return (T)Convert.ChangeType(value, typeof(T));
				}
				catch
				{
					return fallback;
				}
			}
			return fallback;
		}

		public static void SetSetting<T>(string settingName, T value)
		{
			if (_customSettings.ContainsKey(settingName))
			{
				_customSettings[settingName].CurrentValue = value;
				_runtimeValues[settingName] = value;
				SaveCustomSettings();
			}
			else
			{
				WKLog.Warn("WKSettings: Attempted to set unregistered setting '" + settingName + "'");
			}
		}

		public static bool IsCustomSetting(string settingName)
		{
			return _customSettings.ContainsKey(settingName);
		}

		public static Dictionary<string, SettingInfo> GetAllCustomSettings()
		{
			return new Dictionary<string, SettingInfo>(_customSettings);
		}

		private static void ApplyHarmonyPatches(Harmony harmony)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			try
			{
				MethodInfo method = typeof(SettingsManager).GetMethod("GetSetting", new Type[1] { typeof(string) });
				MethodInfo method2 = typeof(SettingsManager).GetMethod("SetSetting", new Type[1] { typeof(string[]) });
				MethodInfo method3 = typeof(SettingsManager).GetMethod("SaveSettings");
				MethodInfo method4 = typeof(SettingsManager).GetMethod("LoadSettings");
				harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(WKSettings), "GetSetting_Patch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)method2, new HarmonyMethod(typeof(WKSettings), "SetSetting_Patch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)method3, (HarmonyMethod)null, new HarmonyMethod(typeof(WKSettings), "SaveSettings_Patch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)method4, (HarmonyMethod)null, new HarmonyMethod(typeof(WKSettings), "LoadSettings_Patch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				WKLog.Error("WKSettings: Failed to apply Harmony patches: " + ex.Message);
			}
		}

		private static bool GetSetting_Patch(string variableName, ref string __result)
		{
			if (IsCustomSetting(variableName))
			{
				__result = _runtimeValues[variableName]?.ToString() ?? _customSettings[variableName].DefaultValue?.ToString();
				return false;
			}
			return true;
		}

		private static bool SetSetting_Patch(string[] args)
		{
			if (args.Length >= 2 && IsCustomSetting(args[0]))
			{
				try
				{
					SettingInfo settingInfo = _customSettings[args[0]];
					object value = (settingInfo.CurrentValue = ConvertValueToType(args[1], settingInfo.Type));
					_runtimeValues[args[0]] = value;
					SaveCustomSettings();
				}
				catch (Exception ex)
				{
					WKLog.Error("WKSettings: Failed to set '" + args[0] + "': " + ex.Message);
				}
				return false;
			}
			return true;
		}

		private static void SaveSettings_Patch()
		{
			SaveCustomSettings();
		}

		private static void LoadSettings_Patch()
		{
			LoadCustomSettings();
		}

		private static string GetCustomSettingsPath()
		{
			return Path.Combine(Application.persistentDataPath, "WKLib_Settings.json");
		}

		private static void SaveCustomSettings()
		{
			try
			{
				SaveData saveData = new SaveData();
				foreach (KeyValuePair<string, SettingInfo> customSetting in _customSettings)
				{
					SettingEntry item = new SettingEntry
					{
						key = customSetting.Key,
						value = (customSetting.Value.CurrentValue?.ToString() ?? ""),
						type = customSetting.Value.Type.FullName
					};
					saveData.settings.Add(item);
				}
				string contents = JsonConvert.SerializeObject((object)saveData, (Formatting)1);
				File.WriteAllText(GetCustomSettingsPath(), contents);
				WKLog.Info($"WKSettings: Saved {_customSettings.Count} custom settings");
			}
			catch (Exception ex)
			{
				WKLog.Error("WKSettings: Failed to save custom settings: " + ex.Message);
			}
		}

		private static void LoadCustomSettings()
		{
			try
			{
				string customSettingsPath = GetCustomSettingsPath();
				if (!File.Exists(customSettingsPath))
				{
					WKLog.Info("WKSettings: No custom settings file found, using defaults");
					return;
				}
				string text = File.ReadAllText(customSettingsPath);
				SaveData saveData = JsonConvert.DeserializeObject<SaveData>(text);
				if (saveData?.settings == null)
				{
					return;
				}
				foreach (SettingEntry setting in saveData.settings)
				{
					try
					{
						Type type = Type.GetType(setting.type);
						if (type != null)
						{
							object value = ConvertValueToType(setting.value, type);
							_runtimeValues[setting.key] = value;
						}
					}
					catch (Exception ex)
					{
						WKLog.Warn("WKSettings: Failed to load setting '" + setting.key + "': " + ex.Message);
					}
				}
				WKLog.Info($"WKSettings: Loaded {saveData.settings.Count} custom settings from file");
			}
			catch (Exception ex2)
			{
				WKLog.Error("WKSettings: Failed to load custom settings: " + ex2.Message);
			}
		}

		private static object ConvertValueToType(string valueString, Type targetType)
		{
			if (targetType == typeof(bool))
			{
				return bool.Parse(valueString);
			}
			if (targetType == typeof(int))
			{
				return int.Parse(valueString);
			}
			if (targetType == typeof(float))
			{
				return float.Parse(valueString);
			}
			if (targetType == typeof(string))
			{
				return valueString;
			}
			return Convert.ChangeType(valueString, targetType);
		}
	}
}
namespace WKLib.UI.Components
{
	public interface IWKComponent
	{
		void Reset();

		void CreateGameObject();
	}
	public abstract class WKComponent : IWKComponent
	{
		protected UIColumn ParentColumn;

		protected bool IsCreated = false;

		public GameObject GameObject { get; protected set; }

		public string SettingName { get; protected set; }

		public string LabelText { get; protected set; }

		public TextMeshProUGUI Label { get; protected set; }

		protected WKComponent(UIColumn parentColumn, string settingName, string displayName)
		{
			ParentColumn = parentColumn;
			SettingName = settingName;
			LabelText = displayName;
			UIManager.RegisterComponent(this);
		}

		public void Reset()
		{
			IsCreated = false;
			GameObject = null;
			Label = null;
		}

		public void CreateGameObject()
		{
			if (IsCreated)
			{
				return;
			}
			try
			{
				string columnPath = UIManager.GetColumnPath(ParentColumn);
				Transform val = UIManager.FindUIPath(columnPath);
				if ((Object)(object)val == (Object)null)
				{
					WKLog.Error("WkComponent: Could not find parent path: " + columnPath);
					return;
				}
				GameObject = CreateFromTemplate(val);
				if ((Object)(object)GameObject != (Object)null)
				{
					Configure();
					IsCreated = true;
					WKLog.Info("WkComponent: Successfully created " + GetType().Name + " '" + SettingName + "'");
				}
			}
			catch (Exception ex)
			{
				WKLog.Error("WkComponent: Failed to create " + GetType().Name + " '" + SettingName + "': " + ex.Message);
			}
		}

		protected GameObject CreateFromTemplate(Transform parent)
		{
			string templatePath = GetTemplatePath();
			GameObject val = UIManager.FindTemplate(templatePath);
			if ((Object)(object)val == (Object)null)
			{
				WKLog.Error(GetType().Name + ": Could not find template at path: " + templatePath);
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, parent);
			((Object)val2).name = SettingName;
			val2.SetActive(true);
			return val2;
		}

		protected void SetLabelText()
		{
			if ((Object)(object)GameObject == (Object)null)
			{
				WKLog.Warn("WkComponent: Cannot set label text - GameObject is null for '" + SettingName + "'");
				return;
			}
			if (string.IsNullOrEmpty(LabelText))
			{
				WKLog.Warn("WkComponent: LabelText is null or empty for '" + SettingName + "'");
				return;
			}
			TextMeshProUGUI[] componentsInChildren = GameObject.GetComponentsInChildren<TextMeshProUGUI>();
			if (componentsInChildren.Length != 0)
			{
				Label = componentsInChildren[0];
				((TMP_Text)Label).text = LabelText;
				WKLog.Info("WkComponent: Set label to '" + LabelText + "' for '" + SettingName + "'");
			}
			else
			{
				WKLog.Warn("WkComponent: No TextMeshPro components found for '" + SettingName + "'");
			}
		}

		protected void RemoveOldBinders<T>() where T : Component
		{
			T[] componentsInChildren = GameObject.GetComponentsInChildren<T>();
			T[] array = componentsInChildren;
			foreach (T val in array)
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}

		protected abstract string GetTemplatePath();

		protected abstract void Configure();
	}
	public class WKDropdown : WKComponent
	{
		private Action<WKDropdown> _onValueChanged;

		public int DefaultValue { get; private set; }

		public List<string> Options { get; private set; }

		public WKDropdown(UIColumn parentColumn, string settingName, string displayName, List<string> options, int defaultValue = 0)
			: base(parentColumn, settingName, displayName)
		{
			Options = options ?? new List<string>();
			DefaultValue = Mathf.Clamp(defaultValue, 0, Options.Count - 1);
		}

		protected override string GetTemplatePath()
		{
			return UIManager.DropdownTemplatePath;
		}

		protected override void Configure()
		{
			if (!((Object)(object)base.GameObject == (Object)null))
			{
				WKSettings.RegisterSetting(base.SettingName, DefaultValue);
				RemoveOldBinders<DropdownBinder>();
				RemoveOldBinders<Settings_Resolution>();
				TMP_Dropdown componentInChildren = base.GameObject.GetComponentInChildren<TMP_Dropdown>();
				if ((Object)(object)componentInChildren == (Object)null)
				{
					WKLog.Error("WkDropdown: No TMP_Dropdown found in " + ((Object)base.GameObject).name);
					return;
				}
				((UnityEventBase)componentInChildren.onValueChanged).RemoveAllListeners();
				componentInChildren.ClearOptions();
				componentInChildren.AddOptions(Options);
				int value = GetValue();
				componentInChildren.SetValueWithoutNotify(value);
				((UnityEvent<int>)(object)componentInChildren.onValueChanged).AddListener((UnityAction<int>)OnValueChanged);
				SetLabelText();
				_onValueChanged?.Invoke(this);
				WKLog.Info("WkDropdown: Configured '" + base.SettingName + "' successfully");
			}
		}

		private void OnValueChanged(int value)
		{
			WKSettings.SetSetting(base.SettingName, value);
			_onValueChanged?.Invoke(this);
		}

		public int GetValue()
		{
			int setting = WKSettings.GetSetting(base.SettingName, DefaultValue);
			return Mathf.Clamp(setting, 0, Options.Count - 1);
		}

		public string GetText()
		{
			int value = GetValue();
			return (value >= 0 && value < Options.Count) ? Options[value] : "";
		}

		public WKDropdown SetValue(int value)
		{
			value = Mathf.Clamp(value, 0, Options.Count - 1);
			WKSettings.SetSetting(base.SettingName, value);
			if ((Object)(object)base.GameObject != (Object)null)
			{
				TMP_Dropdown componentInChildren = base.GameObject.GetComponentInChildren<TMP_Dropdown>();
				if (componentInChildren != null)
				{
					componentInChildren.SetValueWithoutNotify(value);
				}
			}
			return this;
		}

		public WKDropdown SetValue(string text)
		{
			int num = Options.IndexOf(text);
			if (num >= 0)
			{
				SetValue(num);
			}
			return this;
		}

		public WKDropdown SetOptions(List<string> newOptions)
		{
			Options = newOptions ?? new List<string>();
			if ((Object)(object)base.GameObject != (Object)null)
			{
				TMP_Dropdown componentInChildren = base.GameObject.GetComponentInChildren<TMP_Dropdown>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.ClearOptions();
					componentInChildren.AddOptions(Options);
					int value = GetValue();
					componentInChildren.SetValueWithoutNotify(value);
				}
			}
			return this;
		}

		public WKDropdown SetListener(Action<WKDropdown> listener)
		{
			_onValueChanged = listener;
			if ((Object)(object)base.GameObject != (Object)null)
			{
				_onValueChanged?.Invoke(this);
			}
			return this;
		}

		protected new void SetLabelText()
		{
			if ((Object)(object)base.GameObject == (Object)null)
			{
				WKLog.Warn("WkDropdown: Cannot set label text - GameObject is null for '" + base.SettingName + "'");
				return;
			}
			if (string.IsNullOrEmpty(base.LabelText))
			{
				WKLog.Warn("WkDropdown: LabelText is null or empty for '" + base.SettingName + "'");
				return;
			}
			TextMeshProUGUI component = base.GameObject.GetComponent<TextMeshProUGUI>();
			if ((Object)(object)component != (Object)null)
			{
				base.Label = component;
				((TMP_Text)base.Label).text = base.LabelText;
				WKLog.Info("WkDropdown: Set label to '" + base.LabelText + "' for '" + base.SettingName + "' on parent GameObject");
			}
			else
			{
				WKLog.Warn("WkDropdown: No TextMeshPro component found on parent GameObject for '" + base.SettingName + "'");
			}
		}
	}
	public class WKSlider : WKComponent
	{
		private Action<WKSlider> _onValueChanged;

		public float DefaultValue { get; private set; }

		public float MinValue { get; private set; }

		public float MaxValue { get; private set; }

		public WKSlider(UIColumn parentColumn, string settingName, string displayName, float defaultValue = 0f, float minValue = 0f, float maxValue = 1f)
			: base(parentColumn, settingName, displayName)
		{
			DefaultValue = defaultValue;
			MinValue = minValue;
			MaxValue = maxValue;
		}

		protected override string GetTemplatePath()
		{
			return UIManager.SliderTemplatePath;
		}

		protected override void Configure()
		{
			if (!((Object)(object)base.GameObject == (Object)null))
			{
				WKSettings.RegisterSetting(base.SettingName, DefaultValue);
				RemoveOldBinders<SliderSettingBinder>();
				RemoveOldBinders<TextSettingsBinder>();
				SubmitSlider componentInChildren = base.GameObject.GetComponentInChildren<SubmitSlider>();
				if ((Object)(object)componentInChildren == (Object)null)
				{
					WKLog.Error("WkSlider: No SubmitSlider found in " + ((Object)base.GameObject).name);
					return;
				}
				((UnityEventBase)componentInChildren.onValueChanged).RemoveAllListeners();
				componentInChildren.minValue = MinValue;
				componentInChildren.maxValue = MaxValue;
				float value = GetValue();
				componentInChildren.SetValueWithoutNotify(value);
				componentInChildren.value = value;
				((UnityEvent<float>)(object)componentInChildren.onValueChanged).AddListener((UnityAction<float>)OnValueChanged);
				SetLabelText();
				UpdateValueDisplay(value);
				_onValueChanged?.Invoke(this);
				WKLog.Info("WkSlider: Configured '" + base.SettingName + "' successfully");
			}
		}

		private void OnValueChanged(float value)
		{
			WKSettings.SetSetting(base.SettingName, value);
			UpdateValueDisplay(value);
			_onValueChanged?.Invoke(this);
		}

		private void UpdateValueDisplay(float value)
		{
			if ((Object)(object)base.GameObject == (Object)null)
			{
				return;
			}
			Transform val = base.GameObject.transform.Find("Value (1)");
			if ((Object)(object)val != (Object)null)
			{
				TMP_Text component = ((Component)val).GetComponent<TMP_Text>();
				if ((Object)(object)component != (Object)null)
				{
					component.text = ((float)Math.Round(value, 2)).ToString();
				}
			}
		}

		public WKSlider SetListener(Action<WKSlider> listener)
		{
			_onValueChanged = listener;
			if ((Object)(object)base.GameObject != (Object)null)
			{
				_onValueChanged?.Invoke(this);
			}
			return this;
		}

		public float GetValue()
		{
			return WKSettings.GetSetting(base.SettingName, DefaultValue);
		}

		public WKSlider SetValue(float value)
		{
			value = Mathf.Clamp(value, MinValue, MaxValue);
			WKSettings.SetSetting(base.SettingName, value);
			if ((Object)(object)base.GameObject != (Object)null)
			{
				SubmitSlider componentInChildren = base.GameObject.GetComponentInChildren<SubmitSlider>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.SetValueWithoutNotify(value);
					UpdateValueDisplay(value);
				}
			}
			return this;
		}
	}
	public class WKToggle : WKComponent
	{
		private Action<WKToggle> _onValueChanged;

		private Toggle _toggleComponent;

		public bool DefaultValue { get; private set; }

		public WKToggle(UIColumn parentColumn, string settingName, string displayName, bool defaultValue = false)
			: base(parentColumn, settingName, displayName)
		{
			DefaultValue = defaultValue;
		}

		protected override string GetTemplatePath()
		{
			return UIManager.ToggleTemplatePath;
		}

		protected override void Configure()
		{
			if (!((Object)(object)base.GameObject == (Object)null))
			{
				WKSettings.RegisterSetting(base.SettingName, DefaultValue);
				RemoveOldBinders<ToggleSettingsBinder>();
				_toggleComponent = base.GameObject.GetComponentInChildren<Toggle>();
				if ((Object)(object)_toggleComponent == (Object)null)
				{
					WKLog.Error("WkToggle: No Toggle found in " + ((Object)base.GameObject).name);
					return;
				}
				((UnityEventBase)_toggleComponent.onValueChanged).RemoveAllListeners();
				bool value = GetValue();
				_toggleComponent.SetIsOnWithoutNotify(value);
				((UnityEvent<bool>)(object)_toggleComponent.onValueChanged).AddListener((UnityAction<bool>)OnValueChanged);
				SetLabelText();
				_onValueChanged?.Invoke(this);
				WKLog.Info("WkToggle: Configured '" + base.SettingName + "' successfully");
			}
		}

		private void OnValueChanged(bool value)
		{
			WKSettings.SetSetting(base.SettingName, value);
			_onValueChanged?.Invoke(this);
		}

		public WKToggle SetListener(Action<WKToggle> listener)
		{
			_onValueChanged = listener;
			if ((Object)(object)base.GameObject != (Object)null)
			{
				_onValueChanged?.Invoke(this);
			}
			return this;
		}

		public bool GetValue()
		{
			return WKSettings.GetSetting(base.SettingName, DefaultValue);
		}

		public WKToggle SetValue(bool value)
		{
			WKSettings.SetSetting(base.SettingName, value);
			if ((Object)(object)base.GameObject != (Object)null)
			{
				_toggleComponent.SetIsOnWithoutNotify(value);
			}
			return this;
		}
	}
}
namespace WKLib.Gamemodes.Builders
{
	public class GamemodeBuilder
	{
		private List<M_Region> _regions = new List<M_Region>();

		private string _modeName = "Custom Gamemode";

		private string _introText = "ASCEND";

		private bool _isEndless;

		private bool _hasPerks;

		private bool _hasRevives;

		private Sprite _capsuleSprite;

		private Sprite _screenArtSprite;

		private List<SpawnItem> _spawnItems;

		private GameType _gameType;

		public GamemodeBuilder WithRegions(List<M_Region> regions)
		{
			_regions = regions ?? new List<M_Region>();
			return this;
		}

		public GamemodeBuilder WithName(string modeName)
		{
			_modeName = modeName;
			return this;
		}

		public GamemodeBuilder WithIntroText(string introText)
		{
			_introText = introText;
			return this;
		}

		public GamemodeBuilder IsEndless(bool isEndless)
		{
			_isEndless = isEndless;
			return this;
		}

		public GamemodeBuilder HasPerks(bool hasPerks)
		{
			_hasPerks = hasPerks;
			return this;
		}

		public GamemodeBuilder HasRevives(bool hasRevives)
		{
			_hasRevives = hasRevives;
			return this;
		}

		public GamemodeBuilder WithCapsuleSprite(Sprite sprite)
		{
			_capsuleSprite = sprite;
			return this;
		}

		public GamemodeBuilder WithScreenArt(Sprite sprite)
		{
			_screenArtSprite = sprite;
			return this;
		}

		public GamemodeBuilder WithStartItems(List<SpawnItem> spawnItems)
		{
			_spawnItems = spawnItems;
			return this;
		}

		public GamemodeBuilder WithGameType(string gameType)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			string text = gameType.ToLower();
			if (1 == 0)
			{
			}
			GameType gameType2 = (GameType)(text switch
			{
				"endless" => 3, 
				"standard" => 0, 
				"playlist" => 1, 
				"playlist-shuffle" => 2, 
				"single" => 4, 
				_ => _gameType, 
			});
			if (1 == 0)
			{
			}
			_gameType = gameType2;
			return this;
		}

		public M_Gamemode Build()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Expected O, but got Unknown
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Invalid comparison between Unknown and I4
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0528: Unknown result type (might be due to invalid IL or missing references)
			//IL_052d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0539: Expected O, but got Unknown
			M_Gamemode gm = ScriptableObject.CreateInstance<M_Gamemode>();
			gm.allowAchievements = false;
			gm.allowCheatedScores = false;
			gm.allowCheats = true;
			gm.allowLeaderboardScoring = true;
			gm.steamLeaderboardName = "";
			gm.allowHeightAchievements = false;
			gm.baseGamemode = true;
			gm.modeType = (GameType)((!_isEndless) ? 1 : 3);
			gm.capsuleName = _modeName;
			gm.gamemodeName = _modeName;
			gm.introText = _introText;
			gm.isEndless = _isEndless;
			gm.hasPerks = _hasPerks;
			gm.hasRevives = _hasRevives;
			gm.gamemodeScene = "Game-Main";
			gm.roachBankID = "custom-" + _modeName;
			gm.gamemodePanel = ((IEnumerable<UI_GamemodeScreen_Panel>)Resources.FindObjectsOfTypeAll<UI_GamemodeScreen_Panel>()).FirstOrDefault((Func<UI_GamemodeScreen_Panel, bool>)((UI_GamemodeScreen_Panel x) => ((Object)x).name == "Gamemode_Panel_Base"));
			gm.loseScreen = ((IEnumerable<UI_ScoreScreen>)Resources.FindObjectsOfTypeAll<UI_ScoreScreen>()).FirstOrDefault((Func<UI_ScoreScreen, bool>)((UI_ScoreScreen x) => ((Object)x).name == "ScorePanel_Standard_Death"));
			gm.winScreen = ((IEnumerable<UI_ScoreScreen>)Resources.FindObjectsOfTypeAll<UI_ScoreScreen>()).FirstOrDefault((Func<UI_ScoreScreen, bool>)((UI_ScoreScreen x) => ((Object)x).name == "ScorePanel_Standard_Win"));
			gm.modeTags = new List<string>(1) { "" };
			gm.unlockAchievement = "";
			GamemodeModule_Standard gamemodeModule = new GamemodeModule_Standard
			{
				winScoreMultiplier = 1f
			};
			gm.gamemodeModule = (GamemodeModule)(object)gamemodeModule;
			int numLevelsToLoad = 0;
			_regions.ForEach(delegate(M_Region reg)
			{
				reg.subregionGroups.ForEach(delegate(SubregionGroup subRegGroup)
				{
					subRegGroup.subregions.ForEach(delegate(M_Subregion subReg)
					{
						numLevelsToLoad += subReg.levels.Count;
					});
				});
			});
			WKLog.Debug($"[Gamemode Builder] Will load {numLevelsToLoad} levels for {_modeName}");
			int num = numLevelsToLoad;
			int num2 = num;
			if (num2 <= 1)
			{
				if (num2 == 1)
				{
					gm.modeType = (GameType)4;
					gm.playlistLevels = new List<M_Level>(1) { _regions[0].subregionGroups[0].subregions[0].levels[0] };
					WKLog.Debug("[Gamemode Builder] Loading one singular level");
				}
			}
			else if ((int)_gameType == 4)
			{
				gm.modeType = (GameType)1;
				_regions.ForEach(delegate(M_Region reg)
				{
					reg.subregionGroups.ForEach(delegate(SubregionGroup subRegGroup)
					{
						subRegGroup.subregions.ForEach(delegate(M_Subregion subReg)
						{
							gm.playlistLevels.AddRange(subReg.levels);
						});
					});
				});
			}
			else
			{
				gm.modeType = _gameType;
				List<M_Level> list = new List<M_Level>();
				int num3 = 0;
				foreach (M_Level item2 in from region in _regions
					from subRegionGroup in region.subregionGroups
					from subRegion in subRegionGroup.subregions
					from level in subRegion.levels
					select level)
				{
					try
					{
						list.Add(item2);
						num3++;
					}
					catch (Exception ex)
					{
						WKLog.Error("[Gamemode Builder] Failed to load: " + ex.Message);
					}
				}
				WKLog.Debug($"[Gamemode Builder] Loaded {num3}/{numLevelsToLoad} levels");
				gm.playlistLevels = list;
			}
			gm.levelsToGenerate = numLevelsToLoad;
			((Object)gm).name = _modeName;
			if (_capsuleSprite != null)
			{
				gm.capsuleArt = _capsuleSprite;
			}
			if (_screenArtSprite != null)
			{
				gm.screenArt = _screenArtSprite;
			}
			gm.regions = _regions;
			GameObject val = ((IEnumerable<GameObject>)Resources.FindObjectsOfTypeAll<GameObject>()).FirstOrDefault((Func<GameObject, bool>)((GameObject go) => ((Object)go).name == "World_Root"));
			gm.gamemodeObjects = ((val != null) ? new List<GameObject>(1) { val } : new List<GameObject>());
			SpawnItem item = new SpawnItem
			{
				itemid = "Item_Hammer"
			};
			gm.startItems = _spawnItems ?? new List<SpawnItem>(1) { item };
			return gm;
		}
	}
	public class RegionBuilder
	{
		private string _name = "New Region";

		private List<M_Subregion> _subregions = new List<M_Subregion>();

		private bool _hasStartingLevel = true;

		public RegionBuilder WithName(string regionName)
		{
			_name = regionName;
			return this;
		}

		public RegionBuilder WithSubregions(List<M_Subregion> subregions)
		{
			_subregions = subregions ?? new List<M_Subregion>();
			return this;
		}

		[Obsolete("Game Handles this automatically, Let the game decide")]
		public RegionBuilder WithStartingLevel(bool hasStartingLevel)
		{
			_hasStartingLevel = hasStartingLevel;
			return this;
		}

		public M_Region Build()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			M_Region val = ScriptableObject.CreateInstance<M_Region>();
			val.regionName = _name;
			((Object)val).name = _name;
			List<SubregionGroup> list = new List<SubregionGroup>();
			foreach (M_Subregion subregion in _subregions)
			{
				list.Add(new SubregionGroup
				{
					subregions = new List<M_Subregion>(1) { subregion }
				});
			}
			val.subregionGroups = list;
			if (_subregions.Count > 1 && _subregions[0].levels.Count > 1)
			{
				List<TransitionLevels> list2 = new List<TransitionLevels>(1);
				TransitionLevels val2 = new TransitionLevels
				{
					fromRegion = _name
				};
				List<M_Level> list3 = new List<M_Level>(1);
				List<M_Level> levels = _subregions[0].levels;
				list3.Add(levels[levels.Count - 1]);
				val2.levels = list3;
				list2.Add(val2);
				val.transitionLevels = list2;
				_subregions[0].levels.RemoveAt(_subregions[0].levels.Count - 1);
			}
			val.regionHeight = _subregions.Sum((M_Subregion sr) => sr.subregionHeight);
			GameObject val3 = ((IEnumerable<GameObject>)CL_AssetManager.instance.assetDatabase.levelPrefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject pref) => ((Object)pref).name == "M1_Intro_01"));
			M_Level val4 = ((val3 != null) ? val3.GetComponent<M_Level>() : null);
			if (val4 != null && _hasStartingLevel)
			{
				val.startLevels = new List<M_Level>(1) { val4 };
			}
			val.regionOrder = (RegionOrder)1;
			val.introText = _name;
			val.sessionEventLists = _subregions.SelectMany((M_Subregion sr) => sr.sessionEventLists).ToList();
			return val;
		}
	}
	public class SubRegionBuilder
	{
		private string _name = "New Subregion";

		private List<M_Level> _levels = new List<M_Level>();

		public SubRegionBuilder WithName(string subregionName)
		{
			_name = subregionName;
			return this;
		}

		public SubRegionBuilder WithLevels(List<M_Level> levels)
		{
			_levels = levels ?? new List<M_Level>();
			return this;
		}

		public M_Subregion Build()
		{
			M_Subregion val = ScriptableObject.CreateInstance<M_Subregion>();
			val.subregionName = _name;
			((Object)val).name = _name;
			val.levels = _levels;
			val.subregionHeight = _levels.Sum((M_Level lv) => lv.GetHeight());
			val.sessionEventLists = _levels.SelectMany((M_Level lv) => lv.sessionEventLists).ToList();
			return val;
		}
	}
}
namespace WKLib.Core
{
	public class ModContext
	{
		public string ModID { get; }

		public string Version { get; }

		internal ModContext(string modID, string version = null)
		{
			ModID = modID;
			Version = version;
		}
	}
	public static class ModRegistry
	{
		private static readonly Dictionary<string, ModContext> Contexts = new Dictionary<string, ModContext>();

		public static ModContext Register(string modID, string version = null)
		{
			if (Contexts.TryGetValue(modID, out var value))
			{
				return value;
			}
			ModContext modContext = new ModContext(modID, version);
			Contexts[modID] = modContext;
			return modContext;
		}

		public static ModContext Get(string modID)
		{
			if (!Contexts.TryGetValue(modID, out var value))
			{
				throw new KeyNotFoundException("Mod '" + modID + "' not registered.");
			}
			return value;
		}
	}
	public enum UIColumn
	{
		AccessibilityInterface,
		AccessibilityVisuals,
		AccessibilityOther,
		VideoScreenInfo,
		VideoGraphics,
		VideoAudio,
		ControlsCamera,
		ControlsToggles
	}
	public static class UIManager
	{
		private static bool _initialized;

		private static string _currentSceneName;

		private static readonly List<IWKComponent> RegisteredComponents;

		private static readonly List<Action> RegisteredActions;

		private static readonly List<IWKComponent> PendingComponents;

		private static readonly List<Action> PendingActions;

		public static string SliderTemplatePath { get; private set; }

		public static string ToggleTemplatePath { get; private set; }

		public static string DropdownTemplatePath { get; private set; }

		public static string AccessibilityInterfaceColumn { get; private set; }

		public static string AccessibilityVisualsColumn { get; private set; }

		public static string AccessibilityOtherColumn { get; private set; }

		public static string VideoScreenInfoColumn { get; private set; }

		public static string VideoGraphicsColumn { get; private set; }

		public static string VideoAudioColumn { get; private set; }

		public static string ControlsCameraColumn { get; private set; }

		public static string ControlsTogglesColumn { get; private set; }

		static UIManager()
		{
			_initialized = false;
			_currentSceneName = "";
			RegisteredComponents = new List<IWKComponent>();
			RegisteredActions = new List<Action>();
			PendingComponents = new List<IWKComponent>();
			PendingActions = new List<Action>();
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			string text = (_currentSceneName = ((Scene)(ref scene)).name);
			WKLog.Info("UIManager: Scene loaded - " + text);
			if (text == "Main-Menu" || text == "Game-Main")
			{
				WKLog.Info("UIManager: Compatible scene detected, attempting initialization...");
				_initialized = false;
				foreach (IWKComponent registeredComponent in RegisteredComponents)
				{
					registeredComponent.Reset();
				}
				PendingComponents.AddRange(RegisteredComponents);
				PendingActions.AddRange(RegisteredActions);
				TryInitialize();
			}
			else
			{
				WKLog.Info("UIManager: Non-compatible scene, UI components will wait for next compatible scene");
				_initialized = false;
			}
		}

		public static void RegisterComponent(IWKComponent component)
		{
			if (!RegisteredComponents.Contains(component))
			{
				RegisteredComponents.Add(component);
			}
			ExecuteWhenReady(component.CreateGameObject);
		}

		public static void ExecuteWhenReady(Action action)
		{
			if (!RegisteredActions.Contains(action))
			{
				RegisteredActions.Add(action);
			}
			if (_initialized)
			{
				action?.Invoke();
			}
			else if (!PendingActions.Contains(action))
			{
				PendingActions.Add(action);
			}
		}

		public static bool TryInitialize()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (_initialized)
			{
				return true;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			_currentSceneName = ((Scene)(ref activeScene)).name;
			if (!IsValidUIScene(_currentSceneName))
			{
				return false;
			}
			Initialize();
			return _initialized;
		}

		private static bool IsValidUIScene(string sceneName)
		{
			return sceneName == "Main-Menu" || sceneName == "Game-Main";
		}

		public static void Initialize()
		{
			if (_initialized)
			{
				return;
			}
			WKSettings.Initialize();
			string text = FindObjectPath("Accessibility Settings");
			string text2 = FindObjectPath("Video Settings");
			string text3 = FindObjectPath("Controls Page");
			if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(text3))
			{
				WKLog.Warn("UIManager: Could not find UI template paths in scene '" + _currentSceneName + "'. Will retry when entering compatible scene.");
				return;
			}
			BuildPaths(text, text2, text3);
			_initialized = true;
			WKLog.Info("UIManager: Successfully initialized in scene '" + _currentSceneName + "'");
			foreach (IWKComponent pendingComponent in PendingComponents)
			{
				try
				{
					pendingComponent.CreateGameObject();
				}
				catch (Exception ex)
				{
					WKLog.Error("UIManager: Error creating pending component: " + ex.Message);
				}
			}
			PendingComponents.Clear();
			foreach (Action pendingAction in PendingActions)
			{
				try
				{
					pendingAction?.Invoke();
				}
				catch (Exception ex2)
				{
					WKLog.Error("UIManager: Error executing pending action: " + ex2.Message);
				}
			}
			PendingActions.Clear();
			WKLog.Info("UIManager: Processed all pending components and actions");
		}

		private static void BuildPaths(string accessibilityPath, string videoPath, string controlsPath)
		{
			AccessibilityInterfaceColumn = accessibilityPath + "/Options Tab/Interface Column";
			AccessibilityVisualsColumn = accessibilityPath + "/Options Tab/Accessibility";
			AccessibilityOtherColumn = accessibilityPath + "/Options Tab/Other Column";
			VideoScreenInfoColumn = videoPath + "/Options Tab/Video";
			VideoGraphicsColumn = videoPath + "/Options Tab/Other";
			VideoAudioColumn = videoPath + "/Options Tab/Audio";
			ControlsCameraColumn = controlsPath + "/Options Tab/Column 01";
			ControlsTogglesColumn = controlsPath + "/Options Tab/Toggles";
			SliderTemplatePath = AccessibilityInterfaceColumn + "/SliderAsset - UI Scale";
			ToggleTemplatePath = AccessibilityVisualsColumn + "/Item High Visibility";
			DropdownTemplatePath = VideoScreenInfoColumn + "/Screen Resolution";
		}

		private static string FindObjectPath(string uniqueName)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				Transform val2 = ((IEnumerable<Transform>)val.GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)((Component)t).gameObject).name == uniqueName));
				if ((Object)(object)val2 != (Object)null)
				{
					LinkedList<string> linkedList = new LinkedList<string>();
					Transform val3 = val2;
					while ((Object)(object)val3 != (Object)null)
					{
						linkedList.AddFirst(((Object)val3).name);
						val3 = val3.parent;
					}
					return string.Join("/", linkedList);
				}
			}
			return null;
		}

		public static bool IsUIReady()
		{
			return _initialized;
		}

		public static string GetColumnPath(UIColumn column)
		{
			if (!_initialized)
			{
				WKLog.Warn($"UIManager: Attempted to resolve {column} before initialization");
				return null;
			}
			if (1 == 0)
			{
			}
			string result = column switch
			{
				UIColumn.AccessibilityInterface => AccessibilityInterfaceColumn, 
				UIColumn.AccessibilityVisuals => AccessibilityVisualsColumn, 
				UIColumn.AccessibilityOther => AccessibilityOtherColumn, 
				UIColumn.VideoScreenInfo => VideoScreenInfoColumn, 
				UIColumn.VideoGraphics => VideoGraphicsColumn, 
				UIColumn.VideoAudio => VideoAudioColumn, 
				UIColumn.ControlsCamera => ControlsCameraColumn, 
				UIColumn.ControlsToggles => ControlsTogglesColumn, 
				_ => throw new ArgumentException($"Unknown UIColumn: {column}"), 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static Transform FindUIPath(string path)
		{
			if (!IsUIReady())
			{
				WKLog.Warn("UIManager.FindUIPath called before UI was ready. Path: " + path);
				return null;
			}
			if (string.IsNullOrEmpty(path))
			{
				return null;
			}
			GameObject val = GameObject.Find(path);
			if ((Object)(object)val == (Object)null)
			{
				WKLog.Warn("UIManager: Could not find object at path: " + path);
			}
			return (val != null) ? val.transform : null;
		}

		public static GameObject FindTemplate(string templatePath)
		{
			if (!IsUIReady())
			{
				WKLog.Warn("UIManager.FindTemplate called before UI was ready. Path: " + templatePath);
				return null;
			}
			if (string.IsNullOrEmpty(templatePath))
			{
				return null;
			}
			return GameObject.Find(templatePath);
		}
	}
}
namespace WKLib.Assets
{
	public class AssetService
	{
		private readonly ModContext _modContext;

		private readonly string _assemblyFolder;

		private readonly Dictionary<string, AssetBundle> _bundleCache = new Dictionary<string, AssetBundle>();

		private readonly Dictionary<string, Dictionary<string, M_Level>> _loadedLevelsCache = new Dictionary<string, Dictionary<string, M_Level>>();

		private readonly Dictionary<string, M_Gamemode> _gamemodeCache = new Dictionary<string, M_Gamemode>();

		private readonly CancellationTokenSource _sQuitCts = new CancellationTokenSource();

		public AssetService(ModContext modContext)
		{
			_modContext = modContext ?? throw new ArgumentNullException("modContext");
			string location = Assembly.GetExecutingAssembly().Location;
			_assemblyFolder = Path.GetDirectoryName(location) ?? string.Empty;
			Application.quitting += delegate
			{
				WKLog.Debug("[AssetService] Quitting...");
				_sQuitCts.Cancel();
			};
		}

		public async Task<AssetBundle> LoadBundleRelativeAsync(string relativePath, IProgress<float> progress = null)
		{
			progress?.Report(0f);
			if (string.IsNullOrEmpty(relativePath))
			{
				WKLog.Error("[AssetService] Path is null or empty.");
				progress?.Report(1f);
				return null;
			}
			string cacheKey = _modContext.ModID + ":" + Path.GetFileNameWithoutExtension(relativePath);
			if (_bundleCache.TryGetValue(cacheKey, out var cached) && cached != null)
			{
				WKLog.Debug("[AssetService] Returning cached bundle: " + cacheKey);
				progress?.Report(1f);
				return cached;
			}
			string fullPath = Path.Combine(_assemblyFolder, relativePath);
			if (!File.Exists(fullPath))
			{
				WKLog.Error("[AssetService] Bundle not found at " + fullPath);
				progress?.Report(1f);
				return null;
			}
			AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(fullPath);
			if (request == null)
			{
				WKLog.Error("[AssetService] Failed to load bundle: " + fullPath + " (request)");
				progress?.Report(1f);
				return null;
			}
			try
			{
				while (!((AsyncOperation)request).isDone)
				{
					_sQuitCts.Token.ThrowIfCancellationRequested();
					progress?.Report(((AsyncOperation)request).progress * 1.1f);
					await Task.Yield();
				}
			}
			catch (OperationCanceledException)
			{
				WKLog.Debug("[AssetService] Asset Bundle Load cancelled");
				return null;
			}
			AssetBundle bundle = request.assetBundle;
			if (bundle == null)
			{
				WKLog.Error("[AssetService] Failed to load bundle at " + fullPath + " (bundle)");
				progress?.Report(1f);
				return null;
			}
			_bundleCache[cacheKey] = bundle;
			WKLog.Debug("[AssetService] Loaded & cached bundle: " + cacheKey);
			progress?.Report(1f);
			return bundle;
		}

		public void UnloadBundleRelative(string relativePath, bool unloadAllLoadedObjects = false)
		{
			string text = _modContext.ModID + ":" + relativePath;
			if (_bundleCache.TryGetValue(text, out var value) && value != null)
			{
				try
				{
					value.Unload(unloadAllLoadedObjects);
				}
				catch
				{
					WKLog.Error("[AssetService] Failed to unload bundle: " + text);
					return;
				}
				WKLog.Debug("[AssetService] Unloaded bundle: " + text);
				_bundleCache.Remove(text);
			}
		}

		public void UnloadAllBundles(bool unloadAllLoadedObjects = false)
		{
			List<string> list = _bundleCache.Keys.Where((string k) => k.StartsWith(_modContext.ModID + ":")).ToList();
			foreach (string item in list)
			{
				if (_bundleCache[item] != null)
				{
					try
					{
						_bundleCache[item].Unload(unloadAllLoadedObjects);
					}
					catch
					{
						WKLog.Error("[AssetService] Failed to unload bundle: " + item);
						continue;
					}
					WKLog.Debug("[AssetService] Unloaded bundle: " + item);
				}
				_bundleCache.Remove(item);
			}
		}

		public async Task<Dictionary<string, M_Level>> LoadAllLevelsFromBundle(AssetBundle bundle, IProgress<float> progress = null)
		{
			Dictionary<string, M_Level> foundLevels = new Dictionary<string, M_Level>();
			if (bundle == null)
			{
				WKLog.Error("[AssetService] LoadAllLevelsFromBundle called with null bundle.");
				progress?.Report(1f);
				return foundLevels;
			}
			string cacheKey = _modContext.ModID + ":" + ((Object)bundle).name;
			if (_loadedLevelsCache.ContainsKey(cacheKey))
			{
				WKLog.Debug("[AssetService] Returning Cached loaded levels for bundle: " + cacheKey);
				progress?.Report(1f);
				return _loadedLevelsCache.GetValueOrDefault(cacheKey);
			}
			AssetBundleRequest request = bundle.LoadAllAssetsAsync<GameObject>();
			try
			{
				while (!((AsyncOperation)request).isDone)
				{
					_sQuitCts.Token.ThrowIfCancellationRequested();
					progress?.Report(((AsyncOperation)request).progress * 0.5f);
					await Task.Yield();
				}
			}
			catch (OperationCanceledException)
			{
				WKLog.Debug("[AssetService] LoadAllLevelsFromBundle canceled.");
				return null;
			}
			List<GameObject> allGOs = request.allAssets.Cast<GameObject>().ToList();
			int total = allGOs.Count;
			M_Level level = default(M_Level);
			for (int i = 0; i < total; i += 20)
			{
				for (int j = i; j < i + 20 && j < total; j++)
				{
					GameObject go = allGOs[j];
					if (go.TryGetComponent<M_Level>(ref level))
					{
						if (!CL_AssetManager.instance.assetDatabase.levelPrefabs.Contains(go))
						{
							CL_AssetManager.instance.assetDatabase.levelPrefabs.Add(go);
						}
						WKLog.Debug("[AssetService] Found level: " + ((Object)level).name);
						if (!foundLevels.TryAdd(((Object)level).name, level))
						{
							WKLog.Debug("[AssetService] Duplicate prefab.name '" + ((Object)level).name + "' found; skipping the duplicate.");
						}
					}
					level = null;
				}
				progress?.Report(0.5f + (float)i / (float)total * 0.5f);
				await Task.Yield();
			}
			_loadedLevelsCache[cacheKey] = foundLevels;
			progress?.Report(1f);
			return foundLevels;
		}

		public List<M_Level> FindLevelsByName(string nameContains)
		{
			return (from prefab in CL_AssetManager.instance.assetDatabase.levelPrefabs
				where ((Object)prefab).name.Contains(nameContains)
				select prefab.GetComponent<M_Level>() into level
				where level != null
				select level).ToList();
		}

		public async Task<M_Gamemode> LoadGameModeFromBundle(AssetBundle bundle, string assetName, IProgress<float> progress = null)
		{
			if (bundle == null)
			{
				WKLog.Error("[AssetService] Bundle is null; cannot load gamemode.");
				progress?.Report(1f);
				return null;
			}
			string cacheKey = _modContext.ModID + ":" + assetName;
			if (_gamemodeCache.TryGetValue(cacheKey, out var cachedGamemode))
			{
				WKLog.Debug("[AssetService] Returning cached gamemode: '" + cacheKey + "'");
				progress?.Report(1f);
				return cachedGamemode;
			}
			AssetBundleRequest request = bundle.LoadAssetAsync<ScriptableObject>(assetName);
			while (!((AsyncOperation)request).isDone)
			{
				progress?.Report(((AsyncOperation)request).progress);
				await Task.Yield();
			}
			Object asset = request.asset;
			M_Gamemode gamemode = (M_Gamemode)(object)((asset is M_Gamemode) ? asset : null);
			if (gamemode == null)
			{
				WKLog.Error("[AssetService] Gamemode '" + assetName + "' not found in bundle " + ((Object)bundle).name);
				progress?.Report(1f);
				return null;
			}
			if (string.IsNullOrEmpty(gamemode.unlockAchievement))
			{
				gamemode.unlockAchievement = "ACH_TUTORIAL";
			}
			gamemode.gamemodePanel = ((IEnumerable<UI_GamemodeScreen_Panel>)Resources.FindObjectsOfTypeAll<UI_GamemodeScreen_Panel>()).FirstOrDefault((Func<UI_GamemodeScreen_Panel, bool>)((UI_GamemodeScreen_Panel x) => ((Object)x).name == "Gamemode_Panel_Base"));
			gamemode.loseScreen = ((IEnumerable<UI_ScoreScreen>)Resources.FindObjectsOfTypeAll<UI_ScoreScreen>()).FirstOrDefault((Func<UI_ScoreScreen, bool>)((UI_ScoreScreen x) => ((Object)x).name == "ScorePanel_Standard_Death"));
			gamemode.winScreen = ((IEnumerable<UI_ScoreScreen>)Resources.FindObjectsOfTypeAll<UI_ScoreScreen>()).FirstOrDefault((Func<UI_ScoreScreen, bool>)((UI_ScoreScreen x) => ((Object)x).name == "ScorePanel_Standard_Win"));
			_gamemodeCache[cacheKey] = gamemode;
			progress?.Report(1f);
			WKLog.Debug("[AssetService] Loaded and cached gamemode: '" + assetName + "'");
			return gamemode;
		}

		public Sprite LoadPngAsSpriteRelative(string relativePngPath)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(_assemblyFolder, relativePngPath);
			if (!File.Exists(text))
			{
				WKLog.Error("[AssetService] PNG not found at: " + text);
				return null;
			}
			byte[] array = File.ReadAllBytes(text);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				WKLog.Error("[AssetService] Failed to load image: " + relativePngPath);
				return null;
			}
			Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			((Object)val2).name = Path.GetFileNameWithoutExtension(relativePngPath);
			return val2;
		}

		public Sprite LoadPngAsSprite(string pngFileName)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadPngTexture(pngFileName);
			if (val == null)
			{
				return null;
			}
			Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			((Object)val2).name = pngFileName.Split(".png")[0];
			return val2;
		}

		private Texture2D LoadPngTexture(string pngFileName)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			string text = Path.Combine(_assemblyFolder, "Assets", pngFileName);
			if (!File.Exists(text))
			{
				WKLog.Error("[AssetService] PNG not found at: " + text);
				return null;
			}
			byte[] array = File.ReadAllBytes(text);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (ImageConversion.LoadImage(val, array))
			{
				return val;
			}
			WKLog.Error("[AssetService] Failed to decode PNG: " + text);
			return null;
		}
	}
}