Decompiled source of NineSolsAPI v0.4.1

NineSolsAPI.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.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using I2.Loc;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using NineSolsAPI.Menu;
using NineSolsAPI.Preload;
using NineSolsAPI.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.Device;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("[email protected]")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Nine Sols Modding API")]
[assembly: AssemblyFileVersion("0.4.1.0")]
[assembly: AssemblyInformationalVersion("0.4.1+66a8d3a7094ed5e84aff6a8f477efba25dd4a724")]
[assembly: AssemblyProduct("NineSolsAPI")]
[assembly: AssemblyTitle("NineSolsAPI")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/nine-sols-modding/NineSolsAPI")]
[assembly: AssemblyVersion("0.4.1.0")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 NineSolsAPI
{
	internal class KeyBind
	{
		public MonoBehaviour Owner;

		public Func<KeyboardShortcut> Shortcut;

		public Action Action;
	}
	[PublicAPI]
	public class KeybindManager
	{
		private List<KeyBind> keybindings = new List<KeyBind>();

		internal void Unload()
		{
			keybindings.Clear();
		}

		public static void Add(MonoBehaviour owner, Action action, params KeyCode[] keys)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			KeyCode val = keys[^1];
			KeyCode[] subArray = keys[..^1];
			KeyboardShortcut shortcut = default(KeyboardShortcut);
			((KeyboardShortcut)(ref shortcut))..ctor(val, subArray);
			Add(owner, action, shortcut);
		}

		public static void Add(MonoBehaviour owner, Action action, KeyboardShortcut shortcut)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Add(owner, action, (Func<KeyboardShortcut>)(() => shortcut));
		}

		public static void Add(MonoBehaviour owner, Action action, Func<KeyboardShortcut> shortcut)
		{
			NineSolsAPICore.Instance.KeybindManager.AddKeybind(owner, action, shortcut);
		}

		private void AddKeybind(MonoBehaviour owner, Action action, Func<KeyboardShortcut> shortcut)
		{
			keybindings.Add(new KeyBind
			{
				Owner = owner,
				Action = action,
				Shortcut = shortcut
			});
		}

		internal void Update()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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)
			//IL_005b: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			foreach (KeyBind keybinding in keybindings)
			{
				if (!Object.op_Implicit((Object)(object)keybinding.Owner))
				{
					flag = true;
					continue;
				}
				KeyboardShortcut val = keybinding.Shortcut();
				bool flag2 = Input.GetKeyDown(((KeyboardShortcut)(ref val)).MainKey);
				foreach (KeyCode modifier in ((KeyboardShortcut)(ref val)).Modifiers)
				{
					flag2 = flag2 && Input.GetKey(modifier);
				}
				if (flag2)
				{
					try
					{
						keybinding.Action();
					}
					catch (Exception arg)
					{
						Log.Error($"Failed to run action: {arg}");
					}
				}
			}
			if (flag)
			{
				keybindings.RemoveAll((KeyBind keybinding) => !Object.op_Implicit((Object)(object)keybinding.Owner));
			}
		}
	}
	internal static class Log
	{
		private static ManualLogSource logSource;

		internal static void Init(ManualLogSource logSource)
		{
			Log.logSource = logSource;
		}

		internal static void Debug(object data)
		{
			logSource.LogDebug(data);
		}

		internal static void Error(object data)
		{
			logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			logSource.LogFatal(data);
		}

		internal static void Info(object data)
		{
			logSource.LogInfo(data);
		}

		internal static void Message(object data)
		{
			logSource.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			logSource.LogWarning(data);
		}
	}
	[PublicAPI]
	[BepInPlugin("ninesolsapi", "NineSolsAPI", "1.0.0")]
	public class NineSolsAPICore : BaseUnityPlugin
	{
		public const string PluginGUID = "ninesolsapi";

		public const string PluginName = "NineSolsAPI";

		public const string PluginVersion = "1.0.0";

		internal static NineSolsAPICore Instance;

		private Canvas fullscreenCanvas;

		private Preloader preloader;

		internal ToastManager ToastManager;

		internal KeybindManager KeybindManager = new KeybindManager();

		private TitlescreenModifications titlescreenModifications = new TitlescreenModifications();

		private Harmony harmony;

		private RectTransform? progressBar;

		private const int ProgressWidth = 600;

		private const int ProgressHeight = 30;

		public static Canvas FullscreenCanvas => Instance.fullscreenCanvas;

		private float LoadProgress
		{
			set
			{
				SetProgress(value);
				if (value >= 1f)
				{
					OnLoadDone();
				}
			}
		}

		public static Preloader Preloader => Instance.preloader;

		private void Awake()
		{
			Instance = this;
			Log.Init(((BaseUnityPlugin)this).Logger);
			try
			{
				LoadProgress = 0f;
				fullscreenCanvas = CreateFullscreenCanvas();
				preloader = new Preloader(delegate(float progress)
				{
					LoadProgress = progress;
				});
				ToastManager = new ToastManager();
				titlescreenModifications.Load();
				SceneManager.sceneLoaded += OnSceneLoaded;
				RCGLifeCycle.DontDestroyForever(((Component)this).gameObject);
				harmony = Harmony.CreateAndPatchAll(typeof(NineSolsAPICore).Assembly, "ninesolsapi");
			}
			catch (Exception arg)
			{
				Log.Error($"Failed to initialized modding API: {arg}");
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Nine Sols API loaded");
		}

		private void Start()
		{
			((MonoBehaviour)this).Invoke("AfterStart", 0f);
			((MonoBehaviour)this).StartCoroutine(preloader.Preload());
		}

		private void AfterStart()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name == "Logo")
			{
				progressBar = CreateProgressBar();
			}
		}

		private void OnLoadDone()
		{
			if (!((Object)(object)progressBar == (Object)null))
			{
				Object.Destroy((Object)(object)((Component)((Transform)progressBar).parent).gameObject);
				progressBar = null;
				SceneManager.LoadScene("TitleScreenMenu");
			}
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			KeybindManager.Unload();
			titlescreenModifications.Unload();
			Object.Destroy((Object)(object)((Component)FullscreenCanvas).gameObject);
			preloader.Unload();
			harmony.UnpatchSelf();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Nine Sols API unloaded");
		}

		private void Update()
		{
			ToastManager?.Update();
			KeybindManager?.Update();
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			titlescreenModifications.MaybeExtendMainMenu(scene);
		}

		private Canvas CreateFullscreenCanvas()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			GameObject val = new GameObject("NineSolsAPI-FullscreenCanvas");
			Canvas obj = val.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			RCGLifeCycle.DontDestroyForever(val);
			return obj;
		}

		private RectTransform CreateProgressBar()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_005d: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject();
			val.SetActive(false);
			val.transform.SetParent(((Component)FullscreenCanvas).transform);
			Image val2 = val.AddComponent<Image>();
			val2.sprite = NullSprite(new byte[4] { 255, 255, 255, 255 });
			val2.useSpriteMesh = true;
			RectTransform component = val.GetComponent<RectTransform>();
			component.pivot = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(600f, 30f);
			component.anchoredPosition = Vector2.zero;
			component.anchorMin = new Vector2(0.5f, 0.2f);
			component.anchorMax = new Vector2(0.5f, 0.2f);
			GameObject val3 = new GameObject();
			val3.transform.SetParent(val.transform);
			Image val4 = val3.AddComponent<Image>();
			val4.sprite = NullSprite(new byte[4] { 52, 52, 235, 255 });
			val4.useSpriteMesh = true;
			RectTransform component2 = val3.GetComponent<RectTransform>();
			component2.pivot = new Vector2(0f, 0.5f);
			component2.sizeDelta = new Vector2(0f, 30f);
			component2.anchoredPosition = Vector2.zero;
			component2.anchorMin = new Vector2(0f, 0.5f);
			component2.anchorMax = new Vector2(0f, 0.5f);
			return component2;
			static Sprite NullSprite(byte[]? data = null)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Expected O, but got Unknown
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				Texture2D val5 = new Texture2D(1, 1);
				if (data == null)
				{
					data = new byte[4];
				}
				val5.LoadRawTextureData(data);
				val5.Apply();
				return Sprite.Create(val5, new Rect(0f, 0f, 1f, 1f), Vector2.zero);
			}
		}

		private void SetProgress(float progress)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)progressBar == (Object)null))
			{
				if (!((Component)progressBar).gameObject.activeSelf && progress != 0f && (double)progress < 1.0)
				{
					((Component)((Transform)progressBar).parent).gameObject.SetActive(true);
				}
				RectTransform? obj = progressBar;
				Vector2 sizeDelta = progressBar.sizeDelta;
				sizeDelta.x = 600f * progress;
				obj.sizeDelta = sizeDelta;
			}
		}
	}
	internal record struct ToastMessage(float StartTime, string Text);
	public class ToastManager
	{
		private const float MaxToastAge = 5f;

		private bool toastsDirty;

		private List<ToastMessage> toasts = new List<ToastMessage>();

		private TMP_Text toastText;

		private float Now => Time.realtimeSinceStartup;

		public ToastManager()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Toast");
			val.transform.SetParent(((Component)NineSolsAPICore.FullscreenCanvas).transform);
			toastText = (TMP_Text)(object)val.AddComponent<TextMeshProUGUI>();
			toastText.alignment = (TextAlignmentOptions)1028;
			toastText.fontSize = 20f;
			((Graphic)toastText).color = Color.white;
			RectTransform component = ((Component)toastText).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(1f, 0f);
			component.anchorMax = new Vector2(1f, 0f);
			component.pivot = new Vector2(1f, 0f);
			component.anchoredPosition = new Vector2(-10f, 10f);
			component.sizeDelta = new Vector2((float)Screen.width, 0f);
		}

		[PublicAPI]
		public static void Toast(object message)
		{
			Log.Info($"Toast: {message}");
			NineSolsAPICore.Instance.ToastManager.AddToastMessage(message?.ToString() ?? "null");
		}

		private void AddToastMessage(string message)
		{
			toasts.Add(new ToastMessage(Now, message));
			toastsDirty = true;
		}

		internal void Update()
		{
			float now = Now;
			toastsDirty |= toasts.RemoveAll((ToastMessage toast) => now - toast.StartTime > 5f) > 0;
			if (toastsDirty)
			{
				toastText.text = string.Join('\n', toasts.Select((ToastMessage toast) => toast.Text));
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "NineSolsAPI";

		public const string PLUGIN_NAME = "NineSolsAPI";

		public const string PLUGIN_VERSION = "0.4.1";
	}
}
namespace NineSolsAPI.Utils
{
	[PublicAPI]
	public static class AssemblyUtils
	{
		private static Stream? GetEmbeddedResource(Assembly assembly, string fileName)
		{
			Stream manifestResourceStream = assembly.GetManifestResourceStream(fileName);
			if (manifestResourceStream == null)
			{
				string[] manifestResourceNames = assembly.GetManifestResourceNames();
				Log.Error((manifestResourceNames.Length == 0) ? ("Could not load embedded resource '" + fileName + "', the assembly " + assembly.GetName().Name + " contains no resources") : ("Could not load embedded resource '" + fileName + "', did you mean one of " + GeneralExtensions.Join<string>((IEnumerable<string>)manifestResourceNames, (Func<string, string>)null, ", ") + "?"));
				return null;
			}
			return manifestResourceStream;
		}

