Decompiled source of AdvancedStructureSkins v1.1.0

Mods/AdvancedStructureSkins.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppRUMBLE.Environment;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.MoveSystem;
using Il2CppRUMBLE.Players;
using Il2CppSmartLocalization;
using Il2CppSystem;
using MelonLoader;
using MelonLoader.Utils;
using RumbleModUI;
using RumbleModdingAPI;
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(AdvancedStructureSkins), "Advanced Structure Skins", "1.1.0", "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")]
public static class BuildInfo
{
	public const string ModName = "Advanced Structure Skins";

	public const string ModVersion = "1.1.0";

	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 AdvancedStructureSkins : MelonMod
{
	public SkinHandler Skins = new SkinHandler();

	public static Mod AssUI = new Mod();

	public static Dictionary<string, ModSetting> Settings = new Dictionary<string, ModSetting>();

	private float _clearCacheHoldTime = 0f;

	private const string SimpleShading = "Advanced Structure Skins Warning!\nYou're currently using RUMBLE's Simple Visual Settings. Advanced Structure Skins may behave strangely.";

	public override void OnLateInitializeMelon()
	{
		((MelonBase)this).OnLateInitializeMelon();
		PersistentSettings.LoadSettings();
		Skins.Init();
		UIInit();
		AddLocalizationKeys();
		Log("Advanced Structure Skins Initialized!");
	}

	public override void OnSceneWasLoaded(int buildIndex, string sceneName)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		((MelonMod)this).OnSceneWasLoaded(buildIndex, sceneName);
		if (!(sceneName != "Gym") && !PersistentSettings.data.shownGraphicsNotification)
		{
			QualityManager qualityManager = Managers.GetQualityManager();
			if (qualityManager.Config.QualityLevel <= 0)
			{
				SlabManager slabManager = Managers.GetSlabManager();
				Nullable<int> val = default(Nullable<int>);
				slabManager.SpawnNotificationSlab("ASS.Notifications.SimpleShading", ref val, (ControllerType)1, (Il2CppReferenceArray<Location>)null);
				PersistentSettings.data.shownGraphicsNotification = true;
				PersistentSettings.SaveSettings();
			}
		}
	}

	public override void OnUpdate()
	{
		((MelonBase)this).OnUpdate();
		if (Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)115))
		{
			CustomShaders.LogCache();
		}
		if (Input.GetKeyDown((KeyCode)286))
		{
			foreach (Structure item in Object.FindObjectsOfType<Structure>())
			{
				if (!item.isSceneStructure)
				{
					Skins.ApplySkinTo(item);
				}
			}
		}
		if (Input.GetKey((KeyCode)287))
		{
			_clearCacheHoldTime += Time.deltaTime;
			if (_clearCacheHoldTime >= 3f)
			{
				_clearCacheHoldTime = -100f;
				CustomShaders.ClearCache();
				Skins.ReloadTexturesFromFile();
			}
		}
		if (Input.GetKeyUp((KeyCode)287))
		{
			_clearCacheHoldTime = 0f;
		}
	}

	public void UIInit()
	{
		//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.1.0";
		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 v1.1.0");
		}
		SavePersistentModUISettings();
	}

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

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

	public void SavePersistentModUISettings()
	{
		PersistentSettings.data.ApplyFromModUISettings(Settings);
		PersistentSettings.SaveSettings();
	}

	public void AddLocalizationKeys()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		LanguageManager.instance.RawTextDatabase.Add("ASS.Notifications.SimpleShading", "Advanced Structure Skins Warning!\nYou're currently using RUMBLE's Simple Visual Settings. Advanced Structure Skins may behave strangely.");
		LocalizedObject val = new LocalizedObject(LanguageManager.instance.LanguageDatabase["Rank.Mountain.Name"]);
		val.textValue = "Advanced Structure Skins Warning!\nYou're currently using RUMBLE's Simple Visual Settings. Advanced Structure Skins may behave strangely.";
		LanguageManager.instance.LanguageDatabase.Add("ASS.Notifications.SimpleShading", val);
	}

	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);
	}
}
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))
				{
					AdvancedStructureSkins.Warn("Shader bundle not found at path: " + text);
					return null;
				}
			}
			value2 = Calls.LoadAssetBundleFromFile(text);
			if ((Object)(object)value2 == (Object)null)
			{
				AdvancedStructureSkins.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)
		{
			AdvancedStructureSkins.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))
				{
					AdvancedStructureSkins.Warn("Shader bundle not found at path: " + text);
					return null;
				}
			}
			value2 = Calls.LoadAssetBundleFromFile(text);
			if ((Object)(object)value2 == (Object)null)
			{
				AdvancedStructureSkins.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)
		{
			AdvancedStructureSkins.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))
				{
					AdvancedStructureSkins.Warn("Shader bundle not found at path: " + text);
					return null;
				}
			}
			value2 = Calls.LoadAssetBundleFromFile(text);
			if ((Object)(object)value2 == (Object)null)
			{
				AdvancedStructureSkins.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)
		{
			AdvancedStructureSkins.Warn("Failed to load overrides from: " + bundleName);
		}
		List<MaterialPropertyOverride> overrides = ReadDataFile(val.text).overrides;
		if (overrides == null)
		{
			AdvancedStructureSkins.Warn("Material asset not found in bundle: " + bundleName);
			return null;
		}
		CachedOverrides[bundleName] = overrides;
		return overrides;
	}

	public 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();
			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)
		{
			AdvancedStructureSkins.Warn("Please specify a shader or material to add to cache.");
			return;
		}
		if (IsInShaderCache(bundleName))
		{
			AdvancedStructureSkins.Warn("AddToCache Shader already exists in cache!");
		}
		else if ((Object)(object)shader != (Object)null)
		{
			CachedShaders[bundleName] = shader;
		}
		if (IsInMaterialCache(bundleName))
		{
			AdvancedStructureSkins.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;
	}

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

	public 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;
		}
		AdvancedStructureSkins.Log(text);
	}
}
public class SkinHandler
{
	[HarmonyPatch(typeof(Structure), "OnFetchFromPool")]
	public static class StructureSpawnPatch
	{
		private static void Postfix(ref Structure __instance)
		{
			try
			{
				if (!__instance.isSceneStructure)
				{
					Skins.ApplySkinTo(__instance);
				}
			}
			catch (Exception msg)
			{
				AdvancedStructureSkins.Log(msg);
			}
		}
	}

