Decompiled source of CotLSpineLoader v1.0.8
plugins/CultTweaker/CultTweaker.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using COTL_API.CustomFollowerCommand; using COTL_API.CustomInventory; using COTL_API.CustomSkins; using COTL_API.CustomStructures; using COTL_API.CustomTarotCard; using COTL_API.Helpers; using CustomSpineLoader.APIHelper; using CustomSpineLoader.Commands; using CustomSpineLoader.SpineLoaderHelper; using HarmonyLib; using Lamb.UI; using Microsoft.CodeAnalysis; using Newtonsoft.Json; 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+5f1b39f3af13b3ff94ec611c421b036c388582ed")] [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.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.0.8")] [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.0.8"; internal static ManualLogSource Log; internal static readonly Harmony Harmony = new Harmony("InfernoDragon0.cotl.CustomSpineLoader"); internal static string PluginPath; public static ConfigEntry<int> CurrentFleeceIndexP1 { get; set; } public static ConfigEntry<int> CurrentFleeceIndexP2 { get; set; } public static ConfigEntry<bool> DebugDumpFollowerSpineAtlas { get; set; } public static ConfigEntry<bool> FleeceCyclingEnabled { get; set; } private void Awake() { //IL_003d: 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<int>("Fleece", "CurrentFleeceIndexP1", -1, "Current Fleece Index for Player 1"); CurrentFleeceIndexP2 = ((BaseUnityPlugin)this).Config.Bind<int>("Fleece", "CurrentFleeceIndexP2", -1, "Current Fleece Index for Player 2"); DebugDumpFollowerSpineAtlas = ((BaseUnityPlugin)this).Config.Bind<bool>("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<bool>("Fleece", "FleeceCyclingEnabled", true, "Enable Fleece Cycling for all players."); PlayerSpineLoader.currentFleeceIndexP1 = CurrentFleeceIndexP1.Value; PlayerSpineLoader.currentFleeceIndexP2 = CurrentFleeceIndexP2.Value; } 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); } } 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<int, CustomFollowerColor> CustomColors { get; private set; } = new Dictionary<int, CustomFollowerColor>(); public static Dictionary<int, CustomFollowerSpineSkin> CustomFollowerSkinConfigs { get; private set; } = new Dictionary<int, CustomFollowerSpineSkin>(); 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<Dictionary<int, CustomFollowerColor>>(text) ?? new Dictionary<int, CustomFollowerColor>(); } } 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<string> SkinsApplied; } public class FollowerSpineLoader { public static Dictionary<string, List<Tuple<int, string, Texture2D, FollowerSkinPartConfig>>> FollowerSkinOverrides = new Dictionary<string, List<Tuple<int, string, Texture2D, FollowerSkinPartConfig>>>(); public static Dictionary<string, List<SlotsAndColours>> FollowerSlotColors = new Dictionary<string, List<SlotsAndColours>>(); public static Dictionary<string, Skin> CustomFollowerSkins = new Dictionary<string, Skin>(); 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<string> list = new List<string>(1) { "Cat" }; string[] array3 = new string[0]; if (files3.Length != 0) { TextAsset val = new TextAsset(File.ReadAllText(files3[0])); FollowerSpineConfig followerSpineConfig = JsonConvert.DeserializeObject<FollowerSpineConfig>(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<string> list = new List<string>(); 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<FollowerSkinConfig>(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<Tuple<int, string, Texture2D, FollowerSkinPartConfig>> list2 = new List<Tuple<int, string, Texture2D, FollowerSkinPartConfig>>(); 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<int, string, Texture2D, FollowerSkinPartConfig>(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<Tuple<int, string, Texture2D, FollowerSkinPartConfig>> 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<BoneData>)val.Bones).ToList().ForEach((Action<BoneData>)finalSkin.Bones.Add); ((IEnumerable<ConstraintData>)val.Constraints).ToList().ForEach((Action<ConstraintData>)finalSkin.Constraints.Add); foreach (Tuple<int, string, Texture2D, FollowerSkinPartConfig> 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<string> variantNames, List<SlotsAndColours> 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<CharacterSkin> skin = ((IEnumerable<string>)variantNames).Select((Func<string, CharacterSkin>)((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<SlotsAndColours> 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<FollowerSkinPartConfig> 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<SlotsAndColours>(1) { new SlotsAndColours { SlotAndColours = new List<SlotAndColor>(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, SlotsAndColours>)((int i) => new SlotsAndColours { SlotAndColours = ((IEnumerable<FollowerSkinPartConfig>)parts).Select((Func<FollowerSkinPartConfig, SlotAndColor>)((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<string> 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<string, FollowerSkinPartConfig> 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<string> ColorChoices { get; set; } = new List<string>(1) { "#FFF" }; } [Serializable] public class DebugOutputSkin { public int SlotIndex { get; set; } public string PartName { get; set; } } public class PlayerSpineLoader { public static List<string> FleeceRotation = new List<string>(); public static Dictionary<string, Tuple<SkeletonDataAsset, List<string>>> FleeceCyclingSpines = new Dictionary<string, Tuple<SkeletonDataAsset, List<string>>>(); 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<PlayerSpineConfig>(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<SkeletonDataAsset, List<string>>(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<string, List<StructureBuildingOverride>> StructureBuildingOverrides { get; private set; } = new Dictionary<string, List<StructureBuildingOverride>>(); 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<StructureBuildingOverride> list = new List<StructureBuildingOverride>(); if (File.Exists(Path.Combine(text, "config.json"))) { string text2 = File.ReadAllText(Path.Combine(text, "config.json")); try { StructureBuildingOverrideData structureBuildingOverrideData = JsonConvert.DeserializeObject<StructureBuildingOverrideData>(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<CustomStructureBuildingData> 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<StructureBuildingOverride> value; List<StructureBuildingOverride> list = (StructureBuildingOverrides.TryGetValue(buildingName, out value) ? value : null); if (list == null) { return null; } List<CustomStructureBuildingData> list2 = new List<CustomStructureBuildingData>(); 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<StructureBuildingOverride> Overrides = new List<StructureBuildingOverride>(); } [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 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<Skin> 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<string, Tuple<SkeletonDataAsset, List<string>>> 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<DebugOutputSkin> list = new List<DebugOutputSkin>(); 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<CustomStructureBuildingData> 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<FollowerCommandCategory> Categories { get; } = new List<FollowerCommandCategory>(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<UIManager>.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<TMP_Text>() : 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<TMP_Text>() : 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<TMP_Text>() : 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<UIManager>.Instance.SettingsMenuControllerTemplate._audioSettings).GetComponentInChildren<ScrollRect>().content).GetChild(0)).gameObject; GameObject gameObject2 = ((Component)((Transform)((Component)MonoSingleton<UIManager>.Instance.SettingsMenuControllerTemplate._graphicsSettings).GetComponentInChildren<ScrollRect>().content).GetChild(4)).gameObject; GameObject gameObject3 = ((Component)((Transform)((Component)MonoSingleton<UIManager>.Instance.SettingsMenuControllerTemplate._graphicsSettings).GetComponentInChildren<ScrollRect>().content).GetChild(3)).gameObject; GameObject val21 = Object.Instantiate<GameObject>(gameObject2, val11); Transform val22 = Object.Instantiate<Transform>(val20, val11); GameObject val23 = Object.Instantiate<GameObject>(gameObject, val11); Transform val24 = Object.Instantiate<Transform>(val20, val11); GameObject val25 = Object.Instantiate<GameObject>(gameObject, val11); Transform val26 = Object.Instantiate<Transform>(val20, val11); GameObject val27 = Object.Instantiate<GameObject>(gameObject, val11); Transform val28 = Object.Instantiate<Transform>(val20, val11); GameObject val29 = Object.Instantiate<GameObject>(gameObject, val11); Transform val30 = Object.Instantiate<Transform>(val20, val11); GameObject val31 = Object.Instantiate<GameObject>(gameObject, val11); Transform val32 = Object.Instantiate<Transform>(val20, val11); GameObject val33 = Object.Instantiate<GameObject>(gameObject2, val11); Transform val34 = Object.Instantiate<Transform>(val20, val11); GameObject val35 = Object.Instantiate<GameObject>(gameObject3, val11); Transform val36 = Object.Instantiate<Transform>(val20, val11); GameObject val37 = Object.Instantiate<GameObject>(gameObject3, val11); Transform val38 = Object.Instantiate<Transform>(val20, val11); GameObject val39 = Object.Instantiate<GameObject>(gameObject3, val11); Transform val40 = Object.Instantiate<Transform>(val20, val11); GameObject val41 = Object.Instantiate<GameObject>(gameObject3, val11); Transform val42 = Object.Instantiate<Transform>(val20, val11); GameObject val43 = Object.Instantiate<GameObject>(gameObject3, val11); TMP_Text componentInChildren = val23.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren2 = val25.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren3 = val27.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren4 = val29.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren5 = val31.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren6 = val21.GetComponentInChildren<TMP_Text>(); MMSlider componentInChildren7 = val23.GetComponentInChildren<MMSlider>(); MMSlider componentInChildren8 = val25.GetComponentInChildren<MMSlider>(); MMSlider componentInChildren9 = val27.GetComponentInChildren<MMSlider>(); MMSlider componentInChildren10 = val29.GetComponentInChildren<MMSlider>(); MMSlider componentInChildren11 = val31.GetComponentInChildren<MMSlider>(); MMToggle componentInChildren12 = val21.GetComponentInChildren<MMToggle>(); ((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<float>)(object)((Slider)componentInChildren7).onValueChanged).AddListener((UnityAction<float>)delegate(float value) { OnSliderValueChanged("Red", value); }); ((UnityEvent<float>)(object)((Slider)componentInChildren8).onValueChanged).AddListener((UnityAction<float>)delegate(float value) { OnSliderValueChanged("Green", value); }); ((UnityEvent<float>)(object)((Slider)componentInChildren9).onValueChanged).AddListener((UnityAction<float>)delegate(float value) { OnSliderValueChanged("Blue", value); }); ((UnityEvent<float>)(object)((Slider)componentInChildren10).onValueChanged).AddListener((UnityAction<float>)delegate(float value) { OnSliderValueChanged("Alpha", value); }); ((UnityEvent<float>)(object)((Slider)componentInChildren11).onValueChanged).AddListener((UnityAction<float>)delegate(float value) { OnSliderValueChanged("Scale", value); }); componentInChildren12.OnValueChanged = (Action<bool>)Delegate.Combine(componentInChildren12.OnValueChanged, (Action<bool>)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<MMToggle>(); TMP_Text componentInChildren14 = val33.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren15 = val35.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren16 = val37.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren17 = val39.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren18 = val41.GetComponentInChildren<TMP_Text>(); TMP_Text componentInChildren19 = val43.GetComponentInChildren<TMP_Text>(); ((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<string> list = (from FollowerClothingType x in values select ((object)(FollowerClothingType)(ref x)).ToString()).ToList(); Array values2 = Enum.GetValues(typeof(FollowerSpecialType)); List<string> 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<string> list3 = (from FollowerHatType x in values3 select ((object)(FollowerHatType)(ref x)).ToString()).ToList(); Array values4 = Enum.GetValues(typeof(FollowerOutfitType)); List<string> list4 = (from FollowerOutfitType x in values4 select ((object)(FollowerOutfitType)(ref x)).ToString()).ToList(); List<string> 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<bool>)Delegate.Combine(componentInChildren13.OnValueChanged, (Action<bool>)delegate(bool value) { OnFollowerCostumeToggleChanged(value, _followerSummaryMenuController._follower); }); MMHorizontalSelector componentInChildren20 = val35.GetComponentInChildren<MMHorizontalSelector>(); componentInChildren20._localizeContent = false; componentInChildren20.UpdateContent(list.ToArray()); componentInChildren20.OnSelectionChanged = (Action<int>)Delegate.Combine(componentInChildren20.OnSelectionChanged, (Action<int>)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(FollowerClothingType), index); }); MMHorizontalSelector componentInChildren21 = val37.GetComponentInChildren<MMHorizontalSelector>(); componentInChildren21._localizeContent = false; componentInChildren21.UpdateContent(list2.ToArray()); componentInChildren21.OnSelectionChanged = (Action<int>)Delegate.Combine(componentInChildren21.OnSelectionChanged, (Action<int>)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(FollowerSpecialType), index); }); MMHorizontalSelector componentInChildren22 = val39.GetComponentInChildren<MMHorizontalSelector>(); componentInChildren22._localizeContent = false; componentInChildren22.UpdateContent(list3.ToArray()); componentInChildren22.OnSelectionChanged = (Action<int>)Delegate.Combine(componentInChildren22.OnSelectionChanged, (Action<int>)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(FollowerHatType), index); }); MMHorizontalSelector componentInChildren23 = val41.GetComponentInChildren<MMHorizontalSelector>(); componentInChildren23._localizeContent = false; componentInChildren23.UpdateContent(list4.ToArray()); componentInChildren23.OnSelectionChanged = (Action<int>)Delegate.Combine(componentInChildren23.OnSelectionChanged, (Action<int>)delegate(int index) { OnFollowerCostumeSelectorsChanged(typeof(FollowerOutfitType), index); }); MMHorizontalSelector componentInChildren24 = val43.GetComponentInChildren<MMHorizontalSelector>(); componentInChildren24._localizeContent = false; componentInChildren24.UpdateContent(list5.ToArray()); componentInChildren24.OnSelectionChanged = (Action<int>)Delegate.Combine(componentInChildren24.OnSelectionChanged, (Action<int>)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 CustomItemLoader : Loader<CustomItemConfig> { public static List<ITEM_TYPE> loadedItems = new List<ITEM_TYPE>(); 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<LoaderResult<CustomItemConfig>> list = customItemLoader.LoadAll(); foreach (LoaderResult<CustomItemConfig> 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<CustomMealConfig> { public static List<ITEM_TYPE> loadedMeals = new List<ITEM_TYPE>(); 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<LoaderResult<CustomMealConfig>> list = customMealLoader.LoadAll(); foreach (LoaderResult<CustomMealConfig> 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<string, int> Recipe = new Dictionary<string, int>(); public Dictionary<string, int> MealEffectsDictionary = new Dictionary<string, int>(); } 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<string, int> _recipe; private readonly Dictionary<string, int> _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 => _safeToEa