Decompiled source of CybergrindSlideshow v1.2.0

plugins\CybergrindSlideshow.dll

Decompiled 3 weeks 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.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Jukebox.Components;
using Microsoft.CodeAnalysis;
using Notiffy.API;
using NukeLib.Assets;
using NukeLib.ImageUtils;
using NukeLib.Reflection;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Fields;
using PluginConfig.API.Functionals;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using VolumetricSkyboxes;
using VolumetricSkyboxes.Components;
using VolumetricSkyboxes.Utils;

[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("CybergrindSlideshow")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+83964a13f97589b0eea8a6ea16cfd2d7d5ecfb4d")]
[assembly: AssemblyProduct("CybergrindSlideshow")]
[assembly: AssemblyTitle("CybergrindSlideshow")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 CybergrindSlideshow
{
	public class ConfigManager
	{
		public enum SelectionMode
		{
			Random,
			DeterministicSequential
		}

		public enum SecondarySelectionMode
		{
			Independent,
			StrictlyMatchSkyboxName,
			ClosestColorToSkybox
		}

		public enum MonochromeSelectionMode
		{
			Independent
		}

		internal static readonly string ApplicationPath;

		internal static readonly string SkyboxesPath;

		internal static readonly string GridPath;

		internal static readonly string GlowPath;

		internal static readonly string MusicPath;

		internal static readonly string VolumetricSkyboxesPath;

		private static PluginConfigurator config;

		public static IntField ThemeChangeWaveInterval;

		public static BoolField ThemeChangeWhenMusicChanges;

		public static BoolField SkyboxEnabled;

		public static StringField SkyboxDir;

		public static BoolField SkyboxDirRecursive;

		public static EnumField<SelectionMode> SkyboxChangeOrder;

		public static BoolField SkyboxAllowVolumetric;

		public static BoolField ForceDisableVolumetricSkyboxGridTexture;

		public static BoolField LightingEnabled;

		public static FloatField LightingIntensity;

		public static BoolField LightingAdjustment;

		public static BoolField GridEnabled;

		public static StringField GridDir;

		public static BoolField GridDirRecursive;

		public static EnumField<SecondarySelectionMode> GridSelectionMode;

		public static BoolField GlowEnabled;

		public static StringField GlowDir;

		public static BoolField GlowDirRecursive;

		public static EnumField<MonochromeSelectionMode> GlowSelectionMode;

		public static StringField LastVersion;

		public static void Initialize()
		{
		}

		static ConfigManager()
		{
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Expected O, but got Unknown
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Expected O, but got Unknown
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Expected O, but got Unknown
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Expected O, but got Unknown
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Expected O, but got Unknown
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Expected O, but got Unknown
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Expected O, but got Unknown
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Expected O, but got Unknown
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Expected O, but got Unknown
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Expected O, but got Unknown
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Expected O, but got Unknown
			//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Expected O, but got Unknown
			//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Expected O, but got Unknown
			//IL_0436: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Expected O, but got Unknown
			//IL_0455: Unknown result type (might be due to invalid IL or missing references)
			//IL_045f: Expected O, but got Unknown
			//IL_048f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cb: Expected O, but got Unknown
			//IL_04e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ee: Expected O, but got Unknown
			//IL_0503: Unknown result type (might be due to invalid IL or missing references)
			//IL_050d: Expected O, but got Unknown
			//IL_053d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0554: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0573: Unknown result type (might be due to invalid IL or missing references)
			//IL_0580: Expected O, but got Unknown
			//IL_057b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_058e: Expected O, but got Unknown
			//IL_0589: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a3: Expected O, but got Unknown
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a8: Expected O, but got Unknown
			ApplicationPath = Path.Combine(Directory.GetParent(Application.dataPath)?.FullName);
			SkyboxesPath = Path.Combine(ApplicationPath, "Cybergrind", "Textures", "Skyboxes");
			GridPath = Path.Combine(ApplicationPath, "Cybergrind", "Textures");
			GlowPath = Path.Combine(ApplicationPath, "Cybergrind", "Textures", "Glows");
			MusicPath = Path.Combine(ApplicationPath, "Cybergrind", "Music");
			VolumetricSkyboxesPath = Path.Combine(ApplicationPath, "Cybergrind", "VolumetricSkyboxes");
			config = PluginConfigurator.Create("Cybergrind Slideshow", "com.github.end-4.cybergrindSlideshow");
			string text = Path.Combine(Plugin.workingDir, "icon.png");
			if (File.Exists(text))
			{
				config.SetIconWithURL(text);
			}
			new ConfigHeader(config.rootPanel, "", 10);
			new ConfigHeader(config.rootPanel, "-- <color=#95f857>USAGE NOTES</color> --", 24);
			new ConfigHeader(config.rootPanel, "- <color=#95f857><u>Folders</u></color>: The defaults follow the default organization of the base game, adjust if needed\n- <color=#95f857><u>Grid</u></color>:\n  - By default, the texture that has the closest color to the skybox will be chosen. To force a specific tile for a certain skybox, name it exactly the same except the file extension. Example: Skybox is SpAcE.png or SpAcE.cgvsb -> Matching grid is SpAcE.jpg or SpAcE.png\n  - You can create grid sets by adding \"_base\", \"_top\", \"_topRow\" at the end of each texture (and make sure they're of same file extension), for example \"griddy_base.png\", \"griddy_top.png\", and \"griddy_topRow.png\" are always loaded together.\n- <color=#95f857><u>Glow</u></color>: You can also match with skybox with precise file naming like grids, but other than that it's random\n- <color=#95f857><u>Volumetric skyboxes</u></color>: Can be used, but they cause Slideshow to be inconsistent in dominant color detection & grid swapping, so they're disabled by default.", 13, (TextAlignmentOptions)513);
			new ConfigHeader(config.rootPanel, "Quick open", 18, (TextAlignmentOptions)513);
			ButtonArrayField val = new ButtonArrayField(config.rootPanel, "openDirButtons", 3, new float[3] { 0.33f, 0.33f, 0.33f }, new string[3] { "Skybox folder", "Grid folder", "Glow folder" }, 10f);
			val.OnClickEventHandler(0).onClick += (OnClick)delegate
			{
				Application.OpenURL(SkyboxDir.value);
			};
			val.OnClickEventHandler(1).onClick += (OnClick)delegate
			{
				Application.OpenURL(GridDir.value);
			};
			val.OnClickEventHandler(2).onClick += (OnClick)delegate
			{
				Application.OpenURL(GlowDir.value);
			};
			new ConfigHeader(config.rootPanel, "", 10);
			new ConfigHeader(config.rootPanel, "-- <color=#69fff7>GENERAL</color> --", 24);
			ThemeChangeWaveInterval = new IntField(config.rootPanel, "Change theme every x wave, where x=", "themeChangeWaveInterval", 1);
			ThemeChangeWhenMusicChanges = new BoolField(config.rootPanel, "Change theme when music changes", "themeChangeWhenMusicChanges", false);
			new ConfigHeader(config.rootPanel, "", 10);
			new ConfigHeader(config.rootPanel, "-- <color=#55bcec>SKYBOX</color> --", 24);
			SkyboxEnabled = new BoolField(config.rootPanel, "Change skybox", "skyboxEnabled", true);
			SkyboxDir = new StringField(config.rootPanel, "Skybox folder", "skyboxDir", SkyboxesPath);
			SkyboxDirRecursive = new BoolField(config.rootPanel, "Consider subfolders", "skyboxDirRecursive", false);
			SkyboxChangeOrder = new EnumField<SelectionMode>(config.rootPanel, "Skybox change order", "skyboxChangeOrder", SelectionMode.Random);
			SkyboxAllowVolumetric = new BoolField(config.rootPanel, "Allow volumetric skyboxes", "skyboxAllowVolumetric", false);
			ForceDisableVolumetricSkyboxGridTexture = new BoolField(config.rootPanel, "Disallow grid change from volumetric skyboxes", "forceDisableVolumetricSkyboxGridTexture", false);
			new ConfigHeader(config.rootPanel, "", 10);
			new ConfigHeader(config.rootPanel, "-- <color=#f1c40f>LIGHTING</color> --", 24);
			LightingEnabled = new BoolField(config.rootPanel, "Sync with skybox", "lightingEnabled", true);
			LightingIntensity = new FloatField(config.rootPanel, "Lighting intensity", "lightingIntensity", 5f);
			LightingAdjustment = new BoolField(config.rootPanel, "Adjust intensity based on lightness", "lightingAdjustment", true);
			new ConfigHeader(config.rootPanel, "", 10);
			new ConfigHeader(config.rootPanel, "-- <color=#9c87f4>GRID</color> --", 24);
			GridEnabled = new BoolField(config.rootPanel, "Change grid", "gridEnabled", true);
			GridDir = new StringField(config.rootPanel, "Grid folder", "gridDir", GridPath);
			GridDirRecursive = new BoolField(config.rootPanel, "Consider subfolders", "gridDirRecursive", false);
			GridSelectionMode = new EnumField<SecondarySelectionMode>(config.rootPanel, "Grid selection mode", "gridSelectionMode", SecondarySelectionMode.ClosestColorToSkybox);
			new ConfigHeader(config.rootPanel, "", 10);
			new ConfigHeader(config.rootPanel, "-- <color=#f77428>GLOW</color> --", 24);
			GlowEnabled = new BoolField(config.rootPanel, "Change glow", "glowEnabled", true);
			GlowDir = new StringField(config.rootPanel, "Glow folder", "growDir", GlowPath);
			GlowDirRecursive = new BoolField(config.rootPanel, "Consider subfolders", "glowDirRecursive", false);
			GlowSelectionMode = new EnumField<MonochromeSelectionMode>(config.rootPanel, "Glow selection mode", "glowSelectionMode", MonochromeSelectionMode.Independent);
			new ConfigHeader(config.rootPanel, "", 10);
			new ConfigHeader(config.rootPanel, "-- DEBUG --", 24);
			ConfigPanel val2 = new ConfigPanel(config.rootPanel, "Developer options", "devOptions");
			new ConfigHeader(val2, "", 10);
			new ConfigHeader(val2, "These don't do anything exciting. Don't bother.", 13);
			LastVersion = new StringField(val2, "Last version", "lastVersion", "0.0.0");
		}
	}
	public static class JukeboxHelper
	{
		private static JukeboxMusicPlayer? _cachedCustomMusicPlayer;

		public static AudioClip? GetCurrentAudioClip()
		{
			if ((Object)(object)_cachedCustomMusicPlayer == (Object)null)
			{
				_cachedCustomMusicPlayer = Object.FindObjectOfType<JukeboxMusicPlayer>();
				if ((Object)(object)_cachedCustomMusicPlayer == (Object)null)
				{
					return null;
				}
			}
			return _cachedCustomMusicPlayer.Source.clip;
		}

		public static void ResetCache()
		{
			_cachedCustomMusicPlayer = null;
		}
	}
	public static class PlaylistListener
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static PostBoolValueChangeEvent <>9__3_0;

			public static UnityAction<Scene, LoadSceneMode> <>9__3_1;

			internal void <Initialize>b__3_0(bool val)
			{
				_listening = val;
			}

			internal void <Initialize>b__3_1(Scene _, LoadSceneMode __)
			{
				_cachedCustomMusicPlayer = null;
				if (Plugin.JukeboxAvailable)
				{
					JukeboxHelper.ResetCache();
				}
			}
		}

		private static bool _listening;

		private static CustomMusicPlayer? _cachedCustomMusicPlayer;

		private static AudioClip? _lastClip;

		public static void Initialize()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			_listening = ConfigManager.ThemeChangeWhenMusicChanges.value;
			BoolField themeChangeWhenMusicChanges = ConfigManager.ThemeChangeWhenMusicChanges;
			object obj = <>c.<>9__3_0;
			if (obj == null)
			{
				PostBoolValueChangeEvent val = delegate(bool listening)
				{
					_listening = listening;
				};
				<>c.<>9__3_0 = val;
				obj = (object)val;
			}
			themeChangeWhenMusicChanges.postValueChangeEvent += (PostBoolValueChangeEvent)obj;
			SceneManager.sceneLoaded += delegate
			{
				_cachedCustomMusicPlayer = null;
				if (Plugin.JukeboxAvailable)
				{
					JukeboxHelper.ResetCache();
				}
			};
		}

		private static AudioClip? GetCurrentVanillaAudioClip()
		{
			if ((Object)(object)_cachedCustomMusicPlayer == (Object)null)
			{
				_cachedCustomMusicPlayer = Object.FindObjectOfType<CustomMusicPlayer>();
				if ((Object)(object)_cachedCustomMusicPlayer == (Object)null)
				{
					return null;
				}
			}
			return _cachedCustomMusicPlayer.source.clip;
		}

		public static void OnUpdate()
		{
			if (_listening)
			{
				AudioClip val = (Plugin.JukeboxAvailable ? JukeboxHelper.GetCurrentAudioClip() : GetCurrentVanillaAudioClip());
				if ((Object)(object)val != (Object)(object)_lastClip)
				{
					ThemeChanger.ChangeTheme();
					_lastClip = val;
				}
			}
		}
	}
	[BepInPlugin("com.github.end-4.cybergrindSlideshow", "CybergrindSlideshow", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(EndlessGrid))]
		[HarmonyPatch("NextWave")]
		public class EndlessGridPatch
		{
			public static void Prefix()
			{
				try
				{
					ThemeChanger.SetupFirstWaveIfNecessary();
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)ex);
				}
			}

			public static void Postfix()
			{
				ThemeChanger.ChangeTheme();
			}
		}

		[HarmonyPatch(typeof(EndlessGrid))]
		[HarmonyPatch("Start")]
		public class EndlessGridStart
		{
			public static void Postfix()
			{
				ThemeChanger.SetupScene();
			}
		}

		internal static ManualLogSource Log;

		public static string workingPath = Assembly.GetExecutingAssembly().Location;

		public static string workingDir = Path.GetDirectoryName(workingPath);

		public const string PluginGUID = "com.github.end-4.cybergrindSlideshow";

		public const string PluginName = "CybergrindSlideshow";

		public const string PluginVersion = "1.2.0";

		internal static bool VolumetricAvailable = false;

		internal static bool JukeboxAvailable = false;

		private void Awake()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigManager.Initialize();
			UserHints.Initialize();
			new Harmony("CybergrindSlideshow").PatchAll();
			Log.LogInfo((object)"CybergrindSlideshow loaded");
		}

		private void Start()
		{
			if (Chainloader.PluginInfos.ContainsKey("dev.flazhik.volumetric-skyboxes"))
			{
				VolumetricAvailable = true;
			}
			if (Chainloader.PluginInfos.ContainsKey("dev.flazhik.jukebox"))
			{
				JukeboxAvailable = true;
			}
			Log.LogInfo((object)$"Volumetric available: {VolumetricAvailable}");
			Log.LogInfo((object)$"Jukebox available: {JukeboxAvailable}");
			PlaylistListener.Initialize();
		}

		private void Update()
		{
			if (!(SceneHelper.CurrentScene != "Endless"))
			{
				PlaylistListener.OnUpdate();
			}
		}
	}
	public static class ThemeChanger
	{
		private record struct GridSet
		{
			public string Top;

			public string Base;

			public string TopRow;

			public static GridSet FromSingleFile(string filePath)
			{
				string fileExt = Path.GetExtension(filePath);
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
				string baseDir = Path.GetDirectoryName(filePath) ?? "";
				string baseName = Regex.Replace(fileNameWithoutExtension, "(base|topRow|toprow|top)$", "");
				(string, string[])[] obj = new(string, string[])[3]
				{
					("Top", new string[2] { "top", "TOP" }),
					("Base", new string[2] { "base", "BASE" }),
					("TopRow", new string[4] { "topRow", "toprow", "TOPROW", "TOP ROW" })
				};
				string text = (File.Exists(GetPath("")) ? GetPath("") : filePath);
				GridSet result = default(GridSet);
				(string, string[])[] array = obj;
				for (int i = 0; i < array.Length; i++)
				{
					(string, string[]) tuple = array[i];
					string text2 = text;
					string[] item = tuple.Item2;
					for (int j = 0; j < item.Length; j++)
					{
						string text3 = GetPath(item[j]);
						if (File.Exists(text3))
						{
							text2 = text3;
							break;
						}
					}
					switch (tuple.Item1)
					{
					case "Top":
						result.Top = text2;
						break;
					case "Base":
						result.Base = text2;
						break;
					case "TopRow":
						result.TopRow = text2;
						break;
					}
				}
				return result;
				string GetPath(string suffix)
				{
					return Path.Join(baseDir.AsSpan(), (baseName + suffix + fileExt).AsSpan());
				}
			}

			public static GridSet FromPrefs()
			{
				PrefsManager instance = MonoSingleton<PrefsManager>.Instance;
				GridSet result = default(GridSet);
				if ((Object)(object)instance == (Object)null)
				{
					return result;
				}
				result.Top = instance.GetStringLocal("cyberGrind.customGrid_1", (string)null);
				result.TopRow = instance.GetStringLocal("cyberGrind.customGrid_2", (string)null);
				result.Base = instance.GetStringLocal("cyberGrind.customGrid_0", (string)null);
				return result;
			}
		}

		private static string LastSkyboxPath = "";

		private static Color CachedSkyboxColor = Color.black;

		private static CustomTextures? CustomTexObj;

		private static GameObject LightObj;

		private static Light LightComp;

		private static Dictionary<string, string[]> DirectoryCache = new Dictionary<string, string[]>();

		private static Dictionary<string, Color> DominantColorCache = new Dictionary<string, Color>();

		private static readonly string[] ImageExtensions = new string[3] { ".jpg", ".jpeg", ".png" };

		private static readonly string[] AudioExtensions = new string[3] { ".mp3", ".wav", ".ogg" };

		private static readonly string[] GridFaceSuffixes = new string[12]
		{
			"", "base", "top", "topRow", "toprow", "_base", "_top", "_topRow", "_toprow", "_BASE",
			"_TOP", "_TOP ROW"
		};

		private static bool FirstWaveChange = true;

		private static int wavesPassed = 0;

		private static bool IsVolumetricSkybox(string filePath)
		{
			return filePath.EndsWith(".cgvsb");
		}

		private static Color GetDominantColorCached(string cacheKey, Texture2D? tex)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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)
			//IL_002d: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)tex == (Object)null)
			{
				return Color.black;
			}
			if (DominantColorCache.TryGetValue(cacheKey, out var value))
			{
				return value;
			}
			Color dominantColor = ImageUtils.GetDominantColor(tex);
			DominantColorCache[cacheKey] = dominantColor;
			return dominantColor;
		}

		private static string SelectFile(string folderPath, ConfigManager.SelectionMode selectionMode, string[] allowedExtensions, bool recursive = false)
		{
			if (!Directory.Exists(folderPath))
			{
				return "";
			}
			string key = folderPath + "_" + recursive;
			if (!DirectoryCache.TryGetValue(key, out string[] value))
			{
				SearchOption searchOption = (recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
				value = (from file in Directory.EnumerateFiles(folderPath, "*.*", searchOption)
					where allowedExtensions.Contains<string>(Path.GetExtension(file), StringComparer.OrdinalIgnoreCase)
					select file).ToArray();
				DirectoryCache[key] = value;
			}
			if (value.Length == 0)
			{
				return "";
			}
			int num = 0;
			num = selectionMode switch
			{
				ConfigManager.SelectionMode.Random => Random.Range(0, value.Length), 
				_ => MonoSingleton<EndlessGrid>.Instance.currentWave % value.Length, 
			};
			if (value[num] == LastSkyboxPath)
			{
				num = (num + 1) % value.Length;
			}
			return LastSkyboxPath = value[num];
		}

		private static string SelectSkyboxFile(string folderPath, ConfigManager.SelectionMode selectionMode)
		{
			return SelectFile(folderPath, selectionMode, (!Plugin.VolumetricAvailable || !ConfigManager.SkyboxAllowVolumetric.value) ? new string[3] { ".jpg", ".jpeg", ".png" } : new string[4] { ".jpg", ".jpeg", ".png", ".cgvsb" }, ConfigManager.SkyboxDirRecursive.value);
		}

		private static string SelectGridFile(string folderPath, ConfigManager.SelectionMode selectionMode, bool recursive)
		{
			return SelectFile(folderPath, selectionMode, new string[3] { ".jpg", ".jpeg", ".png" }, recursive);
		}

		private static string SelectMatchingFile(string searchDir, string baseFilePath, string[] suffixes, string[] extensions)
		{
			string text = Path.GetFileNameWithoutExtension(baseFilePath).Trim();
			foreach (string text2 in suffixes)
			{
				foreach (string text3 in extensions)
				{
					string text4 = Path.Join(searchDir.AsSpan(), (text + text2 + text3).AsSpan());
					if (File.Exists(text4))
					{
						return text4;
					}
				}
			}
			return "";
		}

		private static async Task ChangeSkybox(string filePath)
		{
			Plugin.Log.LogInfo((object)("Skybox -> " + filePath));
			Material mat = ReflectionUtils.GetPrivate<Material>((object)(OutdoorLightMaster)Object.FindObjectsOfType(typeof(OutdoorLightMaster))[0], "skyboxMaterial");
			Material mat2 = ReflectionUtils.GetPrivate<Material>((object)(OutdoorLightMaster)Object.FindObjectsOfType(typeof(OutdoorLightMaster))[0], "tempSkybox");
			if (Plugin.VolumetricAvailable)
			{
				VolumetricSkyboxHelper.UnloadAllVolumetricSkyboxes();
			}
			if (IsVolumetricSkybox(filePath))
			{
				try
				{
					string guid = VolumetricSkyboxHelper.GuidForVolumetricSkyboxFile(filePath);
					if (Plugin.VolumetricAvailable)
					{
						VolumetricSkyboxHelper.LoadVolumetricSkybox(guid);
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)ex);
				}
			}
			else
			{
				Texture2D mainTexture = (Texture2D)(object)(mat.mainTexture = (Texture)(object)(await FileAssetHelper.LoadTextureAsync(filePath)));
				mat2.mainTexture = (Texture)(object)mainTexture;
			}
			if (ConfigManager.GridSelectionMode.value == ConfigManager.SecondarySelectionMode.ClosestColorToSkybox || ConfigManager.LightingEnabled.value)
			{
				try
				{
					Texture mainTexture2 = mat.mainTexture;
					CachedSkyboxColor = GetDominantColorCached(filePath, (Texture2D?)(((object)((mainTexture2 is Texture2D) ? mainTexture2 : null)) ?? ((object)(/*isinst with value type is only supported in some contexts*/ ?? null))));
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("Failed to get dominant color: " + ex2.Message));
				}
			}
		}

		private static async void ChangeTechnicalGridTexture(string[] files, string textureName)
		{
			if ((Object)(object)CustomTexObj == (Object)null)
			{
				Plugin.Log.LogWarning((object)"CustomTextures not found");
				return;
			}
			if ((Object)(object)((Component)CustomTexObj).gameObject != (Object)null && !((Component)CustomTexObj).gameObject.activeSelf)
			{
				((Component)CustomTexObj).gameObject.SetActive(true);
			}
			Material[] mats = ReflectionUtils.GetPrivate<Material[]>((object)CustomTexObj, "gridMaterials");
			if (mats == null)
			{
				Plugin.Log.LogWarning((object)"CustomTextures::gridMaterials not found");
				return;
			}
			for (int i = 0; i < files.Length && i < mats.Length; i++)
			{
				string text = files[i];
				if (File.Exists(text))
				{
					Material val = mats[i];
					val.SetTexture(textureName, (Texture)(object)(await FileAssetHelper.LoadTextureAsync(text)));
				}
			}
		}

		private static async void ChangeGridTexture(GridSet gridSet)
		{
			ChangeTechnicalGridTexture(new string[3] { gridSet.Base, gridSet.Top, gridSet.TopRow }, "_MainTex");
		}

		private static void ChangeGlowTexture(GridSet gridSet)
		{
			ChangeTechnicalGridTexture(new string[3] { gridSet.Base, gridSet.Top, gridSet.TopRow }, "_EmissiveTex");
		}

		private static async void ChangeGrid(string skyboxFilePath)
		{
			GridSet gridSet = default(GridSet);
			string text = SelectMatchingFile(ConfigManager.GridDir.value, skyboxFilePath, GridFaceSuffixes, ImageExtensions);
			if (text != "")
			{
				gridSet = GridSet.FromSingleFile(text);
			}
			else
			{
				switch (ConfigManager.GridSelectionMode.value)
				{
				case ConfigManager.SecondarySelectionMode.Independent:
					text = SelectGridFile(ConfigManager.GridDir.value, ConfigManager.SkyboxChangeOrder.value, ConfigManager.GridDirRecursive.value);
					gridSet = GridSet.FromSingleFile(text);
					break;
				case ConfigManager.SecondarySelectionMode.StrictlyMatchSkyboxName:
					gridSet = GridSet.FromPrefs();
					break;
				case ConfigManager.SecondarySelectionMode.ClosestColorToSkybox:
				{
					Color targetColor = CachedSkyboxColor;
					await Task.Yield();
					gridSet = GridSet.FromSingleFile(ImageUtils.FindClosestColorImage(targetColor, ConfigManager.GridDir.value));
					break;
				}
				}
			}
			Plugin.Log.LogInfo((object)("Grid   -> " + gridSet.Base + "\n          + " + gridSet.Top + "\n          + " + gridSet.TopRow));
			ChangeGridTexture(gridSet);
		}

		private static void ChangeLighting(string skyboxFilePath)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			OutdoorLightMaster instance = MonoSingleton<OutdoorLightMaster>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			foreach (Light item in (from light in ((Component)instance).gameObject.GetComponentsInChildren<Light>()
				where (int)light.type == 1
				select light).ToList())
			{
				item.color = CachedSkyboxColor;
				float num = (ConfigManager.LightingAdjustment.value ? (1f + 0.39999998f * ColorUtils.PerceivedLightness(CachedSkyboxColor)) : 1f);
				item.intensity = ConfigManager.LightingIntensity.value * num;
			}
		}

		private static async void ChangeGlow(string skyboxFilePath)
		{
			string text = SelectMatchingFile(ConfigManager.GlowDir.value, skyboxFilePath, GridFaceSuffixes, ImageExtensions);
			if (text == "" && ConfigManager.GlowSelectionMode.value == ConfigManager.MonochromeSelectionMode.Independent)
			{
				text = SelectGridFile(ConfigManager.GlowDir.value, ConfigManager.SkyboxChangeOrder.value, ConfigManager.GlowDirRecursive.value);
			}
			ChangeGlowTexture(GridSet.FromSingleFile(text));
		}

		public static async Task ChangeTheme()
		{
			if (FirstWaveChange)
			{
				FirstWaveChange = false;
				return;
			}
			wavesPassed++;
			if (wavesPassed < ConfigManager.ThemeChangeWaveInterval.value)
			{
				return;
			}
			wavesPassed = 0;
			string filePath = SelectSkyboxFile(ConfigManager.SkyboxDir.value, ConfigManager.SkyboxChangeOrder.value);
			if (!(filePath == ""))
			{
				Plugin.Log.LogInfo((object)"---- New wave ----");
				await Task.Yield();
				if (ConfigManager.SkyboxEnabled.value)
				{
					await ChangeSkybox(filePath);
				}
				if (ConfigManager.LightingEnabled.value)
				{
					ChangeLighting(filePath);
				}
				if (ConfigManager.GridEnabled.value)
				{
					ChangeGrid(filePath);
				}
				if (ConfigManager.GlowEnabled.value)
				{
					ChangeGlow(filePath);
				}
			}
		}

		public static void SetupScene()
		{
			FirstWaveChange = true;
			DirectoryCache.Clear();
			DominantColorCache.Clear();
		}

		public static void SetupFirstWaveIfNecessary()
		{
			if ((Object)(object)CustomTexObj == (Object)null)
			{
				CustomTexObj = Object.Instantiate<GameObject>(((Component)Object.FindObjectOfType<CustomTextures>()).gameObject).GetComponent<CustomTextures>();
				Plugin.Log.LogInfo((object)"Duped CustomTextures");
			}
		}
	}
	internal static class UserHints
	{
		private static readonly Dictionary<string, string> VolumetricCopyActions;

		private static uint notificationId;

		private static void Hook()
		{
			NotificationSystem.ActionInvoked += OnActionInvoked;
			NotificationSystem.NotificationDeleted += OnNotificationDeleted;
		}

		private static void Unhook()
		{
			NotificationSystem.ActionInvoked -= OnActionInvoked;
			NotificationSystem.NotificationDeleted -= OnNotificationDeleted;
		}

		private static void OnActionInvoked(uint id, string actionIdentifier)
		{
			if (id == notificationId)
			{
				switch (actionIdentifier)
				{
				case "yes":
					CopyAndEnableCopyVolumetricSkyboxes();
					break;
				case "remind":
					ConfigManager.LastVersion.value = "0.0.0";
					break;
				}
				Unhook();
			}
		}

		private static void OnNotificationDeleted(uint id)
		{
			if (id == notificationId)
			{
				Unhook();
			}
		}

		private static void IssueFirstRunNoticeIfNecessary()
		{
			Version value = new Version(ConfigManager.LastVersion.value);
			if (new Version("1.1.0").CompareTo(value) == 1)
			{
				ConfigManager.LastVersion.value = "1.2.0";
				if (Plugin.VolumetricAvailable)
				{
					notificationId = NotificationSystem.NotifySend("<color=#9ccaed>Cybergrind Slideshow</color>", "1. Default settings should work, but configuration and usage notes are in <color=#55c7f6>Options > Plugin Config > Cybergrind Slideshow</color>\n2. Would you like to enable Volumetric skyboxes support (might be inconsistent) and copy them to the slideshow folder?", (Sprite)null, Path.Combine(Plugin.workingDir, "icon.png"), (Urgency)1, "CybergrindSlideshow", 0u, VolumetricCopyActions, 20000);
					Hook();
				}
				else
				{
					NotificationSystem.NotifySend("<color=#9ccaed>Cybergrind Slideshow</color>", "Default settings should work, but configuration and usage notes are in <color=#55c7f6>Options > Plugin Config > Cybergrind Slideshow</color>", (Sprite)null, Path.Combine(Plugin.workingDir, "icon.png"), (Urgency)1, "CybergrindSlideshow", 0u, (Dictionary<string, string>)null, 10000);
				}
			}
		}

		private static void OnSceneLoaded(Scene s, LoadSceneMode m)
		{
			if (SceneHelper.CurrentScene == "Endless")
			{
				IssueFirstRunNoticeIfNecessary();
			}
		}

		private static void CopyAndEnableCopyVolumetricSkyboxes()
		{
			ConfigManager.SkyboxAllowVolumetric.value = true;
			string volumetricSkyboxesPath = ConfigManager.VolumetricSkyboxesPath;
			string value = ConfigManager.SkyboxDir.value;
			string[] files = Directory.GetFiles(volumetricSkyboxesPath);
			foreach (string obj in files)
			{
				string fileName = Path.GetFileName(obj);
				string destFileName = Path.Combine(value, fileName);
				File.Copy(obj, destFileName, overwrite: true);
				Plugin.Log.LogInfo((object)("Copied: " + fileName));
			}
		}

		public static void Initialize()
		{
		}

		static UserHints()
		{
			VolumetricCopyActions = new Dictionary<string, string>
			{
				{ "yes", "Yes" },
				{ "no", "No" },
				{ "remind", "Remind me later" }
			};
			SceneManager.sceneLoaded += OnSceneLoaded;
		}
	}
	public static class VolumetricSkyboxHelper
	{
		public static void UnloadAllVolumetricSkyboxes()
		{
			VolumetricSkyboxesManager instance = MonoSingleton<VolumetricSkyboxesManager>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			Dictionary<string, VolumetricSkyboxContainer> dictionary = ReflectionUtils.GetPrivate<Dictionary<string, VolumetricSkyboxContainer>>((object)instance, "_skyboxes");
			if (dictionary == null)
			{
				return;
			}
			Dictionary<string, VolumetricSkyboxContainer>.KeyCollection keyCollection = dictionary?.Keys;
			if (keyCollection == null)
			{
				return;
			}
			foreach (string item in new List<string>(keyCollection))
			{
				if ((Object)(object)instance == (Object)null)
				{
					break;
				}
				instance.RemoveSkybox(item);
			}
		}

		public static void LoadVolumetricSkybox(string guid)
		{
			int num;
			if (!ConfigManager.ForceDisableVolumetricSkyboxGridTexture.value)
			{
				num = 0;
			}
			else
			{
				num = (MonoSingleton<PrefsManager>.Instance.GetBoolLocal("cyberGrind.volumetricSkyboxes.useSkyboxesGridTextures", true) ? 1 : 0);
				if (num != 0)
				{
					MonoSingleton<PrefsManager>.Instance.SetBoolLocal("cyberGrind.volumetricSkyboxes.useSkyboxesGridTextures", false);
				}
			}
			VolumetricSkyboxesManager instance = MonoSingleton<VolumetricSkyboxesManager>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.AddSkybox(guid);
			}
			if (num != 0)
			{
				MonoSingleton<PrefsManager>.Instance.SetBoolLocal("cyberGrind.volumetricSkyboxes.useSkyboxesGridTextures", true);
			}
		}

		public static VolumetricSkyboxBundleData UnpackFile(string filePath)
		{
			return SkyboxFileUtility.UnpackSkybox(filePath, false);
		}

		public static string GuidForVolumetricSkyboxFile(string filePath)
		{
			return UnpackFile(filePath).guid;
		}
	}
}