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 SprintImprovements v1.1.0
SprintImprovements.dll
Decompiled 9 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Bandit2.Weapon; using EntityStates.Captain.Weapon; using EntityStates.Drifter; using EntityStates.DroneTech.Weapon; using EntityStates.Engi.EngiMissilePainter; using EntityStates.Huntress.HuntressWeapon; using EntityStates.Mage.Weapon; using EntityStates.Railgunner.Scope; using EntityStates.Toolbot; using EntityStates.VoidSurvivor.Weapon; using HG.Reflection; using HarmonyLib; using IL.RoR2; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using MonoMod.Cil; using MonoMod.RuntimeDetour; using Rewired; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.Skills; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: OptIn] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SprintImprovements")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("SprintImprovements")] [assembly: AssemblyTitle("SprintImprovements")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.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 SprintImprovements { public enum SprintKeyMode { Toggle, Hold, Always } internal static class PluginConfig { private const string Section = "General"; internal static ConfigEntry<bool> Enabled { get; private set; } internal static ConfigEntry<SprintKeyMode> SprintMode { get; private set; } internal static ConfigEntry<bool> BlockForcedSprint { get; private set; } internal static void Init(ConfigFile config) { Enabled = config.Bind<bool>("General", "Enabled", true, "Off gives you the normal game's sprint."); SprintMode = config.Bind<SprintKeyMode>("General", "SprintMode", SprintKeyMode.Toggle, "How the sprint key works. Toggle: press to sprint, press again to stop; stopping, strafing, skills and stuns only pause sprint. Hold: sprint while you hold the key. Always: sprint whenever you can and hold the key to walk."); BlockForcedSprint = config.Bind<bool>("General", "BlockForcedSprint", true, "Skills no longer turn sprint on when you don't want to sprint (e.g. Mercenary's dashes, Commando's Tactical Dive, Huntress's Blink, MUL-T's Transport Mode, Acrid's leaps). When you do want to sprint, they work as in the normal game: in Toggle mode your toggle is on (also while sprint is paused) or you turn it on during the skill; in Hold mode you hold the key; in Always mode you don't. Off: they turn sprint on, and in Toggle mode that turns your toggle on, as in the normal game."); Enabled.SettingChanged += delegate { SprintGuard.OnModeChanged(); }; SprintMode.SettingChanged += delegate { SprintGuard.OnModeChanged(); }; } } internal static class RiskOfOptionsCompat { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static IsDisabledDelegate <>9__4_0; public static IsDisabledDelegate <>9__4_1; internal bool <Init>b__4_0() { return !PluginConfig.Enabled.Value; } internal bool <Init>b__4_1() { return !PluginConfig.Enabled.Value; } } public const string Guid = "com.rune580.riskofoptions"; private const string IconResource = "SprintImprovements.icon.png"; public static bool IsInstalled => Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"); [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] internal static void Init() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0090: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_007b: 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_0086: Expected O, but got Unknown ModSettingsManager.SetModDescription("Sprint changes only when you want it to. Skills like Mercenary's dash no longer force it on; stopping, strafing, skills and stuns only pause it; and you can pick toggle, hold or always-on sprint. Only affects your own character."); ModSettingsManager.SetModIcon(LoadIcon()); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PluginConfig.Enabled)); ConfigEntry<SprintKeyMode> sprintMode = PluginConfig.SprintMode; ChoiceConfig val = new ChoiceConfig(); object obj = <>c.<>9__4_0; if (obj == null) { IsDisabledDelegate val2 = () => !PluginConfig.Enabled.Value; <>c.<>9__4_0 = val2; obj = (object)val2; } ((BaseOptionConfig)val).checkIfDisabled = (IsDisabledDelegate)obj; ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)sprintMode, val)); ConfigEntry<bool> blockForcedSprint = PluginConfig.BlockForcedSprint; CheckBoxConfig val3 = new CheckBoxConfig(); object obj2 = <>c.<>9__4_1; if (obj2 == null) { IsDisabledDelegate val4 = () => !PluginConfig.Enabled.Value; <>c.<>9__4_1 = val4; obj2 = (object)val4; } ((BaseOptionConfig)val3).checkIfDisabled = (IsDisabledDelegate)obj2; ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(blockForcedSprint, val3)); } private static Sprite LoadIcon() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) byte[] array; using (Stream stream = typeof(RiskOfOptionsCompat).Assembly.GetManifestResourceStream("SprintImprovements.icon.png")) { using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } Texture2D val = new Texture2D(2, 2); ImageConversion.LoadImage(val, array); ((Texture)val).wrapMode = (TextureWrapMode)1; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } } internal static class ServerSprintSync { internal static void OnForcedSprintBlocked(PlayerSprintState state) { state.blockedSinceLastPoll = true; } internal static void Update(CharacterBody body, PlayerSprintState state) { if (state.blockedSinceLastPoll) { state.blockedSinceLastPoll = false; state.serverMaySprint = true; } else if (state.serverMaySprint) { state.serverMaySprint = false; if (!NetworkServer.active && NetworkClient.active && !body.isSprinting) { body.CallCmdUpdateSprint(false); } } } } internal static class SprintGuard { private const float ResumeDelay = 0.15f; private static readonly ConditionalWeakTable<PlayerCharacterMasterController, PlayerSprintState> players = new ConditionalWeakTable<PlayerCharacterMasterController, PlayerSprintState>(); private static int modeVersion; internal static void OnModeChanged() { modeVersion++; } internal static bool AllowSprintWrite(CharacterBody body, bool value) { if (!value || body.isSprinting || !PluginConfig.Enabled.Value || !PluginConfig.BlockForcedSprint.Value || !body.hasEffectiveAuthority || body.isRemoteOp) { return true; } CharacterMaster master = body.master; PlayerCharacterMasterController val = (Object.op_Implicit((Object)(object)master) ? master.playerCharacterMasterController : null); if (!Object.op_Implicit((Object)(object)val) || !players.TryGetValue(val, out var value2) || value2.wantsSprint) { return true; } InputBankTest inputBank = body.inputBank; if (Object.op_Implicit((Object)(object)inputBank) && inputBank.sprint.down) { return true; } ServerSprintSync.OnForcedSprintBlocked(value2); return false; } internal static void OnPoll(PlayerCharacterMasterController pcmc, bool sprinting) { CharacterBody body = pcmc.body; if (!PluginConfig.Enabled.Value || body.isRemoteOp) { return; } PlayerSprintState state = GetState(pcmc, body, sprinting); ServerSprintSync.Update(body, state); float fixedTime = Time.fixedTime; bool flag = SprintPause.IsHeldOff(body, state); if (flag) { state.lastHeldOffTime = fixedTime; } SprintKeyMode value = PluginConfig.SprintMode.Value; bool flag2 = false; switch (value) { case SprintKeyMode.Hold: flag2 = TakePress(pcmc); state.wantsSprint = IsSprintKeyHeld(pcmc); break; case SprintKeyMode.Always: TakePress(pcmc); state.wantsSprint = !IsSprintKeyHeld(pcmc); break; case SprintKeyMode.Toggle: if (pcmc.sprintInputPressReceived) { OnTogglePress(pcmc, body, state, sprinting, flag); return; } break; } if (state.wantsSprint) { if (!sprinting && (flag2 || (!flag && fixedTime - state.lastHeldOffTime >= 0.15f && SprintPause.CanStartMoving(body)))) { Press(pcmc); } } else if (sprinting && !flag) { if (value == SprintKeyMode.Toggle && !PluginConfig.BlockForcedSprint.Value) { state.wantsSprint = true; } else { Press(pcmc); } } } private static void OnTogglePress(PlayerCharacterMasterController pcmc, CharacterBody body, PlayerSprintState state, bool sprinting, bool heldOff) { if (sprinting && (state.wantsSprint || !heldOff)) { state.wantsSprint = false; } else if (!state.wantsSprint) { state.wantsSprint = true; if (sprinting) { TakePress(pcmc); } } else if (!SprintPause.CanStartMoving(body) || SprintPause.IsBusy(state.bodyMachine)) { state.wantsSprint = false; TakePress(pcmc); } } private static PlayerSprintState GetState(PlayerCharacterMasterController pcmc, CharacterBody body, bool sprinting) { PlayerSprintState orCreateValue = players.GetOrCreateValue(pcmc); if (orCreateValue.modeVersion != modeVersion) { orCreateValue.modeVersion = modeVersion; orCreateValue.wantsSprint = sprinting; } if ((Object)(object)orCreateValue.body != (Object)(object)body) { orCreateValue.SetBody(body); } return orCreateValue; } private static void Press(PlayerCharacterMasterController pcmc) { pcmc.sprintInputPressReceived = true; } private static bool TakePress(PlayerCharacterMasterController pcmc) { bool sprintInputPressReceived = pcmc.sprintInputPressReceived; pcmc.sprintInputPressReceived = false; return sprintInputPressReceived; } private static bool IsSprintKeyHeld(PlayerCharacterMasterController pcmc) { NetworkUser networkUser = pcmc.networkUser; Player val = (Object.op_Implicit((Object)(object)networkUser) ? networkUser.inputPlayer : null); if (val != null) { return val.GetButton(18); } return false; } } internal static class SprintHooks { [CompilerGenerated] private static class <>O { public static Manipulator <0>__PlayerCharacterMasterController_PollButtonInput; public static Action<Action<CharacterBody, bool>, CharacterBody, bool> <1>__CharacterBody_set_isSprinting; public static Action<PlayerCharacterMasterController, bool> <2>__OnPoll; } private static Hook isSprintingSetterHook; internal static void Init() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown object obj = <>O.<0>__PlayerCharacterMasterController_PollButtonInput; if (obj == null) { Manipulator val = PlayerCharacterMasterController_PollButtonInput; <>O.<0>__PlayerCharacterMasterController_PollButtonInput = val; obj = (object)val; } PlayerCharacterMasterController.PollButtonInput += (Manipulator)obj; isSprintingSetterHook = new Hook((MethodBase)AccessTools.PropertySetter(typeof(CharacterBody), "isSprinting"), (Delegate)new Action<Action<CharacterBody, bool>, CharacterBody, bool>(CharacterBody_set_isSprinting)); } private static void CharacterBody_set_isSprinting(Action<CharacterBody, bool> orig, CharacterBody self, bool value) { if (SprintGuard.AllowSprintWrite(self, value)) { orig(self, value); } } private static void PlayerCharacterMasterController_PollButtonInput(ILContext il) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); int sprintingLocal = -1; if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)AccessTools.PropertyGetter(typeof(CharacterBody), "isSprinting")), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref sprintingLocal) })) { SprintImprovementsPlugin.Log.LogError((object)(((MemberReference)il.Method).Name + " IL hook failed: the game changed. SprintImprovements does nothing until it is updated.")); return; } val.Emit(OpCodes.Ldarg_0); val.Emit(OpCodes.Ldloc, sprintingLocal); val.EmitDelegate<Action<PlayerCharacterMasterController, bool>>((Action<PlayerCharacterMasterController, bool>)SprintGuard.OnPoll); } } [BepInPlugin("revor.SprintImprovements", "SprintImprovements", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class SprintImprovementsPlugin : BaseUnityPlugin { public const string PluginGUID = "revor.SprintImprovements"; public const string PluginName = "SprintImprovements"; public const string PluginVersion = "1.1.0"; internal static ManualLogSource Log { get; private set; } private void Awake() { Log = ((BaseUnityPlugin)this).Logger; PluginConfig.Init(((BaseUnityPlugin)this).Config); SprintHooks.Init(); if (RiskOfOptionsCompat.IsInstalled) { RiskOfOptionsCompat.Init(); } } } internal static class SprintPause { private const float ResumeMinMove = 0.6f; private const float ResumeMaxAimAngle = 50f; private static readonly float resumeMinAimMoveDot = Mathf.Cos(0.87266463f); internal static bool IsHeldOff(CharacterBody body, PlayerSprintState state) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) bool flag = IsBusy(state.bodyMachine); EntityStateMachine[] machines = state.machines; foreach (EntityStateMachine val in machines) { EntityState val2 = (Object.op_Implicit((Object)(object)val) ? val.state : null); if (val2 != null && !val.IsInMainState() && SprintStates.IsSprintSensitive(((object)val2).GetType()) && !state.heldMachines.Contains(val)) { state.heldMachines.Add(val); } } for (int num = state.heldMachines.Count - 1; num >= 0; num--) { if (IsBusy(state.heldMachines[num])) { flag = true; } else { state.heldMachines.RemoveAt(num); } } SkillLocator skillLocator = body.skillLocator; InputBankTest inputBank = body.inputBank; if (!flag) { if (Object.op_Implicit((Object)(object)skillLocator) && Object.op_Implicit((Object)(object)inputBank)) { if (!IsSkillHeld(skillLocator.primary, inputBank.skill1) && !IsSkillHeld(skillLocator.secondary, inputBank.skill2) && !IsSkillHeld(skillLocator.utility, inputBank.skill3)) { return IsSkillHeld(skillLocator.special, inputBank.skill4); } return true; } return false; } return true; } internal static bool CanStartMoving(CharacterBody body) { //IL_0012: 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) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) InputBankTest inputBank = body.inputBank; if (!Object.op_Implicit((Object)(object)inputBank)) { return false; } Vector3 moveVector = inputBank.moveVector; if (((Vector3)(ref moveVector)).magnitude <= 0.6f) { return false; } if ((body.bodyFlags & 0x20) != 0) { return true; } Vector3 aimDirection = inputBank.aimDirection; aimDirection.y = 0f; moveVector.y = 0f; return Vector3.Dot(((Vector3)(ref aimDirection)).normalized, ((Vector3)(ref moveVector)).normalized) >= resumeMinAimMoveDot; } internal static bool IsBusy(EntityStateMachine machine) { if (Object.op_Implicit((Object)(object)machine)) { if (machine.IsInMainState()) { return machine.HasPendingState(); } return true; } return false; } private static bool IsSkillHeld(GenericSkill slot, ButtonState button) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) SkillDef val = (Object.op_Implicit((Object)(object)slot) ? slot.skillDef : null); if (Object.op_Implicit((Object)(object)val) && (val.cancelSprintingOnActivation || val.canceledFromSprinting) && button.down && (!val.mustKeyPress || !button.hasPressBeenClaimed)) { return slot.IsReady(); } return false; } } internal sealed class PlayerSprintState { internal bool wantsSprint; internal int modeVersion = -1; internal CharacterBody body; internal EntityStateMachine bodyMachine; internal EntityStateMachine[] machines; internal readonly List<EntityStateMachine> heldMachines = new List<EntityStateMachine>(); internal float lastHeldOffTime = float.NegativeInfinity; internal bool blockedSinceLastPoll; internal bool serverMaySprint; internal void SetBody(CharacterBody newBody) { body = newBody; bodyMachine = EntityStateMachine.FindByCustomName(((Component)newBody).gameObject, "Body"); machines = ((Component)newBody).GetComponents<EntityStateMachine>(); heldMachines.Clear(); } } internal static class SprintStates { private static readonly Type[] extraStates = new Type[15] { typeof(BaseSidearmState), typeof(BaseScopeState), typeof(FireNailgun), typeof(ToolbotDualWieldBase), typeof(FireCorruptHandBeam), typeof(ShieldFormation), typeof(ChargeArrow), typeof(Flamethrower), typeof(PrepWall), typeof(Paint), typeof(SetupAirstrike), typeof(SetupAirstrikeAlt), typeof(SetupSupplyDrop), typeof(AimThrowableBase), typeof(AimRepossess) }; private static readonly Dictionary<Type, bool> sensitive = new Dictionary<Type, bool>(); [SystemInitializer(new Type[] { typeof(SkillCatalog) })] private static void Init() { foreach (SkillDef allSkillDef in SkillCatalog.allSkillDefs) { Type stateType = ((SerializableEntityStateType)(ref allSkillDef.activationState)).stateType; if (stateType != null && (allSkillDef.cancelSprintingOnActivation || allSkillDef.canceledFromSprinting || allSkillDef.forceSprintDuringState)) { sensitive[stateType] = true; } } } internal static bool IsSprintSensitive(Type stateType) { if (!sensitive.TryGetValue(stateType, out var value)) { Type[] array = extraStates; foreach (Type type in array) { value |= type.IsAssignableFrom(stateType); } sensitive[stateType] = value; } return value; } } }