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 TrulySmoothLadders v0.5.0
TrulySmoothLadders.dll
Decompiled 8 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JG224.ModCore.API; using JG224.TrulySmoothLadders.Core; using JG224.TrulySmoothLadders.Patches; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("TrulySmoothLadders")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0")] [assembly: AssemblyProduct("TrulySmoothLadders")] [assembly: AssemblyTitle("TrulySmoothLadders")] [assembly: AssemblyVersion("0.5.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 JG224.TrulySmoothLadders { [BepInPlugin("jg224.TrulySmoothLadders", "TrulySmoothLadders", "0.5.0")] [BepInProcess("valheim.exe")] [BepInDependency("com.jg224.modcore", "0.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "jg224.TrulySmoothLadders"; public const string PluginName = "TrulySmoothLadders"; public const string PluginVersion = "0.5.0"; public const string ModCoreGuid = "com.jg224.modcore"; public const string GeneralTweaksGuid = "JG224.GeneralTweaks"; public const int ProtocolVersion = 1; public static readonly ModuleId ModuleId = new ModuleId("trulysmoothladders"); private readonly List<IDisposable> _registrations = new List<IDisposable>(); private Harmony _harmony; private bool _runtimeActive; private bool _shutDown; internal static ManualLogSource Log { get; private set; } internal static TrulySmoothLaddersConfig Settings { get; private set; } internal static ICoreServices Core { get; private set; } private void Awake() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00cb: 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_0073: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Settings = TrulySmoothLaddersConfig.Load((BaseUnityPlugin)(object)this, Paths.ConfigPath, ((BaseUnityPlugin)this).Logger); try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore did not initialize before TrulySmoothLadders."); } Core = ModCoreApi.Services; RegisterWithCore(); if (TryGetLegacyLadderOwner(out var version)) { string text = "GeneralTweaks " + version?.ToString() + " still contains smooth ladders; TrulySmoothLadders is paused to prevent duplicate ramps."; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)3, text); ((BaseUnityPlugin)this).Logger.LogWarning((object)(text + " Update GeneralTweaks to 2.0.0 or newer.")); return; } _harmony = new Harmony("jg224.TrulySmoothLadders"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); _runtimeActive = true; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Client-local smooth ladder ramps ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("TrulySmoothLadders 0.5.0 loaded; protocol " + 1 + ".")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("TrulySmoothLadders failed to initialize safely: " + ex)); if (Core != null) { Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } Shutdown(); throw; } } private void Update() { if (_runtimeActive) { LadderRampRuntime.Tick(); } } private void OnDestroy() { Shutdown(); } private void RegisterWithCore() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.0", ref val)) { throw new InvalidOperationException("Invalid plugin version."); } _registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "jg224.TrulySmoothLadders", "TrulySmoothLadders", val, 1, (ModuleSide)1, (ModuleRequirement)1, 0uL, 1, 1))); foreach (IDisposable item in Settings.RegisterMetadata(Core, ModuleId)) { _registrations.Add(item); } _registrations.Add(Core.Compatibility.Register(new CompatibilityRule("jg224.TrulySmoothLadders", "BetterLaddersContinued", (CompatibilityRuleKind)2, (CompatibilitySeverity)2, "Both mods replace vanilla ladder movement; remove one implementation.", "ladders"))); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)9, (Action<LifecycleEvent>)delegate { LadderRampRuntime.DestroyAll(); }, 0)); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)3, (Action<LifecycleEvent>)delegate { LadderRampRuntime.DestroyAll(); }, 0)); } private static bool TryGetLegacyLadderOwner(out Version version) { version = null; if (!Chainloader.PluginInfos.TryGetValue("JG224.GeneralTweaks", out var value)) { return false; } version = value.Metadata.Version; if (version != null) { return version.CompareTo(new Version(2, 0, 0)) < 0; } return false; } private void Shutdown() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (_shutDown) { return; } _shutDown = true; _runtimeActive = false; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; LadderRampRuntime.DestroyAll(); for (int num = _registrations.Count - 1; num >= 0; num--) { try { _registrations[num].Dispose(); } catch (Exception ex) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogWarning((object)("Registration cleanup failed: " + ex.Message)); } } } _registrations.Clear(); if (Core != null) { Core.Metrics.RemoveOwner(ModuleId); } Core = null; Settings = null; Log = null; } } internal sealed class TrulySmoothLaddersConfig { private readonly ConfigFile _file; internal ConfigEntry<bool> BetterLaddersEnabled { get; } internal ConfigEntry<string> PrefabAdjustments { get; } internal ConfigEntry<bool> FitDiagnostics { get; } private TrulySmoothLaddersConfig(ConfigFile file) { _file = file; BetterLaddersEnabled = file.Bind<bool>("Movement", "BetterLadders", true, "Replace vanilla ladder auto-jump bouncing with smooth forward climbing."); PrefabAdjustments = file.Bind<string>("Movement", "PrefabAdjustments", "", "Optional runtime prefab=width,normalOffset,endMargin in metres; e.g. wood_ladder=1.3,0.42,0.35. Width 0.5-3, offset 0-0.75, margin 0-1. Upper ends are capped at the highest tread plus 2 cm. Changes rebuild ramps on next contact."); FitDiagnostics = file.Bind<bool>("Diagnostics", "FitDiagnostics", false, "Log each successful ramp fit and rejected ladder once, including measured geometry. No per-frame success logs."); } internal static TrulySmoothLaddersConfig Load(BaseUnityPlugin plugin, string configDirectory, ManualLogSource log) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown if (!Directory.Exists(configDirectory)) { Directory.CreateDirectory(configDirectory); } string text = LegacyLadderConfigRules.FindImportSource(Directory.GetFiles(configDirectory, "*.cfg", SearchOption.TopDirectoryOnly)); string text2 = Path.Combine(configDirectory, "jg224.TrulySmoothLadders.cfg"); TrulySmoothLaddersConfig trulySmoothLaddersConfig = new TrulySmoothLaddersConfig(PluginConfigFiles.Attach(plugin, new ConfigFile(text2, true, plugin.Info.Metadata))); if (text != null) { trulySmoothLaddersConfig.ImportLegacyGeneralTweaks(text, log); } return trulySmoothLaddersConfig; } internal IEnumerable<IDisposable> RegisterMetadata(ICoreServices services, ModuleId owner) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, ((ConfigEntryBase)PrefabAdjustments).Definition.Section, ((ConfigEntryBase)PrefabAdjustments).Definition.Key, (ConfigScope)1, (Func<string>)(() => PrefabAdjustments.Value), 1)); yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, ((ConfigEntryBase)FitDiagnostics).Definition.Section, ((ConfigEntryBase)FitDiagnostics).Definition.Key, (ConfigScope)5, (Func<string>)(() => FitDiagnostics.Value.ToString()), 1)); yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, ((ConfigEntryBase)BetterLaddersEnabled).Definition.Section, ((ConfigEntryBase)BetterLaddersEnabled).Definition.Key, (ConfigScope)1, (Func<string>)(() => Convert.ToString(((ConfigEntryBase)BetterLaddersEnabled).BoxedValue, CultureInfo.InvariantCulture)), 1)); } private void ImportLegacyGeneralTweaks(string path, ManualLogSource log) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown try { ConfigFile val = new ConfigFile(path, false); BetterLaddersEnabled.Value = val.Bind<bool>("Movement", "BetterLadders", BetterLaddersEnabled.Value, (ConfigDescription)null).Value; _file.Save(); if (log != null) { log.LogInfo((object)("Imported the BetterLadders setting from " + Path.GetFileName(path) + " into jg224.TrulySmoothLadders.cfg.")); } } catch (Exception ex) { if (log != null) { log.LogWarning((object)("Could not import the GeneralTweaks BetterLadders setting; using the TrulySmoothLadders default. " + ex.Message)); } } } } } namespace JG224.TrulySmoothLadders.Patches { [HarmonyPatch(typeof(Piece), "Awake")] internal static class BetterLaddersPiecePatch { [HarmonyPostfix] private static void Postfix(Piece __instance) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) TrulySmoothLaddersConfig settings = Plugin.Settings; if (settings == null || !settings.BetterLaddersEnabled.Value || !Object.op_Implicit((Object)(object)__instance) || !PrefabRules.IsVanillaLadder(((Object)((Component)__instance).gameObject).name)) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { AutoJumpLedge componentInChildren = ((Component)__instance).GetComponentInChildren<AutoJumpLedge>(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { LadderRampRuntime.Ensure(__instance, ((Component)componentInChildren).transform.forward); } } } } [HarmonyPatch(typeof(AutoJumpLedge), "OnTriggerStay")] internal static class BetterLaddersPatch { [HarmonyPrefix] private static bool Prefix(AutoJumpLedge __instance, Collider collider) { //IL_006f: 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_0076: Unknown result type (might be due to invalid IL or missing references) TrulySmoothLaddersConfig settings = Plugin.Settings; if (settings == null || !settings.BetterLaddersEnabled.Value) { return true; } Character val = (Object.op_Implicit((Object)(object)collider) ? ((Component)collider).GetComponent<Character>() : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return true; } Piece componentInParent = ((Component)__instance).GetComponentInParent<Piece>(); if (!Object.op_Implicit((Object)(object)componentInParent) || !PrefabRules.IsVanillaLadder(((Object)((Component)componentInParent).gameObject).name)) { return true; } Vector3 forward = ((Component)__instance).transform.forward; return LadderRampRules.ShouldUseVanillaJump(LadderRampRuntime.Ensure(componentInParent, forward)); } } [HarmonyPatch(typeof(Character), "GetSlideAngle")] internal static class BetterLaddersSlidePatch { private const float LadderSlideAngle = 55f; [HarmonyPostfix] private static void Postfix(Character __instance, ref float __result) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && LadderRampRuntime.IsRampCollider(__instance.GetLastGroundCollider())) { __result = Mathf.Max(__result, 55f); } } } internal static class LadderRampRuntime { private sealed class Rejection { internal Piece Piece; internal float RetryAfter; } internal const string RampObjectName = "JG224_BetterLadderRamp"; private const float RampThickness = 0.08f; private static readonly Dictionary<int, GameObject> Ramps = new Dictionary<int, GameObject>(); private static readonly Dictionary<int, Rejection> Rejected = new Dictionary<int, Rejection>(); private static readonly List<int> Stale = new List<int>(); private static Dictionary<string, LadderAdjustment> _adjustments = LadderAdjustment.Parse(""); private static string _raw; private static float _nextCleanup; internal static bool Ensure(Piece ladder, Vector3 ladderForward) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_047d: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Expected O, but got Unknown //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04bc: Unknown result type (might be due to invalid IL or missing references) //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04f7: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) //IL_0528: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_054f: Unknown result type (might be due to invalid IL or missing references) //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_055d: Unknown result type (might be due to invalid IL or missing references) //IL_0562: Unknown result type (might be due to invalid IL or missing references) //IL_0578: Unknown result type (might be due to invalid IL or missing references) //IL_057e: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Unknown result type (might be due to invalid IL or missing references) //IL_058b: Unknown result type (might be due to invalid IL or missing references) //IL_058d: Unknown result type (might be due to invalid IL or missing references) //IL_0592: Unknown result type (might be due to invalid IL or missing references) //IL_059c: Unknown result type (might be due to invalid IL or missing references) //IL_05c2: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: 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) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)ladder)) { TrulySmoothLaddersConfig settings = Plugin.Settings; if (settings != null && settings.BetterLaddersEnabled.Value) { RefreshSettings(); int instanceID = ((Object)ladder).GetInstanceID(); if (Ramps.TryGetValue(instanceID, out var value) && Object.op_Implicit((Object)(object)value)) { return true; } if (Rejected.TryGetValue(instanceID, out var value2) && (Object)(object)value2.Piece == (Object)(object)ladder && Time.unscaledTime < value2.RetryAfter) { return false; } string text = ((Object)((Component)ladder).gameObject).name.Replace("(Clone)", "").Trim(); if (!_adjustments.TryGetValue(text, out var value3)) { value3 = LadderAdjustment.Default; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(ladderForward.x, 0f, ladderForward.z); if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { return Reject(ladder, "ladder forward direction is vertical"); } ((Vector3)(ref val)).Normalize(); Vector3 val2 = Vector3.Cross(Vector3.up, val); Vector3 normalized = ((Vector3)(ref val2)).normalized; Collider[] componentsInChildren = ((Component)ladder).GetComponentsInChildren<Collider>(true); Collider val3 = null; Collider val4 = null; float num = float.MaxValue; float num2 = float.MinValue; float num3 = 0f; int num4 = 0; int layer = ((Component)ladder).gameObject.layer; Bounds bounds; foreach (Collider val5 in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val5) || val5.isTrigger || ((Object)((Component)val5).gameObject).name == "JG224_BetterLadderRamp") { continue; } layer = ((Component)val5).gameObject.layer; bounds = val5.bounds; Vector3 size = ((Bounds)(ref bounds)).size; if (LadderColliderRules.IsStepSurface(size.x, size.y, size.z)) { bounds = val5.bounds; float num5 = Vector3.Dot(((Bounds)(ref bounds)).center, val); float num6 = num3; bounds = val5.bounds; num3 = num6 + Vector3.Dot(((Bounds)(ref bounds)).center, normalized); num4++; if (num5 < num) { num = num5; val3 = val5; } if (num5 > num2) { num2 = num5; val4 = val5; } } } if (num4 >= 2 && Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val4)) { float lowerForward = num; bounds = val3.bounds; float y = ((Bounds)(ref bounds)).max.y; float upperForward = num2; bounds = val4.bounds; if (LadderRampRules.TryCreateProfile(lowerForward, y, upperForward, ((Bounds)(ref bounds)).max.y, out var profile)) { float num7 = float.MinValue; foreach (Collider val6 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val6) && !val6.isTrigger && !(((Object)((Component)val6).gameObject).name == "JG224_BetterLadderRamp")) { bounds = val6.bounds; Vector3 size2 = ((Bounds)(ref bounds)).size; if (LadderColliderRules.IsStepSurface(size2.x, size2.y, size2.z)) { bounds = val6.bounds; float num8 = Vector3.Dot(((Bounds)(ref bounds)).center, val); float num9 = num7; bounds = val6.bounds; num7 = Mathf.Max(num9, ((Bounds)(ref bounds)).max.y - profile.Slope * num8); } } } float num10 = (num + num2) * 0.5f; float num11 = num3 / (float)num4; val2 = val + Vector3.up * profile.Slope; Vector3 normalized2 = ((Vector3)(ref val2)).normalized; val2 = Vector3.up - val * profile.Slope; Vector3 normalized3 = ((Vector3)(ref val2)).normalized; Vector3 val7 = val * num10 + normalized * num11; val7.y = profile.Slope * num10 + num7; Vector3 val8 = val7 + normalized3 * value3.Offset; float length = profile.SurfaceLength + value3.Margin * 2f; float centerForward = Vector3.Dot(val8, val); float y2 = val8.y; float slope = profile.Slope; bounds = val4.bounds; if (!LadderRampRules.TryCreateLanding(centerForward, y2, slope, length, ((Bounds)(ref bounds)).max.y, out var landing)) { return Reject(ladder, "ramp cannot meet the upper tread safely"); } val8 = val * ((landing.LowerForward + landing.UpperForward) * 0.5f) + normalized * num11; val8.y = (landing.LowerHeight + landing.UpperHeight) * 0.5f; GameObject val9 = new GameObject("JG224_BetterLadderRamp"); ((Object)val9).hideFlags = (HideFlags)61; val9.layer = layer; val9.transform.position = val8 - normalized3 * 0.04f; val9.transform.rotation = Quaternion.LookRotation(normalized2, normalized3); val9.transform.SetParent(((Component)ladder).transform, true); val9.AddComponent<BoxCollider>().size = new Vector3(value3.Width, 0.08f, landing.InclineLength); float num12 = landing.CapEndForward - landing.UpperForward; if (num12 > 0.001f) { GameObject val10 = new GameObject("JG224_BetterLadderRamp") { hideFlags = (HideFlags)61, layer = layer }; Vector3 position = val * ((landing.UpperForward + landing.CapEndForward) * 0.5f) + normalized * num11; position.y = landing.UpperHeight - 0.04f; val10.transform.position = position; val10.transform.rotation = Quaternion.LookRotation(val, Vector3.up); val10.transform.SetParent(val9.transform, true); val10.AddComponent<BoxCollider>().size = new Vector3(value3.Width, 0.08f, num12); } Ramps[instanceID] = val9; Rejected.Remove(instanceID); if (Plugin.Settings.FitDiagnostics.Value) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("Ladder fit " + text + ": steps=" + num4 + ", slope=" + profile.Slope + ", inclineLength=" + landing.InclineLength + ", landingLength=" + num12 + ", landingHeight=" + landing.UpperHeight)); } } return true; } } return Reject(ladder, "fewer than two suitable steps or unsupported slope/span"); } } return false; } private static bool Reject(Piece ladder, string reason) { int instanceID = ((Object)ladder).GetInstanceID(); if (!Rejected.TryGetValue(instanceID, out var value) || (Object)(object)value.Piece != (Object)(object)ladder) { value = new Rejection { Piece = ladder }; Rejected[instanceID] = value; TrulySmoothLaddersConfig settings = Plugin.Settings; if (settings != null && settings.FitDiagnostics.Value) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Ladder fit rejected for " + ((Object)ladder).name + ": " + reason + "; vanilla auto-jump retained.")); } } } value.RetryAfter = Time.unscaledTime + 2f; return false; } private static void RefreshSettings() { string text = Plugin.Settings?.PrefabAdjustments.Value ?? ""; if (!(_raw == text)) { DestroyAll(); _raw = text; _adjustments = LadderAdjustment.Parse(text); } } internal static void Tick() { TrulySmoothLaddersConfig settings = Plugin.Settings; if (settings == null || !settings.BetterLaddersEnabled.Value) { DestroyAll(); return; } RefreshSettings(); if (Time.unscaledTime < _nextCleanup) { return; } _nextCleanup = Time.unscaledTime + 1f; Stale.Clear(); foreach (KeyValuePair<int, GameObject> ramp in Ramps) { if (!Object.op_Implicit((Object)(object)ramp.Value)) { Stale.Add(ramp.Key); } } for (int i = 0; i < Stale.Count; i++) { Ramps.Remove(Stale[i]); } Stale.Clear(); foreach (KeyValuePair<int, Rejection> item in Rejected) { if (!Object.op_Implicit((Object)(object)item.Value.Piece)) { Stale.Add(item.Key); } } for (int j = 0; j < Stale.Count; j++) { Rejected.Remove(Stale[j]); } } internal static bool IsRampCollider(Collider collider) { if (Object.op_Implicit((Object)(object)collider)) { return ((Object)((Component)collider).gameObject).name == "JG224_BetterLadderRamp"; } return false; } internal static void DestroyAll() { foreach (GameObject value in Ramps.Values) { if (Object.op_Implicit((Object)(object)value)) { value.SetActive(false); Object.Destroy((Object)(object)value); } } Ramps.Clear(); Rejected.Clear(); Stale.Clear(); _nextCleanup = 0f; } } } namespace JG224.TrulySmoothLadders.Core { internal readonly struct LadderAdjustment { internal float Width { get; } internal float Offset { get; } internal float Margin { get; } internal static LadderAdjustment Default => new LadderAdjustment(1.3f, 0.42f, 0.35f); internal LadderAdjustment(float width, float offset, float margin) { Width = width; Offset = offset; Margin = margin; } internal static Dictionary<string, LadderAdjustment> Parse(string raw) { Dictionary<string, LadderAdjustment> dictionary = new Dictionary<string, LadderAdjustment>(StringComparer.OrdinalIgnoreCase); string[] array = (raw ?? "").Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { '=' }); if (array2.Length == 2 && PrefabRules.IsVanillaLadder(array2[0].Trim())) { string[] array3 = array2[1].Split(new char[1] { ',' }); if (array3.Length == 3 && Number(array3[0], 0.5f, 3f, out var number) && Number(array3[1], 0f, 0.75f, out var number2) && Number(array3[2], 0f, 1f, out var number3)) { dictionary[array2[0].Trim()] = new LadderAdjustment(number, number2, number3); } } } return dictionary; } private static bool Number(string value, float min, float max, out float number) { if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out number) && !float.IsNaN(number) && !float.IsInfinity(number) && number >= min) { return number <= max; } return false; } } internal static class LadderColliderRules { internal static bool IsStepSurface(float width, float height, float depth) { if (!IsFinitePositive(width) || !IsFinitePositive(height) || !IsFinitePositive(depth)) { return false; } float num = Math.Max(width, depth); if (height <= 0.35f) { return height <= num * 0.5f; } return false; } private static bool IsFinitePositive(float value) { if (value > 0f) { return IsFinite(value); } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal readonly struct LadderRampProfile { internal float Slope { get; } internal float HorizontalSpan { get; } internal float SurfaceLength => HorizontalSpan * (float)Math.Sqrt(1f + Slope * Slope); internal LadderRampProfile(float slope, float horizontalSpan) { Slope = slope; HorizontalSpan = horizontalSpan; } } internal static class LadderRampRules { internal const float LandingClearance = 0.02f; internal static bool TryCreateLanding(float centerForward, float centerHeight, float slope, float length, float highestTread, out LadderLanding landing) { landing = default(LadderLanding); if (!IsFinite(centerForward) || !IsFinite(centerHeight) || !IsFinite(slope) || !IsFinite(length) || !IsFinite(highestTread) || slope <= 0f || length <= 0f) { return false; } float num = (float)Math.Sqrt(1f + slope * slope); float num2 = length / (2f * num); float num3 = num2 * slope; float num4 = centerHeight - num3; float num5 = Math.Min(centerHeight + num3, highestTread + 0.02f); if (num5 - num4 < 0.01f) { return false; } float num6 = centerForward - num2; float num7 = num6 + (num5 - num4) / slope; landing = new LadderLanding(num6, num4, num7, num5, Math.Max(num7, centerForward + num2)); return true; } internal static bool ShouldUseVanillaJump(bool rampReady) { return !rampReady; } internal static bool TryCreateProfile(float lowerForward, float lowerTop, float upperForward, float upperTop, out LadderRampProfile profile) { profile = default(LadderRampProfile); if (!IsFinite(lowerForward) || !IsFinite(lowerTop) || !IsFinite(upperForward) || !IsFinite(upperTop)) { return false; } float num = upperForward - lowerForward; float num2 = upperTop - lowerTop; if (num < 0.25f || num2 < 0.1f) { return false; } float num3 = num2 / num; if (num3 < 0.4f || num3 > 2.5f) { return false; } float slope = Math.Min(num3, 1.35f); profile = new LadderRampProfile(slope, num); return true; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal readonly struct LadderLanding { internal float LowerForward { get; } internal float LowerHeight { get; } internal float UpperForward { get; } internal float UpperHeight { get; } internal float CapEndForward { get; } internal float InclineLength => (float)Math.Sqrt((UpperForward - LowerForward) * (UpperForward - LowerForward) + (UpperHeight - LowerHeight) * (UpperHeight - LowerHeight)); internal LadderLanding(float lowerForward, float lowerHeight, float upperForward, float upperHeight, float capEndForward) { LowerForward = lowerForward; LowerHeight = lowerHeight; UpperForward = upperForward; UpperHeight = upperHeight; CapEndForward = capEndForward; } } internal static class PrefabRules { private static readonly HashSet<string> Ladders = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "piece_wood_ladder", "piece_wood_ladder_45", "piece_woodstepladder", "piece_grausten_stoneladder", "wood_ladder", "wood_stepladder", "woodstepladder", "grausten_ladder", "grausten_stone_ladder", "piece_grausten_stone_ladder" }; internal static bool IsVanillaLadder(string prefabName) { return Ladders.Contains(Clean(prefabName)); } private static string Clean(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } int num = value.IndexOf("(Clone)", StringComparison.OrdinalIgnoreCase); return ((num >= 0) ? value.Substring(0, num) : value).Trim(); } } internal static class LegacyLadderConfigRules { internal const string CurrentFileName = "jg224.TrulySmoothLadders.cfg"; internal const string GeneralTweaksFileName = "jg224.GeneralTweaks.cfg"; internal const string LegacyGeneralTweaksFileName = "JG224.GeneralTweaks.cfg"; internal static string FindImportSource(IEnumerable<string> candidatePaths) { string[] paths = ((candidatePaths == null) ? Array.Empty<string>() : candidatePaths.ToArray()); if (FindExact(paths, "jg224.TrulySmoothLadders.cfg") != null) { return null; } return FindExact(paths, "jg224.GeneralTweaks.cfg") ?? FindExact(paths, "JG224.GeneralTweaks.cfg"); } private static string FindExact(IEnumerable<string> paths, string fileName) { return paths.FirstOrDefault((string path) => string.Equals(Path.GetFileName(path), fileName, StringComparison.Ordinal)); } } }