using System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using AmmoBag.Patches; using BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalNetworkAPI; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("AmmoBag")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AmmoBag")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("da0de89f-9696-4ca2-a169-d360d37a3b8f")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace AmmoBag { internal static class AmmoBagHelper { internal const int encode_base_number = 1000000; internal static ulong pendingBagNetworkObjectId; internal static int pendingAmmoInBagIndex; internal static int FindAmmoInBelt(PlayerControllerB player, ShotgunItem __instance) { for (int i = 0; i < player.ItemSlots.Length; i++) { if (CheckSlot(__instance, player.ItemSlots[i])) { BeltBagPatchBase.logSource.LogInfo((object)("Found shell in slot " + i)); return 1000000; } } if (CheckSlot(__instance, player.ItemOnlySlot)) { BeltBagPatchBase.logSource.LogInfo((object)"Found shell in utilitySlot"); return 1000000; } BeltBagPatchBase.logSource.LogInfo((object)"No shells found"); return -1; } private static bool CheckSlot(ShotgunItem __instance, GrabbableObject slot) { if ((Object)(object)slot == (Object)null) { return false; } BeltBagItem val = (BeltBagItem)(object)((slot is BeltBagItem) ? slot : null); if ((Object)(object)val == (Object)null) { return false; } int num = FindAmmoInBag(val, __instance.gunCompatibleAmmoID); if (num == -1) { return false; } pendingBagNetworkObjectId = ((Component)val).GetComponent().NetworkObjectId; pendingAmmoInBagIndex = num; return true; } private static int FindAmmoInBag(BeltBagItem bag, int ammoTypeID) { for (int num = bag.objectsInBag.Count - 1; num >= 0; num--) { GrabbableObject val = bag.objectsInBag[num]; if (!((Object)(object)val == (Object)null)) { GunAmmo val2 = (GunAmmo)(object)((val is GunAmmo) ? val : null); if ((Object)(object)val2 != (Object)null && val2.ammoType == ammoTypeID) { return num; } } } return -1; } } internal static class AmmoNetworking { private const string MessageId_sv = "PixelIndieDev_AmmoBag.msg_DeleteOnServer"; private const string MessageId_cl = "PixelIndieDev_AmmoBag.msg_DeleteOnClients"; private static LNetworkMessage msg_deleteShell_Server; private static LNetworkMessage msg_deleteShell_Client; internal static bool isHosting; internal static void SetNetworkMessage() { msg_deleteShell_Server = LNetworkMessage.Connect("PixelIndieDev_AmmoBag.msg_DeleteOnServer", (Action)OnRemoveAmmoReceivedServer, (Action)null, (Action)null); msg_deleteShell_Client = LNetworkMessage.Connect("PixelIndieDev_AmmoBag.msg_DeleteOnClients", (Action)null, (Action)OnRemoveAmmoReceivedClient, (Action)null); } public static void RequestRemoveAmmo(ulong bagNetworkObjectId, int ammoInBagIndex) { BeltBagPatchBase.logSource.LogInfo((object)"Requested remove ammo"); msg_deleteShell_Server.SendServer(new NetworkRequestStruct(bagNetworkObjectId, ammoInBagIndex)); } private static void OnRemoveAmmoReceivedServer(NetworkRequestStruct data, ulong senderClientId) { if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(data.bagNetworkObjectId, out var value)) { BeltBagItem component = ((Component)value).GetComponent(); if ((Object)(object)component != (Object)null && data.ammoInBagIndex >= 0 && data.ammoInBagIndex < component.objectsInBag.Count) { component.objectsInBag.RemoveAt(data.ammoInBagIndex); BeltBagPatchBase.logSource.LogInfo((object)"Host removed shell from bag"); } else { BeltBagPatchBase.logSource.LogWarning((object)"SyncBagAmmoRemovalServerRpc: bag null or index out of range"); } } else { BeltBagPatchBase.logSource.LogWarning((object)("SyncBagAmmoRemovalServerRpc: could not find bag with id " + data.bagNetworkObjectId)); } msg_deleteShell_Client.SendClients(new NetworkRequestStruct(data.bagNetworkObjectId, data.ammoInBagIndex)); } private static void OnRemoveAmmoReceivedClient(NetworkRequestStruct @struct) { if (isHosting) { return; } if (!NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(@struct.bagNetworkObjectId, out var value)) { BeltBagPatchBase.logSource.LogWarning((object)("SyncBagAmmoRemoval: could not find bag with NetworkObjectId " + @struct.bagNetworkObjectId)); return; } BeltBagItem component = ((Component)value).GetComponent(); if ((Object)(object)component == (Object)null) { BeltBagPatchBase.logSource.LogWarning((object)"SyncBagAmmoRemoval: NetworkObject is not a BeltBagItem"); } else if (@struct.ammoInBagIndex < 0 || @struct.ammoInBagIndex >= component.objectsInBag.Count) { BeltBagPatchBase.logSource.LogWarning((object)"SyncBagAmmoRemoval: ammoInBagIndex out of range"); } else { component.objectsInBag.RemoveAt(@struct.ammoInBagIndex); } } } public struct NetworkRequestStruct { public ulong bagNetworkObjectId; public int ammoInBagIndex; public NetworkRequestStruct(ulong bagNetworkObjectId, int ammoInBagIndex) { this.bagNetworkObjectId = bagNetworkObjectId; this.ammoInBagIndex = ammoInBagIndex; } } [BepInPlugin("PixelIndieDev_AmmoBag", "Ammo Bag", "1.2.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class BeltBagPatchBase : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("PixelIndieDev_AmmoBag"); private static BeltBagPatchBase instance; internal static ManualLogSource logSource; private void Awake() { if ((Object)(object)instance == (Object)null) { instance = this; } logSource = Logger.CreateLogSource("PixelIndieDev_AmmoBag"); harmony.PatchAll(typeof(BeltBagPatchBase)); harmony.PatchAll(typeof(NetworkPatch)); harmony.PatchAll(typeof(ShotgunPatch)); harmony.PatchAll(typeof(PlayerPatch)); harmony.PatchAll(typeof(MenuManagerPatch)); AmmoNetworking.SetNetworkMessage(); logSource.LogInfo((object)"Ammo Bag (version - 1.2.0.0): patches applied successfully"); } } internal static class ModInfo { internal const string modGUID = "PixelIndieDev_AmmoBag"; internal const string modName = "Ammo Bag"; internal const string modVersion = "1.2.0.0"; } } namespace AmmoBag.Patches { [HarmonyPatch(typeof(MenuManager))] internal class MenuManagerPatch { [HarmonyPatch("StartHosting")] [HarmonyPrefix] [HarmonyPriority(0)] private static void OnStartHostingPatch() { AmmoNetworking.isHosting = true; } [HarmonyPatch("StartAClient")] [HarmonyPrefix] [HarmonyPriority(0)] private static void OnStartConnectingPatch() { AmmoNetworking.isHosting = false; } } [HarmonyPatch(typeof(NetworkManager))] internal static class NetworkPatch { [HarmonyPostfix] [HarmonyPatch("SetSingleton")] private static void RegisterPrefab() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("PixelIndieDev_AmmoBag Prefab"); ((Object)val).hideFlags = (HideFlags)(((Object)val).hideFlags | 0x3D); Object.DontDestroyOnLoad((Object)(object)val); NetworkObject obj = val.AddComponent(); typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(obj, GetHash("PixelIndieDev_AmmoBag")); NetworkManager.Singleton.PrefabHandler.AddNetworkPrefab(val); } private static uint GetHash(string value) { return value?.Aggregate(17u, (uint current, char c) => (current * 31) ^ c) ?? 0; } } [HarmonyPatch(typeof(PlayerControllerB))] internal class PlayerPatch { [HarmonyPatch("DestroyItemInSlotAndSync")] [HarmonyPrefix] [HarmonyPriority(0)] private static bool PatchFindAmmo(PlayerControllerB __instance, int itemSlot) { if (itemSlot < 1000000) { return true; } ulong pendingBagNetworkObjectId = AmmoBagHelper.pendingBagNetworkObjectId; int pendingAmmoInBagIndex = AmmoBagHelper.pendingAmmoInBagIndex; if (!NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(pendingBagNetworkObjectId, out var _)) { BeltBagPatchBase.logSource.LogWarning((object)("Could not find belt bag NetworkObject with id " + pendingBagNetworkObjectId)); return false; } AmmoNetworking.RequestRemoveAmmo(pendingBagNetworkObjectId, pendingAmmoInBagIndex); return false; } } [HarmonyPatch(typeof(ShotgunItem))] internal class ShotgunPatch { [HarmonyPatch("FindAmmoInInventory")] [HarmonyPostfix] [HarmonyPriority(0)] private static void PatchFindAmmo(ref int __result, ShotgunItem __instance) { if (__result == -1) { PlayerControllerB playerHeldBy = ((GrabbableObject)__instance).playerHeldBy; if (!((Object)(object)playerHeldBy == (Object)null)) { __result = AmmoBagHelper.FindAmmoInBelt(playerHeldBy, __instance); } } } } }