Decompiled source of AdvancedStructureSkins v1.2.1

Mods/AdvancedStructureSkins.dll

Decompiled 2 hours 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 AdvancedStructureSkins;
using AdvancedStructureSkins.API;
using AdvancedStructureSkins.Skins;
using AdvancedStructureSkins.Util;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppRUMBLE.Environment;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.MoveSystem;
using Il2CppRUMBLE.Players;
using Il2CppRUMBLE.Utilities;
using Il2CppSmartLocalization;
using Il2CppSystem;
using MelonLoader;
using MelonLoader.Utils;
using RumbleModUI;
using RumbleModdingAPI.RMAPI;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(ASS), "Advanced Structure Skins", "1.2.1", "Cxntrxl", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: MelonColor(255, 210, 180, 145)]
[assembly: MelonAuthorColor(255, 5, 210, 240)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("AdvancedStructureSkins")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AdvancedStructureSkins")]
[assembly: AssemblyTitle("AdvancedStructureSkins")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace AdvancedStructureSkins
{
	public static class ModInfo
	{
		public const string ModName = "Advanced Structure Skins";

		public const string ModVersion = "1.2.1";

		public const string ModAuthor = "Cxntrxl";

		public const string Description = "Allows custom shaders and skins to be applied to structures, and provides mod developers with a simple API for loading their own shaders.";
	}
	public class ASS : MelonMod
	{
		public static readonly Dictionary<string, ModSetting> Settings = new Dictionary<string, ModSetting>();

		public override void OnLateInitializeMelon()
		{
			((MelonBase)this).OnLateInitializeMelon();
			PersistentSettings.LoadSettings();
			SkinHandler.Init();
			UIHandler.Init();
			InputHandler.Init();
			AddInputs();
			ModDebug.AddInputs();
			LocalizationHandler.AddLocalizationKey("ASS.Notifications.BuggyBuild", "Advanced Structure Skins Warning!\nThis version is incomplete, Advanced Structure Skins may behave strangely.");
			Log("Advanced Structure Skins Initialized!");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			((MelonMod)this).OnSceneWasLoaded(buildIndex, sceneName);
			if (!(sceneName != "Gym") && !PersistentSettings.data.shownGraphicsNotification)
			{
				SlabManager instance = Singleton<SlabManager>.Instance;
				Nullable<int> val = default(Nullable<int>);
				instance.SpawnNotificationSlab("ASS.Notifications.BuggyBuild", ref val, (ControllerType)1, (Il2CppReferenceArray<Location>)null);
				PersistentSettings.data.shownGraphicsNotification = true;
				PersistentSettings.SaveSettings();
			}
		}

		private void AddInputs()
		{
			InputHandler.GetKeyDown((KeyCode)286, (Action)delegate
			{
				foreach (Structure item in Object.FindObjectsOfType<Structure>())
				{
					SkinHandler.ApplySkinTo(item);
				}
			});
			InputHandler.GetKeyHeld((KeyCode)287, (Action)delegate
			{
				CustomShaders.ClearCache();
				SkinHandler.ReloadTexturesFromFile();
			}, 3f);
		}

		public static void Log(object msg)
		{
			MelonLogger.Msg(msg);
		}

		public static void Warn(object msg)
		{
			MelonLogger.Warning(msg);
		}

		public static void Error(object msg)
		{
			MelonLogger.Error(msg);
		}
	}
}
namespace AdvancedStructureSkins.Skins
{
	[Serializable]
	public class MaterialPropertyOverrides
	{
		public List<MaterialPropertyOverride> overrides = new List<MaterialPropertyOverride>();
	}
	[Serializable]
	public class MaterialPropertyOverride
	{
		public string propertyName;

		public int propertyType;

		public Color colorValue;

		public float floatValue;

		public int intValue;

		public Vector4 vectorValue;

		public List<int> targetStructures = new List<int>();
	}
	public enum StructureType
	{
		Disc,
		Pillar,
		Ball,
		Cube,
		Wall,
		SmallRock,
		LargeRock
	}
	public static class SkinHandler
	{
		[HarmonyPatch(typeof(Structure), "OnFetchFromPool")]
		public static class StructureSpawnPatch
		{
			private static void Postfix(ref Structure __instance)
			{
				try
				{
					ApplySkinTo(__instance);
				}
				catch (Exception msg)
				{
					ASS.Log(msg);
				}
			}
		}

		private static readonly Dictionary<string, int> Types = new Dictionary<string, int>
		{
			{ "Disc", 0 },
			{ "Pillar", 1 },
			{ "Ball", 2 },
			{ "RockCube", 3 },
			{ "Wall", 4 },
			{ "SmallRock", 5 },
			{ "LargeRock", 6 },
			{ "StructureTarget", 0 },
			{ "DockedDisk", 0 },
			{ "PrisonedPillar", 1 },
			{ "BoulderBall", 2 },
			{ "CageCube", 3 },
			{ "WrappedWall", 4 }
		};

		private static readonly string[] TEXProperties = new string[4] { "Texture2D_2058E65A", "Texture2D_3812B1EC", "Texture2D_8F187FEF", "_Grounded_noise" };

		private static readonly string[] TEXTypes = new string[4] { "Normal", "Main", "Mat", "Grounded" };

		private static readonly string[] TEXPaths = new string[7] { "Skins/Disc/", "Skins/Pillar/", "Skins/Ball/", "Skins/Cube/", "Skins/Wall/", "Skins/SmallRock/", "Skins/LargeRock/" };

		private static List<SkinTextures>[] _textures = new List<SkinTextures>[7];

		private static readonly Random Random = new Random();

		public static void Init()
		{
			ReloadTexturesFromFile();
			ASS.Log("Structure Shaders passed loading");
		}

		public static void ReloadTexturesFromFile()
		{
			_textures = new List<SkinTextures>[7];
			for (int i = 0; i < _textures.Length; i++)
			{
				_textures[i] = new List<SkinTextures>();
				string text = Path.Combine(MelonEnvironment.UserDataDirectory, TEXPaths[i]);
				if (!Directory.Exists(text))
				{
					continue;
				}
				string[] directories = Directory.GetDirectories(text);
				if ((directories.Length == 0) | IsMultiTextureSingleSkin(directories))
				{
					if (!Path.GetFileName(text).StartsWith("_"))
					{
						_textures[i].Add(new SkinTextures(text));
					}
					continue;
				}
				string[] array = directories;
				foreach (string text2 in array)
				{
					if (!Path.GetFileName(text2).StartsWith("_"))
					{
						_textures[i].Add(new SkinTextures(text2));
					}
				}
			}
		}

		private static bool IsMultiTextureSingleSkin(string[] paths)
		{
			foreach (string path in paths)
			{
				if (!TEXTypes.Contains<string>(Path.GetFileName(path), StringComparer.OrdinalIgnoreCase))
				{
					return false;
				}
			}
			return true;
		}

		public static void ApplySkinTo(Structure structure)
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			if (!Types.Keys.Contains(((Object)((Component)structure).gameObject).name))
			{
				ASS.Warn("Found unsupported structure with name '" + ((Object)((Component)structure).gameObject).name + "'");
				return;
			}
			MeshRenderer meshRenderer = structure.meshRenderer;
			int num = Types[((Object)((Component)structure).gameObject).name];
			if ((Object)(object)meshRenderer == (Object)null)
			{
				ASS.Error("Could not find MeshRenderer on structure!");
				return;
			}
			if (!CustomShaders.IsInAnyCache("default_" + Types.Keys.ElementAt(num)))
			{
				Material val = new Material(((Renderer)meshRenderer).material)
				{
					hideFlags = (HideFlags)32
				};
				val.SetTexture("Texture2D_8F187FEF", (Texture)(object)Texture2D.blackTexture);
				CustomShaders.AddToCache("default_" + Types.Keys.ElementAt(num), val.shader, val);
			}
			bool flag = (bool)ASS.Settings["GlobalSkinEnabled"].SavedValue;
			string text = (string)ASS.Settings["GlobalSkinPath"].SavedValue;
			string text2 = (string)ASS.Settings[Types.Keys.ElementAt(num) + "SkinPath"].SavedValue;
			string text3 = (flag ? text : text2);
			if (text3 == "default")
			{
				text3 = "default_" + Types.Keys.ElementAt(num);
			}
			text3 = text3.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
			if (string.Equals(Path.GetFileName(text3), "random", StringComparison.OrdinalIgnoreCase))
			{
				string path = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins", text3);
				path = Path.GetDirectoryName(path);
				if (path != null)
				{
					string[] files = Directory.GetFiles(path, "*.bundle");
					text3 = files[Random.Next(files.Length)];
				}
				string relativeTo = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins");
				text3 = Path.GetRelativePath(relativeTo, text3);
			}
			ApplyTexturesTo(meshRenderer, num);
			ApplyShaderTo(meshRenderer, num, text3);
			ApplyOverridesTo(meshRenderer, num, text3);
		}

		private static void ApplyTexturesTo(MeshRenderer mr, int type)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			Material material = CustomShaders.GetMaterial("default_" + Types.Keys.ElementAt(type));
			MaterialPropertyBlock val = new MaterialPropertyBlock();
			((Renderer)mr).GetPropertyBlock(val);
			int index = Random.Next(_textures[type].Count);
			for (int i = 0; i < TEXProperties.Length; i++)
			{
				if (_textures[type].Count <= 0 || !_textures[type][index].HasTextureFor(i))
				{
					ApplyDefaultTexturesTo(val, material, i);
					continue;
				}
				Texture2D texture = _textures[type][index].GetTexture(i);
				val.SetTexture(TEXProperties[i], (Texture)(object)texture);
			}
			if (_textures[type].Count > 0 && _textures[type][index].HasTextureFor(1))
			{
				val.SetColor("Color_D943764B", Color.white);
			}
			else
			{
				val.SetColor("Color_D943764B", new Color(0.6901961f, 0.5568628f, 23f / 51f));
			}
			((Renderer)mr).SetPropertyBlock(val);
		}

		private static void ApplyDefaultTexturesTo(MaterialPropertyBlock properties, Material defaultMat, int textureIndex)
		{
			properties.SetTexture(TEXProperties[textureIndex], (Texture)(object)Texture2D.blackTexture);
			Texture texture = defaultMat.GetTexture(TEXProperties[textureIndex]);
			if (!((Object)(object)texture == (Object)null))
			{
				properties.SetTexture(TEXProperties[textureIndex], texture);
			}
		}

		private static void ApplyShaderTo(MeshRenderer mr, int type, string path)
		{
			Material material = CustomShaders.GetMaterial(path);
			if (!((Object)(object)material == (Object)null))
			{
				material.CopyMatchingPropertiesFromMaterial(((Renderer)mr).material);
				((Renderer)mr).material = material;
			}
		}

		private static void ApplyOverridesTo(MeshRenderer mr, int type, string path)
		{
			//IL_0062: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected I4, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if (path.Contains("default_"))
			{
				return;
			}
			List<MaterialPropertyOverride> overrides = CustomShaders.GetOverrides(path);
			if (overrides == null)
			{
				return;
			}
			foreach (MaterialPropertyOverride item in overrides)
			{
				if (item.targetStructures.Contains(type))
				{
					ShaderPropertyType val = (ShaderPropertyType)item.propertyType;
					ShaderPropertyType val2 = val;
					switch ((int)val2)
					{
					case 0:
						((Renderer)mr).material.SetColor(item.propertyName, item.colorValue);
						break;
					case 1:
						((Renderer)mr).material.SetVector(item.propertyName, item.vectorValue);
						break;
					case 2:
						((Renderer)mr).material.SetFloat(item.propertyName, item.floatValue);
						break;
					case 3:
						((Renderer)mr).material.SetFloat(item.propertyName, item.floatValue);
						break;
					case 5:
						((Renderer)mr).material.SetInt(item.propertyName, item.intValue);
						break;
					}
				}
			}
		}
	}
	public class SkinTextures
	{
		public string Name;

		private Texture2D[][] _textures = new Texture2D[4][];

		private static Random _random = new Random();

		private readonly string[] _texTypes = new string[4] { "Normal", "Main", "Mat", "Grounded" };

		public SkinTextures(string folderPath)
		{
			Name = Path.GetFileName(folderPath);
			_textures = LoadTexturesFromPath(folderPath);
		}

		private Texture2D[][] LoadTexturesFromPath(string folderPath)
		{
			Texture2D[][] array = new Texture2D[4][];
			for (int i = 0; i < array.Length; i++)
			{
				string path = Path.Combine(folderPath, _texTypes[i] + ".png");
				if (File.Exists(path))
				{
					array[i] = (Texture2D[])(object)new Texture2D[1];
					array[i][0] = LoadTexture(path, i);
					continue;
				}
				string path2 = Path.Combine(folderPath, _texTypes[i]);
				if (Directory.Exists(path2))
				{
					string[] files = Directory.GetFiles(path2);
					array[i] = (Texture2D[])(object)new Texture2D[files.Length];
					for (int j = 0; j < files.Length; j++)
					{
						array[i][j] = LoadTexture(files[j], i);
					}
				}
			}
			return array;
		}

		private Texture2D LoadTexture(string path, int textureType)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0055: 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_0063: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if (!File.Exists(path))
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2);
			byte[] array = File.ReadAllBytes(path);
			ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array));
			((Object)val).hideFlags = (HideFlags)61;
			if (textureType == 0)
			{
				Texture2D val2 = new Texture2D(((Texture)val).width, ((Texture)val).height, val.format, true, true);
				Color[] array2 = Il2CppArrayBase<Color>.op_Implicit((Il2CppArrayBase<Color>)(object)val.GetPixels());
				Color[] array3 = (Color[])(object)new Color[array2.Length];
				for (int i = 0; i < array2.Length; i++)
				{
					array3[i] = ((Color)(ref array2[i])).linear;
				}
				val2.SetPixels(Il2CppStructArray<Color>.op_Implicit(array3));
				((Object)val2).hideFlags = (HideFlags)61;
				val2.Apply();
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			return val;
		}

		public Texture2D GetTexture(int textureType)
		{
			if (_textures[textureType] == null)
			{
				ASS.Error("Requested SkinTexture type is null.");
				return null;
			}
			if (_textures[textureType].Length == 0)
			{
				ASS.Error("Requested SkinTexture type is empty.");
				return null;
			}
			int num = _random.Next(_textures[textureType].Length);
			if ((Object)(object)_textures[textureType][num] == (Object)null)
			{
				ASS.Error("Requested SkinTexture image is null");
				return null;
			}
			return _textures[textureType][num];
		}

		public bool HasTextureFor(int textureType)
		{
			if (_textures[textureType] == null)
			{
				return false;
			}
			return _textures[textureType].Length != 0;
		}
	}
}
namespace AdvancedStructureSkins.Util
{
	public static class PersistentSettings
	{
		public static SettingsDataV1 data;