		public static AssetBundle? GetEmbeddedAssetBundle(string name)
		{
			Stream embeddedResource = GetEmbeddedResource(Assembly.GetCallingAssembly(), name);
			if (embeddedResource == null)
			{
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			embeddedResource.CopyTo(memoryStream);
			return AssetBundle.LoadFromMemory(memoryStream.ToArray());
		}

		public static T? GetEmbeddedJson<T>(string name)
		{
			Stream embeddedResource = GetEmbeddedResource(Assembly.GetCallingAssembly(), name);
			if (embeddedResource == null)
			{
				return default(T);
			}
			using StreamReader streamReader = new StreamReader(embeddedResource);
			return JsonConvert.DeserializeObject<T>(streamReader.ReadToEnd());
		}
	}
	[PublicAPI]
	public static class JsonUtils
	{
		public static string Serialize(object? value, bool indent = false)
		{
			return JsonConvert.SerializeObject(value, (Formatting)(indent ? 1 : 0));
		}

		public static T? Deserialize<T>(string value)
		{
			return JsonConvert.DeserializeObject<T>(value);
		}

		public static T? DeserializeStream<T>(Stream stream)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			using StreamReader streamReader = new StreamReader(stream);
			JsonTextReader val = new JsonTextReader((TextReader)streamReader);
			try
			{
				return JsonSerializer.CreateDefault().Deserialize<T>((JsonReader)(object)val);
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}
	}
	[PublicAPI]
	public static class ObjectUtils
	{
		public static GameObject InstantiateAutoReference(GameObject orig, Transform? parent, bool autoReferenceChildren = true)
		{
			GameObject val = Object.Instantiate<GameObject>(orig, parent, false);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return val;
			}
			AutoAttributeManager.AutoReference(val);
			if (autoReferenceChildren)
			{
				AutoAttributeManager.AutoReferenceAllChildren(val);
			}
			return val;
		}

