using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterLadders;
using BetterLadders.Patches;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BetterLadders")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Configurable climbing speed, extension ladder time, and climbing with two-handed items")]
[assembly: AssemblyFileVersion("1.4.3.0")]
[assembly: AssemblyInformationalVersion("1.4.3+ec9e47752cb829c5e645f0727a36b300d0a848f1")]
[assembly: AssemblyProduct("BetterLadders")]
[assembly: AssemblyTitle("BetterLadders")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.3.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;
}
}
}
[Serializable]
public class SyncedInstance<T>
{
[CompilerGenerated]
private static class <>O
{
public static HandleNamedMessageDelegate <0>__OnRequestSync;
public static HandleNamedMessageDelegate <1>__OnRequestHideItem;
public static HandleNamedMessageDelegate <2>__OnReceiveHideItem;
public static HandleNamedMessageDelegate <3>__OnReceiveSync;
}
[NonSerialized]
protected static int IntSize = 4;
internal static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager;
internal static bool IsClient => NetworkManager.Singleton.IsClient;
internal static bool IsHost => NetworkManager.Singleton.IsHost;
internal static Harmony harmony => Plugin.Instance.harmony;
public static T Default { get; private set; }
public static T Instance { get; private set; }
public static bool SyncedPatchesApplied { get; private set; }
public static bool Synced { get; internal set; }
protected void InitInstance(T instance)
{
Default = instance;
Instance = instance;
IntSize = 4;
}
internal static void SyncInstance(byte[] data)
{
Instance = DeserializeFromBytes(data);
Synced = true;
}
internal static void RevertSync()
{
Instance = Default;
Synced = false;
}
public static byte[] SerializeToBytes(T val)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
using MemoryStream memoryStream = new MemoryStream();
try
{
binaryFormatter.Serialize(memoryStream, val);
return memoryStream.ToArray();
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"Error serializing instance: {arg}");
return null;
}
}
public static T DeserializeFromBytes(byte[] data)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
using MemoryStream serializationStream = new MemoryStream(data);
try
{
return (T)binaryFormatter.Deserialize(serializationStream);
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"Error deserializing instance: {arg}");
return default(T);
}
}
public static void RequestSync()
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
if (!IsClient)
{
return;
}
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(IntSize, (Allocator)2, -1);
try
{
MessageManager.SendNamedMessage("BetterLadders_OnRequestConfigSync", 0uL, val, (NetworkDelivery)3);
Plugin.Logger.LogInfo((object)"Requested sync from server");
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
public static void OnRequestSync(ulong clientId, FastBufferReader _)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
if (!IsHost)
{
return;
}
Plugin.Logger.LogInfo((object)$"Config sync request received from client: {clientId}");
byte[] array = SerializeToBytes(Instance);
int num = array.Length;
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(num + IntSize, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0);
MessageManager.SendNamedMessage("BetterLadders_OnReceiveConfigSync", clientId, val, (NetworkDelivery)3);
}
catch (Exception arg)
{
Plugin.Logger.LogInfo((object)$"Error occurred syncing config with client: {clientId}\n{arg}");
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
public static void OnReceiveSync(ulong _, FastBufferReader reader)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if (!((FastBufferReader)(ref reader)).TryBeginRead(IntSize))
{
Plugin.Logger.LogError((object)"Config sync error: Could not begin reading buffer.");
return;
}
int num = default(int);
((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
if (!((FastBufferReader)(ref reader)).TryBeginRead(num))
{
Plugin.Logger.LogError((object)"Config sync error: Host could not sync.");
return;
}
byte[] data = new byte[num];
((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
SyncInstance(data);
Plugin.Logger.LogInfo((object)"Successfully synced config with host.");
}
public static void RequestHideItem(bool enabled)
{
//IL_0016: 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_002e: Unknown result type (might be due to invalid IL or missing references)
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(1 + IntSize, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref enabled, default(ForPrimitives));
MessageManager.SendNamedMessage("BetterLadders_OnRequestHideItem", 0uL, val, (NetworkDelivery)3);
if (GameNetworkManager.Instance.localPlayerController.playerClientId != 0L)
{
Plugin.Logger.LogInfo((object)("Requested server to " + (enabled ? "show" : "hide") + " this client's held item"));
}
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
public static void OnRequestHideItem(ulong clientId, FastBufferReader reader)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: 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_0090: Unknown result type (might be due to invalid IL or missing references)
if (!IsHost)
{
return;
}
if (!((FastBufferReader)(ref reader)).TryBeginRead(1))
{
Plugin.Logger.LogError((object)"Hide item error: Could not begin reading buffer.");
return;
}
bool flag = default(bool);
((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives));
if (clientId != 0L)
{
Plugin.Logger.LogInfo((object)$"Hide item request received from client: {clientId}");
}
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(9 + IntSize, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref clientId, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives));
MessageManager.SendNamedMessageToAll("BetterLadders_OnReceiveHideItem", val, (NetworkDelivery)3);
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
public static void OnReceiveHideItem(ulong _, FastBufferReader reader)
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
if (!((FastBufferReader)(ref reader)).TryBeginRead(9))
{
Plugin.Logger.LogError((object)"Hide item error: Could not begin reading buffer.");
return;
}
ulong requestingClientId = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref requestingClientId, default(ForPrimitives));
bool flag = default(bool);
((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives));
if (GameNetworkManager.Instance.localPlayerController.playerClientId == requestingClientId)
{
return;
}
PlayerControllerB val = ((IEnumerable<PlayerControllerB>)Object.FindObjectsOfType<PlayerControllerB>()).FirstOrDefault((Func<PlayerControllerB, bool>)((PlayerControllerB player) => player.playerClientId == requestingClientId));
if ((Object)(object)val != (Object)null)
{
if ((val.twoHanded && SyncedInstance<Config>.Default.hideTwoHanded) || (!val.twoHanded && SyncedInstance<Config>.Default.hideOneHanded))
{
val.currentlyHeldObjectServer.EnableItemMeshes(flag);
Plugin.Logger.LogInfo((object)string.Format("Successfully {0} client {1}'s held item.", flag ? "showed" : "hid", requestingClientId));
}
}
else
{
Plugin.Logger.LogError((object)$"Failed to find client with id {requestingClientId}.");
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameNetworkManager), "StartDisconnect")]
public static void PlayerLeave()
{
SyncedInstance<Config>.RevertSync();
if (SyncedPatchesApplied)
{
Plugin.Logger.LogInfo((object)"Unpatching transpilers");
Plugin.Instance.UnpatchSyncedTranspilers();
SyncedPatchesApplied = false;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
public static void InitializeLocalPlayer()
{
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Expected O, but got Unknown
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Expected O, but got Unknown
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Expected O, but got Unknown
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Expected O, but got Unknown
if (IsHost)
{
CustomMessagingManager messageManager = SyncedInstance<Config>.MessageManager;
object obj = <>O.<0>__OnRequestSync;
if (obj == null)
{
HandleNamedMessageDelegate val = SyncedInstance<Config>.OnRequestSync;
<>O.<0>__OnRequestSync = val;
obj = (object)val;
}
messageManager.RegisterNamedMessageHandler("BetterLadders_OnRequestConfigSync", (HandleNamedMessageDelegate)obj);
CustomMessagingManager messageManager2 = SyncedInstance<Config>.MessageManager;
object obj2 = <>O.<1>__OnRequestHideItem;
if (obj2 == null)
{
HandleNamedMessageDelegate val2 = SyncedInstance<Config>.OnRequestHideItem;
<>O.<1>__OnRequestHideItem = val2;
obj2 = (object)val2;
}
messageManager2.RegisterNamedMessageHandler("BetterLadders_OnRequestHideItem", (HandleNamedMessageDelegate)obj2);
CustomMessagingManager messageManager3 = SyncedInstance<Config>.MessageManager;
object obj3 = <>O.<2>__OnReceiveHideItem;
if (obj3 == null)
{
HandleNamedMessageDelegate val3 = SyncedInstance<Config>.OnReceiveHideItem;
<>O.<2>__OnReceiveHideItem = val3;
obj3 = (object)val3;
}
messageManager3.RegisterNamedMessageHandler("BetterLadders_OnReceiveHideItem", (HandleNamedMessageDelegate)obj3);
SyncedInstance<Config>.Synced = true;
}
else
{
SyncedInstance<Config>.Synced = false;
CustomMessagingManager messageManager4 = SyncedInstance<Config>.MessageManager;
object obj4 = <>O.<3>__OnReceiveSync;
if (obj4 == null)
{
HandleNamedMessageDelegate val4 = SyncedInstance<Config>.OnReceiveSync;
<>O.<3>__OnReceiveSync = val4;
obj4 = (object)val4;
}
messageManager4.RegisterNamedMessageHandler("BetterLadders_OnReceiveConfigSync", (HandleNamedMessageDelegate)obj4);
CustomMessagingManager messageManager5 = SyncedInstance<Config>.MessageManager;
object obj5 = <>O.<2>__OnReceiveHideItem;
if (obj5 == null)
{
HandleNamedMessageDelegate val5 = SyncedInstance<Config>.OnReceiveHideItem;
<>O.<2>__OnReceiveHideItem = val5;
obj5 = (object)val5;
}
messageManager5.RegisterNamedMessageHandler("BetterLadders_OnReceiveHideItem", (HandleNamedMessageDelegate)obj5);
SyncedInstance<Config>.RequestSync();
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(StartMatchLever), "PullLeverAnim")]
private static void PostSyncOrNoResponse()
{
if (!IsHost && !SyncedInstance<Config>.Synced && !SyncedInstance<Config>.Default.hostMissingMod)
{
Plugin.Logger.LogInfo((object)"Config wasn't synced with host (likely doesn't have mod), setting vanilla config defaults");
SyncedInstance<Config>.Instance.SetVanillaDefaults();
}
Plugin.Logger.LogInfo((object)"All config syncing operations finished, starting synced patches");
if (!SyncedPatchesApplied)
{
Plugin.Instance.PatchSyncedTranspilers();
SyncedPatchesApplied = true;
}
}
}
namespace BetterLadders
{
[Serializable]
public class Config : SyncedInstance<Config>
{
public float climbSpeedMultiplier { get; internal set; }
public float sprintingClimbSpeedMultiplier { get; internal set; }
public float transitionSpeedMultiplier { get; internal set; }
public bool allowTwoHanded { get; internal set; }
public bool scaleAnimationSpeed { get; internal set; }
public bool hideOneHanded { get; internal set; }
public bool hideTwoHanded { get; internal set; }
public float timeMultiplier { get; internal set; }
public bool enableKillTrigger { get; internal set; }
public bool holdToPickup { get; internal set; }
public float holdTime { get; internal set; }
public bool debugMode { get; internal set; }
public bool hostMissingMod { get; internal set; }
internal Config(ConfigFile cfg)
{
InitInstance(this);
climbSpeedMultiplier = cfg.Bind<float>("General", "climbSpeedMultipler", 1f, "Ladder climb speed multiplier").Value;
sprintingClimbSpeedMultiplier = cfg.Bind<float>("General", "sprintingClimbSpeedMultiplier", 1.5f, "Ladder climb speed multiplier while sprinting, stacks with climbSpeedMultiplier").Value;
transitionSpeedMultiplier = cfg.Bind<float>("General", "transitionSpeedMultiplier", 1f, "Ladder entrance animation speed multiplier").Value;
allowTwoHanded = cfg.Bind<bool>("General", "allowTwoHanded", true, "Whether to allow using ladders while carrying a two-handed object").Value;
scaleAnimationSpeed = cfg.Bind<bool>("General", "scaleAnimationSpeed", true, "Whether to scale the speed of the climbing animation to the climbing speed").Value;
hideOneHanded = cfg.Bind<bool>("General", "hideOneHanded", true, "Whether to hide one-handed items while climbing a ladder - false in vanilla").Value;
hideTwoHanded = cfg.Bind<bool>("General", "hideTwoHanded", true, "Whether to hide two-handed items while climbing a ladder").Value;
timeMultiplier = cfg.Bind<float>("Extension Ladders", "timeMultiplier", 0f, "Extension ladder time multiplier (0 for permanent) - lasts 20 seconds in vanilla").Value;
enableKillTrigger = cfg.Bind<bool>("Extension Ladders", "enableKillTrigger", true, "Whether extension ladders should kill players they land on").Value;
holdToPickup = cfg.Bind<bool>("Extension Ladders", "holdToPickup", true, "Whether the interact key needs to be held to pick up an activated extension ladder").Value;
holdTime = cfg.Bind<float>("Extension Ladders", "holdTime", 0.5f, "How long, in seconds, the interact key must be held if holdToPickup is true").Value;
debugMode = cfg.Bind<bool>("Debug", "debugMode", false, "Displays debug messages in the BepInEx console if true").Value;
hostMissingMod = false;
}
internal void SetVanillaDefaults()
{
SyncedInstance<Config>.Instance.climbSpeedMultiplier = 1f;
SyncedInstance<Config>.Instance.sprintingClimbSpeedMultiplier = 1f;
SyncedInstance<Config>.Instance.transitionSpeedMultiplier = 1f;
SyncedInstance<Config>.Instance.allowTwoHanded = false;
SyncedInstance<Config>.Instance.timeMultiplier = 1f;
SyncedInstance<Config>.Instance.enableKillTrigger = true;
hostMissingMod = true;
}
}
[BepInPlugin("e3s1.BetterLadders", "BetterLadders", "1.4.3")]
public class Plugin : BaseUnityPlugin
{
public static Plugin Instance;
internal readonly Harmony harmony = new Harmony("e3s1.BetterLadders");
public const string GUID = "e3s1.BetterLadders";
public const string NAME = "BetterLadders";
public const string VERSION = "1.4.3";
internal static ManualLogSource Logger { get; private set; }
public static Config Config { get; internal set; }
private void Awake()
{
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
Config = new Config(((BaseUnityPlugin)this).Config);
harmony.PatchAll(typeof(SyncedInstance<Config>));
harmony.PatchAll(typeof(AllowTwoHanded));
harmony.PatchAll(typeof(ClimbSpeed));
harmony.PatchAll(typeof(HideItems));
harmony.PatchAll(typeof(HoverTip));
if (SyncedInstance<Config>.Default.holdToPickup)
{
harmony.PatchAll(typeof(HoldToPickup));
}
Logger.LogInfo((object)"BetterLadders loaded");
}
internal void PatchSyncedTranspilers()
{
harmony.PatchAll(typeof(ExtLadderTime));
harmony.PatchAll(typeof(KillTrigger));
harmony.PatchAll(typeof(TransitionSpeed));
}
internal void UnpatchSyncedTranspilers()
{
harmony.Unpatch((MethodBase)AccessTools.Method(typeof(ExtensionLadderItem), "Update", (Type[])null, (Type[])null), (HarmonyPatchType)3, harmony.Id);
harmony.Unpatch((MethodBase)AccessTools.Method(typeof(ExtensionLadderItem), "LadderAnimation", (Type[])null, (Type[])null), (HarmonyPatchType)3, harmony.Id);
harmony.Unpatch((MethodBase)AccessTools.Method(typeof(InteractTrigger), "ladderClimbAnimation", (Type[])null, (Type[])null), (HarmonyPatchType)3, harmony.Id);
}
internal void TranspilerLogger(List<CodeInstruction> code, int i, int startRelative, int endRelative, string name)
{
if (SyncedInstance<Config>.Instance.debugMode)
{
Logger.LogInfo((object)("Found code match in " + name));
for (int j = startRelative; j < endRelative; j++)
{
Logger.LogInfo((object)code[i + j]);
}
Logger.LogInfo((object)"============================================================");
}
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "BetterLadders";
public const string PLUGIN_NAME = "BetterLadders";
public const string PLUGIN_VERSION = "1.4.3";
}
}
namespace BetterLadders.Patches
{
internal class AllowTwoHanded
{
[HarmonyPrefix]
[HarmonyPatch(typeof(PlayerControllerB), "Interact_performed")]
private static void LadderTwoHandedAccessPatch(ref InteractTrigger ___hoveringOverTrigger, ref bool ___twoHanded)
{
if ((SyncedInstance<Config>.Instance.allowTwoHanded && (Object)(object)___hoveringOverTrigger != (Object)null && ___hoveringOverTrigger.isLadder) & ___twoHanded)
{
___hoveringOverTrigger.twoHandedItemAllowed = true;
___hoveringOverTrigger.specialCharacterAnimation = false;
}
}
}
internal class ClimbSpeed
{
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerControllerB), "Update")]
private static void LadderClimbSpeedPatch(ref bool ___isSprinting, ref float ___climbSpeed, ref bool ___isClimbingLadder, ref PlayerControllerB __instance)
{
if (!___isClimbingLadder)
{
return;
}
float num = (___climbSpeed = 4f * SyncedInstance<Config>.Instance.climbSpeedMultiplier * (___isSprinting ? SyncedInstance<Config>.Instance.sprintingClimbSpeedMultiplier : 1f));
if (__instance.moveInputVector.y != 0f && SyncedInstance<Config>.Instance.scaleAnimationSpeed)
{
float num2 = num / 4f * ((__instance.moveInputVector.y > 0f) ? 1f : (-1f));
if (__instance.currentAnimationSpeed != num2)
{
__instance.previousAnimationSpeed = num2;
__instance.currentAnimationSpeed = num2;
Plugin.Logger.LogInfo((object)$"Setting animationSpeed to {num2}");
__instance.playerBodyAnimator.SetFloat("animationSpeed", num2);
}
}
else if (__instance.moveInputVector.y == 0f && __instance.currentAnimationSpeed != 0f)
{
__instance.previousAnimationSpeed = 0f;
__instance.currentAnimationSpeed = 0f;
Plugin.Logger.LogInfo((object)"Setting animationSpeed to 0");
__instance.playerBodyAnimator.SetFloat("animationSpeed", 0f);
}
}
}
internal class ExtLadderTime
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(ExtensionLadderItem), "Update")]
private static IEnumerable<CodeInstruction> ExtLadderTimeTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Expected O, but got Unknown
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Expected O, but got Unknown
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
//IL_01b7: Expected O, but got Unknown
Plugin.Logger.LogInfo((object)"Starting ExtLadderTimeTranspiler");
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
if (SyncedInstance<Config>.Instance.timeMultiplier < 0f)
{
Plugin.Logger.LogWarning((object)"timeMultiplier is set to a negative value, not changing extension ladder time");
return list;
}
if (SyncedInstance<Config>.Instance.timeMultiplier > 0f)
{
for (int i = 0; i < list.Count - 1; i++)
{
if (list[i].opcode == OpCodes.Ldfld && list[i].operand is FieldInfo fieldInfo && fieldInfo.Name == "ladderTimer" && list[i + 1].opcode == OpCodes.Ldc_R4)
{
list.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_R4, (object)SyncedInstance<Config>.Instance.timeMultiplier));
list.Insert(i + 3, new CodeInstruction(OpCodes.Mul, (object)null));
Plugin.Instance.TranspilerLogger(list, i, -2, 5, "ExtLadderTime");
}
}
return list;
}
if (SyncedInstance<Config>.Instance.timeMultiplier == 0f)
{
for (int j = 0; j < list.Count - 5; j++)
{
if (list[j].opcode == OpCodes.Ret && list[j + 2].opcode == OpCodes.Ldfld && list[j + 2].operand is FieldInfo fieldInfo2 && fieldInfo2.Name == "ladderAnimationBegun" && list[j + 5].opcode == OpCodes.Ldarg_0)
{
list.Insert(j + 4, new CodeInstruction(OpCodes.Ret, (object)null));
Plugin.Instance.TranspilerLogger(list, j, -2, 6, "ExtLadderTime");
return list;
}
}
return list;
}
return list;
}
}
internal class HideItems
{
private static bool hasUsedLadder;
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")]
private static void SetVisibilityOnItemSwitch(ref PlayerControllerB __instance)
{
SetVisibility(ref __instance.isClimbingLadder);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(InteractTrigger), "SetUsingLadderOnLocalClient")]
private static void SetVisibilityOnStartClimb(ref bool ___usingLadder)
{
hasUsedLadder = true;
SetVisibility(ref ___usingLadder);
}
internal static void SetVisibility(ref bool ___usingLadder)
{
if (!hasUsedLadder)
{
return;
}
PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
if ((Object)(object)localPlayerController.currentlyHeldObjectServer != (Object)null && ((SyncedInstance<Config>.Instance.allowTwoHanded && localPlayerController.twoHanded) || !localPlayerController.twoHanded))
{
SyncedInstance<Config>.RequestHideItem(!___usingLadder);
Plugin.Logger.LogInfo((object)"Sending request to other clients to hide held item");
if ((localPlayerController.twoHanded && SyncedInstance<Config>.Default.hideTwoHanded) || (!localPlayerController.twoHanded && SyncedInstance<Config>.Default.hideOneHanded))
{
Plugin.Logger.LogInfo((object)"Hiding held item");
localPlayerController.currentlyHeldObjectServer.EnableItemMeshes(!___usingLadder);
hasUsedLadder = false;
}
}
}
}
internal class HoldToPickup
{
private static bool canPickupLadder;
[HarmonyPrefix]
[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
private static bool ControlExtLadderPickup(ref PlayerControllerB __instance)
{
if (LookingAtGrabbableExtLadder(ref __instance, out var _, out var extLadderObj) && (Object)(object)extLadderObj != (Object)null && extLadderObj.ladderActivated)
{
if (canPickupLadder)
{
canPickupLadder = false;
return true;
}
return false;
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerControllerB), "ClickHoldInteraction")]
private static void ShowHoldInteractHUD(ref PlayerControllerB __instance)
{
if (!Object.op_Implicit((Object)(object)__instance.hoveringOverTrigger))
{
RaycastHit hit;
ExtensionLadderItem extLadderObj;
if (!IngamePlayerSettings.Instance.playerInput.actions.FindAction("Interact", false).IsPressed())
{
HUDManager.Instance.holdFillAmount = 0f;
}
else if (LookingAtGrabbableExtLadder(ref __instance, out hit, out extLadderObj) && (Object)(object)extLadderObj != (Object)null && extLadderObj.ladderActivated && HUDManager.Instance.HoldInteractionFill(SyncedInstance<Config>.Default.holdTime, 1f))
{
canPickupLadder = true;
__instance.BeginGrabObject();
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(PlayerControllerB), "StopHoldInteractionOnTrigger")]
private static bool StopHoldInteractionOnTrigger(ref PlayerControllerB __instance)
{
if (LookingAtGrabbableExtLadder(ref __instance, out var _, out var extLadderObj))
{
if ((Object)(object)extLadderObj != (Object)null && extLadderObj.ladderActivated)
{
if (IngamePlayerSettings.Instance.playerInput.actions.FindAction("Interact", false).IsPressed())
{
return false;
}
HUDManager.Instance.holdFillAmount = 0f;
}
else
{
HUDManager.Instance.holdFillAmount = 0f;
}
}
else
{
HUDManager.Instance.holdFillAmount = 0f;
}
if ((Object)(object)__instance.previousHoveringOverTrigger != (Object)null)
{
__instance.previousHoveringOverTrigger.StopInteraction();
}
if ((Object)(object)__instance.hoveringOverTrigger != (Object)null)
{
__instance.hoveringOverTrigger.StopInteraction();
}
return false;
}
private static bool LookingAtGrabbableExtLadder(ref PlayerControllerB __instance, out RaycastHit hit, out ExtensionLadderItem extLadderObj)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
Ray val = default(Ray);
((Ray)(ref val))..ctor(((Component)__instance.gameplayCamera).transform.position, ((Component)__instance.gameplayCamera).transform.forward);
bool flag = Physics.Raycast(val, ref hit, __instance.grabDistance, __instance.interactableObjectsMask) && ((Component)((RaycastHit)(ref hit)).collider).gameObject.layer != 8;
if (flag)
{
extLadderObj = ((Component)((RaycastHit)(ref hit)).collider).gameObject.GetComponent<ExtensionLadderItem>();
if (__instance.twoHanded || ((Object)(object)extLadderObj != (Object)null && !((GrabbableObject)extLadderObj).grabbable))
{
return false;
}
}
else
{
extLadderObj = null;
}
return flag;
}
}
internal class HoverTip
{
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerControllerB), "SetHoverTipAndCurrentInteractTrigger")]
private static void LadderHandsFullTipPatch(ref PlayerControllerB __instance, ref InteractTrigger ___hoveringOverTrigger, ref bool ___isHoldingInteract, ref bool ___twoHanded)
{
if (((SyncedInstance<Config>.Instance.allowTwoHanded && (Object)(object)___hoveringOverTrigger != (Object)null) & ___isHoldingInteract & ___twoHanded) && ___hoveringOverTrigger.isLadder)
{
((TMP_Text)__instance.cursorTip).text = ___hoveringOverTrigger.hoverTip.Replace("[LMB]", "[E]");
}
}
}
internal class KillTrigger
{
[HarmonyTranspiler]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static IEnumerable<CodeInstruction> KillTriggerTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Expected O, but got Unknown
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Expected O, but got Unknown
Plugin.Logger.LogInfo((object)"Starting KillTrigger transpiler");
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
for (int i = 0; i < list.Count - 1; i++)
{
if (list[i].opcode == OpCodes.Ldfld && list[i].operand is FieldInfo fieldInfo && fieldInfo.Name == "killTrigger" && list[i + 1].opcode == OpCodes.Ldc_I4_1)
{
list.Insert(i + 2, new CodeInstruction(OpCodes.Pop, (object)null));
list.Insert(i + 3, new CodeInstruction(SyncedInstance<Config>.Instance.enableKillTrigger ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0, (object)null));
Plugin.Instance.TranspilerLogger(list, i, -2, 6, "KillTrigger");
}
}
return list;
}
}
internal class TransitionSpeed
{
[HarmonyTranspiler]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static IEnumerable<CodeInstruction> TransitionSpeedTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Expected O, but got Unknown
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Expected O, but got Unknown
Plugin.Logger.LogInfo((object)"Starting TransitionSpeed transpiler");
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
if (SyncedInstance<Config>.Instance.transitionSpeedMultiplier <= 0f)
{
Plugin.Logger.LogError((object)$"transitionSpeedMultiplier ({SyncedInstance<Config>.Instance.transitionSpeedMultiplier}) is an invalid value");
return list;
}
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Call && list[i].operand is MethodInfo methodInfo && methodInfo.Name == "get_deltaTime")
{
list.Insert(i + 1, new CodeInstruction(OpCodes.Ldc_R4, (object)SyncedInstance<Config>.Instance.transitionSpeedMultiplier));
list.Insert(i + 2, new CodeInstruction(OpCodes.Mul, (object)null));
Plugin.Instance.TranspilerLogger(list, i, -2, 4, "TransitionSpeed");
}
}
return list;
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}