		public static readonly string path = Path.Combine(MelonEnvironment.UserDataDirectory, "AdvancedStructureSkins", "Persistence.txt");

		public static void LoadSettings()
		{
			Dictionary<string, string> dictionary = LoadSettingsDictFromFile();
			int num = int.Parse(dictionary["version"]);
			int num2 = num;
			if (num2 == 1)
			{
				data = LoadSettingsV1(dictionary);
			}
			else
			{
				ASS.Warn("Persistent Settings failed to load or does not exist.");
			}
		}

		public static void SaveSettings()
		{
			SaveSettingsV1();
		}

		public static Dictionary<string, string> LoadSettingsDictFromFile()
		{
			if (!Directory.Exists(Path.GetDirectoryName(path)))
			{
				Directory.CreateDirectory(Path.GetDirectoryName(path));
			}
			if (!File.Exists(path))
			{
				return new Dictionary<string, string> { ["version"] = 1.ToString() };
			}
			string[] array = File.ReadAllText(path).Split(Environment.NewLine);
			Array.Resize(ref array, array.Length - 1);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string[] array2 = array;
			foreach (string text in array2)
			{
				string[] array3 = text.Split(": ");
				dictionary.Add(array3[0], array3[1]);
			}
			return dictionary;
		}

		public static SettingsDataV1 LoadSettingsV1(Dictionary<string, string> settings)
		{
			SettingsDataV1 result = new SettingsDataV1();
			Type typeFromHandle = typeof(SettingsDataV1);
			FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				if (settings.TryGetValue(fieldInfo.Name, out var value))
				{
					object value2 = Convert.ChangeType(value, fieldInfo.FieldType);
					fieldInfo.SetValueDirect(__makeref(result), value2);
				}
			}
			return result;
		}