		public static GameObject InstantiateAutoReference(GameObject orig, bool autoReferenceChildren = true)
		{
			GameObject val = Object.Instantiate<GameObject>(orig);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return val;
			}
			AutoAttributeManager.AutoReference(val);
			if (autoReferenceChildren)
			{
				AutoAttributeManager.AutoReferenceAllChildren(val);
			}
			return val;
		}

		public static GameObject InstantiateInit(GameObject orig, Transform? parent = null)
		{
			GameObject val = InstantiateAutoReference(orig, parent);
			ILevelAwake[] componentsInChildren = val.GetComponentsInChildren<ILevelAwake>(true);
			for (int num = componentsInChildren.Length - 1; num >= 0; num--)
			{
				ILevelAwake val2 = componentsInChildren[num];
				try
				{
					val2.EnterLevelAwake();
				}
				catch (Exception ex)
				{
					Log.Error(ex.StackTrace);
				}
			}
			ILevelAwakeReverse[] componentsInChildren2 = val.GetComponentsInChildren<ILevelAwakeReverse>(true);
			for (int num2 = componentsInChildren2.Length - 1; num2 >= 0; num2--)
			{
				ILevelAwakeReverse val3 = componentsInChildren2[num2];
				try
				{
					val3.EnterLevelAwakeReverse();
				}
				catch (Exception ex2)
				{
					Log.Error(ex2.StackTrace);
				}
			}
			ILevelStart[] componentsInChildren3 = val.GetComponentsInChildren<ILevelStart>(true);
			for (int num3 = componentsInChildren3.Length - 1; num3 >= 0; num3--)
			{
				ILevelStart val4 = componentsInChildren3[num3];
				try
				{
					val4.EnterLevelStart();
				}
				catch (Exception ex3)
				{
					Log.Error(ex3.StackTrace);
				}
			}
			IResetter[] componentsInChildren4 = val.GetComponentsInChildren<IResetter>(true);
			for (int num4 = componentsInChildren4.Length - 1; num4 >= 0; num4--)
			{
				IResetter val5 = componentsInChildren4[num4];
				try
				{
					val5.EnterLevelReset();
				}
				catch (Exception ex4)
				{
					Log.Error(ex4.StackTrace);
				}
			}
			return val;
		}

