using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FistVR; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("Niko666")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Gradually slower bullet loading speed as the magazine fills up, mimicking H3VR2 behavior.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Niko666.DynamicMagazineBulletLoad")] [assembly: AssemblyTitle("DynamicMagazineBulletLoad")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string id = null, string name = null, string version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null) { } } } namespace Niko666 { [BepInProcess("h3vr.exe")] [BepInPlugin("Niko666.DynamicMagazineBulletLoad", "DynamicMagazineBulletLoad", "1.0.0")] public class DynamicMagazineBulletLoad : BaseUnityPlugin { public ConfigEntry configFastestLoadTime; public ConfigEntry configSlowestLoadTime; private const float DefaultFastestLoadTime = 0.1f; private const float DefaultSlowestLoadTime = 0.5f; public const string Id = "Niko666.DynamicMagazineBulletLoad"; public static DynamicMagazineBulletLoad Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } public static string Name => "DynamicMagazineBulletLoad"; public static string Version => "1.0.0"; public void Awake() { Instance = this; Logger = ((BaseUnityPlugin)this).Logger; configFastestLoadTime = ((BaseUnityPlugin)this).Config.Bind("General", "FastestLoadTime", 0.1f, "The fastest possible load time for magazines (when empty). H3VR default: 0.3s."); configSlowestLoadTime = ((BaseUnityPlugin)this).Config.Bind("General", "SlowestLoadTime", 0.5f, "The slowest possible load time for magazines (when near full). H3VR default: 0.3s."); Harmony.CreateAndPatchAll(typeof(DynamicMagazineBulletLoadPatch), (string)null); Logger.LogMessage((object)("H3VR2 Release when? Sent from Niko666.DynamicMagazineBulletLoad " + Version)); } } public static class MagazineLoadTimeCache { public static float GetLoadTime(FVRFireArmMagazine magazine) { if ((Object)(object)magazine == (Object)null) { return 0.3f; } if (magazine.m_capacity > 0) { return Mathf.Lerp(DynamicMagazineBulletLoad.Instance.configFastestLoadTime.Value, DynamicMagazineBulletLoad.Instance.configSlowestLoadTime.Value, (float)magazine.m_numRounds / (float)magazine.m_capacity); } return 0.3f; } } public class DynamicMagazineBulletLoadPatch { [HarmonyPatch(typeof(FVRFireArmRound), "FVRFixedUpdate")] [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Ldc_R4, (object)0.3f, (string)null) }); if (val.IsInvalid) { DynamicMagazineBulletLoad.Logger.LogError((object)"Could not find the round loading speed instruction to patch!"); return instructions; } FieldInfo field = typeof(FVRFireArmRound).GetField("m_hoverOverReloadTrigger", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = typeof(FVRFireArmMagazineReloadTrigger).GetField("Magazine"); val.SetInstructionAndAdvance(new CodeInstruction(OpCodes.Ldarg_0, (object)null)).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldfld, (object)field) }).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldfld, (object)field2) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)typeof(MagazineLoadTimeCache).GetMethod("GetLoadTime")) }); return val.InstructionEnumeration(); } [HarmonyPatch(typeof(SteamVR_LoadLevel), "Begin")] [HarmonyPrefix] public static bool BeginPatch() { ((BaseUnityPlugin)DynamicMagazineBulletLoad.Instance).Config.Reload(); return true; } } }