using 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 _registrations = new List(); 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)delegate { LadderRampRuntime.DestroyAll(); }, 0)); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)3, (Action)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 BetterLaddersEnabled { get; } internal ConfigEntry PrefabAdjustments { get; } internal ConfigEntry FitDiagnostics { get; } private TrulySmoothLaddersConfig(ConfigFile file) { _file = file; BetterLaddersEnabled = file.Bind("Movement", "BetterLadders", true, "Replace vanilla ladder auto-jump bouncing with smooth forward climbing."); PrefabAdjustments = file.Bind("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("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 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)(() => PrefabAdjustments.Value), 1)); yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, ((ConfigEntryBase)FitDiagnostics).Definition.Section, ((ConfigEntryBase)FitDiagnostics).Definition.Key, (ConfigScope)5, (Func)(() => FitDiagnostics.Value.ToString()), 1)); yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, ((ConfigEntryBase)BetterLaddersEnabled).Definition.Section, ((ConfigEntryBase)BetterLaddersEnabled).Definition.Key, (ConfigScope)1, (Func)(() => 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("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(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { AutoJumpLedge componentInChildren = ((Component)__instance).GetComponentInChildren(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() : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return true; } Piece componentInParent = ((Component)__instance).GetComponentInParent(); 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 Ramps = new Dictionary(); private static readonly Dictionary Rejected = new Dictionary(); private static readonly List Stale = new List(); private static Dictionary _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(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().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().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 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 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 Parse(string raw) { Dictionary dictionary = new Dictionary(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 Ladders = new HashSet(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 candidatePaths) { string[] paths = ((candidatePaths == null) ? Array.Empty() : 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 paths, string fileName) { return paths.FirstOrDefault((string path) => string.Equals(Path.GetFileName(path), fileName, StringComparison.Ordinal)); } } }