		public static GameObject? LookupPath(Scene scene, string path)
		{
			return GetGameObjectFromArray(((Scene)(ref scene)).GetRootGameObjects(), path);
		}

		public static GameObject? LookupPath(string path)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				GameObject val = LookupPath(SceneManager.GetSceneAt(i), path);
				if (val != null)
				{
					return val;
				}
			}
			return null;
		}

		internal static GameObject? GetGameObjectFromArray(GameObject[] objects, string objName)
		{
			string text = null;
			int num = objName.IndexOf('/');
			string rootName;
			if (num == -1)
			{
				rootName = objName;
			}
			else
			{
				if (num == 0 || num == objName.Length - 1)
				{
					throw new ArgumentException("Invalid GameObject path");
				}
				rootName = objName.Substring(0, num);
				int num2 = num + 1;
				text = objName.Substring(num2, objName.Length - num2);
			}
			GameObject val = ((IEnumerable<GameObject>)objects).FirstOrDefault((Func<GameObject, bool>)((GameObject o) => ((Object)o).name == rootName));
			if (val == null)
			{
				Log.Warning("root does not exist: " + rootName);
				return null;
			}
			if (text == null)
			{
				return val;
			}
			Transform val2 = val.transform.Find(text);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				Log.Warning("does not exist: " + text + " in " + rootName);
				return null;
			}
			return ((Component)val2).gameObject;
		}

		public static T? FindDisabledByName<T>(string name) where T : Object
		{
			string name2 = name;
			T? val = Object.FindObjectsOfType<T>(true).FirstOrDefault((T x) => ((Object)x).name == name2);
			if (!Object.op_Implicit((Object)(object)val))
			{
				Log.Warning("FindDisabledByName(" + name2 + ") not found");
			}
			return val;
		}

		public static string ObjectPath(GameObject obj)
		{
			List<string> list = new List<string>();
			GameObject val = obj;
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)val).name);
				Transform parent = val.transform.parent;
				val = ((parent != null) ? ((Component)parent).gameObject : null);
			}
			list.Reverse();
			return GeneralExtensions.Join<string>((IEnumerable<string>)list, (Func<string, string>)null, "/");
		}
	}
	public static class StringExtensions
	{
		public static ReadOnlySpan<char> TrimEndMatches(this string str, ReadOnlySpan<char> substr)
		{
			ReadOnlySpan<char> readOnlySpan = str.AsSpan();
			int num = readOnlySpan.LastIndexOf(substr);
			if (num != -1)
			{
				return readOnlySpan.Slice(0, num);
			}
			return readOnlySpan;
		}

		public static ReadOnlySpan<char> TrimEndMatches(this ReadOnlySpan<char> span, ReadOnlySpan<char> substr)
		{
			int num = span.LastIndexOf(substr);
			if (num != -1)
			{
				return span.Slice(0, num);
			}
			return span;
		}

		public static ReadOnlySpan<char> TrimStartMatches(this string str, ReadOnlySpan<char> substr)
		{
			ReadOnlySpan<char> readOnlySpan = str.AsSpan();
			int num = readOnlySpan.LastIndexOf(substr);
			if (num != -1)
			{
				int num2 = num + substr.Length;
				return readOnlySpan.Slice(num2, readOnlySpan.Length - num2);
			}
			return readOnlySpan;
		}

		public static ReadOnlySpan<char> TrimStartMatches(this ReadOnlySpan<char> span, ReadOnlySpan<char> substr)
		{
			int num = span.LastIndexOf(substr);
			if (num != -1)
			{
				int num2 = num + substr.Length;
				return span.Slice(num2, span.Length - num2);
			}
			return span;
		}
	}
}
namespace NineSolsAPI.Preload
{
	[AttributeUsage(AttributeTargets.Field)]
	[MeansImplicitUse]
	[PublicAPI]
	public class PreloadAttribute : Attribute
	{
		public string Scene;

