using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using COTL_API.CustomEnemy; using COTL_API.CustomFollowerCommand; using COTL_API.CustomInventory; using COTL_API.CustomSkins; using COTL_API.CustomStructures; using COTL_API.CustomTarotCard; using COTL_API.Guid; using COTL_API.Helpers; using CustomSpineLoader.APIHelper; using CustomSpineLoader.Commands; using CustomSpineLoader.SpineLoaderHelper; using HarmonyLib; using Lamb.UI; using Lamb.UI.DeathScreen; using MMBiomeGeneration; using MMRoomGeneration; using MMTools; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Pathfinding; using Spine; using Spine.Unity; using Spine.Unity.AttachmentTools; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("CultTweaker")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+6ba6dd7a71f3b2d20d3065563c95237c021ae4aa")] [assembly: AssemblyProduct("CultTweaker")] [assembly: AssemblyTitle("CultTweaker")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CustomSpineLoader { [BepInPlugin("InfernoDragon0.cotl.CustomSpineLoader", "CultTweaker", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [HarmonyPatch] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "InfernoDragon0.cotl.CustomSpineLoader"; public const string PluginName = "CultTweaker"; public const string PluginVer = "1.1.0"; internal static ManualLogSource Log; internal static readonly Harmony Harmony = new Harmony("InfernoDragon0.cotl.CustomSpineLoader"); internal static string PluginPath; public static ConfigEntry CurrentFleeceIndexP1 { get; set; } public static ConfigEntry CurrentFleeceIndexP2 { get; set; } public static ConfigEntry DebugDumpFollowerSpineAtlas { get; set; } public static ConfigEntry FleeceCyclingEnabled { get; set; } private void Awake() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; PluginPath = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); PlayerSpineLoader.LoadAllPlayerSpines(); Log.LogInfo((object)"Cult Tweaker is loading! For more information or templates on how to use this mod, go to the NexusMods page!"); CustomFollowerCommandManager.Add((CustomFollowerCommand)(object)new CustomColorCommand()); StructureBuildingOverrideHelper.LoadBuildingOverrides(); Log.LogInfo((object)"Loading Custom Items..."); CustomItemLoader.LoadAllCustomItems(); Log.LogInfo((object)"Loading Custom Meals..."); CustomMealLoader.LoadAllCustomMeals(); Log.LogInfo((object)"Loading Custom Tarots..."); CustomTarotLoader.LoadAllCustomTarots(); Log.LogInfo((object)"Loading Custom Structures..."); CustomStructureLoader.LoadAllCustomStructures(); Log.LogInfo((object)"Loading Custom Follower Overrides..."); FollowerSpineLoader.LoadAllNonSpineSkins(); CurrentFleeceIndexP1 = ((BaseUnityPlugin)this).Config.Bind("Fleece", "CurrentFleeceIndexP1", -1, "Current Fleece Index for Player 1"); CurrentFleeceIndexP2 = ((BaseUnityPlugin)this).Config.Bind("Fleece", "CurrentFleeceIndexP2", -1, "Current Fleece Index for Player 2"); DebugDumpFollowerSpineAtlas = ((BaseUnityPlugin)this).Config.Bind("Debug", "DumpFollowerSpineAtlas", false, "If true, will dump the follower spine slots to a json file. May impact performance when enabled. Ensure followerSlots.json is not present before dumping."); FleeceCyclingEnabled = ((BaseUnityPlugin)this).Config.Bind("Fleece", "FleeceCyclingEnabled", true, "Enable Fleece Cycling for all players."); PlayerSpineLoader.currentFleeceIndexP1 = CurrentFleeceIndexP1.Value; PlayerSpineLoader.currentFleeceIndexP2 = CurrentFleeceIndexP2.Value; CustomDungeon customDungeon = new CustomDungeon(); BaseCustomEnemy baseCustomEnemy = new BaseCustomEnemy(); Enemy val = CustomEnemyManager.Add((CustomEnemy)(object)baseCustomEnemy); ((MonoBehaviour)this).StartCoroutine(CustomEnemyManager.BuildEnemyPrefab((CustomEnemy)(object)baseCustomEnemy)); customDungeon.NormalEnemyList.Add(val); Log.LogInfo((object)$"Custom Test Enemy added with type {val}, now size is {customDungeon.NormalEnemyList.Count}"); CustomDungeonManager.Add(customDungeon); } public void Update() { if (Input.GetKeyDown((KeyCode)290)) { Log.LogInfo((object)("Toggling Fleece Cycling to " + !FleeceCyclingEnabled.Value)); FleeceCyclingEnabled.Value = !FleeceCyclingEnabled.Value; if (!FleeceCyclingEnabled.Value && (Object)(object)PlayerFarming.Instance != (Object)null) { if (CoopManager.CoopActive) { PlayerFarming.players[1].SetSkin(); } PlayerFarming.Instance.SetSkin(); } else { TestApplySpineOverride(0, cycle: false); } } if (Input.GetKeyDown((KeyCode)288)) { Log.LogInfo((object)"F7 Pressed - Fleece Cycle Player 1"); TestApplySpineOverride(); } if (Input.GetKeyDown((KeyCode)289)) { Log.LogInfo((object)"F8 Pressed - Fleece Cycle Player 2"); TestApplySpineOverride(1); } if (Input.GetKeyDown((KeyCode)286)) { Log.LogInfo((object)"F5 Pressed - Test Custom Dungeon"); CustomDungeonManager.CustomDungeonList.Values.ElementAt(0).EnterDungeon(); } } private void TestApplySpineOverride(int playerID = 0, bool cycle = true) { if (!FleeceCyclingEnabled.Value) { Log.LogWarning((object)"Fleece Cycling is disabled, Press F9 to enable first!"); return; } int num = -1; if (cycle) { num = PlayerSpineLoader.CycleNextFleece(playerID); } else { if (1 == 0) { } int num2 = playerID switch { 0 => CurrentFleeceIndexP1.Value, 1 => CurrentFleeceIndexP2.Value, _ => -1, }; if (1 == 0) { } num = num2; } string text = PlayerSpineLoader.FleeceRotation[num]; Log.LogInfo((object)("Applying fleece skin: " + text)); SkeletonAnimation spine = PlayerFarming.Instance.Spine; if (playerID >= 1) { if (!CoopManager.CoopActive) { Log.LogInfo((object)"Coop not active, no fleece cycling"); return; } spine = PlayerFarming.players[1].Spine; CurrentFleeceIndexP2.Value = num; } else { CurrentFleeceIndexP1.Value = num; } Skin val; if (text.Contains("CultTweaker_")) { string[] array = text.Split(new char[1] { '_' }, 3); if (array.Length < 3) { Log.LogWarning((object)("Invalid custom fleece skin name: " + text)); return; } string text2 = array[1]; if (!PlayerSpineLoader.FleeceCyclingSpines.ContainsKey(text2)) { Log.LogWarning((object)("Invalid spine skin name: " + text + " for spine: " + text2)); return; } val = PlayerSpineLoader.FleeceCyclingSpines[text2].Item1.skeletonData.FindSkin(array[2]); if (val == null) { Log.LogWarning((object)("Defaulting to default as Custom Fleece skin not found: " + text)); val = ((SkeletonRenderer)spine).Skeleton.Data.FindSkin("Lamb"); } } else { val = ((SkeletonRenderer)spine).Skeleton.Data.FindSkin(text); } if ((Object)(object)spine == (Object)null || val == null) { Log.LogInfo((object)("Lamb skin was null after cycling, an error occurred! at skin name " + text)); return; } Skin skin = ((SkeletonRenderer)spine).Skeleton.Skin; foreach (var fleeceOverrideSlot in PlayerSpineLoader.FleeceOverrideSlots) { int num3 = ((SkeletonRenderer)spine).Skeleton.FindSlotIndex(fleeceOverrideSlot.Item1); Attachment attachment = val.GetAttachment(num3, fleeceOverrideSlot.Item2); Log.LogInfo((object)string.Format("Slot {0} index is {1}, attachment {2}", fleeceOverrideSlot.Item1, num3, (attachment != null) ? "found" : "not found")); if (attachment == null) { skin.RemoveAttachment(num3, fleeceOverrideSlot.Item2); } else { skin.SetAttachment(num3, fleeceOverrideSlot.Item2, attachment); } Log.LogInfo((object)("Applied " + fleeceOverrideSlot.Item2 + " attachment to current skin.")); } Log.LogInfo((object)("Applied" + text + " attachment to current skin.")); ((SkeletonRenderer)spine).Skeleton.SetSlotsToSetupPose(); spine.Update(0f, false); } private void OnEnable() { Harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded CultTweaker!"); } private void OnDisable() { Harmony.UnpatchSelf(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Unloaded CultTweaker!"); } } } namespace CustomSpineLoader.SpineLoaderHelper { public class CustomColorHelper { public static Dictionary CustomColors { get; private set; } = new Dictionary(); public static Dictionary CustomFollowerSkinConfigs { get; private set; } = new Dictionary(); public static void LoadCustomColors(int saveSlot) { if (!File.Exists(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json"))) { Plugin.Log.LogInfo((object)("Creating new CustomColors.json file for save slot " + saveSlot + ".")); string contents = JsonConvert.SerializeObject((object)CustomColors, (Formatting)1); File.WriteAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json"), contents); } else { string text = File.ReadAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json")); CustomColors = JsonConvert.DeserializeObject>(text) ?? new Dictionary(); } } public static void SaveCustomColors() { string contents = JsonConvert.SerializeObject((object)CustomColors, (Formatting)1); File.WriteAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{SaveAndLoad.SAVE_SLOT}.json"), contents); Plugin.Log.LogInfo((object)"Saved custom colors"); } public static CustomFollowerColor GetCustomColor(int id) { CustomFollowerColor value; return CustomColors.TryGetValue(id, out value) ? value : null; } public static float GetCustomScale(int id) { CustomFollowerColor value; return CustomColors.TryGetValue(id, out value) ? CustomColors[id].scale : (-1f); } public static void SetCustomColor(int id, float r, float g, float b, float a, float scale = 1f) { CustomFollowerColor value = new CustomFollowerColor(id, r, g, b, a, scale); CustomColors[id] = value; Plugin.Log.LogInfo((object)$"Set custom color for follower {id} to ({r}, {g}, {b}, {a}) with scale {scale}"); } public static void SetCustomCostume(int id, bool enabled, int FollowerClothingType, int FollowerSpecialType, int FollowerHatType, int FollowerOutfitType, int FollowerNecklaceType) { if (CustomColors.ContainsKey(id)) { CustomColors[id].CustomFollowerCostume = enabled; CustomColors[id].FollowerClothingType = FollowerClothingType; CustomColors[id].FollowerSpecialType = FollowerSpecialType; CustomColors[id].FollowerHatType = FollowerHatType; CustomColors[id].FollowerOutfitType = FollowerOutfitType; CustomColors[id].FollowerNecklaceType = FollowerNecklaceType; Plugin.Log.LogInfo((object)$"Set custom costume for follower {id} to ClothingType: {FollowerClothingType}, SpecialType: {FollowerSpecialType}, HatType: {FollowerHatType}, OutfitType: {FollowerOutfitType}"); } else { Plugin.Log.LogWarning((object)("Tried to set custom costume for follower " + id + " but no custom color exists. Enable Customization first.")); } } public static void RemoveCustomColor(int id) { if (CustomColors.ContainsKey(id)) { CustomColors.Remove(id); Plugin.Log.LogInfo((object)$"Removed custom color for follower {id}"); } } } [Serializable] public class CustomFollowerColor { public bool CustomFollowerCostume; public float scale; public int FollowerId { get; set; } public float R { get; set; } public float G { get; set; } public float B { get; set; } public float A { get; set; } public int FollowerClothingType { get; set; } public int FollowerSpecialType { get; set; } public int FollowerHatType { get; set; } public int FollowerOutfitType { get; set; } public int FollowerNecklaceType { get; set; } public CustomFollowerColor(int id, float r, float g, float b, float a, float scale = 1f) { FollowerId = id; R = Mathf.Clamp(r, 0f, 1f); G = Mathf.Clamp(g, 0f, 1f); B = Mathf.Clamp(b, 0f, 1f); A = Mathf.Clamp(a, 0f, 1f); CustomFollowerCostume = false; FollowerClothingType = 0; FollowerSpecialType = 0; FollowerHatType = 0; FollowerOutfitType = 0; FollowerNecklaceType = 0; this.scale = Mathf.Clamp(scale, 0.1f, 5f); base..ctor(); } } [Serializable] public class CustomFollowerSpineSkin { public string SpineName; public List SkinsApplied; } public class FollowerSpineLoader { public static Dictionary>> FollowerSkinOverrides = new Dictionary>>(); public static Dictionary> FollowerSlotColors = new Dictionary>(); public static Dictionary CustomFollowerSkins = new Dictionary(); public static void LoadAllFollowerSpines(Material material = null) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) string path = Path.Combine(Plugin.PluginPath, "FollowerSpines"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string[] directories = Directory.GetDirectories(path); string[] array = directories; foreach (string path2 in array) { string fileName = Path.GetFileName(path2); string[] array2 = (from x in Directory.GetFiles(path2, "*.json", SearchOption.TopDirectoryOnly) where !x.Contains("config") select x).ToArray(); string[] files = Directory.GetFiles(path2, "*.png", SearchOption.TopDirectoryOnly); string[] files2 = Directory.GetFiles(path2, "*.atlas", SearchOption.TopDirectoryOnly); string[] files3 = Directory.GetFiles(path2, "config.json", SearchOption.TopDirectoryOnly); List list = new List(1) { "Cat" }; string[] array3 = new string[0]; if (files3.Length != 0) { TextAsset val = new TextAsset(File.ReadAllText(files3[0])); FollowerSpineConfig followerSpineConfig = JsonConvert.DeserializeObject(val.text); if (followerSpineConfig != null) { list = followerSpineConfig.DefaultSkin; array3 = followerSpineConfig.Skins; Plugin.Log.LogInfo((object)$"Using default skin: {list}"); Plugin.Log.LogInfo((object)("Using skin list: " + string.Join(", ", array3))); } } if (array2.Length != 0 && files.Length != 0 && files2.Length != 0) { Plugin.Log.LogInfo((object)("Reading atlas from " + files2[0])); TextAsset val2 = new TextAsset(File.ReadAllText(files2[0])); Plugin.Log.LogInfo((object)("Reading skeleton from " + array2[0])); TextAsset val3 = new TextAsset(File.ReadAllText(array2[0])); Texture2D[] array4 = (Texture2D[])(object)new Texture2D[files.Length]; string[] array5 = files; foreach (string text in array5) { Plugin.Log.LogInfo((object)("Reading texture from " + text)); Texture2D val4 = TextureHelper.CreateTextureFromPath(text, (TextureFormat)4, false, false); ((Object)val4).name = Path.GetFileNameWithoutExtension(text); array4[Array.IndexOf(files, text)] = val4; } Material val5 = (Material)(((object)material) ?? ((object)new Material(Shader.Find("Spine/Skeleton")))); SpineAtlasAsset val6 = SpineAtlasAsset.CreateRuntimeInstance(val2, array4, val5, true); SkeletonDataAsset val7 = SkeletonDataAsset.CreateRuntimeInstance(val3, (AtlasAssetBase)(object)val6, true, 0.005f); Plugin.Log.LogInfo((object)("Creating skeleton for " + fileName)); Plugin.Log.LogInfo((object)("Using material name " + ((Object)val5).name)); CustomSkinManager.AddFollowerSpine(fileName, val7); for (int k = 0; k < list.Count; k++) { string text2 = list[k]; } } else { Plugin.Log.LogInfo((object)("Failed to load follower skin " + fileName + ", ensure that the folder contains at least one of each .json, .png and .atlas file.")); } } } public static void LoadAllNonSpineSkins() { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown string path = Path.Combine(Plugin.PluginPath, "FollowerSkins"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string[] directories = Directory.GetDirectories(path); string[] array = directories; foreach (string path2 in array) { string fileName = Path.GetFileName(path2); Plugin.Log.LogInfo((object)("Loading Follower Override Skin: " + fileName)); List list = new List(); string[] directories2 = Directory.GetDirectories(path2); foreach (string text in directories2) { Plugin.Log.LogInfo((object)("Creating Variant: " + Path.GetFileName(text))); string[] files = Directory.GetFiles(text, "*.png", SearchOption.TopDirectoryOnly); string[] files2 = Directory.GetFiles(text, "config.json", SearchOption.TopDirectoryOnly); Plugin.Log.LogInfo((object)("Variant has a total of " + files.Length + " overrides.")); if (files2.Length != 0) { TextAsset val = new TextAsset(File.ReadAllText(files2[0])); FollowerSkinConfig followerSkinConfig = JsonConvert.DeserializeObject(val.text); if (followerSkinConfig == null) { Plugin.Log.LogWarning((object)("Failed to deserialize config.json for follower skin " + fileName + " variant: " + text + ", please check syntax.")); continue; } Plugin.Log.LogInfo((object)("Variant will be created using base skin: " + followerSkinConfig.OverrideBaseSkin)); List> list2 = new List>(); string[] array2 = files; foreach (string text2 in array2) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2); if (!followerSkinConfig.PartConfigs.ContainsKey(fileNameWithoutExtension)) { Plugin.Log.LogWarning((object)(fileName + " variant: " + text + " - " + fileNameWithoutExtension + " is not registered as a part in the config.json! Ignoring...")); } else { FollowerSkinPartConfig followerSkinPartConfig = followerSkinConfig.PartConfigs[fileNameWithoutExtension]; Plugin.Log.LogInfo((object)("Reading texture from " + Path.GetFileName(text2))); Texture2D val2 = TextureHelper.CreateTextureFromPath(text2, (TextureFormat)4, false, false); ((Object)val2).name = Path.GetFileNameWithoutExtension(text2); list2.Add(new Tuple(followerSkinPartConfig.SlotIndex, followerSkinPartConfig.PartName, val2, followerSkinPartConfig)); } } Plugin.Log.LogInfo((object)(fileName + " variant " + text + " has a total of " + files.Length + " and " + list2.Count + " were registered successfully.")); FollowerSkinOverrides.Add(fileName + "_" + Path.GetFileName(text), list2); FollowerSlotColors.Add(fileName + "_" + Path.GetFileName(text), BuildColorsByIndex(followerSkinConfig)); string text3 = BuildCustomOverrideSkin(fileName + "_" + Path.GetFileName(text), followerSkinConfig.OverrideBaseSkin); if (text3 != null) { list.Add(text3); } } else { Plugin.Log.LogWarning((object)("No config.json found for follower skin " + fileName + " variant: " + text + ", please create one.")); } } if (list.Count > 0) { Plugin.Log.LogInfo((object)("Creating Follower Skin " + fileName + " with " + list.Count + " variant(s).")); CreateNewFollowerType(list[0], list, FollowerSlotColors[list[0]]); } } } public static string BuildCustomOverrideSkin(string skinVariantName, string baseSkinName) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Expected O, but got Unknown //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Expected O, but got Unknown if (CustomFollowerSkins.ContainsKey(skinVariantName)) { Plugin.Log.LogWarning((object)(skinVariantName + " has already been built!")); return null; } List> list = FollowerSkinOverrides[skinVariantName]; Skin val = ((SkeletonRenderer)WorshipperData.Instance.SkeletonData).Skeleton.Data.FindSkin(baseSkinName); if (val == null) { Plugin.Log.LogWarning((object)("Could not find base skin " + baseSkinName + " for variant " + skinVariantName + "! Defaulting to Cat.")); val = ((SkeletonRenderer)WorshipperData.Instance.SkeletonData).Skeleton.Data.FindSkin("Cat"); } Skin finalSkin = new Skin(skinVariantName); Plugin.Log.LogInfo((object)$"Attempting to build skin with {list.Count} override parts for variant {skinVariantName}"); val.Attachments.ToList().ForEach(delegate(SkinEntry attachment) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) finalSkin.SetAttachment(((SkinEntry)(ref attachment)).SlotIndex, ((SkinEntry)(ref attachment)).Name, attachment.attachment.Copy()); }); ((IEnumerable)val.Bones).ToList().ForEach((Action)finalSkin.Bones.Add); ((IEnumerable)val.Constraints).ToList().ForEach((Action)finalSkin.Constraints.Add); foreach (Tuple item in list) { try { ((Object)item.Item3).name = skinVariantName + "_" + item.Item2; Material val2 = new Material(Shader.Find("Spine/Skeleton")) { mainTexture = (Texture)(object)item.Item3 }; Material[] array = (Material[])(object)new Material[1] { val2 }; SpineAtlasAsset val3 = SpineAtlasAsset.CreateRuntimeInstance(GenerateAtlasText(skinVariantName + "_" + item.Item2, item.Item2, ((Texture)item.Item3).width.ToString(), ((Texture)item.Item3).height.ToString()), array, true); Attachment attachment2 = val.GetAttachment(item.Item1, item.Item2); if (attachment2 == null) { continue; } attachment2 = attachment2.Copy(); float offsetX = item.Item4.OffsetX; float offsetY = item.Item4.OffsetY; float rotation = item.Item4.Rotation; float scaleX = item.Item4.ScaleX; float scaleY = item.Item4.ScaleY; Attachment val4 = attachment2; Attachment val5 = val4; MeshAttachment val6 = (MeshAttachment)(object)((val5 is MeshAttachment) ? val5 : null); if (val6 == null) { RegionAttachment val7 = (RegionAttachment)(object)((val5 is RegionAttachment) ? val5 : null); if (val7 != null) { ((Attachment)val7).Name = skinVariantName + "_" + item.Item2; ((AtlasAssetBase)val3).GetAtlas().regions[0].name = "Custom" + ((AtlasAssetBase)val3).GetAtlas().regions[0].name; AttachmentRegionExtensions.SetRegion(val7, ((AtlasAssetBase)val3).GetAtlas().regions[0], true); val7.X += offsetX; val7.Y += offsetY; val7.ScaleX = scaleX; val7.ScaleY = scaleY; val7.rotation = rotation; finalSkin.SetAttachment(item.Item1, item.Item2, (Attachment)(object)val7); } else { Plugin.Log.LogWarning((object)("Attachment " + attachment2.Name + " is not a MeshAttachment or RegionAttachment, skipping...")); } } else { float num = 2.1474836E+09f; float num2 = -2.1474836E+09f; float num3 = 2.1474836E+09f; float num4 = -2.1474836E+09f; for (int i = 0; i < ((VertexAttachment)val6).Vertices.Length; i++) { switch (i % 3) { case 0: num3 = Math.Min(num3, ((VertexAttachment)val6).Vertices[i]); num4 = Math.Max(num4, ((VertexAttachment)val6).Vertices[i]); break; case 1: num = Math.Min(num, ((VertexAttachment)val6).Vertices[i]); num2 = Math.Max(num2, ((VertexAttachment)val6).Vertices[i]); break; } } float num5 = num2 - num; float num6 = num4 - num3; float num7 = num + num5 / 2f; float num8 = num3 + num6 / 2f; RegionAttachment val8 = new RegionAttachment(item.Item2); AttachmentRegionExtensions.SetRegion(val8, ((AtlasAssetBase)val3).GetAtlas().regions[0], true); val8.X = num8 - offsetY; val8.Y = num7 - offsetX; val8.rotation = rotation; val8.ScaleX = scaleX; val8.ScaleY = scaleY; val8.Width = num5; val8.Height = num6; finalSkin.SetAttachment(item.Item1, item.Item2, (Attachment)(object)val8); } Plugin.Log.LogInfo((object)("Attached override part " + item.Item2 + " to slot " + item.Item1 + " for skin variant " + skinVariantName)); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to apply override part " + item.Item2 + " to skin variant " + skinVariantName + ": " + ex.Message)); return null; } } Plugin.Log.LogInfo((object)("Successfully created skin variant " + skinVariantName)); Material val9 = default(Material); Texture2D val10 = default(Texture2D); Skin repackedSkin = AtlasUtilities.GetRepackedSkin(finalSkin, skinVariantName, ((SkeletonRenderer)WorshipperData.Instance.SkeletonData).SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, ref val9, ref val10, 1024, 2, (TextureFormat)4, false, true, false, (int[])null, (Texture2D[])null, (TextureFormat[])null, (bool[])null); CustomFollowerSkins.Add(skinVariantName, repackedSkin); DataManager.SetFollowerSkinUnlocked(skinVariantName); return skinVariantName; } public static void CreateNewFollowerType(string name, List variantNames, List colors, bool hidden = false, bool twitchPremium = false, bool invariant = false) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0073: Expected O, but got Unknown List skin = ((IEnumerable)variantNames).Select((Func)((string v) => new CharacterSkin { Skin = v })).ToList(); WorshipperData.Instance.Characters.Add(new SkinAndData { Title = name, Skin = skin, SlotAndColours = colors, TwitchPremium = twitchPremium, _hidden = hidden, _dropLocation = (DropLocation)4, _invariant = invariant }); } public static TextAsset GenerateAtlasText(string filename, string name, string width, string height) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(); stringBuilder.AppendLine(filename ?? ""); stringBuilder.AppendLine("size: " + width + ", " + height); stringBuilder.AppendLine("format: RGBA8888"); stringBuilder.AppendLine("filter: Linear,Linear"); stringBuilder.AppendLine("repeat: none"); stringBuilder.AppendLine(name ?? ""); stringBuilder.AppendLine(" rotate: false"); stringBuilder.AppendLine(" xy: 0,0"); stringBuilder.AppendLine(" size: " + width + "," + height); stringBuilder.AppendLine(" orig: " + width + "," + height); stringBuilder.AppendLine(" offset: 0,0"); stringBuilder.AppendLine(" index: -1"); return new TextAsset(stringBuilder.ToString()); } public static List BuildColorsByIndex(FollowerSkinConfig config) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Expected O, but got Unknown //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Expected O, but got Unknown //IL_01e3: Expected O, but got Unknown List parts = config.PartConfigs.Values.Where((FollowerSkinPartConfig p) => p.ColorChoices?.Any() ?? false).ToList(); int num = parts.Min((FollowerSkinPartConfig p) => p.ColorChoices.Count); if (num == 0) { return new List(1) { new SlotsAndColours { SlotAndColours = new List(9) { new SlotAndColor("ARM_LEFT_SKIN", new Color(1f, 1f, 1f)), new SlotAndColor("ARM_RIGHT_SKIN", new Color(1f, 1f, 1f)), new SlotAndColor("LEG_LEFT_SKIN", new Color(1f, 1f, 1f)), new SlotAndColor("LEG_RIGHT_SKIN", new Color(1f, 1f, 1f)), new SlotAndColor("Body_Naked", new Color(1f, 1f, 1f)), new SlotAndColor("Body_Naked_Up", new Color(1f, 1f, 1f)), new SlotAndColor("BODY_BTM", new Color(1f, 1f, 1f)), new SlotAndColor("BODY_BTM_UP", new Color(1f, 1f, 1f)), new SlotAndColor("BODY_TOP", new Color(1f, 1f, 1f)) } } }; } return Enumerable.Range(0, num).Select((Func)((int i) => new SlotsAndColours { SlotAndColours = ((IEnumerable)parts).Select((Func)((FollowerSkinPartConfig p) => new SlotAndColor(p.PartName, HexToColor(p.ColorChoices[i])))).ToList() })).ToList(); } public static Color HexToColor(string hex) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); ColorUtility.TryParseHtmlString(hex, ref result); return result; } } public class FollowerSpineConfig { public List DefaultSkin { get; set; } public string[] Skins { get; set; } public bool InitializeWithoutBase { get; set; } = true; } [Serializable] public class FollowerSkinConfig { public string OverrideBaseSkin { get; set; } = "Cat"; public Dictionary PartConfigs { get; set; } } [Serializable] public class FollowerSkinPartConfig { public int SlotIndex { get; set; } public string PartName { get; set; } public float ScaleX { get; set; } = 1f; public float ScaleY { get; set; } = 1f; public float Rotation { get; set; } = -90f; public float OffsetX { get; set; } = 0f; public float OffsetY { get; set; } = 0f; public List ColorChoices { get; set; } = new List(1) { "#FFF" }; } [Serializable] public class DebugOutputSkin { public int SlotIndex { get; set; } public string PartName { get; set; } } public class PlayerSpineLoader { public static List FleeceRotation = new List(); public static Dictionary>> FleeceCyclingSpines = new Dictionary>>(); public static int currentFleeceIndexP1 = -1; public static int currentFleeceIndexP2 = -1; public static string currentFleeceSpineNameP1 = ""; public static string currentFleeceSpineNameP2 = ""; public static bool LoadedCustomSpines = false; public static bool LoadedFleeceCycling = false; public static List<(string, string)> FleeceOverrideSlots = new List<(string, string)>(14) { ("images/PonchoLeft", "PonchoLeft"), ("images/PonchoRight", "PonchoRight"), ("images/PonchoLeft", "PonchoLeft2"), ("images/PonchoRight", "PonchoRight2"), ("images/PonchoExtra", "PonchoExtra"), ("images/PonchoRightCorner2", "PonchoRightCorner"), ("images/PonchoRightCorner", "PonchoRightCorner"), ("images/PonchoShoulder", "PonchoShoulder"), ("images/PonchoShoulder2", "PonchoShoulder_Right"), ("RopeTopLeft", "images/RopeTopLeft"), ("RopeTopRight", "images/RopeTopRight"), ("images/Rope", "images/Rope"), ("images/Bell", "Bell"), ("images/Body", "Body") }; public static int CycleNextFleece(int playerID) { int num = 0; switch (playerID) { case 0: currentFleeceIndexP1++; if (currentFleeceIndexP1 >= FleeceRotation.Count) { currentFleeceIndexP1 = 0; } num = currentFleeceIndexP1; break; case 1: currentFleeceIndexP2++; if (currentFleeceIndexP2 >= FleeceRotation.Count) { currentFleeceIndexP2 = 0; } num = currentFleeceIndexP2; break; } Plugin.Log.LogInfo((object)("Player " + (playerID + 1) + " cycled to fleece index " + num + " (" + FleeceRotation[num] + ")")); return num; } public static void LoadAllPlayerSpines(Material material = null) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown //IL_0258: Unknown result type (might be due to invalid IL or missing references) if (LoadedCustomSpines) { Plugin.Log.LogInfo((object)"Load Player Spines was called again but already loaded!"); return; } string path = Path.Combine(Plugin.PluginPath, "PlayerSkins"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string[] directories = Directory.GetDirectories(path); string[] array = directories; foreach (string path2 in array) { string fileName = Path.GetFileName(path2); string[] array2 = (from x in Directory.GetFiles(path2, "*.json", SearchOption.TopDirectoryOnly) where !x.Contains("config") select x).ToArray(); string[] files = Directory.GetFiles(path2, "*.png", SearchOption.TopDirectoryOnly); string[] files2 = Directory.GetFiles(path2, "*.atlas", SearchOption.TopDirectoryOnly); string[] files3 = Directory.GetFiles(path2, "config.json", SearchOption.TopDirectoryOnly); string text = "Lamb"; string[] array3 = new string[0]; bool flag = false; if (files3.Length != 0) { TextAsset val = new TextAsset(File.ReadAllText(files3[0])); PlayerSpineConfig playerSpineConfig = JsonConvert.DeserializeObject(val.text); if (playerSpineConfig != null) { text = playerSpineConfig.DefaultSkin; array3 = playerSpineConfig.Skins; flag = playerSpineConfig.FleeceCyclingOnly; Plugin.Log.LogInfo((object)("Using default skin: " + text)); Plugin.Log.LogInfo((object)("Using skin list: " + string.Join(", ", array3))); } } if (array2.Length != 0 && files.Length != 0 && files2.Length != 0) { Plugin.Log.LogInfo((object)("Reading atlas from " + files2[0])); TextAsset val2 = new TextAsset(File.ReadAllText(files2[0])); Plugin.Log.LogInfo((object)("Reading skeleton from " + array2[0])); TextAsset val3 = new TextAsset(File.ReadAllText(array2[0])); Texture2D[] array4 = (Texture2D[])(object)new Texture2D[files.Length]; string[] array5 = files; foreach (string text2 in array5) { Plugin.Log.LogInfo((object)("Reading texture from " + text2)); Texture2D val4 = TextureHelper.CreateTextureFromPath(text2, (TextureFormat)4, false, false); ((Object)val4).name = Path.GetFileNameWithoutExtension(text2); array4[Array.IndexOf(files, text2)] = val4; } Material val5 = (Material)(((object)material) ?? ((object)new Material(Shader.Find("Spine/Skeleton")))); SpineAtlasAsset val6 = SpineAtlasAsset.CreateRuntimeInstance(val2, array4, val5, true); SkeletonDataAsset val7 = SkeletonDataAsset.CreateRuntimeInstance(val3, (AtlasAssetBase)(object)val6, true, 0.005f); Plugin.Log.LogInfo((object)("Creating skeleton for " + fileName)); Plugin.Log.LogInfo((object)("Using material name " + ((Object)val5).name)); if (flag) { Plugin.Log.LogInfo((object)("Skin: " + fileName + " is added as a fleece cycle skin.")); FleeceCyclingSpines.Add(fileName, new Tuple>(val7, array3.ToList())); } else { CustomSkinManager.AddPlayerSpine(fileName, val7, array3.ToList()); CustomSkinManager.ChangeSelectedPlayerSpine(fileName + "/" + text, 0); } } else { Plugin.Log.LogInfo((object)("Failed to load player skin " + fileName + ", ensure that the folder contains at least one of each .json, .png and .atlas file.")); } } LoadedCustomSpines = true; } } public class PlayerSpineConfig { public string DefaultSkin { get; set; } public string[] Skins { get; set; } public bool FleeceCyclingOnly { get; set; } = false; } public class StructureBuildingOverrideHelper { public static Dictionary> StructureBuildingOverrides { get; private set; } = new Dictionary>(); public static void LoadBuildingOverrides() { if (!Directory.Exists(Path.Combine(Plugin.PluginPath, "BuildingOverrides"))) { Directory.CreateDirectory(Path.Combine(Plugin.PluginPath, "BuildingOverrides")); Plugin.Log.LogInfo((object)"Created BuildingOverrides directory."); return; } string[] directories = Directory.GetDirectories(Path.Combine(Plugin.PluginPath, "BuildingOverrides")); foreach (string text in directories) { string name = new DirectoryInfo(text).Name; List list = new List(); if (File.Exists(Path.Combine(text, "config.json"))) { string text2 = File.ReadAllText(Path.Combine(text, "config.json")); try { StructureBuildingOverrideData structureBuildingOverrideData = JsonConvert.DeserializeObject(text2) ?? null; if (structureBuildingOverrideData != null && structureBuildingOverrideData.Overrides != null) { list.AddRange(structureBuildingOverrideData.Overrides); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Error loading building override from config.json in {text}: {arg}"); } } if (list.Count > 0) { StructureBuildingOverrides[name] = list; Plugin.Log.LogInfo((object)$"Loaded {list.Count} overrides for building {name}."); } } } public static List GetOverridesForBuilding(string buildingName) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) List value; List list = (StructureBuildingOverrides.TryGetValue(buildingName, out value) ? value : null); if (list == null) { return null; } List list2 = new List(); foreach (StructureBuildingOverride item in list) { CustomStructureBuildingData val = new CustomStructureBuildingData { Offset = item.Offset.ToVector3(), Scale = item.Scale.ToVector3(), Rotation = item.Rotation.ToVector3(), Sprite = TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "BuildingOverrides/" + buildingName + "/" + item.SpriteImageName)) }; list2.Add(val); Plugin.Log.LogInfo((object)$"Custom Spine Loader: Loaded override with sprite {item.SpriteImageName} for building {buildingName}: offset {val.Offset}, scale {val.Scale}, rotation {val.Rotation}."); } return list2; } } [Serializable] public class StructureBuildingOverrideData { public List Overrides = new List(); } [Serializable] public class StructureBuildingOverride { public SerializableVector3 Offset; public SerializableVector3 Scale; public SerializableVector3 Rotation; public string SpriteImageName; } [Serializable] public class SerializableVector3 { public float X; public float Y; public float Z; public Vector3 ToVector3() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(X, Y, Z); } } [Serializable] public class SerializableVector2 { public float X; public float Y; public Vector2 ToVector2() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return new Vector2(X, Y); } } } namespace CustomSpineLoader.Patches { [HarmonyPatch] public class DungeonPatches { public static ConnectionTypes NextRoomConnectionType = (ConnectionTypes)2; public static bool GenCheck = false; [HarmonyPatch(typeof(BiomeGenerator), "OnEnable")] [HarmonyPrefix] private static void BiomeGenerator_OnEnable(BiomeGenerator __instance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (CustomDungeonManager.CustomDungeonList.ContainsKey(CustomDungeonManager.EnteringCustomDungeon)) { Plugin.Log.LogInfo((object)("Entering Custom Dungeon ONENABLE " + ((object)(FollowerLocation)(ref CustomDungeonManager.EnteringCustomDungeon)).ToString())); __instance.DungeonLocation = CustomDungeonManager.EnteringCustomDungeon; Plugin.Log.LogInfo((object)("Custom Room Count for " + ((object)(FollowerLocation)(ref __instance.DungeonLocation)).ToString() + ": " + CustomDungeonManager.CustomDungeonList[__instance.DungeonLocation].NumRooms)); __instance.NumberOfRooms = CustomDungeonManager.CustomDungeonList[__instance.DungeonLocation].NumRooms; CustomDungeonManager.EnteringCustomDungeon = (FollowerLocation)(-1); } else { Plugin.Log.LogInfo((object)("Not a custom dungeon, using default dungeon for " + ((object)(FollowerLocation)(ref __instance.DungeonLocation)).ToString())); } } [HarmonyPatch(typeof(GameManager), "IsDungeon")] [HarmonyPrefix] private static bool GameManager_IsDungeon(GameManager __instance, FollowerLocation location, ref bool __result) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (!CustomDungeonManager.CustomDungeonList.ContainsKey(location)) { return true; } __result = true; return false; } [HarmonyPatch(typeof(Door), "OnTriggerEnter2D")] [HarmonyPrefix] public static bool Door_OnTriggerEnter2D(Door __instance) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)BiomeGenerator.Instance == (Object)null) { return true; } if (!CustomDungeonManager.CustomDungeonList.ContainsKey(BiomeGenerator.Instance.DungeonLocation)) { return true; } if ((int)__instance.ConnectionType == 6) { Plugin.Log.LogInfo((object)("Exit Door Triggered for custom dungeon " + ((object)(FollowerLocation)(ref BiomeGenerator.Instance.DungeonLocation)).ToString())); CustomDungeonManager.CustomDungeonList[BiomeGenerator.Instance.DungeonLocation].ExitDoor(); return false; } Plugin.Log.LogInfo((object)("Entering room type " + ((object)(ConnectionTypes)(ref __instance.ConnectionType)).ToString())); NextRoomConnectionType = __instance.ConnectionType; GenCheck = false; return true; } [HarmonyPatch(typeof(LocationManager), "LocationIsDungeon")] [HarmonyPrefix] public static bool LocationManager_LocationIsDungeon(LocationManager __instance, FollowerLocation location, ref bool __result) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (!CustomDungeonManager.CustomDungeonList.ContainsKey(location)) { return true; } __result = true; return false; } [HarmonyPatch(typeof(HUD_DisplayName), "Play")] [HarmonyPatch(new Type[] { typeof(string), typeof(int), typeof(Positions), typeof(textBlendMode), typeof(int) })] [HarmonyPrefix] public static bool HUD_DisplayName_Play(ref string Name, ref Positions Position, ref textBlendMode blend, ref int winterSeverity) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected I4, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected I4, but got Unknown if ((Object)(object)BiomeGenerator.Instance == (Object)null) { return true; } if (!CustomDungeonManager.CustomDungeonList.ContainsKey(BiomeGenerator.Instance.DungeonLocation)) { return true; } Plugin.Log.LogInfo((object)("Custom Dungeon HUD_DisplayName_Play for " + ((object)(FollowerLocation)(ref BiomeGenerator.Instance.DungeonLocation)).ToString())); CustomDungeon customDungeon = CustomDungeonManager.CustomDungeonList[BiomeGenerator.Instance.DungeonLocation]; Position = (Positions)(int)customDungeon.TitleTextPosition; blend = (textBlendMode)(int)customDungeon.TitleTextBlendMode; winterSeverity = customDungeon.Difficulty; return true; } [HarmonyPatch(typeof(HUD_DisplayName), "Show")] [HarmonyPrefix] public static bool HUD_DisplayName_Show(ref string Name) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)BiomeGenerator.Instance == (Object)null) { return true; } if (!CustomDungeonManager.CustomDungeonList.ContainsKey(BiomeGenerator.Instance.DungeonLocation)) { return true; } Plugin.Log.LogInfo((object)("Custom Dungeon HUD_DisplayName_Show for " + ((object)(FollowerLocation)(ref BiomeGenerator.Instance.DungeonLocation)).ToString())); CustomDungeon customDungeon = CustomDungeonManager.CustomDungeonList[BiomeGenerator.Instance.DungeonLocation]; Name = customDungeon.DungeonName; return true; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(new Type[] { })] [HarmonyPostfix] public static void GenerateRoom_Generate(GenerateRoom __instance) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected I4, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)BiomeGenerator.Instance == (Object)null || GenCheck || !CustomDungeonManager.CustomDungeonList.ContainsKey(BiomeGenerator.Instance.DungeonLocation)) { return; } GenCheck = true; Plugin.Log.LogInfo((object)("GenerateRoom_Generate for custom dungeon " + ((object)(FollowerLocation)(ref BiomeGenerator.Instance.DungeonLocation)).ToString())); Plugin.Log.LogInfo((object)("Room complete status: " + BiomeGenerator.Instance.CurrentRoom.Completed)); if (!BiomeGenerator.Instance.CurrentRoom.Completed) { ConnectionTypes nextRoomConnectionType = NextRoomConnectionType; ConnectionTypes val = nextRoomConnectionType; switch ((int)val) { case 0: Plugin.Log.LogInfo((object)"False Room Generated"); break; case 1: Plugin.Log.LogInfo((object)"True Room Generated"); CustomDungeonManager.CustomDungeonList[BiomeGenerator.Instance.DungeonLocation].SpawnEnemies(__instance, NextRoomConnectionType); break; case 2: Plugin.Log.LogInfo((object)"Entrance Room Generated"); break; case 3: Plugin.Log.LogInfo((object)"Exit Room Generated"); break; case 4: Plugin.Log.LogInfo((object)"Boss Room Generated"); break; case 5: Plugin.Log.LogInfo((object)"Door Room Generated"); break; case 6: Plugin.Log.LogInfo((object)"NextLayer Room Generated"); break; case 7: Plugin.Log.LogInfo((object)"DungeonFirstRoom Generated"); break; case 8: Plugin.Log.LogInfo((object)"LeaderBoss Room Generated"); break; case 9: Plugin.Log.LogInfo((object)"Tarot Room Generated"); break; case 10: Plugin.Log.LogInfo((object)"WeaponShop Room Generated"); break; case 11: Plugin.Log.LogInfo((object)"RelicShop Room Generated"); break; case 12: Plugin.Log.LogInfo((object)"LoreStoneRoom Generated"); break; default: Plugin.Log.LogInfo((object)"Default Room Generated"); break; } } } } [HarmonyPatch] public class SkinSelectorPatch { [HarmonyPatch(typeof(FollowerInformationBox), "ConfigureImpl")] [HarmonyPostfix] private static void FollowerInformationBox_ConfigureImpl(FollowerInformationBox __instance) { if (FollowerSpineLoader.CustomFollowerSkins.ContainsKey(((FollowerSelectItem)__instance).FollowerInfo.SkinName)) { __instance.FollowerSpine.Skeleton.Skin = FollowerSpineLoader.CustomFollowerSkins[((FollowerSelectItem)__instance).FollowerInfo.SkinName]; } } [HarmonyPatch(typeof(SkeletonData), "FindSkin", new Type[] { typeof(string) })] [HarmonyPostfix] private static void SkeletonData_FindSkin(ref Skin? __result, SkeletonData __instance, string skinName) { if (__result == null && FollowerSpineLoader.CustomFollowerSkins.TryGetValue(skinName, out var value)) { __result = value; DataManager.SetFollowerSkinUnlocked(skinName); } } [HarmonyPatch(typeof(PlayerFarming), "Awake")] [HarmonyPrefix] private static bool PlayerFarming_Awake(PlayerFarming __instance) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) if (!PlayerSpineLoader.LoadedFleeceCycling) { Plugin.Log.LogInfo((object)"Creating Fleece Rotation!"); SkeletonAnimation spine = __instance.Spine; Enumerator enumerator = ((SkeletonRenderer)spine).Skeleton.Data.Skins.GetEnumerator(); try { while (enumerator.MoveNext()) { Skin current = enumerator.Current; if (!PlayerSpineLoader.FleeceRotation.Contains(current.Name) && !current.Name.ToLower().Contains("lamb_0") && current.Name.ToLower().Contains("lamb")) { PlayerSpineLoader.FleeceRotation.Add(current.Name); Plugin.Log.LogInfo((object)("Added fleece skin: " + current.Name)); } } } finally { ((IDisposable)enumerator).Dispose(); } if (!PlayerSpineLoader.FleeceRotation.Contains("Goat")) { PlayerSpineLoader.FleeceRotation.Add("Goat"); Plugin.Log.LogInfo((object)"Added fleece skin: Goat"); } if (!PlayerSpineLoader.FleeceRotation.Contains("Snake")) { PlayerSpineLoader.FleeceRotation.Add("Snake"); Plugin.Log.LogInfo((object)"Added fleece skin: Snake"); } if (!PlayerSpineLoader.FleeceRotation.Contains("Owl")) { PlayerSpineLoader.FleeceRotation.Add("Owl"); Plugin.Log.LogInfo((object)"Added fleece skin: Owl"); } foreach (KeyValuePair>> fleeceCyclingSpine in PlayerSpineLoader.FleeceCyclingSpines) { string key = fleeceCyclingSpine.Key; foreach (string item in fleeceCyclingSpine.Value.Item2) { string text = "CultTweaker_" + key + "_" + item; if (!PlayerSpineLoader.FleeceRotation.Contains(text)) { PlayerSpineLoader.FleeceRotation.Add(text); Plugin.Log.LogInfo((object)("Added custom fleece skin: " + text)); } } } PlayerSpineLoader.LoadedFleeceCycling = true; } if (!PlayerSpineLoader.LoadedCustomSpines) { Plugin.Log.LogInfo((object)"PlayerFarming Awake called, checking for custom spines..."); Material primaryMaterial = ((SkeletonRenderer)__instance.Spine).skeletonDataAsset.atlasAssets[0].PrimaryMaterial; Plugin.Log.LogInfo((object)("Test result is " + ((Object)primaryMaterial).name)); Plugin.Log.LogInfo((object)("Test shader is " + ((Object)primaryMaterial.shader).name)); primaryMaterial.SetTextureScale("_EmissionMap", new Vector2(0f, 0f)); PlayerSpineLoader.LoadAllPlayerSpines(primaryMaterial); } return true; } [HarmonyPatch(typeof(PlayerFarming), "SetSkin", new Type[] { typeof(bool) })] [HarmonyPostfix] private static void PlayerFarming_SetSkin(ref Skin __result, PlayerFarming __instance, bool BlackAndWhite) { if (!Plugin.FleeceCyclingEnabled.Value) { return; } int num = -1; string text = ""; if (CoopManager.CoopActive && __instance.playerID == 1) { num = PlayerSpineLoader.currentFleeceIndexP2; Plugin.Log.LogInfo((object)("Applying fleece skin for Player 2: " + text)); } else { num = PlayerSpineLoader.currentFleeceIndexP1; } if (num == -1) { Plugin.Log.LogInfo((object)"No fleece skin to apply."); return; } if (num >= PlayerSpineLoader.FleeceRotation.Count) { Plugin.Log.LogInfo((object)"Fleece skin index out of range. Cycle with F7 or F8 to fix."); return; } text = PlayerSpineLoader.FleeceRotation[num]; Plugin.Log.LogInfo((object)("Applying fleece skin: " + text)); SkeletonAnimation spine = __instance.Spine; Skin val; if (text.Contains("CultTweaker_")) { string[] array = text.Split(new char[1] { '_' }, 3); if (array.Length < 3) { Plugin.Log.LogWarning((object)("Invalid custom fleece skin name: " + text)); return; } string text2 = array[1]; if (!PlayerSpineLoader.FleeceCyclingSpines.ContainsKey(text2)) { Plugin.Log.LogWarning((object)("Invalid spine skin name: " + text + " for spine: " + text2)); return; } val = PlayerSpineLoader.FleeceCyclingSpines[text2].Item1.skeletonData.FindSkin(array[2]); if (val == null) { Plugin.Log.LogWarning((object)("Defaulting to default as Custom Fleece skin not found: " + text)); val = ((SkeletonRenderer)spine).Skeleton.Data.FindSkin("Lamb"); } } else { val = ((SkeletonRenderer)spine).Skeleton.Data.FindSkin(text); } if ((Object)(object)spine == (Object)null) { Plugin.Log.LogInfo((object)("Lamb skin was null after cycling, an error occurred! at skin name " + text)); return; } Skin skin = ((SkeletonRenderer)spine).Skeleton.Skin; foreach (var fleeceOverrideSlot in PlayerSpineLoader.FleeceOverrideSlots) { int num2 = ((SkeletonRenderer)spine).Skeleton.FindSlotIndex(fleeceOverrideSlot.Item1); Attachment attachment = val.GetAttachment(num2, fleeceOverrideSlot.Item2); Plugin.Log.LogInfo((object)string.Format("Slot {0} index is {1}, attachment {2}", fleeceOverrideSlot.Item1, num2, (attachment != null) ? "found" : "not found")); if (attachment == null) { skin.RemoveAttachment(num2, fleeceOverrideSlot.Item2); } else { skin.SetAttachment(num2, fleeceOverrideSlot.Item2, attachment); } Plugin.Log.LogInfo((object)("Applied " + fleeceOverrideSlot.Item2 + " attachment to current skin.")); } Plugin.Log.LogInfo((object)("Applied" + text + " attachment to current skin.")); ((SkeletonRenderer)spine).Skeleton.SetSlotsToSetupPose(); spine.Update(0f, false); } [HarmonyPatch(typeof(Follower), "Update")] [HarmonyPostfix] public static void Follower_FacePosition(Follower __instance) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) int iD = __instance.Brain.Info.ID; float customScale = CustomColorHelper.GetCustomScale(iD); if (!(customScale <= 0f)) { ((SkeletonRenderer)__instance.Spine).skeleton.ScaleX = ((((Component)__instance).transform.position.x < __instance._destPos.x) ? (0f - customScale) : customScale); } } [HarmonyPatch(typeof(FollowerBrain), "SetFollowerCostume", new Type[] { typeof(Skeleton), typeof(int), typeof(string), typeof(int), typeof(FollowerOutfitType), typeof(FollowerHatType), typeof(FollowerClothingType), typeof(FollowerCustomisationType), typeof(FollowerSpecialType), typeof(ITEM_TYPE), typeof(string), typeof(FollowerInfo) })] [HarmonyPrefix] public static bool FollowerBrain_SetFollowerCostume_Prefix(FollowerBrain __instance, Skeleton skeleton, ref string skinName, ref FollowerOutfitType outfit, ref FollowerHatType hat, ref FollowerClothingType clothing, FollowerCustomisationType customisation, ref FollowerSpecialType special, ref ITEM_TYPE necklace, FollowerInfo info) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected I4, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Invalid comparison between Unknown and I4 //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Invalid comparison between Unknown and I4 //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Invalid comparison between Unknown and I4 //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Invalid comparison between Unknown and I4 if (info != null) { Plugin.Log.LogInfo((object)$"Follower ID: {info.ID}, Name: {info.Name}"); CustomFollowerColor customColor = CustomColorHelper.GetCustomColor(info.ID); if (customColor == null) { return true; } if (!customColor.CustomFollowerCostume) { return true; } Plugin.Log.LogInfo((object)$"Custom costume enabled: {customColor.CustomFollowerCostume}, ClothingType: {customColor.FollowerClothingType}, SpecialType: {customColor.FollowerSpecialType}, HatType: {customColor.FollowerHatType}, OutfitType: {customColor.FollowerOutfitType}"); hat = (FollowerHatType)customColor.FollowerHatType; necklace = (ITEM_TYPE)(int)CustomColorCommand.GetNecklaceToUse(customColor.FollowerNecklaceType, info); special = (FollowerSpecialType)customColor.FollowerSpecialType; clothing = (FollowerClothingType)customColor.FollowerClothingType; outfit = (FollowerOutfitType)customColor.FollowerOutfitType; FollowerSpecialType val = special; if (val - 11 <= 2) { skinName = CustomColorCommand.GetSnowmanRandomSkin(special); Plugin.Log.LogInfo((object)("Applying snowman skin: " + skinName)); } FollowerClothingType val2 = clothing; if (((int)val2 == 1 || val2 - 3 <= 1 || (int)val2 == 40) ? true : false) { clothing = (FollowerClothingType)27; Plugin.Log.LogInfo((object)"Clothing type was blacklisted, defaulting to Normal."); } if ((int)outfit == 4) { outfit = (FollowerOutfitType)18; Plugin.Log.LogInfo((object)"Outfit type was blacklisted, defaulting to None."); } } return true; } [HarmonyPatch(typeof(FollowerBrain), "SetFollowerCostume", new Type[] { typeof(Skeleton), typeof(int), typeof(string), typeof(int), typeof(FollowerOutfitType), typeof(FollowerHatType), typeof(FollowerClothingType), typeof(FollowerCustomisationType), typeof(FollowerSpecialType), typeof(ITEM_TYPE), typeof(string), typeof(FollowerInfo) })] [HarmonyPostfix] private static void FollowerBrain_SetFollowerCostume(FollowerBrain __instance, Skeleton skeleton, FollowerInfo info) { //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (Plugin.DebugDumpFollowerSpineAtlas.Value) { Plugin.Log.LogWarning((object)"Debug Dump is enabled! Performance may be impacted"); string path = Path.Combine(Plugin.PluginPath, "followerSlots.json"); if (File.Exists(path)) { Plugin.Log.LogInfo((object)"followerSlots.json already exists, skipping dump. Delete the file to dump again."); } else { Plugin.Log.LogInfo((object)"Creating dump for followerslots"); List list = new List(); foreach (SkinEntry attachment in skeleton.Skin.Attachments) { SkinEntry current = attachment; list.Add(new DebugOutputSkin { SlotIndex = ((SkinEntry)(ref current)).SlotIndex, PartName = ((SkinEntry)(ref current)).Name }); } string contents = JsonConvert.SerializeObject((object)list, (Formatting)1); File.AppendAllText(path, contents); } } Plugin.Log.LogInfo((object)"Setting follower costume for"); if (info != null) { Plugin.Log.LogInfo((object)$"Follower ID: {info.ID}, Name: {info.Name}"); CustomFollowerColor customColor = CustomColorHelper.GetCustomColor(info.ID); if (customColor == null) { return; } Plugin.Log.LogInfo((object)$"Custom color found for follower {info.ID}: R={customColor.R}, G={customColor.G}, B={customColor.B}, A={customColor.A}"); SkeletonExtensions.SetColor(skeleton.FindSlot("ARM_LEFT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f)); SkeletonExtensions.SetColor(skeleton.FindSlot("LEG_LEFT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f)); SkeletonExtensions.SetColor(skeleton.FindSlot("LEG_RIGHT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f)); SkeletonExtensions.SetColor(skeleton.FindSlot("ARM_RIGHT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f)); SkeletonExtensions.SetColor(skeleton.FindSlot("HEAD_SKIN_BTM"), new Color(customColor.R, customColor.G, customColor.B, 1f)); skeleton.A = customColor.A; Follower val = FollowerManager.FindFollowerByID(info.ID); if ((Object)(object)val != (Object)null) { ((SkeletonRenderer)val.Spine).skeleton.scaleY = customColor.scale; ((SkeletonRenderer)val.Spine).skeleton.scaleX = customColor.scale; Plugin.Log.LogInfo((object)("Set follower scale to " + customColor.scale)); } if (customColor.CustomFollowerCostume) { try { Plugin.Log.LogInfo((object)"Costume override applied successfully."); } catch (Exception) { Plugin.Log.LogWarning((object)"The costume combinations were invalid, try another!"); } } } else { Plugin.Log.LogInfo((object)"Follower info is null, skipping costume setting."); } } [HarmonyPatch(typeof(SaveAndLoad), "Load")] [HarmonyPostfix] private static void SaveAndLoad_Load(int saveSlot) { CustomColorHelper.LoadCustomColors(saveSlot); } [HarmonyPatch(typeof(SaveAndLoad), "Save", new Type[] { })] [HarmonyPostfix] private static void SaveAndLoad_Save() { CustomColorHelper.SaveCustomColors(); } [HarmonyPatch(typeof(Structure), "Start")] [HarmonyPostfix] private static void Structure_Start(Structure __instance) { string text = ((object)(TYPES)(ref __instance.Type)).ToString(); List overridesForBuilding = StructureBuildingOverrideHelper.GetOverridesForBuilding(text); if (overridesForBuilding != null && overridesForBuilding.Count != 0) { Plugin.Log.LogInfo((object)$"Custom Spine Loader: {overridesForBuilding.Count} overrides to building {text}."); CustomStructureManager.OverrideStructureBuilding(((Component)__instance).gameObject, overridesForBuilding); } } } } namespace CustomSpineLoader.Commands { public class CustomColorCommand : CustomFollowerCommand { public UIFollowerSummaryMenuController _followerSummaryMenuController; public float currentRed = 1f; public float currentGreen = 1f; public float currentBlue = 1f; public float currentAlpha = 1f; public float currentScale = 1f; public bool isCustomColorEnabled = false; public bool isCustomFollowerCostumeEnabled = false; public int selectedClothingTypeIndex = 0; public int selectedSpecialTypeIndex = 0; public int selectedHatTypeIndex = 0; public int selectedOutfitTypeIndex = 0; public int selectedNecklaceTypeIndex = 0; public override string InternalName => "CustomColor_Command"; public override Sprite CommandIcon => TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "Assets/colorwheel.png")); public override List Categories { get; } = new List(1) { (FollowerCommandCategory)0 }; public override string GetTitle(Follower follower) { return "Customize Follower"; } public override string GetDescription(Follower follower) { return "Customize Me!"; } public override void Execute(interaction_FollowerInteraction interaction, FollowerCommands finalCommand) { ((MonoBehaviour)interaction).StartCoroutine(interaction.FrameDelayCallback((Action)delegate { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown interaction.follower.Brain.HardSwapToTask((FollowerTask)new FollowerTask_ManualControl()); _followerSummaryMenuController = MonoSingleton.Instance.ShowFollowerSummaryMenu(interaction.follower); CreateColorUI(); UIFollowerSummaryMenuController followerSummaryMenuController = _followerSummaryMenuController; ((UIMenuBase)followerSummaryMenuController).OnHidden = (Action)Delegate.Combine(((UIMenuBase)followerSummaryMenuController).OnHidden, (Action)delegate { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) _followerSummaryMenuController = null; if (isCustomColorEnabled) { CustomColorHelper.SetCustomColor(interaction.follower.Brain.Info.ID, currentRed, currentGreen, currentBlue, currentAlpha, currentScale); SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f)); SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("LEG_LEFT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f)); SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("LEG_RIGHT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f)); SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("ARM_RIGHT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f)); SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("HEAD_SKIN_BTM"), new Color(currentRed, currentGreen, currentBlue, 1f)); ((SkeletonRenderer)interaction.follower.Spine).skeleton.A = currentAlpha; ((SkeletonRenderer)interaction.follower.Spine).skeleton.ScaleX = currentScale; ((SkeletonRenderer)interaction.follower.Spine).skeleton.ScaleY = currentScale; Plugin.Log.LogInfo((object)("Scale is set to: " + currentScale + "X is " + ((SkeletonRenderer)interaction.follower.Spine).Skeleton.ScaleX + " Y is " + ((SkeletonRenderer)interaction.follower.Spine).Skeleton.ScaleY)); if (isCustomFollowerCostumeEnabled) { CustomColorHelper.SetCustomCostume(interaction.follower.Brain.Info.ID, enabled: true, selectedClothingTypeIndex, selectedSpecialTypeIndex, selectedHatTypeIndex, selectedOutfitTypeIndex, selectedNecklaceTypeIndex); } else { CustomColorHelper.SetCustomCostume(interaction.follower.Brain.Info.ID, enabled: false, 0, 0, 0, 0, 0); } } else { CustomColorHelper.RemoveCustomColor(interaction.follower.Brain.Info.ID); } interaction.Close(true, true, false); }); HUD_Manager.Instance.Hide(false, 0, false); })); } public void CreateColorUI() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0c04: Unknown result type (might be due to invalid IL or missing references) //IL_0c0e: Expected I4, but got Unknown //IL_0c26: Unknown result type (might be due to invalid IL or missing references) //IL_0c30: Expected I4, but got Unknown //IL_0c48: Unknown result type (might be due to invalid IL or missing references) //IL_0c52: Expected I4, but got Unknown //IL_0c6a: Unknown result type (might be due to invalid IL or missing references) //IL_0c74: Expected I4, but got Unknown if ((Object)(object)_followerSummaryMenuController == (Object)null) { Debug.LogError((object)"Follower Summary Menu Controller is not initialized."); return; } Debug.Log((object)"Creating color picker UI..."); Time.timeScale = 1f; Transform val = ((Component)_followerSummaryMenuController).transform.Find("BlurImageBackground"); ((Component)val).gameObject.SetActive(false); GameManager.GetInstance().CameraSetOffset(new Vector3(-2f, 0f, 0f)); Transform val2 = ((Component)_followerSummaryMenuController).transform.Find("FollowerSummaryContainer"); Transform val3 = ((val2 != null) ? val2.Find("Left") : null); Transform val4 = ((val3 != null) ? val3.Find("Transform") : null); Transform val5 = ((val4 != null) ? val4.Find("Top") : null); Transform val6 = ((val5 != null) ? val5.Find("Header") : null); TMP_Text val7 = ((val6 != null) ? ((Component)val6).GetComponent() : null); if ((Object)(object)val7 != (Object)null) { val7.text = "Customize Follower"; } Transform val8 = ((val4 != null) ? val4.Find("Content") : null); Transform val9 = ((val8 != null) ? val8.Find("Scroll View") : null); Transform val10 = ((val9 != null) ? val9.Find("Viewport") : null); Transform val11 = ((val10 != null) ? val10.Find("Content") : null); Transform val12 = ((val11 != null) ? val11.Find("Follower Traits Header") : null); TMP_Text val13 = ((val12 != null) ? ((Component)val12).GetComponent() : null); if ((Object)(object)val13 != (Object)null) { val13.text = "Color preview above."; } Transform val14 = ((val11 != null) ? val11.Find("Follower Traits Content") : null); if (val14 != null) { ((Component)val14).gameObject.SetActive(false); } Transform val15 = ((val11 != null) ? val11.Find("Cult Traits Header") : null); TMP_Text val16 = ((val15 != null) ? ((Component)val15).GetComponent() : null); if ((Object)(object)val15 != (Object)null) { val16.text = "Costume Preview on the right."; } Transform val17 = ((val11 != null) ? val11.Find("Cult Traits Content") : null); if (val17 != null) { ((Component)val17).gameObject.SetActive(false); } Transform val18 = ((val11 != null) ? val11.Find("Follower Thoughts") : null); if (val18 != null) { ((Component)val18).gameObject.SetActive(false); } Transform val19 = ((val11 != null) ? val11.Find("Follower Thoughts Content") : null); if (val19 != null) { ((Component)val19).gameObject.SetActive(false); } Transform val20 = ((val11 != null) ? val11.Find("Spacer") : null); GameObject gameObject = ((Component)((Transform)((Component)MonoSingleton.Instance.SettingsMenuControllerTemplate._audioSettings).GetComponentInChildren().content).GetChild(0)).gameObject; GameObject gameObject2 = ((Component)((Transform)((Component)MonoSingleton.Instance.SettingsMenuControllerTemplate._graphicsSettings).GetComponentInChildren().content).GetChild(4)).gameObject; GameObject gameObject3 = ((Component)((Transform)((Component)MonoSingleton.Instance.SettingsMenuControllerTemplate._graphicsSettings).GetComponentInChildren().content).GetChild(3)).gameObject; GameObject val21 = Object.Instantiate(gameObject2, val11); Transform val22 = Object.Instantiate(val20, val11); GameObject val23 = Object.Instantiate(gameObject, val11); Transform val24 = Object.Instantiate(val20, val11); GameObject val25 = Object.Instantiate(gameObject, val11); Transform val26 = Object.Instantiate(val20, val11); GameObject val27 = Object.Instantiate(gameObject, val11); Transform val28 = Object.Instantiate(val20, val11); GameObject val29 = Object.Instantiate(gameObject, val11); Transform val30 = Object.Instantiate(val20, val11); GameObject val31 = Object.Instantiate(gameObject, val11); Transform val32 = Object.Instantiate(val20, val11); GameObject val33 = Object.Instantiate(gameObject2, val11); Transform val34 = Object.Instantiate(val20, val11); GameObject val35 = Object.Instantiate(gameObject3, val11); Transform val36 = Object.Instantiate(val20, val11); GameObject val37 = Object.Instantiate(gameObject3, val11); Transform val38 = Object.Instantiate(val20, val11); GameObject val39 = Object.Instantiate(gameObject3, val11); Transform val40 = Object.Instantiate(val20, val11); GameObject val41 = Object.Instantiate(gameObject3, val11); Transform val42 = Object.Instantiate(val20, val11); GameObject val43 = Object.Instantiate(gameObject3, val11); TMP_Text componentInChildren = val23.GetComponentInChildren(); TMP_Text componentInChildren2 = val25.GetComponentInChildren(); TMP_Text componentInChildren3 = val27.GetComponentInChildren(); TMP_Text componentInChildren4 = val29.GetComponentInChildren(); TMP_Text componentInChildren5 = val31.GetComponentInChildren(); TMP_Text componentInChildren6 = val21.GetComponentInChildren(); MMSlider componentInChildren7 = val23.GetComponentInChildren(); MMSlider componentInChildren8 = val25.GetComponentInChildren(); MMSlider componentInChildren9 = val27.GetComponentInChildren(); MMSlider componentInChildren10 = val29.GetComponentInChildren(); MMSlider componentInChildren11 = val31.GetComponentInChildren(); MMToggle componentInChildren12 = val21.GetComponentInChildren(); ((Object)val23).name = "SliderRed"; ((Object)val25).name = "SliderGreen"; ((Object)val27).name = "SliderBlue"; ((Object)val29).name = "SliderAlpha"; ((Object)val31).name = "SliderScale"; ((Object)val21).name = "ToggleCustomColor"; componentInChildren.text = "Red"; componentInChildren2.text = "Green"; componentInChildren3.text = "Blue"; componentInChildren4.text = "Alpha"; componentInChildren5.text = "Scale"; componentInChildren6.text = "Enable Customization"; ((UnityEvent)(object)((Slider)componentInChildren7).onValueChanged).AddListener((UnityAction)delegate(float value) { OnSliderValueChanged("Red", value); }); ((UnityEvent)(object)((Slider)componentInChildren8).onValueChanged).AddListener((UnityAction)delegate(float value) { OnSliderValueChanged("Green", value); }); ((UnityEvent)(object)((Slider)componentInChildren9).onValueChanged).AddListener((UnityAction)delegate(float value) { OnSliderValueChanged("Blue", value); }); ((UnityEvent)(object)((Slider)componentInChildren10).onValueChanged).AddListener((UnityAction)delegate(float value) { OnSliderValueChanged("Alpha", value); }); ((UnityEvent)(object)((Slider)componentInChildren11).onValueChanged).AddListener((UnityAction)delegate(float value) { OnSliderValueChanged("Scale", value); }); componentInChildren12.OnValueChanged = (Action)Delegate.Combine(componentInChildren12.OnValueChanged, (Action)delegate(bool value) { OnToggleValueChanged(value, _followerSummaryMenuController._follower); }); componentInChildren7._increment = 1; componentInChildren8._increment = 1; componentInChildren9._increment = 1; componentInChildren10._increment = 1; componentInChildren11._increment = 1; ((Slider)componentInChildren7).value = ((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN").R * 100f; ((Slider)componentInChildren8).value = ((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN").G * 100f; ((Slider)componentInChildren9).value = ((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN").B * 100f; ((Slider)componentInChildren10).value = ((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton.A * 100f; ((Slider)componentInChildren11).value = (currentScale - 0.1f) / 4.9f * 100f; MMToggle componentInChildren13 = val33.GetComponentInChildren(); TMP_Text componentInChildren14 = val33.GetComponentInChildren(); TMP_Text componentInChildren15 = val35.GetComponentInChildren(); TMP_Text componentInChildren16 = val37.GetComponentInChildren(); TMP_Text componentInChildren17 = val39.GetComponentInChildren(); TMP_Text componentInChildren18 = val41.GetComponentInChildren(); TMP_Text componentInChildren19 = val43.GetComponentInChildren(); ((Object)val35).name = "FollowerClothingType"; ((Object)val37).name = "FollowerSpecialOverlayType"; ((Object)val39).name = "FollowerHatType"; ((Object)val41).name = "FollowerOutfitType"; ((Object)val43).name = "FollowerNecklaceType"; ((Object)val33).name = "EnableFollowerCostumeOverride"; componentInChildren15.text = "Clothing Type"; componentInChildren16.text = "Special Type"; componentInChildren17.text = "Hat Type"; componentInChildren18.text = "Outfit Type"; componentInChildren19.text = "Necklace Type"; componentInChildren14.text = "Follower Costume Override"; Array values = Enum.GetValues(typeof(FollowerClothingType)); List list = (from FollowerClothingType x in values select ((object)(FollowerClothingType)(ref x)).ToString()).ToList(); Array values2 = Enum.GetValues(typeof(FollowerSpecialType)); List list2 = (from FollowerSpecialType x in values2 select ((object)(FollowerSpecialType)(ref x)).ToString()).ToList(); for (int i = 0; i < list2.Count; i++) { if (list2[i].Contains("Palworld")) { list2[i] = "Unused_" + i; } } Array values3 = Enum.GetValues(typeof(FollowerHatType)); List list3 = (from FollowerHatType x in values3 select ((object)(FollowerHatType)(ref x)).ToString()).ToList(); Array values4 = Enum.GetValues(typeof(FollowerOutfitType)); List list4 = (from FollowerOutfitType x in values4 select ((object)(FollowerOutfitType)(ref x)).ToString()).ToList(); List list5 = DataManager.AllNecklaces.Select((ITEM_TYPE x) => ((object)(ITEM_TYPE)(ref x)).ToString()).ToList(); list5.Insert(0, "Original"); list5.Insert(1, "None"); componentInChildren13.OnValueChanged = (Action)Delegate.Combine(componentInChildren13.OnValueChanged, (Action)delegate(bool value) { OnFollowerCostumeToggleChanged(value, _followerSummaryMenuController._follower); }); MMHorizontalSelector componentInChildren20 = val35.GetComponentInChildren(); componentInChildren20._localizeContent = false; componentInChildren20.UpdateContent(list.ToArray()); componentInChildren20.OnSelectionChanged = (Action)Delegate.Combine(componentInChildren20.OnSelectionChanged, (Action)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(FollowerClothingType), index); }); MMHorizontalSelector componentInChildren21 = val37.GetComponentInChildren(); componentInChildren21._localizeContent = false; componentInChildren21.UpdateContent(list2.ToArray()); componentInChildren21.OnSelectionChanged = (Action)Delegate.Combine(componentInChildren21.OnSelectionChanged, (Action)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(FollowerSpecialType), index); }); MMHorizontalSelector componentInChildren22 = val39.GetComponentInChildren(); componentInChildren22._localizeContent = false; componentInChildren22.UpdateContent(list3.ToArray()); componentInChildren22.OnSelectionChanged = (Action)Delegate.Combine(componentInChildren22.OnSelectionChanged, (Action)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(FollowerHatType), index); }); MMHorizontalSelector componentInChildren23 = val41.GetComponentInChildren(); componentInChildren23._localizeContent = false; componentInChildren23.UpdateContent(list4.ToArray()); componentInChildren23.OnSelectionChanged = (Action)Delegate.Combine(componentInChildren23.OnSelectionChanged, (Action)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(FollowerOutfitType), index); }); MMHorizontalSelector componentInChildren24 = val43.GetComponentInChildren(); componentInChildren24._localizeContent = false; componentInChildren24.UpdateContent(list5.ToArray()); componentInChildren24.OnSelectionChanged = (Action)Delegate.Combine(componentInChildren24.OnSelectionChanged, (Action)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(ITEM_TYPE), index); }); CustomFollowerColor customColor = CustomColorHelper.GetCustomColor(_followerSummaryMenuController._follower.Brain.Info.ID); if (customColor != null) { componentInChildren12.Value = true; componentInChildren12.UpdateState(true); isCustomColorEnabled = true; componentInChildren13.Value = customColor.CustomFollowerCostume; componentInChildren13.UpdateState(true); isCustomFollowerCostumeEnabled = customColor.CustomFollowerCostume; componentInChildren20.ContentIndex = Mathf.Clamp(customColor.FollowerClothingType, 0, list.Count - 1); componentInChildren21.ContentIndex = Mathf.Clamp(customColor.FollowerSpecialType, 0, list2.Count - 1); componentInChildren22.ContentIndex = Mathf.Clamp(customColor.FollowerHatType, 0, list3.Count - 1); componentInChildren23.ContentIndex = Mathf.Clamp(customColor.FollowerOutfitType, 0, list4.Count - 1); componentInChildren24.ContentIndex = Mathf.Clamp(customColor.FollowerNecklaceType, 0, list5.Count - 1); } else { componentInChildren12.Value = false; componentInChildren12.UpdateState(true); isCustomColorEnabled = false; componentInChildren13.Value = false; componentInChildren13.UpdateState(true); isCustomFollowerCostumeEnabled = false; componentInChildren20.ContentIndex = (int)_followerSummaryMenuController._follower.Brain.Info.Clothing; componentInChildren21.ContentIndex = (int)_followerSummaryMenuController._follower.Brain.Info.Special; componentInChildren22.ContentIndex = (int)_followerSummaryMenuController._follower.Brain.Info.Hat; componentInChildren23.ContentIndex = (int)_followerSummaryMenuController._follower.Brain.Info.Outfit; componentInChildren24.ContentIndex = 0; } } public void OnFollowerCostumeSelectorsChanged(Type enumType, int value) { //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Invalid comparison between Unknown and I4 //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) switch (enumType.Name) { case "FollowerClothingType": Plugin.Log.LogInfo((object)$"Setting clothing type to {(object)(FollowerClothingType)value}"); selectedClothingTypeIndex = value; break; case "FollowerSpecialType": Plugin.Log.LogInfo((object)$"Setting special type to {(object)(FollowerSpecialType)value}"); selectedSpecialTypeIndex = value; break; case "FollowerHatType": Plugin.Log.LogInfo((object)$"Setting hat type to {(object)(FollowerHatType)value}"); selectedHatTypeIndex = value; break; case "FollowerOutfitType": Plugin.Log.LogInfo((object)$"Setting outfit type to {(object)(FollowerOutfitType)value}"); selectedOutfitTypeIndex = value; break; case "ITEM_TYPE": Plugin.Log.LogInfo((object)$"Setting necklace type to {(object)(ITEM_TYPE)value}"); selectedNecklaceTypeIndex = value; break; default: Plugin.Log.LogWarning((object)("Unknown enum type for follower costume selector change: " + enumType.Name)); break; } if (!isCustomFollowerCostumeEnabled || !isCustomColorEnabled) { Plugin.Log.LogInfo((object)"Custom follower costume not enabled, skipping costume set."); return; } Plugin.Log.LogInfo((object)("Setting costume override now... overrides are: " + $"ClothingType: {(object)(FollowerClothingType)selectedClothingTypeIndex}, " + $"SpecialType: {(object)(FollowerSpecialType)selectedSpecialTypeIndex}, " + $"HatType: {(object)(FollowerHatType)selectedHatTypeIndex}, " + $"OutfitType: {(object)(FollowerOutfitType)selectedOutfitTypeIndex}")); try { FollowerSpecialType val = (FollowerSpecialType)selectedSpecialTypeIndex; string text = _followerSummaryMenuController._follower.Brain.Info.SkinName; if (val - 11 <= 2) { text = GetSnowmanRandomSkin((FollowerSpecialType)selectedSpecialTypeIndex); Plugin.Log.LogInfo((object)("Applying snowman skin: " + text)); } FollowerBrain.SetFollowerCostume(((SkeletonRenderer)_followerSummaryMenuController._follower.Spine).skeleton, _followerSummaryMenuController._follower.Brain.Info.XPLevel, text, _followerSummaryMenuController._follower.Brain.Info.SkinColour, (FollowerOutfitType)selectedOutfitTypeIndex, (FollowerHatType)selectedHatTypeIndex, (FollowerClothingType)selectedClothingTypeIndex, _followerSummaryMenuController._follower.Brain.Info.Customisation, val, GetNecklaceToUse(selectedNecklaceTypeIndex, _followerSummaryMenuController._follower.Brain._directInfoAccess), "", _followerSummaryMenuController._follower.Brain._directInfoAccess); Plugin.Log.LogInfo((object)"Costume override applied successfully."); } catch (Exception) { Plugin.Log.LogWarning((object)"The costume combinations were invalid, try another!"); } } public static string GetSnowmanRandomSkin(FollowerSpecialType snowmanType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown if (1 == 0) { } string text = (snowmanType - 11) switch { 2 => "Snowman/Bad_", 1 => "Snowman/Mid_", 0 => "Snowman/Good_", _ => "Snowman/Good_", }; if (1 == 0) { } string arg = text; return $"{arg}{Random.Range(1, 4)}"; } public static ITEM_TYPE GetNecklaceToUse(int selectedNecklaceTypeIndex, FollowerInfo follower) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) int num = selectedNecklaceTypeIndex - 2; if (selectedNecklaceTypeIndex > 1 && (num < 0 || num >= DataManager.AllNecklaces.Count)) { Plugin.Log.LogWarning((object)"Selected necklace type index is out of bounds, defaulting to Original."); return follower.Necklace; } if (1 == 0) { } ITEM_TYPE result = (ITEM_TYPE)(selectedNecklaceTypeIndex switch { 0 => follower.Necklace, 1 => 0, _ => DataManager.AllNecklaces[selectedNecklaceTypeIndex - 2], }); if (1 == 0) { } return result; } public void OnFollowerCostumeToggleChanged(bool value, Follower follower) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) Debug.Log((object)$"Follower costume toggle changed to {value}"); isCustomFollowerCostumeEnabled = value; if (!isCustomFollowerCostumeEnabled) { Debug.Log((object)"Custom follower costume disabled, reset costume."); FollowerBrain.SetFollowerCostume(((SkeletonRenderer)follower.Spine).skeleton, follower.Brain.Info.XPLevel, follower.Brain.Info.SkinName, follower.Brain.Info.SkinColour, follower.Brain.Info.Outfit, follower.Brain.Info.Hat, follower.Brain.Info.Clothing, follower.Brain.Info.Customisation, follower.Brain.Info.Special, follower.Brain.Info.Necklace, "", follower.Brain._directInfoAccess); } else { OnFollowerCostumeSelectorsChanged(typeof(FollowerClothingType), selectedClothingTypeIndex); } } public void OnToggleValueChanged(bool value, Follower follower) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) Debug.Log((object)$"Toggle value changed to {value}"); isCustomColorEnabled = value; if (!isCustomColorEnabled) { Debug.Log((object)"Custom color disabled, reset to default colors."); FollowerBrain.SetFollowerCostume(((SkeletonRenderer)follower.Spine).skeleton, follower.Brain.Info.XPLevel, follower.Brain.Info.SkinName, follower.Brain.Info.SkinColour, follower.Brain.Info.Outfit, follower.Brain.Info.Hat, follower.Brain.Info.Clothing, follower.Brain.Info.Customisation, follower.Brain.Info.Special, follower.Brain.Info.Necklace, "", follower.Brain._directInfoAccess); } } public void OnSliderValueChanged(string color, float value) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) value /= 100f; Debug.Log((object)$"Slider {color} value changed to {value}"); if ((Object)(object)_followerSummaryMenuController == (Object)null) { Debug.LogError((object)"Follower Summary Menu Controller is not initialized."); return; } Follower follower = _followerSummaryMenuController._follower; SkeletonGraphic followerSpine = _followerSummaryMenuController._infoBox.FollowerSpine; Color color2 = SkeletonExtensions.GetColor(((SkeletonRenderer)follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN")); switch (color) { case "Red": currentRed = value; followerSpine.skeleton.FindSlot("ARM_LEFT_SKIN").R = value; followerSpine.skeleton.FindSlot("LEG_LEFT_SKIN").R = value; followerSpine.skeleton.FindSlot("LEG_RIGHT_SKIN").R = value; followerSpine.skeleton.FindSlot("ARM_RIGHT_SKIN").R = value; followerSpine.skeleton.FindSlot("HEAD_SKIN_BTM").R = value; break; case "Green": currentGreen = value; followerSpine.skeleton.FindSlot("ARM_LEFT_SKIN").G = value; followerSpine.skeleton.FindSlot("LEG_LEFT_SKIN").G = value; followerSpine.skeleton.FindSlot("LEG_RIGHT_SKIN").G = value; followerSpine.skeleton.FindSlot("ARM_RIGHT_SKIN").G = value; followerSpine.skeleton.FindSlot("HEAD_SKIN_BTM").G = value; break; case "Blue": currentBlue = value; followerSpine.skeleton.FindSlot("ARM_LEFT_SKIN").B = value; followerSpine.skeleton.FindSlot("LEG_LEFT_SKIN").B = value; followerSpine.skeleton.FindSlot("LEG_RIGHT_SKIN").B = value; followerSpine.skeleton.FindSlot("ARM_RIGHT_SKIN").B = value; followerSpine.skeleton.FindSlot("HEAD_SKIN_BTM").B = value; break; case "Alpha": currentAlpha = value; ((Graphic)followerSpine).color = new Color(((Graphic)followerSpine).color.r, ((Graphic)followerSpine).color.g, ((Graphic)followerSpine).color.b, value); break; case "Scale": currentScale = value * 4.9f + 0.1f; ((Component)followerSpine).transform.localScale = new Vector3(currentScale, currentScale, 1f); break; } } } } namespace CustomSpineLoader.APIHelper { public class CustomDungeon { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static DieAction <>9__24_0; internal void b__24_0(GameObject Attacker, Vector3 AttackLocation, Health Victim, AttackTypes AttackType, AttackFlags AttackFlags) { Plugin.Log.LogInfo((object)"Custom Enemy died, checking if room is clear..."); if (Health.team2.Count - 1 == 0) { Plugin.Log.LogInfo((object)"Room is clear!"); RoomLockController.RoomCompleted(false, true); } else { Plugin.Log.LogInfo((object)$"Enemies remaining: {Health.team2.Count}"); } } } [CompilerGenerated] private sealed class d__25 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public UnitObject spawned; public CustomDungeon <>4__this; private int 5__1; private Vector3 5__2; private Door 5__3; private Vector3 5__4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__25(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; Plugin.Log.LogInfo((object)$"Repositioning enemies {spawned})"); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; 5__1 = 10; break; case 2: <>1__state = -1; 5__1--; break; } if (5__1 > 0) { if ((Object)(object)Door.GetFirstNonEntranceDoor() == (Object)null && 5__1 > 1) { Plugin.Log.LogWarning((object)"Door not found for enemy repositioning, retrying..."); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 2; return true; } if (5__1 <= 1) { Plugin.Log.LogWarning((object)"Failed to find door for enemy repositioning after multiple attempts, placing enemy in fallback position."); if (Door.Doors.Count > 0) { 5__3 = Door.Doors[0]; 5__4 = ((Component)5__3).transform.position + 5__3.GetDoorDirection() * 7.3f; ((Component)spawned).transform.position = 5__4; Plugin.Log.LogInfo((object)"Enemy placed on fallback door position."); 5__3 = null; } else { Plugin.Log.LogWarning((object)"No doors found in the scene for enemy repositioning, using current position."); } return false; } 5__2 = ((Component)Door.GetFirstNonEntranceDoor()).transform.position; 5__2 += Door.GetFirstNonEntranceDoor().GetDoorDirection() * 7.3f; ((Component)spawned).transform.position = 5__2; Plugin.Log.LogInfo((object)"Enemy placed on entrance position."); return false; } Plugin.Log.LogInfo((object)"Failed to reposition enemy after multiple attempts, leaving in original position."); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal string ModPrefix = ""; public List NormalEnemyList = new List(); public int mobsPerRoom = 3; public virtual string InternalName { get; } = ""; public virtual string SceneName => "Dungeon1"; public virtual string DungeonName => "Meow Dungeon"; public virtual int Difficulty => 1; public textBlendMode TitleTextBlendMode => (textBlendMode)1; public Positions TitleTextPosition => (Positions)1; public virtual int NumRooms => 3; public virtual FollowerLocation Location { get; set; } = (FollowerLocation)7; private Vector3 GetRandomWalkablePosition() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) NavGraph obj = AstarPath.active.graphs[0]; GridGraph val = (GridGraph)(object)((obj is GridGraph) ? obj : null); if (val == null) { Plugin.Log.LogWarning((object)"AStar GridGraph not found, using fallback position for enemy spawn."); return ((Component)PlayerFarming.Instance).transform.position + Random.insideUnitSphere * 2f; } List list = new List(); GridNode[] nodes = val.nodes; foreach (GridNode val2 in nodes) { if (((GraphNode)val2).Walkable) { list.Add(val2); } } if (list.Count == 0) { Plugin.Log.LogWarning((object)"No walkable nodes found in AStar graph, using fallback position for enemy spawn."); return ((Component)PlayerFarming.Instance).transform.position + Random.insideUnitSphere * 2f; } GridNode val3 = list[Random.Range(0, list.Count)]; return (Vector3)((GraphNode)val3).position; } public virtual void EnterDungeon() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Invalid comparison between Unknown and I4 //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) CustomDungeonManager.EnteringCustomDungeon = Location; Plugin.Log.LogInfo((object)$"Entering Custom Dungeon: {Location} with scene {SceneName} and {NumRooms} rooms."); AudioManager.Instance.StopCurrentMusic(); AudioManager.Instance.StopCurrentAtmos(true); AudioManager.Instance.PlayOneShot("event:/Stings/boss_door_complete"); AudioManager.Instance.PlayOneShot("event:/ui/map_location_appear"); PlayerFarming.ReloadAllFaith(-1); MMTransition.StopCurrentTransition(); if ((int)Location == 53 || (int)Location == 86) { DataManager.Instance.CurrentDLCNodeType = (NodeType)3; } Interaction_BaseDungeonDoor.GetFloor(Location); MMTransition.Play((TransitionType)1, (Effect)0, SceneName, 1f, "", (Action)FadeSave, (Action)null); GameManager.GetInstance().OnConversationNew(true, true, (PlayerFarming)null); } public virtual void SpawnEnemies(GenerateRoom room, ConnectionTypes connectionType) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)$"Spawning enemies for connection type {connectionType} in custom dungeon {Location}"); if ((int)connectionType != 1) { if ((int)connectionType == 4) { Plugin.Log.LogInfo((object)"Spawning boss test"); } return; } Plugin.Log.LogInfo((object)"Spawning true test"); if (NormalEnemyList.Count == 0) { Plugin.Log.LogWarning((object)"No enemies to spawn for this dungeon."); if (RoomLockController.RoomLockControllers.Count > 0) { RoomLockController.RoomCompleted(false, true); } return; } for (int i = 0; i < mobsPerRoom; i++) { Enemy val = NormalEnemyList[Random.Range(0, NormalEnemyList.Count)]; Vector3 randomWalkablePosition = GetRandomWalkablePosition(); UnitObject val2 = CustomEnemyManager.Spawn(val, randomWalkablePosition); Health health = val2.health; object obj = <>c.<>9__24_0; if (obj == null) { DieAction val3 = delegate { Plugin.Log.LogInfo((object)"Custom Enemy died, checking if room is clear..."); if (Health.team2.Count - 1 == 0) { Plugin.Log.LogInfo((object)"Room is clear!"); RoomLockController.RoomCompleted(false, true); } else { Plugin.Log.LogInfo((object)$"Enemies remaining: {Health.team2.Count}"); } }; <>c.<>9__24_0 = val3; obj = (object)val3; } health.OnDie += (DieAction)obj; RoomLockController val4 = null; float num = float.PositiveInfinity; foreach (RoomLockController roomLockController in RoomLockController.RoomLockControllers) { if (roomLockController.CanApplyUnitCorrection) { float num2 = Vector3.Distance(((Component)val2).transform.position, ((Component)roomLockController).transform.position); if (num2 < num) { val4 = roomLockController; num = num2; } } } if ((Object)(object)val4 != (Object)null) { Plugin.Log.LogInfo((object)("Found RoomLockController for enemy position correction: " + ((Object)val4).name)); ((Component)val2).transform.position = val4.BlockingCollider.transform.position - val4.BlockingCollider.transform.up * 0.5f; } else { Plugin.Log.LogWarning((object)"No RoomLockController found for enemy position correction."); } Vector3 position = ((Component)val2).transform.position; Plugin.Log.LogInfo((object)"Starting coroutine to reposition enemy after spawn..."); ((MonoBehaviour)val2).StartCoroutine(RepositionEnemies(val2)); } } [IteratorStateMachine(typeof(d__25))] public IEnumerator RepositionEnemies(UnitObject spawned) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__25(0) { <>4__this = this, spawned = spawned }; } public virtual void ExitDoor() { MonoSingleton.Instance.ShowDeathScreenOverlay((Results)1); AudioManager.Instance.PlayOneShot("event:/pentagram_platform/pentagram_platform_curse"); AudioManager.Instance.PlayOneShot("event:/ui/heretics_defeated"); AudioManager.Instance.PlayMusic("event:/music/game_over/game_over", true); } private void FadeSave() { SaveAndLoad.Save(); } } public class CustomDungeonManager { public static FollowerLocation EnteringCustomDungeon = (FollowerLocation)(-1); public static Dictionary CustomDungeonList { get; } = new Dictionary(); public static FollowerLocation Add(CustomDungeon customDungeon) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) string modIdFromCallstack = TypeManager.GetModIdFromCallstack(Assembly.GetCallingAssembly()); FollowerLocation location = customDungeon.Location; FollowerLocation val = (customDungeon.Location = GuidManager.GetEnumValue(modIdFromCallstack, ((object)(FollowerLocation)(ref location)).ToString())); customDungeon.ModPrefix = modIdFromCallstack; CustomDungeonList.Add(val, customDungeon); Plugin.Log.LogWarning((object)$"Added: {val} {customDungeon.SceneName} {customDungeon.ModPrefix}"); return val; } } public class CustomItemLoader : Loader { public static List loadedItems = new List(); public CustomItemLoader() : base("CustomInventoryItems") { } public static void LoadAllCustomItems() { //IL_01ad: Unknown result type (might be due to invalid IL or missing references) CustomItemLoader customItemLoader = new CustomItemLoader(); List> list = customItemLoader.LoadAll(); foreach (LoaderResult item in list) { CustomItemConfig config = item.Config; string folderName = item.FolderName; Plugin.Log.LogInfo((object)("Found custom item folder: " + folderName)); string internalName = "CULT_TWEAKER_" + config.ItemName.ToUpper().Replace(" ", "_"); Plugin.Log.LogInfo((object)("Trying to create custom item : " + config.ItemName)); string text = Path.Combine(item.FolderPath, config.SpritePath); if (!File.Exists(text)) { Plugin.Log.LogError((object)("Sprite file not found for item " + config.ItemName + " at path: " + text)); continue; } Plugin.Log.LogInfo((object)("Loading Sprite via " + text)); try { CustomInventoryItem val = (CustomInventoryItem)(object)new CultTweakerCustomItem(internalName, config.ItemName, config.ItemType, config.CanBeRefined, config.RefineryInputQty, config.CustomRefineryDuration, text, config.FuelWeight, config.FoodSatitation, config.IsFish, config.IsFood, config.IsBigFish, config.IsCurrency, config.IsBurnableFuel, config.CanBeGivenToFollower, config.Lore, config.Description, config.AddItemToOfferingShrine, config.AddItemToDungeonChests, config.DungeonChestSpawnChance, config.DungeonChestMinAmount, config.DungeonChestMaxAmount); Plugin.Log.LogInfo((object)("Successfully created custom item with internal name : " + val.InternalName)); loadedItems.Add(CustomItemManager.Add(val)); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to create custom item : " + config.ItemName)); Plugin.Log.LogError((object)ex); } } } } public class CultTweakerCustomItem : CustomInventoryItem { private readonly string _internalName; private readonly string _itemName; private readonly int _itemType; private readonly bool _canBeRefined; private readonly int _refineryInputQty; private readonly float _customRefineryDuration; private readonly string _spritePath; private readonly int _fuelWeight; private readonly int _foodSatitation; private readonly bool _isFish; private readonly bool _isFood; private readonly bool _isBigFish; private readonly bool _isCurrency; private readonly bool _isBurnableFuel; private readonly bool _canBeGivenToFollower; private readonly string _lore; private readonly string _description; private readonly bool _addItemToOfferingShrine; private readonly bool _addItemToDungeonChests; private readonly int _dungeonChestSpawnChance; private readonly int _dungeonChestMinAmount; private readonly int _dungeonChestMaxAmount; public override string InternalName => _internalName; public override bool CanBeRefined => _canBeRefined; public override int RefineryInputQty => _refineryInputQty; public override float CustomRefineryDuration => _customRefineryDuration; public override Sprite InventoryIcon => TextureHelper.CreateSpriteFromPath(_spritePath); public override Sprite Sprite => TextureHelper.CreateSpriteFromPath(_spritePath); public override int FuelWeight => _fuelWeight; public override int FoodSatitation => _foodSatitation; public override bool IsFish => _isFish; public override bool IsFood => _isFood; public override bool IsBigFish => _isBigFish; public override bool IsCurrency => _isCurrency; public override bool IsBurnableFuel => _isBurnableFuel; public override bool CanBeGivenToFollower => _canBeGivenToFollower; public override bool AddItemToOfferingShrine => _addItemToOfferingShrine; public override bool AddItemToDungeonChests => _addItemToDungeonChests; public override int DungeonChestSpawnChance => _dungeonChestSpawnChance; public override int DungeonChestMinAmount => _dungeonChestMinAmount; public override int DungeonChestMaxAmount => _dungeonChestMaxAmount; public CultTweakerCustomItem(string internalName, string ItemName, int ItemType, bool CanBeRefined, int RefineryInputQty, float CustomRefineryDuration, string SpritePath, int FuelWeight, int FoodSatitation, bool IsFish, bool IsFood, bool IsBigFish, bool IsCurrency, bool IsBurnableFuel, bool CanBeGivenToFollower, string Lore, string Description, bool AddItemToOfferingShrine, bool AddItemToDungeonChests, int DungeonChestSpawnChance, int DungeonChestMinAmount, int DungeonChestMaxAmount) { _internalName = internalName; _itemName = ItemName; _itemType = ItemType; _canBeRefined = CanBeRefined; _refineryInputQty = RefineryInputQty; _customRefineryDuration = CustomRefineryDuration; _spritePath = SpritePath; _fuelWeight = FuelWeight; _foodSatitation = FoodSatitation; _isFish = IsFish; _isFood = IsFood; _isBigFish = IsBigFish; _isCurrency = IsCurrency; _isBurnableFuel = IsBurnableFuel; _canBeGivenToFollower = CanBeGivenToFollower; _lore = Lore; _description = Description; _addItemToOfferingShrine = AddItemToOfferingShrine; _addItemToDungeonChests = AddItemToDungeonChests; _dungeonChestSpawnChance = DungeonChestSpawnChance; _dungeonChestMinAmount = DungeonChestMinAmount; _dungeonChestMaxAmount = DungeonChestMaxAmount; ((CustomInventoryItem)this)..ctor(); } public override string Name() { return _itemName; } public override string Lore() { return _lore; } public override string Description() { return _description; } } [Serializable] public class CustomItemConfig { public string ItemName; public int ItemType; public bool CanBeRefined = false; public int RefineryInputQty = 15; public float CustomRefineryDuration = 0f; public string SpritePath; public int FuelWeight = 1; public int FoodSatitation = 75; public bool IsFish = false; public bool IsFood = false; public bool IsBigFish = false; public bool IsCurrency = false; public bool IsBurnableFuel = false; public bool CanBeGivenToFollower = false; public string Lore = "Custom Item created with CultTweaker."; public string Description = "This is a custom item created with CultTweaker."; public bool AddItemToOfferingShrine = false; public bool AddItemToDungeonChests = false; public int DungeonChestSpawnChance = 100; public int DungeonChestMinAmount = 1; public int DungeonChestMaxAmount = 1; } public class CustomMealLoader : Loader { public static List loadedMeals = new List(); public CustomMealLoader() : base("CustomMeals") { } public static void LoadAllCustomMeals() { //IL_014d: Unknown result type (might be due to invalid IL or missing references) CustomMealLoader customMealLoader = new CustomMealLoader(); List> list = customMealLoader.LoadAll(); foreach (LoaderResult item in list) { CustomMealConfig config = item.Config; string folderName = item.FolderName; Plugin.Log.LogInfo((object)("Found custom meal folder: " + folderName)); string internalName = "CULT_TWEAKER_MEAL_" + (config.ItemName ?? "UNKNOWN").ToUpper().Replace(" ", "_"); Plugin.Log.LogInfo((object)("Trying to create custom meal : " + config.ItemName)); string text = (string.IsNullOrEmpty(config.SpritePath) ? string.Empty : Path.Combine(item.FolderPath, config.SpritePath)); if (!string.IsNullOrEmpty(text) && !File.Exists(text)) { Plugin.Log.LogWarning((object)("Sprite file not found for meal " + config.ItemName + " at path: " + text + ", skipping sprite (this may be optional)")); } try { CultTweakerCustomMeal cultTweakerCustomMeal = new CultTweakerCustomMeal(internalName, config, text); Plugin.Log.LogInfo((object)("Successfully created custom meal with internal name : " + ((CustomInventoryItem)cultTweakerCustomMeal).InternalName)); loadedMeals.Add(CustomItemManager.Add((CustomMeal)(object)cultTweakerCustomMeal)); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to create custom meal : " + config.ItemName)); Plugin.Log.LogError((object)ex.ToString()); } } } } [Serializable] public class CustomMealConfig : CustomItemConfig { public int SatiationLevel = 0; public float TummyRating = 0f; public string MealQuality = "NORMAL"; public bool MealSafeToEat = true; public Dictionary Recipe = new Dictionary(); public Dictionary MealEffectsDictionary = new Dictionary(); } public class CultTweakerCustomMeal : CustomMeal { private readonly string _internalName; private readonly string _mealName; private readonly string _spritePath; private readonly int _satiationLevel; private readonly float _tummyRating; private readonly bool _safeToEat; private readonly string _mealQualityString; private readonly Dictionary _recipe; private readonly Dictionary _effects; private readonly string _lore; private readonly string _description; public override string InternalName => _internalName; public override Sprite InventoryIcon => TextureHelper.CreateSpriteFromPath(_spritePath); public override Sprite Sprite => TextureHelper.CreateSpriteFromPath(_spritePath); public override int SatiationLevel => _satiationLevel; public override float TummyRating => _tummyRating; public override bool MealSafeToEat => _safeToEat; public override MealQuality Quality { get { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) try { return (MealQuality)Enum.Parse(typeof(MealQuality), _mealQualityString, ignoreCase: true); } catch { return (MealQuality)1; } } } public override List> Recipe { get { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown List> list = new List>(); List list2 = new List(); foreach (KeyValuePair item in _recipe) { try { ITEM_TYPE val = (ITEM_TYPE)Enum.Parse(typeof(ITEM_TYPE), item.Key, ignoreCase: true); list2.Add(new InventoryItem(val, item.Value)); } catch { Plugin.Log.LogWarning((object)("Unknown recipe item type: " + item.Key + " for meal " + ((CustomInventoryItem)this).InternalName)); } } list.Add(list2); return list; } } public override MealEffect[] MealEffects { get { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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) List list = new List(); foreach (KeyValuePair effect in _effects) { try { MealEffectType mealEffectType = (MealEffectType)Enum.Parse(typeof(MealEffectType), effect.Key, ignoreCase: true); list.Add(new MealEffect { MealEffectType = mealEffectType, Chance = effect.Value }); } catch { Plugin.Log.LogWarning((object)("Unknown meal effect type: " + effect.Key + " for meal " + ((CustomInventoryItem)this).InternalName)); } } return list.ToArray(); } } public CultTweakerCustomMeal(string internalName, CustomMealConfig cfg, string spritePath) { _internalName = internalName; _mealName = cfg.ItemName ?? internalName; _spritePath = (string.IsNullOrEmpty(spritePath) ? cfg.SpritePath : spritePath); _satiationLevel = cfg.SatiationLevel; _tummyRating = cfg.TummyRating; _safeToEat = cfg.MealSafeToEat; _mealQualityString = cfg.MealQuality ?? "NORMAL"; _recipe = cfg.Recipe ?? new Dictionary(); _effects = cfg.MealEffectsDictionary ?? new Dictionary(); _lore = cfg.Lore ?? "Custom Meal created with CultTweaker."; _description = cfg.Description ?? "This is a custom meal created with CultTweaker."; ((CustomMeal)this)..ctor(); } public override string Name() { return _mealName; } public override string Lore() { return _lore; } public override string Description() { return _description; } } public class CustomQuestLoader { } public class CustomStructureLoader : Loader { public static List loadedStructures = new List(); public CustomStructureLoader() : base("CustomStructures") { } public static void LoadAllCustomStructures() { //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) CustomStructureLoader customStructureLoader = new CustomStructureLoader(); List> list = customStructureLoader.LoadAll(); Vector2Int bounds = default(Vector2Int); foreach (LoaderResult item2 in list) { CustomStructureConfig config = item2.Config; string folderName = item2.FolderName; Plugin.Log.LogInfo((object)("Found custom structure folder: " + folderName)); string internalName = "CULT_TWEAKER_STRUCTURE_" + config.StructureName.ToUpper().Replace(" ", "_"); string text = Path.Combine(item2.FolderPath, config.SpritePath ?? ""); if (!File.Exists(text)) { Plugin.Log.LogError((object)("Sprite file not found for structure " + config.StructureName + " at path: " + text)); continue; } Plugin.Log.LogInfo((object)("Loading structure sprite via " + text)); try { ((Vector2Int)(ref bounds))..ctor((int)config.Bounds.X, (int)config.Bounds.Y); List buildingParts = new List(); List list2 = new List(); foreach (KeyValuePair item3 in config.ItemCost) { if (Enum.TryParse(item3.Key, out ITEM_TYPE result)) { ItemCost item = new ItemCost(result, item3.Value); list2.Add(item); } else { Plugin.Log.LogError((object)("Invalid item type in ItemCost: " + item3.Key)); } } CultTweakerCustomStructure cultTweakerCustomStructure = new CultTweakerCustomStructure { _internalName = internalName, _spritePath = text, _buildDurationMinutes = config.BuildDurationMinutes, _buildOnlyOne = config.BuildOnlyOne, _requiresTempleToBuild = config.RequiresTempleToBuild, _canBeFlipped = config.CanBeFlipped, _bounds = bounds, _itemCost = list2, _buildingParts = buildingParts, _structureNameTemp = config.StructureName, _structureDescriptionTemp = config.StructureDescription }; Plugin.Log.LogInfo((object)("Successfully created custom structure with internal name : " + ((CustomStructure)cultTweakerCustomStructure).InternalName)); loadedStructures.Add(CustomStructureManager.Add((CustomStructure)(object)cultTweakerCustomStructure)); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to create custom structure : " + config.StructureName)); Plugin.Log.LogError((object)ex); } } } } public class CultTweakerCustomStructure : CustomStructure { public string _internalName = "EMPTY_CULTTWEAKER_CUSTOM_STRUCTURE"; public string _spritePath = ""; public string _structureNameTemp = "Nameless CultTweaker Structure"; public string _structureDescriptionTemp = "No description provided."; public int _buildDurationMinutes = 30; public bool _buildOnlyOne = false; public bool _requiresTempleToBuild = true; public bool _canBeFlipped = true; public Vector2Int _bounds = new Vector2Int(1, 1); public List _itemCost = new List(); public List _buildingParts = new List(); public override string InternalName => _internalName; public override Sprite Sprite => TextureHelper.CreateSpriteFromPath(_spritePath); public override List BuildingParts => _buildingParts; public override int BuildDurationMinutes => _buildDurationMinutes; public override Vector2Int Bounds => _bounds; public override List Cost => _itemCost; public override bool GetBuildOnlyOne() { return _buildOnlyOne; } public override bool RequiresTempleToBuild() { return _requiresTempleToBuild; } public override bool CanBeFlipped() { return _canBeFlipped; } public override string GetLocalizedDescription() { return _structureDescriptionTemp; } public override string GetLocalizedName() { return _structureNameTemp; } } public class CustomStructureConfig { public string StructureName; public string StructureDescription; public string SpritePath; public List Overrides = new List(); public int BuildDurationMinutes = 30; public bool BuildOnlyOne = false; public bool RequiresTempleToBuild = true; public bool CanBeFlipped = true; public SerializableVector2 Bounds = new SerializableVector2 { X = 1f, Y = 1f }; public Dictionary ItemCost = new Dictionary(); } public class CustomTarotLoader : Loader { public static List loadedTarots = new List(); public CustomTarotLoader() : base("CustomTarotCards") { } public static void LoadAllCustomTarots() { //IL_0196: Unknown result type (might be due to invalid IL or missing references) CustomTarotLoader customTarotLoader = new CustomTarotLoader(); List> list = customTarotLoader.LoadAll(); foreach (LoaderResult item in list) { CustomTarotConfig config = item.Config; string folderName = item.FolderName; Plugin.Log.LogInfo((object)("Found custom tarot folder: " + folderName)); string internalName = "CULT_TWEAKER_TAROT_" + (config.CardName ?? "UNKNOWN").ToUpper().Replace(" ", "_"); Plugin.Log.LogInfo((object)("Trying to create custom tarot card : " + config.CardName)); string text = (string.IsNullOrEmpty(config.SpritePath) ? string.Empty : Path.Combine(item.FolderPath, config.SpritePath)); if (!string.IsNullOrEmpty(text) && !File.Exists(text)) { Plugin.Log.LogWarning((object)("Sprite file not found for tarot " + config.CardName + " at path: " + text + ", skipping sprite (this may be optional)")); } string text2 = (string.IsNullOrEmpty(config.BackSpritePath) ? string.Empty : Path.Combine(item.FolderPath, config.BackSpritePath)); if (string.IsNullOrEmpty(text2) || !File.Exists(text2)) { } try { CultTweakerCustomTarot cultTweakerCustomTarot = new CultTweakerCustomTarot(internalName, config, text, text2); Plugin.Log.LogInfo((object)("Successfully created custom tarot with internal name : " + ((CustomTarotCard)cultTweakerCustomTarot).InternalName)); loadedTarots.Add(CustomTarotCardManager.Add((CustomTarotCard)(object)cultTweakerCustomTarot)); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to create custom tarot : " + config.CardName)); Plugin.Log.LogError((object)ex.ToString()); } } } } [Serializable] public class CustomTarotConfig { public string CardName; public string SpritePath; public string BackSpritePath; public string Category = "Custom"; public int TarotCardWeight = 150; public int MaxTarotCardLevel = 0; public bool IsCursedRelated = false; public string Lore = "Custom Tarot created with CultTweaker."; public string Description = "This is a custom tarot created with CultTweaker."; public float SpiritHeartCount = 0f; public int SpiritAmmoCount = 0; public float WeaponDamageMultiplierIncrease = 0f; public float CurseDamageMultiplierIncrease = 0f; public float WeaponCritChanceIncrease = 0f; public int LootIncreaseModifier = 0; public float MovementSpeedMultiplier = 0f; public float AttackRateMultiplier = 0f; public float BlackSoulsMultiplier = 0f; public float HealChance = 0f; public float NegateDamageChance = 0f; public int DamageAllEnemiesAmount = 0; public int HealthAmountMultiplier = 0; public float AmmoEfficiency = 0f; public int BlackSoulsOnDamage = 0; public string ItemToDropInternalName = null; public float ChanceOfGainingBlueHeart = 0f; public float ChanceForRelicsMultiplier = 0f; public float RelicChargeMultiplier = 0f; } public class CultTweakerCustomTarot : CustomTarotCard { private readonly string _internalName; private readonly string _cardName; private readonly string _spritePath; private readonly string _backSpritePath; private readonly CardCategory _category; private readonly int _tarotCardWeight; private readonly int _maxTarotCardLevel; private readonly bool _isCursedRelated; private readonly string _lore; private readonly string _description; private readonly float _spiritHeartCount; private readonly int _spiritAmmoCount; private readonly float _weaponDamageMultiplierIncrease; private readonly float _curseDamageMultiplierIncrease; private readonly float _weaponCritChanceIncrease; private readonly int _lootIncreaseModifier; private readonly float _movementSpeedMultiplier; private readonly float _attackRateMultiplier; private readonly float _blackSoulsMultiplier; private readonly float _healChance; private readonly float _negateDamageChance; private readonly int _damageAllEnemiesAmount; private readonly int _healthAmountMultiplier; private readonly float _ammoEfficiency; private readonly int _blackSoulsOnDamage; private readonly string _itemToDropInternalName; private readonly float _chanceOfGainingBlueHeart; private readonly float _chanceForRelicsMultiplier; private readonly float _relicChargeMultiplier; public override string InternalName => _internalName; public override CardCategory Category => _category; public override Sprite CustomSprite => TextureHelper.CreateSpriteFromPath(_spritePath); public override Sprite CustomBackSprite => TextureHelper.CreateSpriteFromPath(_backSpritePath); public override string Skin => "Custom"; public override int TarotCardWeight => _tarotCardWeight; public override int MaxTarotCardLevel => _maxTarotCardLevel; public override string AnimationSuffix => "Card " + ((CustomTarotCard)this).InternalName + " Animation Suffix not set"; public override bool IsCursedRelated => _isCursedRelated; public CultTweakerCustomTarot(string internalName, CustomTarotConfig cfg, string spritePath, string backSpritePath) { _internalName = internalName; _cardName = cfg.CardName ?? internalName; _spritePath = (string.IsNullOrEmpty(spritePath) ? cfg.SpritePath : spritePath); _backSpritePath = (string.IsNullOrEmpty(backSpritePath) ? cfg.BackSpritePath : backSpritePath); _tarotCardWeight = cfg.TarotCardWeight; _maxTarotCardLevel = cfg.MaxTarotCardLevel; _isCursedRelated = cfg.IsCursedRelated; _lore = cfg.Lore; _description = cfg.Description; _spiritHeartCount = cfg.SpiritHeartCount; _spiritAmmoCount = cfg.SpiritAmmoCount; _weaponDamageMultiplierIncrease = cfg.WeaponDamageMultiplierIncrease; _curseDamageMultiplierIncrease = cfg.CurseDamageMultiplierIncrease; _weaponCritChanceIncrease = cfg.WeaponCritChanceIncrease; _lootIncreaseModifier = cfg.LootIncreaseModifier; _movementSpeedMultiplier = cfg.MovementSpeedMultiplier; _attackRateMultiplier = cfg.AttackRateMultiplier; _blackSoulsMultiplier = cfg.BlackSoulsMultiplier; _healChance = cfg.HealChance; _negateDamageChance = cfg.NegateDamageChance; _damageAllEnemiesAmount = cfg.DamageAllEnemiesAmount; _healthAmountMultiplier = cfg.HealthAmountMultiplier; _ammoEfficiency = cfg.AmmoEfficiency; _blackSoulsOnDamage = cfg.BlackSoulsOnDamage; _itemToDropInternalName = cfg.ItemToDropInternalName; _chanceOfGainingBlueHeart = cfg.ChanceOfGainingBlueHeart; _chanceForRelicsMultiplier = cfg.ChanceForRelicsMultiplier; _relicChargeMultiplier = cfg.RelicChargeMultiplier; ((CustomTarotCard)this)..ctor(); } public override string LocalisedName() { return _cardName; } public override string LocalisedDescription() { return _description; } public override string LocalisedLore() { return _lore; } public override float GetSpiritHeartCount(TarotCard card) { return _spiritHeartCount; } public override int GetSpiritAmmoCount(TarotCard card) { return _spiritAmmoCount; } public override float GetWeaponDamageMultiplerIncrease(TarotCard card) { return _weaponDamageMultiplierIncrease; } public override float GetCurseDamageMultiplerIncrease(TarotCard card) { return _curseDamageMultiplierIncrease; } public override float GetWeaponCritChanceIncrease(TarotCard card) { return _weaponCritChanceIncrease; } public override int GetLootIncreaseModifier(TarotCard card, ITEM_TYPE itemType) { return _lootIncreaseModifier; } public override float GetMovementSpeedMultiplier(TarotCard card) { return _movementSpeedMultiplier; } public override float GetAttackRateMultiplier(TarotCard card) { return _attackRateMultiplier; } public override float GetBlackSoulsMultiplier(TarotCard card) { return _blackSoulsMultiplier; } public override float GetHealChance(TarotCard card) { return _healChance; } public override float GetNegateDamageChance(TarotCard card) { return _negateDamageChance; } public override int GetDamageAllEnemiesAmount(TarotCard card) { return _damageAllEnemiesAmount; } public override int GetHealthAmountMultiplier(TarotCard card) { return _healthAmountMultiplier; } public override float GetAmmoEfficiency(TarotCard card) { return _ammoEfficiency; } public override int GetBlackSoulsOnDamage(TarotCard card) { return _blackSoulsOnDamage; } public override InventoryItem GetItemToDrop(TarotCard card) { return null; } public override float GetChanceOfGainingBlueHeart(TarotCard card) { return _chanceOfGainingBlueHeart; } public override float GetChanceForRelicsMultiplier(TarotCard card) { return _chanceForRelicsMultiplier; } public override float GetRelicChargeMultiplier(TarotCard card) { return _relicChargeMultiplier; } public override void ApplyInstantEffects(TarotCard card) { } } public class LoaderResult { public T Config { get; set; } public string FolderPath { get; set; } public string FolderName { get; set; } } public class Loader { public string FolderName { get; set; } public string RootPath => Path.Combine(Plugin.PluginPath, FolderName); public Loader(string folderName) { FolderName = folderName; string rootPath = RootPath; if (!Directory.Exists(rootPath)) { Directory.CreateDirectory(rootPath); } } public List> LoadAll() { List> list = new List>(); string[] directories = Directory.GetDirectories(RootPath); Plugin.Log.LogInfo((object)("Found " + directories.Length + " entries to load from " + FolderName + ".")); string[] array = directories; foreach (string text in array) { string fileName = Path.GetFileName(text); string[] files = Directory.GetFiles(text, "config.json", SearchOption.TopDirectoryOnly); if (files.Length == 0) { Plugin.Log.LogInfo((object)("No config.json found for: " + fileName)); continue; } try { string text2 = File.ReadAllText(files[0]); T val = JsonConvert.DeserializeObject(text2); if (val != null) { list.Add(new LoaderResult { Config = val, FolderPath = text, FolderName = fileName }); } } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to parse config.json for: " + fileName)); Plugin.Log.LogError((object)ex); } } return list; } } public class BaseCustomEnemy : CustomEnemy { public string OverrideSpineName = "SF_Occultist_Scamp"; public static string spineAtlasPath = Path.Combine(Plugin.PluginPath, "Assets/TestEnemy/Human.atlas"); public static string spineSkeletonPath = Path.Combine(Plugin.PluginPath, "Assets/TestEnemy/Human.json"); public static string[] spineTexturePaths = new string[2] { Path.Combine(Plugin.PluginPath, "Assets/TestEnemy/Human.png"), Path.Combine(Plugin.PluginPath, "Assets/TestEnemy/Human2.png") }; public override string InternalName => "CultTweaker_TestEnemy"; public override string EnemyToMimic => "Assets/Prefabs/Enemies/DLC/Enemy Swordsman Wolf.prefab"; public override float maxHealth => 2f; public override Type? EnemyController => typeof(CustomEnemyController); public BaseCustomEnemy() { Plugin.Log.LogInfo((object)("Initializing " + ((CustomEnemy)this).InternalName + " and creating spine override.")); CreateSpineOverride(); } public void CreateSpineOverride() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown Plugin.Log.LogInfo((object)("Reading atlas from " + spineAtlasPath)); TextAsset val = new TextAsset(File.ReadAllText(spineAtlasPath)); Plugin.Log.LogInfo((object)("Reading skeleton from " + spineSkeletonPath)); TextAsset val2 = new TextAsset(File.ReadAllText(spineSkeletonPath)); Texture2D[] array = (Texture2D[])(object)new Texture2D[spineTexturePaths.Length]; string[] array2 = spineTexturePaths; foreach (string text in array2) { Plugin.Log.LogInfo((object)("Reading texture from " + text)); Texture2D val3 = TextureHelper.CreateTextureFromPath(text, (TextureFormat)4, false, false); ((Object)val3).name = Path.GetFileNameWithoutExtension(text); array[Array.IndexOf(spineTexturePaths, text)] = val3; } Material val4 = new Material(Shader.Find("Spine/Skeleton")); SpineAtlasAsset val5 = SpineAtlasAsset.CreateRuntimeInstance(val, array, val4, true); SkeletonDataAsset spineOverride = SkeletonDataAsset.CreateRuntimeInstance(val2, (AtlasAssetBase)(object)val5, true, 0.005f); base.SpineOverride = spineOverride; base.SpineSkinName = OverrideSpineName; } } }