Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ComfyLadders v1.1.0
ComfyLadders.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ComfyLib; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ComfyLadders")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ComfyLadders")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("5f6f3fcc-50e1-4799-974a-8e37089e20a6")] [assembly: AssemblyFileVersion("1.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ComfyLib { public static class ConfigFileExtensions { internal sealed class ConfigurationManagerAttributes { public Action<ConfigEntryBase> CustomDrawer; public bool? Browsable; public bool? HideDefaultButton; public bool? HideSettingName; public bool? IsAdvanced; public int? Order; public bool? ReadOnly; } private static readonly Dictionary<string, int> _sectionToSettingOrder = new Dictionary<string, int>(); private static int GetSettingOrder(string section) { if (!_sectionToSettingOrder.TryGetValue(section, out var value)) { value = 0; } _sectionToSettingOrder[section] = value - 1; return value; } public static ConfigEntry<T> BindInOrder<T>(this ConfigFile config, string section, string key, T defaultValue, string description, AcceptableValueBase acceptableValues, bool browsable = true, bool hideDefaultButton = false, bool hideSettingName = false, bool isAdvanced = false, bool readOnly = false) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown return config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, acceptableValues, new object[1] { new ConfigurationManagerAttributes { Browsable = browsable, CustomDrawer = null, HideDefaultButton = hideDefaultButton, HideSettingName = hideSettingName, IsAdvanced = isAdvanced, Order = GetSettingOrder(section), ReadOnly = readOnly } })); } public static ConfigEntry<T> BindInOrder<T>(this ConfigFile config, string section, string key, T defaultValue, string description, Action<ConfigEntryBase> customDrawer = null, bool browsable = true, bool hideDefaultButton = false, bool hideSettingName = false, bool isAdvanced = false, bool readOnly = false) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown return config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = browsable, CustomDrawer = customDrawer, HideDefaultButton = hideDefaultButton, HideSettingName = hideSettingName, IsAdvanced = isAdvanced, Order = GetSettingOrder(section), ReadOnly = readOnly } })); } public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action settingChangedHandler) { configEntry.SettingChanged += delegate { settingChangedHandler(); }; } public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action<T> settingChangedHandler) { configEntry.SettingChanged += delegate(object _, EventArgs eventArgs) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) settingChangedHandler((T)((SettingChangedEventArgs)eventArgs).ChangedSetting.BoxedValue); }; } public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action<ConfigEntry<T>> settingChangedHandler) { configEntry.SettingChanged += delegate(object _, EventArgs eventArgs) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) settingChangedHandler((ConfigEntry<T>)(object)((SettingChangedEventArgs)eventArgs).ChangedSetting); }; } } public static class ChatExtensions { public static void AddMessage(this Chat chat, object obj) { if (Object.op_Implicit((Object)(object)chat)) { ((Terminal)chat).AddString(obj.ToString()); chat.m_hideTimer = 0f; } } } public static class ComponentExtensions { public static bool TryGetComponentInChildren<T>(this Component parentComponent, out T component) where T : Component { component = parentComponent.GetComponentInChildren<T>(); return Object.op_Implicit((Object)(object)component); } public static bool TryGetComponentInChildren<T>(this GameObject gameObject, out T component) where T : Component { component = gameObject.GetComponentInChildren<T>(); return Object.op_Implicit((Object)(object)component); } public static bool TryGetComponentInParent<T>(this Component childComponent, out T component) where T : Component { component = childComponent.GetComponentInParent<T>(); return Object.op_Implicit((Object)(object)component); } public static bool TryGetComponentInParent<T>(this GameObject gameObject, out T component) where T : Component { component = gameObject.GetComponentInParent<T>(); return Object.op_Implicit((Object)(object)component); } } public static class ObjectExtensions { public static T FirstByNameOrThrow<T>(this T[] unityObjects, string name) where T : Object { foreach (T val in unityObjects) { if (((Object)val).name == name) { return val; } } throw new InvalidOperationException($"Could not find Unity object of type {typeof(T)} with name: {name}"); } public static T Ref<T>(this T unityObject) where T : Object { if (!Object.op_Implicit((Object)(object)unityObject)) { return default(T); } return unityObject; } } } namespace ComfyLadders { [BepInPlugin("redseiko.valheim.comfyladders", "ComfyLadders", "1.1.0")] public sealed class ComfyLadders : BaseUnityPlugin { public const string PluginGuid = "redseiko.valheim.comfyladders"; public const string PluginName = "ComfyLadders"; public const string PluginVersion = "1.1.0"; private static ManualLogSource _logger; private void Awake() { _logger = ((BaseUnityPlugin)this).Logger; PluginConfig.BindConfig(((BaseUnityPlugin)this).Config); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "redseiko.valheim.comfyladders"); } public static void LogInfo(object obj) { _logger.LogInfo((object)$"[{DateTime.Now.ToString(DateTimeFormatInfo.InvariantInfo)}] {obj}"); } } public static class PluginConfig { public static ConfigFile CurrentConfig { get; private set; } public static ConfigEntry<bool> IsModEnabled { get; private set; } public static ConfigEntry<bool> AshlandSteepstairIsEligible { get; private set; } public static ConfigEntry<bool> GoblinStepladderIsEligible { get; private set; } public static ConfigEntry<bool> GraustenStoneLadderIsEligible { get; private set; } public static ConfigEntry<bool> WoodStepladderIsEligible { get; private set; } public static void BindConfig(ConfigFile config) { CurrentConfig = config; IsModEnabled = config.BindInOrder("_Global", "isModEnabled", defaultValue: true, "Globally enable or disable this mod."); AshlandSteepstairIsEligible = config.BindInOrder("Ladders", "ashlandSteepstairIsEligible", defaultValue: true, "If true, prefab `Ashland_Steepstair` is eligible for custom ladder movement."); GoblinStepladderIsEligible = config.BindInOrder("Ladders", "goblinStepladderIsEligible", defaultValue: false, "If true, prefab `goblin_stepladder` is eligible for custom ladder movement."); GraustenStoneLadderIsEligible = config.BindInOrder("Ladders", "graustenStoneLadderIsEligible", defaultValue: true, "If true, prefab `Piece_grausten_stone_ladder` is eligible for custom ladder movement."); WoodStepladderIsEligible = config.BindInOrder("Ladders", "woodStepladderIsEligible", defaultValue: true, "If true, prefab `wood_stepladder` is eligible for custom ladder movement."); } } public static class LadderManager { public const int AshlandSteepstairHash = -571355724; public const int GoblinStepladderHash = 70596228; public const int GraustenStoneLadderHash = 913259269; public const int WoodStepladderHash = -354552934; public const int IsEligibleOverrideHash = 1026132609; public const int IsEligibleOverrideUseVanilla = 1; public static bool IsEligibleLadder(AutoJumpLedge autoJumpLedge) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!((Component)(object)autoJumpLedge).TryGetComponentInParent<ZNetView>(out ZNetView component) || !component.IsValid()) { return false; } int num = default(int); if (ZDOExtraData.GetInt(component.m_zdo.m_uid, 1026132609, ref num) && num == 1) { return false; } return component.m_zdo.m_prefab switch { -571355724 => PluginConfig.AshlandSteepstairIsEligible.Value, 70596228 => PluginConfig.GoblinStepladderIsEligible.Value, 913259269 => PluginConfig.GraustenStoneLadderIsEligible.Value, -354552934 => PluginConfig.WoodStepladderIsEligible.Value, _ => false, }; } } public static class LegacyAutoJump { private static bool _hasAutoJumped; public static void OnFixedUpdate() { _hasAutoJumped = false; } public static void OnAutoJump(AutoJumpLedge autoJumpLedge, Character character) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (!_hasAutoJumped) { _hasAutoJumped = true; Quaternion rotation = ((Component)character).transform.rotation; float y = ((Quaternion)(ref rotation)).eulerAngles.y; rotation = ((Component)autoJumpLedge).transform.rotation; if (!(Mathf.Abs(Mathf.DeltaAngle(((Quaternion)(ref rotation)).eulerAngles.y, y)) > 12f)) { Vector3 position = ((Component)character).transform.position; position.y += (character.m_running ? 0.08f : 0.06f); ((Component)character).transform.position = position + ((Component)character).transform.forward * 0.08f; } } } } [HarmonyPatch(typeof(AutoJumpLedge))] internal static class AutoJumpLedgePatch { [HarmonyTranspiler] [HarmonyPatch("OnTriggerStay")] private static IEnumerable<CodeInstruction> OnTriggerStayTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown return new CodeMatcher(instructions, (ILGenerator)null).Start().MatchStartForward((CodeMatch[])(object)new CodeMatch[4] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Stloc_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)null, (string)null) }).ThrowIfInvalid("Could not patch AutoJumpLedge.OnTriggerStay()! (character-check)") .Advance(3) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(AutoJumpLedgePatch), "CharacterCheckDelegate", (Type[])null, (Type[])null)) }) .InstructionEnumeration(); } private static Character CharacterCheckDelegate(Character character, AutoJumpLedge autoJumpLedge) { if (Object.op_Implicit((Object)(object)character) && (Object)(object)character == (Object)(object)Player.m_localPlayer && PluginConfig.IsModEnabled.Value && LadderManager.IsEligibleLadder(autoJumpLedge)) { LegacyAutoJump.OnAutoJump(autoJumpLedge, character); return null; } return character; } } [HarmonyPatch(typeof(FejdStartup))] internal static class FejdStartupPatch { [HarmonyPostfix] [HarmonyPatch("Awake")] [HarmonyPriority(0)] private static void AwakePostfix() { UnpatchBetterLadders(); } private static void UnpatchBetterLadders() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) MethodInfo methodInfo = AccessTools.Method(typeof(AutoJumpLedge), "OnTriggerStay", (Type[])null, (Type[])null); Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo != null && patchInfo.Owners.Contains("BetterLadders")) { ComfyLadders.LogInfo("Unpatching BetterLadders..."); new PatchProcessor((Harmony)null, (MethodBase)methodInfo).Unpatch((HarmonyPatchType)1, "BetterLadders"); } } } [HarmonyPatch(typeof(MonoUpdaters))] internal static class MonoUpdatersPatch { [HarmonyTranspiler] [HarmonyPatch("FixedUpdate")] private static IEnumerable<CodeInstruction> FixedUpdateTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown return new CodeMatcher(instructions, generator).End().MatchStartBackwards((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Ret, (object)null, (string)null) }).ThrowIfInvalid("Could not patch MonoUpdaters.FixedUpdate()! (ret)") .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(LegacyAutoJump), "OnFixedUpdate", (Type[])null, (Type[])null)) }) .InstructionEnumeration(); } } }