		public string Path;

		public PreloadAttribute(string scene, string path)
		{
			Scene = scene;
			Path = path;
			base..ctor();
		}
	}
	public interface IPreloadTarget
	{
		public class ReflectionPreloadTarget : IPreloadTarget
		{
			[CompilerGenerated]
			private object <instance>P;

			[CompilerGenerated]
			private FieldInfo <field>P;

			public ReflectionPreloadTarget(object instance, FieldInfo field)
			{
				<instance>P = instance;
				<field>P = field;
				base..ctor();
			}

			public void Set(GameObject? preloaded, string scene, string path)
			{
				<field>P.SetValue(<instance>P, preloaded);
			}

			public void Unset(GameObject preloaded)
			{
				<field>P.SetValue(<instance>P, null);
			}
		}

		public class ListPreloadTarget : IPreloadTarget
		{
			[CompilerGenerated]
			private List<GameObject?> <preloads>P;

			public ListPreloadTarget(List<GameObject?> preloads)
			{
				<preloads>P = preloads;
				base..ctor();
			}

			public void Set(GameObject? preloaded, string scene, string path)
			{
				<preloads>P.Add(preloaded);
			}

			public void Unset(GameObject preloaded)
			{
				<preloads>P.Clear();
			}
		}

		void Set(GameObject? preloaded, string scene, string path);

