RUMBLE does not support other mod managers. If you want to use a manager, you must use the RUMBLE Mod Manager, a manager specifically designed for this game.
Decompiled source of AdvancedStructureSkins v1.2.1
Mods/AdvancedStructureSkins.dll
Decompiled 2 hours agousing 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); } } }