		public static void SaveSettingsV1()
		{
			string text = "";
			FieldInfo[] fields = typeof(SettingsDataV1).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				text += $"{fieldInfo.Name}: {fieldInfo.GetValue(data)}{Environment.NewLine}";
			}
			File.WriteAllText(path, text);
		}
	}
	public struct SettingsDataV1
	{
		public int version;

		public bool shownGraphicsNotification;

		public string lastLoadedVersion;

		public bool useGlobalSkin;

		public string globalSkinPath;

		public string discSkinPath;

		public string pillarSkinPath;

		public string ballSkinPath;

		public string cubeSkinPath;

		public string wallSkinPath;

		public string smallRockSkinPath;

		public string boulderSkinPath;

		public SettingsDataV1()
		{
			version = 1;
			shownGraphicsNotification = false;
			lastLoadedVersion = "2.1.2";
			useGlobalSkin = true;
			globalSkinPath = "default";
			discSkinPath = "default";
			pillarSkinPath = "default";
			ballSkinPath = "default";
			cubeSkinPath = "default";
			wallSkinPath = "default";
			smallRockSkinPath = "default";
			boulderSkinPath = "default";
		}

		public void ApplyFromModUISettings(Dictionary<string, ModSetting> settings)
		{
			useGlobalSkin = (bool)settings["GlobalSkinEnabled"].SavedValue;
			globalSkinPath = (string)settings["GlobalSkinPath"].SavedValue;
			discSkinPath = (string)settings["DiscSkinPath"].SavedValue;
			pillarSkinPath = (string)settings["PillarSkinPath"].SavedValue;
			ballSkinPath = (string)settings["BallSkinPath"].SavedValue;
			cubeSkinPath = (string)settings["RockCubeSkinPath"].SavedValue;
			wallSkinPath = (string)settings["WallSkinPath"].SavedValue;
			smallRockSkinPath = (string)settings["SmallRockSkinPath"].SavedValue;
			boulderSkinPath = (string)settings["LargeRockSkinPath"].SavedValue;
		}

		public Dictionary<string, string> GetModSettings()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			dictionary.Add("Use Global Skin", useGlobalSkin.ToString());
			dictionary.Add("Global Skin Path", globalSkinPath);
			dictionary.Add("Disc Skin Path", discSkinPath);
			dictionary.Add("Pillar Skin Path", pillarSkinPath);
			dictionary.Add("Ball Skin Path", ballSkinPath);
			dictionary.Add("Cube Skin Path", cubeSkinPath);
			dictionary.Add("Wall Skin Path", wallSkinPath);
			dictionary.Add("SmallRock Skin Path", smallRockSkinPath);
			dictionary.Add("Boulder Skin Path", boulderSkinPath);
			return dictionary;
		}
	}
	public static class InputHandler
	{
		private static readonly List<KeyInput> KeyDown = new List<KeyInput>();

		private static readonly List<KeyHeldInput> KeyHeld = new List<KeyHeldInput>();

		private static readonly List<KeyInput> Key = new List<KeyInput>();

		private static readonly List<KeyInput> KeyUp = new List<KeyInput>();

		public static void Init()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			((MelonEventBase<LemonAction>)(object)MelonEvents.OnUpdate).Subscribe(new LemonAction(Update), 0, false);
		}

		public static void GetKeyDown(KeyCode key, Delegate action)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected I4, but got Unknown
			KeyDown.Add(new KeyInput((KeyCode[])(object)new KeyCode[1] { (KeyCode)(int)key }, action));
		}

		public static void GetKeyDown(KeyCode[] key, Delegate action)
		{
			KeyDown.Add(new KeyInput(key, action));
		}

		public static void GetKeyHeld(KeyCode key, Delegate action, float holdTime)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected I4, but got Unknown
			KeyHeld.Add(new KeyHeldInput((KeyCode[])(object)new KeyCode[1] { (KeyCode)(int)key }, action, holdTime));
		}

		public static void GetKeyHeld(KeyCode[] key, Delegate action, float holdTime)
		{
			KeyHeld.Add(new KeyHeldInput(key, action, holdTime));
		}

		public static void GetKey(KeyCode key, Delegate action)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected I4, but got Unknown
			Key.Add(new KeyInput((KeyCode[])(object)new KeyCode[1] { (KeyCode)(int)key }, action));
		}

		public static void GetKey(KeyCode[] key, Delegate action)
		{
			Key.Add(new KeyInput(key, action));
		}

		public static void GetKeyUp(KeyCode key, Delegate action)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected I4, but got Unknown
			KeyUp.Add(new KeyInput((KeyCode[])(object)new KeyCode[1] { (KeyCode)(int)key }, action));
		}

		public static void GetKeyUp(KeyCode[] key, Delegate action)
		{
			KeyUp.Add(new KeyInput(key, action));
		}

		private static void Update()
		{
			foreach (KeyInput item in KeyDown)
			{
				if (((IEnumerable<KeyCode>)item.key).All((Func<KeyCode, bool>)Input.GetKey) && ((IEnumerable<KeyCode>)item.key).Any((Func<KeyCode, bool>)Input.GetKeyDown))
				{
					item.action.DynamicInvoke();
				}
			}
			foreach (KeyHeldInput item2 in KeyHeld)
			{
				if (((IEnumerable<KeyCode>)item2.key).All((Func<KeyCode, bool>)Input.GetKey))
				{
					item2.time += Time.deltaTime;
					if (item2.time >= item2.holdTime)
					{
						item2.time = -100f;
						item2.action.DynamicInvoke();
					}
				}
				if (((IEnumerable<KeyCode>)item2.key).Any((Func<KeyCode, bool>)Input.GetKeyUp))
				{
					item2.time = 0f;
				}
			}
			foreach (KeyInput item3 in Key)
			{
				if (((IEnumerable<KeyCode>)item3.key).All((Func<KeyCode, bool>)Input.GetKey))
				{
					item3.action.DynamicInvoke();
				}
			}
			foreach (KeyInput item4 in KeyUp)
			{
				if (((IEnumerable<KeyCode>)item4.key).All((Func<KeyCode, bool>)Input.GetKeyUp))
				{
					item4.action.DynamicInvoke();
				}
			}
		}
	}
	public class KeyInput
	{
		public KeyCode[] key;

		public Delegate action;

		protected KeyInput()
		{
		}

		public KeyInput(KeyCode[] key, Delegate action)
		{
			this.key = key;
			this.action = action;
		}
	}
	public class KeyHeldInput : KeyInput
	{
		public readonly float holdTime;

		public float time;

		public KeyHeldInput(KeyCode[] key, Delegate action, float holdTime)
		{
			base.key = key;
			base.action = action;
			this.holdTime = holdTime;
		}
	}
	public class LocalizationHandler
	{
		public static void AddLocalizationKey(string key, string value)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			LanguageManager.instance.RawTextDatabase.Add(key, value);
			LocalizedObject val = new LocalizedObject(LanguageManager.instance.LanguageDatabase["Rank.Mountain.Name"]);
			val.textValue = value;
			LanguageManager.instance.LanguageDatabase.Add(key, val);
		}
	}
	public class ModDebug
	{
		public static void AddInputs()
		{
			InputHandler.GetKeyDown((KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)308,
				(KeyCode)115
			}, new Action(CustomShaders.LogCache));
			InputHandler.GetKeyDown((KeyCode)290, new Action(LogPropertyNames));
			InputHandler.GetKeyDown((KeyCode)289, new Action(ScanForTextureReference));
			InputHandler.GetKeyDown((KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)308,
				(KeyCode)110
			}, new Action(ReplaceProperties));
		}

		private static void LogPropertyNames()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = ((IEnumerable<GameObject>)Object.FindObjectsOfType<GameObject>()).First((GameObject x) => ((Object)x.gameObject).name == "SmallRock");
			Material material = ((Renderer)val.GetComponentInChildren<MeshRenderer>()).material;
			for (int i = 0; i < 6; i++)
			{
				MaterialPropertyType val2 = (MaterialPropertyType)i;
				ASS.Log("[" + ((object)(MaterialPropertyType)(ref val2)).ToString() + "]: \n");
				foreach (string item in (Il2CppArrayBase<string>)(object)material.GetPropertyNames((MaterialPropertyType)i))
				{
					ASS.Log(item);
				}
			}
		}

		private static void ReplaceProperties()
		{
			foreach (Structure item in Object.FindObjectsOfType<Structure>())
			{
				((Renderer)item.meshRenderer).material.SetTexture("Texture2D_2058E65A", (Texture)(object)Texture2D.normalTexture);
				ASS.Log("Replaced textures for " + ((Object)((Component)item).gameObject).name);
			}
		}

		private static void ScanForTextureReference()
		{
			ASS.Log("[Texture Scan]: Starting...");
			Texture2D val = null;
			foreach (Texture2D item in Resources.FindObjectsOfTypeAll<Texture2D>())
			{
				if (((Object)item).name == "Largerock_Lighting")
				{
					val = item;
				}
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				ASS.Log("[Texture Scan]: Could not find Largerock_Lighting");
			}
			foreach (Material item2 in Resources.FindObjectsOfTypeAll<Material>())
			{
				foreach (string item3 in (Il2CppArrayBase<string>)(object)item2.GetTexturePropertyNames())
				{
					if ((Object)(object)item2.GetTexture(item3) == (Object)(object)val)
					{
						ASS.Log("[Texture Scan]: Found Largerock_Lighting on material \"" + ((Object)item2).name + "\"");
						ASS.Log("[Texture Scan]: Material shader is " + ((Object)item2.shader).name);
						ASS.Log("[Texture Scan]: Property name is \"" + item3 + "\"");
						return;
					}
				}
			}
		}
	}
	public class UIHandler
	{
		private static readonly Mod AssUI = new Mod();

		public static void Init()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			AssUI.ModName = "Advanced Structure Skins";
			AssUI.ModVersion = "1.2.1";
			AssUI.SetFolder("AdvancedStructureSkins");
			AssUI.AddDescription("Keybinds", "", "Press F5 to reload shaders on currently spawned structures. " + Environment.NewLine + "Press Left Alt + S to print cached structure skins data." + Environment.NewLine + "Press and Hold F6 for 3s to clear cached data.", new Tags());
			AddSetting("GlobalSkinEnabled", "Use Global Skin", defaultValue: true, 0, "Toggles on/off the global skin, allowing you to either select one skin for all structures or one skin per structure.");
			AddSetting("GlobalSkinPath", "Global Skin Path", "default", $"The path to the shader used by all structures if Global Skin is enabled. {Environment.NewLine}'myShader' maps to 'RUMBLE/UserData/Skins/myShader.bundle'.{Environment.NewLine}Enter 'default' to select the structure's default shader.{Environment.NewLine}{Environment.NewLine}Don't forget to press Enter after typing your shader path to save the value.{Environment.NewLine}The text box should say 'Current Value: myShader' before you hit save.");
			AddSetting("DiscSkinPath", "Disc Skin Path", "default", $"The path to the shader used by disc. {Environment.NewLine}'Disc/myShader' maps to 'RUMBLE/UserData/Skins/Disc/myShader.bundle'. {Environment.NewLine}Enter 'default' to select the structure's default shader.{Environment.NewLine}{Environment.NewLine}Don't forget to press Enter after typing your shader path to save the value.{Environment.NewLine}The text box should say 'Current Value: myShader' before you hit save.");
			AddSetting("PillarSkinPath", "Pillar Skin Path", "default", $"The path to the shader used by pillar. {Environment.NewLine}'Pillar/myShader' maps to 'RUMBLE/UserData/Skins/Pillar/myShader.bundle'. {Environment.NewLine}Enter 'default' to select the structure's default shader.{Environment.NewLine}{Environment.NewLine}Don't forget to press Enter after typing your shader path to save the value.{Environment.NewLine}The text box should say 'Current Value: myShader' before you hit save.");
			AddSetting("BallSkinPath", "Ball Skin Path", "default", $"The path to the shader used by ball. {Environment.NewLine}'Ball/myShader' maps to 'RUMBLE/UserData/Skins/Ball/myShader.bundle'. {Environment.NewLine}Enter 'default' to select the structure's default shader.{Environment.NewLine}{Environment.NewLine}Don't forget to press Enter after typing your shader path to save the value.{Environment.NewLine}The text box should say 'Current Value: myShader' before you hit save.");
			AddSetting("RockCubeSkinPath", "Cube Skin Path", "default", $"The path to the shader used by cube. {Environment.NewLine}'Cube/myShader' maps to 'RUMBLE/UserData/Skins/Cube/myShader.bundle'. {Environment.NewLine}Enter 'default' to select the structure's default shader.{Environment.NewLine}{Environment.NewLine}Don't forget to press Enter after typing your shader path to save the value.{Environment.NewLine}The text box should say 'Current Value: myShader' before you hit save.");
			AddSetting("WallSkinPath", "Wall Skin Path", "default", $"The path to the shader used by wall. {Environment.NewLine}'Wall/myShader' maps to 'RUMBLE/UserData/Skins/Wall/myShader.bundle'. {Environment.NewLine}Enter 'default' to select the structure's default shader.{Environment.NewLine}{Environment.NewLine}Don't forget to press Enter after typing your shader path to save the value.{Environment.NewLine}The text box should say 'Current Value: myShader' before you hit save.");
			AddSetting("SmallRockSkinPath", "SmallRock Skin Path", "default", $"The path to the shader used by the small rocks found in the gym. {Environment.NewLine}'SmallRock/myShader' maps to 'RUMBLE/UserData/Skins/SmallRock/myShader.bundle'. {Environment.NewLine}Enter 'default' to select the structure's default shader.{Environment.NewLine}{Environment.NewLine}Don't forget to press Enter after typing your shader path to save the value.{Environment.NewLine}The text box should say 'Current Value: myShader' before you hit save.");
			AddSetting("LargeRockSkinPath", "Boulder Skin Path", "default", $"The path to the shader used by boulders. {Environment.NewLine}'LargeRock/myShader' maps to 'RUMBLE/UserData/Skins/LargeRock/myShader.bundle'. {Environment.NewLine}Enter 'default' to select the structure's default shader.{Environment.NewLine}{Environment.NewLine}Don't forget to press Enter after typing your shader path to save the value.{Environment.NewLine}The text box should say 'Current Value: myShader' before you hit save.");
			AssUI.GetFromFile();
			UI.instance.UI_Initialized += delegate
			{
				UI.instance.AddMod(AssUI);
			};
			AssUI.ModSaved += SavePersistentModUISettings;
			if (PersistentSettings.data.lastLoadedVersion != AssUI.ModVersion)
			{
				PersistentSettings.data.lastLoadedVersion = AssUI.ModVersion;
				foreach (KeyValuePair<string, string> modSetting in PersistentSettings.data.GetModSettings())
				{
					AssUI.ChangeValue(modSetting.Key, modSetting.Value);
				}
				AssUI.SaveModData("Overwritten by Advanced Structure Skins v2.1.2");
			}
			SavePersistentModUISettings();
		}

		private static void AddSetting(string dictionaryKey, string name, string defaultValue, string description)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			ASS.Settings.Add(dictionaryKey, (ModSetting)(object)AssUI.AddToList(name, defaultValue, description, new Tags()));
		}

		private static void AddSetting(string dictionaryKey, string name, bool defaultValue, int linkGroup, string description)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			ASS.Settings.Add(dictionaryKey, (ModSetting)(object)AssUI.AddToList(name, defaultValue, linkGroup, description, new Tags()));
		}

		private static void SavePersistentModUISettings()
		{
			PersistentSettings.data.ApplyFromModUISettings(ASS.Settings);
			PersistentSettings.SaveSettings();
		}
	}
}
namespace AdvancedStructureSkins.API
{
	public static class CustomShaders
	{
		private static readonly Dictionary<string, string> CachedFilePaths = new Dictionary<string, string>();