		void Unset(GameObject preloaded);
	}
	[PublicAPI]
	public class Preloader
	{
		[CompilerGenerated]
		private Action<float> <onProgress>P;

		private const int PreloadBatchSize = 4;

		public static bool IsPreloading;

		private Dictionary<string, List<(string, IPreloadTarget)>> preloadTypes;

		private bool preloaded;

		private List<(GameObject, IPreloadTarget)> preloadObjs;

		private List<AsyncOperation> preloadOperationQueue;

		private List<AsyncOperation> inProgressLoads;

		private List<AsyncOperation> inProgressUnloads;

		private int target;

		public Preloader(Action<float> onProgress)
		{
			<onProgress>P = onProgress;
			preloadTypes = new Dictionary<string, List<(string, IPreloadTarget)>>();
			preloadObjs = new List<(GameObject, IPreloadTarget)>();
			preloadOperationQueue = new List<AsyncOperation>();
			inProgressLoads = new List<AsyncOperation>();
			inProgressUnloads = new List<AsyncOperation>();
			base..ctor();
		}

		public void AddPreload(string scene, string path, IPreloadTarget target)
		{
			if (!preloadTypes.TryGetValue(scene, out List<(string, IPreloadTarget)> value))
			{
				value = new List<(string, IPreloadTarget)>();
				preloadTypes.Add(scene, value);
			}
			value.Add((path, target));
		}

		public void AddPreloadList(IEnumerable<(string, string)> paths, List<GameObject?> outList)
		{
			IPreloadTarget.ListPreloadTarget listPreloadTarget = new IPreloadTarget.ListPreloadTarget(outList);
			foreach (var (scene, path) in paths)
			{
				AddPreload(scene, path, listPreloadTarget);
			}
		}

		public void AddPreloadClass<T>(T obj)
		{
			if (IsPreloading)
			{
				Log.Error("tried to call AddPreloadClass during preloading");
				return;
			}
			FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				PreloadAttribute customAttribute = fieldInfo.GetCustomAttribute<PreloadAttribute>();
				if (customAttribute != null)
				{
					AddPreload(customAttribute.Scene, customAttribute.Path, new IPreloadTarget.ReflectionPreloadTarget(obj, fieldInfo));
				}
			}
		}