	private static readonly string[] Types = new string[7] { "Disc", "Pillar", "Ball", "RockCube", "Wall", "SmallRock", "LargeRock" };

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

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

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

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

	private readonly Random _rand = new Random();

	public static SkinHandler Skins;

	public void Init()
	{
		Skins = this;
		ReloadTexturesFromFile();
		AdvancedStructureSkins.Log("Structure Shaders passed loading");
	}

	public 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 bool IsMultiTextureSingleSkin(string[] paths)
	{
		foreach (string path in paths)
		{
			if (!_texTypes.Contains<string>(Path.GetFileName(path), StringComparer.OrdinalIgnoreCase))
			{
				return false;
			}
		}
		return true;
	}

	public void ApplySkinTo(Structure structure)
	{
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Expected O, but got Unknown
		if (!Types.Contains(((Object)((Component)structure).gameObject).name))
		{
			return;
		}
		MeshRenderer componentInChildren = ((Component)structure).GetComponentInChildren<MeshRenderer>();
		int num = Array.IndexOf(Types, ((Object)((Component)structure).gameObject).name);
		if (!Types.Contains(((Object)((Component)structure).gameObject).name))
		{
			AdvancedStructureSkins.Warn("Found unsupported structure with name '" + ((Object)((Component)structure).gameObject).name + "'");
			return;
		}
		if ((Object)(object)componentInChildren == (Object)null)
		{
			AdvancedStructureSkins.Error("Could not find MeshRenderer on structure!");
			return;
		}
		if (!CustomShaders.IsInAnyCache("default_" + Types[num]))
		{
			Material val = new Material(((Renderer)componentInChildren).material);
			((Object)val).hideFlags = (HideFlags)32;
			val.SetTexture("Texture2D_8F187FEF", (Texture)(object)Texture2D.blackTexture);
			CustomShaders.AddToCache("default_" + Types[num], val.shader, val);
		}
		bool flag = (bool)AdvancedStructureSkins.Settings["GlobalSkinEnabled"].SavedValue;
		string text = (string)AdvancedStructureSkins.Settings["GlobalSkinPath"].SavedValue;
		string text2 = (string)AdvancedStructureSkins.Settings[Types[num] + "SkinPath"].SavedValue;
		string text3 = (flag ? text : text2);
		if (text3 == "default")
		{
			text3 = "default_" + Types[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);
			string[] files = Directory.GetFiles(path, "*.bundle");
			text3 = files[_rand.Next(files.Length)];
			string relativeTo = Path.Combine(MelonEnvironment.UserDataDirectory, "Skins");
			text3 = Path.GetRelativePath(relativeTo, text3);
		}
		ApplyTexturesTo(componentInChildren, num);
		ApplyShaderTo(componentInChildren, num, text3);
		ApplyOverridesTo(componentInChildren, num, text3);
	}

	private void ApplyTexturesTo(MeshRenderer mr, int type)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		Material material = CustomShaders.GetMaterial("default_" + Types[type]);
		MaterialPropertyBlock val = new MaterialPropertyBlock();
		((Renderer)mr).GetPropertyBlock(val);
		int index = _rand.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);
		}
		((Renderer)mr).SetPropertyBlock(val);
	}

	private 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 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 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;
				}
			}
		}
	}
}
[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 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
		{
			AdvancedStructureSkins.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 = "1.1.0";
		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 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)
		{
			AdvancedStructureSkins.Error("Requested SkinTexture type is null.");
			return null;
		}
		if (_textures[textureType].Length == 0)
		{
			AdvancedStructureSkins.Error("Requested SkinTexture type is empty.");
			return null;
		}
		int num = _random.Next(_textures[textureType].Length);
		if ((Object)(object)_textures[textureType][num] == (Object)null)
		{
			AdvancedStructureSkins.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;
	}
}