		private static readonly Dictionary<string, Shader> CachedShaders = new Dictionary<string, Shader>();

		private static readonly Dictionary<string, Material> CachedMaterials = new Dictionary<string, Material>();

		private static readonly Dictionary<string, List<MaterialPropertyOverride>> CachedOverrides = new Dictionary<string, List<MaterialPropertyOverride>>();

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

		public static Shader GetShader(string bundleName)
		{
			if (CachedShaders.TryGetValue(bundleName, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if (!CachedBundles.TryGetValue(bundleName, out var value2) || (Object)(object)value2 == (Object)null)
			{
				string text = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins", bundleName + ".bundle");
				if (!File.Exists(text))
				{
					text = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins", bundleName);
					if (!File.Exists(text))
					{
						ASS.Warn("Shader bundle not found at path: " + text);
						return null;
					}
				}
				value2 = AssetBundles.LoadAssetBundleFromFile(text);
				if ((Object)(object)value2 == (Object)null)
				{
					ASS.Warn("Failed to load AssetBundle from: " + text);
					return null;
				}
				CachedBundles[bundleName] = value2;
				CachedFilePaths[bundleName] = text;
			}
			Shader val = value2.LoadAsset<Shader>("shader");
			if ((Object)(object)val == (Object)null)
			{
				ASS.Warn("Shader asset not found in bundle: " + bundleName);
				return null;
			}
			CachedShaders[bundleName] = val;
			return val;
		}

		public static Material GetMaterial(string bundleName)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			if (CachedMaterials.TryGetValue(bundleName, out var value) && (Object)(object)value != (Object)null)
			{
				return new Material(value);
			}
			if (!CachedBundles.TryGetValue(bundleName, out var value2) || (Object)(object)value2 == (Object)null)
			{
				string text = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins", bundleName + ".bundle");
				if (!File.Exists(text))
				{
					text = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins", bundleName);
					if (!File.Exists(text))
					{
						ASS.Warn("Shader bundle not found at path: " + text);
						return null;
					}
				}
				value2 = AssetBundles.LoadAssetBundleFromFile(text);
				if ((Object)(object)value2 == (Object)null)
				{
					ASS.Warn("Failed to load AssetBundle from: " + text);
					return null;
				}
				CachedBundles[bundleName] = value2;
				CachedFilePaths[bundleName] = text;
			}
			Material val = value2.LoadAsset<Material>("material");
			if ((Object)(object)val == (Object)null)
			{
				ASS.Warn("Material asset not found in bundle: " + bundleName);
				return null;
			}
			CachedMaterials[bundleName] = val;
			return new Material(val);
		}

		public static List<MaterialPropertyOverride> GetOverrides(string bundleName)
		{
			if (CachedOverrides.TryGetValue(bundleName, out var value) && value != null)
			{
				return value;
			}
			if (!CachedBundles.TryGetValue(bundleName, out var value2) || (Object)(object)value2 == (Object)null)
			{
				string text = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins", bundleName + ".bundle");
				if (!File.Exists(text))
				{
					text = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins", bundleName);
					if (!File.Exists(text))
					{
						ASS.Warn("Shader bundle not found at path: " + text);
						return null;
					}
				}
				value2 = AssetBundles.LoadAssetBundleFromFile(text);
				if ((Object)(object)value2 == (Object)null)
				{
					ASS.Warn("Failed to load AssetBundle from: " + text);
					return null;
				}
				CachedBundles[bundleName] = value2;
				CachedFilePaths[bundleName] = text;
			}
			TextAsset val = value2.LoadAsset<TextAsset>("overrides");
			if ((Object)(object)val == (Object)null)
			{
				ASS.Warn("Failed to load overrides from: " + bundleName);
			}
			List<MaterialPropertyOverride> overrides = ReadDataFile(val.text).overrides;
			if (overrides == null)
			{
				ASS.Warn("Material asset not found in bundle: " + bundleName);
				return null;
			}
			CachedOverrides[bundleName] = overrides;
			return overrides;
		}

		private static MaterialPropertyOverrides ReadDataFile(string data)
		{
			string[] array = data.Split("|");
			MaterialPropertyOverrides materialPropertyOverrides = new MaterialPropertyOverrides();
			int num = 0;
			while (num < array.Length - 1)
			{
				MaterialPropertyOverride materialPropertyOverride = new MaterialPropertyOverride
				{
					propertyName = array[num]
				};
				num++;
				materialPropertyOverride.propertyType = int.Parse(array[num]);
				num++;
				switch (materialPropertyOverride.propertyType)
				{
				case 0:
					materialPropertyOverride.colorValue.r = float.Parse(array[num]);
					materialPropertyOverride.colorValue.g = float.Parse(array[num + 1]);
					materialPropertyOverride.colorValue.b = float.Parse(array[num + 2]);
					materialPropertyOverride.colorValue.a = float.Parse(array[num + 3]);
					num += 4;
					break;
				case 1:
					materialPropertyOverride.floatValue = float.Parse(array[num]);
					num++;
					break;
				case 2:
					materialPropertyOverride.floatValue = float.Parse(array[num]);
					num++;
					break;
				case 3:
					materialPropertyOverride.intValue = int.Parse(array[num]);
					num++;
					break;
				case 4:
					materialPropertyOverride.vectorValue.x = float.Parse(array[num]);
					materialPropertyOverride.vectorValue.y = float.Parse(array[num + 1]);
					materialPropertyOverride.vectorValue.z = float.Parse(array[num + 2]);
					materialPropertyOverride.vectorValue.w = float.Parse(array[num + 3]);
					num += 4;
					break;
				}
				int num2 = int.Parse(array[num]);
				num++;
				for (int i = 0; i < num2; i++)
				{
					materialPropertyOverride.targetStructures.Add(int.Parse(array[num]));
					num++;
				}
				materialPropertyOverrides.overrides.Add(materialPropertyOverride);
			}
			return materialPropertyOverrides;
		}

		public static void AddToCache(string bundleName, Shader shader = null, Material material = null)
		{
			if ((Object)(object)shader == (Object)null && (Object)(object)material == (Object)null)
			{
				ASS.Warn("Please specify a shader or material to add to cache.");
				return;
			}
			if (IsInShaderCache(bundleName))
			{
				ASS.Warn("AddToCache Shader already exists in cache!");
			}
			else if ((Object)(object)shader != (Object)null)
			{
				CachedShaders[bundleName] = shader;
			}
			if (IsInMaterialCache(bundleName))
			{
				ASS.Warn("AddToCache Material already exists in cache!");
			}
			else if ((Object)(object)material != (Object)null)
			{
				CachedMaterials[bundleName] = material;
			}
		}

		public static bool IsInAnyCache(string bundleName)
		{
			Shader value;
			bool flag = CachedShaders.TryGetValue(bundleName, out value);
			Material value2;
			bool flag2 = CachedMaterials.TryGetValue(bundleName, out value2);
			return flag || flag2;
		}

		private static bool IsInShaderCache(string bundleName)
		{
			Shader value;
			return CachedShaders.TryGetValue(bundleName, out value);
		}

		private static bool IsInMaterialCache(string bundleName)
		{
			Material value;
			return CachedMaterials.TryGetValue(bundleName, out value);
		}

		public static void ClearCache(bool keepDefaults = true)
		{
			Dictionary<string, Shader> dictionary = new Dictionary<string, Shader>();
			Dictionary<string, Material> dictionary2 = new Dictionary<string, Material>();
			foreach (string key in CachedShaders.Keys)
			{
				if (key.Contains("default_"))
				{
					dictionary.Add(key, CachedShaders[key]);
				}
			}
			foreach (string key2 in CachedMaterials.Keys)
			{
				if (key2.Contains("default_"))
				{
					dictionary2.Add(key2, CachedMaterials[key2]);
				}
			}
			CachedFilePaths.Clear();
			CachedShaders.Clear();
			CachedMaterials.Clear();
			CachedOverrides.Clear();
			CachedBundles.Clear();
			if (!keepDefaults)
			{
				return;
			}
			foreach (string key3 in dictionary.Keys)
			{
				CachedShaders.Add(key3, dictionary[key3]);
			}
			foreach (string key4 in dictionary2.Keys)
			{
				CachedMaterials.Add(key4, dictionary2[key4]);
			}
		}

		public static void LogCache()
		{
			string text = "Cached Bundles";
			foreach (string key in CachedFilePaths.Keys)
			{
				text = text + "\nFile Path: " + CachedFilePaths[key];
				text = text + "\nBundle name: " + key;
				text += "\nBundle Contents: ";
				foreach (string item in (Il2CppArrayBase<string>)(object)CachedBundles[key].GetAllAssetNames())
				{
					text += "\n";
					text += item;
				}
				text += "\n\nLoaded Shader: ";
				text += ((Object)CachedShaders[key]).name;
			}
			ASS.Log(text);
		}
	}
}