		private IEnumerator DoPreloadScene(string sceneName, List<(string, IPreloadTarget)> scenePreloads)
		{
			AsyncOperation loadOp = SceneManager.LoadSceneAsync(sceneName, (LoadSceneMode)1);
			if (loadOp == null)
			{
				ToastManager.Toast("Error loading scene: " + sceneName);
				target--;
				yield break;
			}
			preloadOperationQueue.Add(loadOp);
			inProgressLoads.Add(loadOp);
			yield return loadOp;
			Scene sceneByName = SceneManager.GetSceneByName(sceneName);
			try
			{
				GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
				GameObject[] array = rootGameObjects;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetActive(false);
				}
				foreach (var scenePreload in scenePreloads)
				{
					string item = scenePreload.Item1;
					IPreloadTarget item2 = scenePreload.Item2;
					GameObject gameObjectFromArray = ObjectUtils.GetGameObjectFromArray(rootGameObjects, item);
					if (gameObjectFromArray == null)
					{
						Log.Error("could not preload " + item + " in " + sceneName);
						item2.Set(null, sceneName, item);
						continue;
					}
					GameObject val = Object.Instantiate<GameObject>(gameObjectFromArray);
					val.SetActive(false);
					Object.DontDestroyOnLoad((Object)(object)val);
					AutoAttributeManager.AutoReference(val);
					preloadObjs.Add((val, item2));
					item2.Set(val, sceneName, item);
				}
			}
			catch (Exception data)
			{
				Log.Error(data);
			}
			AsyncOperation val2 = SceneManager.UnloadSceneAsync(sceneName);
			inProgressUnloads.Add(val2);
			yield return val2;
			preloadOperationQueue.Remove(loadOp);
		}

		private IEnumerator DoPreload()
		{
			Log.Info($"Preloading {preloadTypes.Count} scenes");
			if (preloadTypes.Count == 0)
			{
				yield break;
			}
			Stopwatch watch = Stopwatch.StartNew();
			IsPreloading = true;
			DestroyAllGameObjects.DestroyingAll = true;
			try
			{
				target = preloadTypes.Count;
				Dictionary<string, List<(string, IPreloadTarget)>>.Enumerator preloadsToDo = preloadTypes.GetEnumerator();
				float num = 0f;
				while (num < 1f)
				{
					while (preloadOperationQueue.Count < 4 && preloadsToDo.MoveNext())
					{
						var (sceneName, scenePreloads) = (KeyValuePair<string, List<(string, IPreloadTarget)>>)(ref preloadsToDo.Current);
						((MonoBehaviour)NineSolsAPICore.Instance).StartCoroutine(DoPreloadScene(sceneName, scenePreloads));
						if (inProgressLoads.Count % 4 == 0)
						{
							Stopwatch watchRes = Stopwatch.StartNew();
							yield return Resources.UnloadUnusedAssets();
							watchRes.Stop();
							Log.Info($"collecting resources in ${watchRes.ElapsedMilliseconds}");
						}
					}
					yield return null;
					float num2 = inProgressLoads.Sum((AsyncOperation loadOp) => loadOp.progress * 0.5f);
					num2 += inProgressUnloads.Sum((AsyncOperation loadOp) => loadOp.progress * 0.5f);
					num = ((target == 0) ? 1f : (num2 / (float)target));
					<onProgress>P(num);
					Log.Info($"progress {num}/1, in flight {preloadOperationQueue.Count}");
				}
			}
			finally
			{
				Preloader preloader = this;
				DestroyAllGameObjects.DestroyingAll = false;
				IsPreloading = false;
				preloader.preloaded = true;
				preloader.inProgressLoads.Clear();
				preloader.inProgressUnloads.Clear();
				preloader.preloadOperationQueue.Clear();
			}
			watch.Stop();
			Log.Info($"Preloading done with {preloadObjs.Count} objects in {watch.ElapsedMilliseconds}ms");
		}

		internal IEnumerator Preload()
		{
			if (preloaded)
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (!(((Scene)(ref activeScene)).name == "TitleScreenMenu"))
				{
					goto IL_005b;
				}
			}
			yield return DoPreload();
			goto IL_005b;
			IL_005b:
			<onProgress>P(1f);
		}

		internal void Unload()
		{
			foreach (var (val, preloadTarget) in preloadObjs)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(object)val);
				}
				preloadTarget.Unset(val);
			}
			preloadObjs.Clear();
		}
	}
}
namespace NineSolsAPI.Patches
{
	[HarmonyPatch]
	public class Patches
	{
		private const string BUILDGUID_SPEEDRUNPATCH = "d4c12f4d7e8442e79988244014fb92d2";

		[HarmonyPatch(typeof(AchievementData), "OnAcquired")]
		[HarmonyPrefix]
		private static bool AchievementAcquired(ref AchievementData __instance)
		{
			Log.Info("Prevented Achievement '" + ((Object)__instance).name + "' from activating.");
			return false;
		}

		[HarmonyPatch(typeof(LogoLogic), "Start")]
		[HarmonyPostfix]
		private static void Start(ref LogoLogic __instance)
		{
			if (!(Application.buildGUID == "d4c12f4d7e8442e79988244014fb92d2"))
			{
				RuntimeInitHandler.LoadCore();
				SceneManager.LoadScene(__instance.NextScene);
			}
		}

		[HarmonyPatch(typeof(GameLevel), "Awake")]
		[HarmonyPrefix]
		private static bool GameLevelAwake()
		{
			return !Preloader.IsPreloading;
		}
	}
	[HarmonyPatch]
	public class SteamAPI
	{
		private const bool ENABLE_STEAM_API = true;

		[HarmonyPatch(typeof(SteamManager), "Awake")]
		[HarmonyPrefix]
		private static bool SteamApiAwake()
		{
			return true;
		}
	}
}
namespace NineSolsAPI.Menu
{
	internal class TitlescreenModifications
	{
		private UIControlGroup? group;

		private UIControlButton? button;

		private const bool Enable = false;

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

		public void Unload()
		{
			if ((Object)(object)button != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)button).gameObject);
			}
			if ((Object)(object)group != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)group).gameObject);
			}
		}

		public void MaybeExtendMainMenu(Scene scene)
		{
		}

		private UIControlButton CreateOptionsButton()
		{
			GameObject val = GameObject.Find("MainMenuButton_Option");
			GameObject obj = ObjectUtils.InstantiateAutoReference(val, val.transform.parent, autoReferenceChildren: false);
			Object.Destroy((Object)(object)obj.GetComponentInChildren<Localize>());
			obj.GetComponentInChildren<TMP_Text>().text = "Mod Options";
			obj.gameObject.transform.SetSiblingIndex(val.transform.GetSiblingIndex() + 1);
			return obj.GetComponentInChildren<UIControlButton>();
		}

		private UIControlGroup CreateUiControlGroup()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_007c: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Expected O, but got Unknown
			//IL_01fd: Expected O, but got Unknown
			UICursorProvider componentInChildren = ((Component)SingletonBehaviour<StartMenuLogic>.Instance).gameObject.GetComponentInChildren<UICursorProvider>();
			GameObject val = new GameObject("ModOptions Panel");
			val.transform.SetParent(((Component)componentInChildren).transform, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			UIControlGroup val3 = val.AddComponent<UIControlGroup>();
			RCGUIPanel component = val.GetComponent<RCGUIPanel>();
			val.AddComponent<CanvasRenderer>();
			val.AddComponent<SelectableNavigationProvider>();
			val.AddComponent<Animator>();
			AutoAttributeManager.AutoReference(val);
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			component.OnShowInit = new UnityEvent();
			component.OnHideInit = new UnityEvent();
			component.OnShowComplete = new UnityEvent();
			component.OnHideComplete = new UnityEvent();
			GameObject val4 = new GameObject();
			RectTransform obj = val4.AddComponent<RectTransform>();
			obj.anchorMin = new Vector2(0.5f, 0.5f);
			obj.anchorMax = new Vector2(0.5f, 0.5f);
			obj.sizeDelta = new Vector2(600f, 800f);
			((HorizontalOrVerticalLayoutGroup)val4.AddComponent<VerticalLayoutGroup>()).spacing = 20f;
			val4.transform.SetParent(((Component)val3).transform, false);
			GameObject val5 = new GameObject();
			((TMP_Text)val5.AddComponent<TextMeshProUGUI>()).text = "Mod options";
			val5.AddComponent<LayoutElement>();
			val5.transform.SetParent(val4.transform, false);
			GameObject val6 = new GameObject();
			val6.AddComponent<CanvasRenderer>();
			val6.AddComponent<RectTransform>();
			val6.AddComponent<LayoutElement>().minHeight = 0f;
			val6.transform.SetParent(val4.transform, false);
			Button val7 = ObjectUtils.FindDisabledByName<Button>("Show HUD");
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				ObjectUtils.InstantiateAutoReference(((Component)val7).gameObject, val4.transform).GetComponentInChildren<TMP_Text>().text = $"{pluginInfo.Key} {pluginInfo.Value.Metadata.Version}";
				FlagFieldEntryInt val8 = new FlagFieldEntryInt();
				GameFlagInt val9 = ScriptableObject.CreateInstance<GameFlagInt>();
				((AbstractScriptableData<FlagFieldInt, int>)(object)val9).field = new FlagFieldInt();
				((FlagFieldEntry<int>)val8).flagBase = (GameFlagBase)(object)val9;
				((FlagFieldEntry<int>)val8).fieldName = "field";
			}
			val3.defaultSelectable = val4.GetComponentInChildren<Selectable>();
			return val3;
		}
	}
}