Decompiled source of SpreadStartingAmmo v1.0.1

SpreadStartingAmmo.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Agents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using GTFO.API;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using SpreadStartingAmmo.Dependencies;
using SpreadStartingAmmo.Patches;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SpreadStartingAmmo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SpreadStartingAmmo")]
[assembly: AssemblyTitle("SpreadStartingAmmo")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace SpreadStartingAmmo
{
	internal static class AmmoSpreadManager
	{
		private static readonly HashSet<ulong> _playerLookups = new HashSet<ulong>();

		public static void PullStartingAmmo(PlayerAgent player, out List<float> ammoMods)
		{
			if (SNet.HubPlayerCount == 0)
			{
				DinoLogger.Error("Tried to pull starting ammo when there were no players in the lobby!");
				ammoMods = new List<float> { 1f, 1f, 1f };
				return;
			}
			float mod = 4f / (float)((_playerLookups.Count > 0) ? _playerLookups.Count : SNet.HubPlayerCount);
			ammoMods = new List<float> { mod, mod, mod };
			if (_playerLookups.Count == 0 || _playerLookups.Contains(player.Owner.Lookup))
			{
				return;
			}
			_playerLookups.Add(player.Owner.Lookup);
			mod = 4f / (float)_playerLookups.Count;
			for (int i = 0; i < ammoMods.Count; i++)
			{
				ammoMods[i] = mod;
			}
			PlayerDataBlock block = GameDataBlockBase<PlayerDataBlock>.GetBlock(1u);
			SpecialExpeditionOverridesData specialOverrideData = RundownManager.ActiveExpedition.SpecialOverrideData;
			List<float> list = new List<float>
			{
				(float)block.AmmoStandardInitial * specialOverrideData.StandardAmmoAtExpeditionStart,
				(float)block.AmmoSpecialInitial * specialOverrideData.SpecialAmmoAtExpeditionStart,
				(float)block.AmmoClassInitial * specialOverrideData.ToolAmmoAtExpeditionStart
			};
			List<float> list2 = list.ConvertAll((float ammo) => mod * ammo);
			if (list2.All((float x) => x == 0f))
			{
				return;
			}
			List<(PlayerBackpack, List<float>)> list3 = new List<(PlayerBackpack, List<float>)>();
			List<int> list4 = new List<int> { 0, 0, 0 };
			Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
			PlayerBackpack val = default(PlayerBackpack);
			BackpackItem val2 = default(BackpackItem);
			while (enumerator.MoveNext())
			{
				PlayerAgent current = enumerator.Current;
				if (((Il2CppObjectBase)current).Pointer == ((Il2CppObjectBase)player).Pointer || !PlayerBackpackManager.TryGetBackpack(current.Owner, ref val))
				{
					continue;
				}
				PlayerAmmoStorage ammoStorage = val.AmmoStorage;
				if (((Agent)current).IsLocallyOwned || (SNet.IsMaster && current.Owner.IsBot))
				{
					ToggleMagsInReserves(val, putInReserves: true);
				}
				List<float> list5 = new List<float>
				{
					ammoStorage.StandardAmmo.AmmoInPack,
					ammoStorage.SpecialAmmo.AmmoInPack,
					ammoStorage.ClassAmmo.AmmoInPack
				};
				if (val.TryGetBackpackItem((InventorySlot)3, ref val2) && (Object)(object)val2.Instance != (Object)null && val2.Instance.ItemDataBlock.BlockToolAmmoRefill)
				{
					list5[2] = 0f;
				}
				list3.Add((val, list5));
				for (int j = 0; j < list5.Count; j++)
				{
					if (list5[j] > 0f)
					{
						list4[j]++;
					}
				}
			}
			if (list4.All((int x) => x == 0))
			{
				for (int k = 0; k < ammoMods.Count; k++)
				{
					ammoMods[k] = 0f;
				}
				return;
			}
			List<float> list6 = new List<float>(list2);
			for (int l = 0; l < 3; l++)
			{
				while (list4[l] > 0 && list6[l] > 0f)
				{
					float val3 = list6[l] / (float)list4[l];
					foreach (var item3 in list3)
					{
						List<float> item = item3.Item2;
						if (!(item[l] <= 0f))
						{
							float num = Math.Min(item[l], val3);
							item[l] -= num;
							list6[l] -= num;
							if (item[l] <= 0f)
							{
								list4[l]--;
							}
						}
					}
				}
			}
			if (!((Agent)player).IsLocallyOwned)
			{
				PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack;
				List<float> item2 = list3.First<(PlayerBackpack, List<float>)>(((PlayerBackpack backpack, List<float> ammoList) x) => ((Il2CppObjectBase)x.backpack).Pointer == ((Il2CppObjectBase)localBackpack).Pointer).Item2;
				PlayerAmmoStorage ammoStorage2 = localBackpack.AmmoStorage;
				ammoStorage2.SetAmmo((AmmoType)0, item2[0]);
				ammoStorage2.SetAmmo((AmmoType)1, item2[1]);
				ammoStorage2.SetAmmo((AmmoType)2, item2[2]);
				ToggleMagsInReserves(localBackpack, putInReserves: false);
			}
			else if (SNet.IsMaster)
			{
				foreach (var (val4, list7) in list3)
				{
					if (val4.Owner.IsBot)
					{
						PlayerAmmoStorage ammoStorage3 = val4.AmmoStorage;
						ammoStorage3.SetAmmo((AmmoType)0, list7[0]);
						ammoStorage3.SetAmmo((AmmoType)1, list7[1]);
						ammoStorage3.SetAmmo((AmmoType)2, list7[2]);
						ToggleMagsInReserves(val4, putInReserves: false);
					}
				}
			}
			for (int m = 0; m < ammoMods.Count; m++)
			{
				ammoMods[m] = (list2[m] - list6[m]) / list[m];
			}
		}

		private static void ToggleMagsInReserves(PlayerBackpack backpack, bool putInReserves)
		{
			PlayerBackpack backpack2 = backpack;
			PlayerAmmoStorage storage = backpack2.AmmoStorage;
			ToggleForSlot((InventorySlot)1);
			ToggleForSlot((InventorySlot)2);
			ToggleForSlot((InventorySlot)3);
			void ToggleForSlot(InventorySlot slot)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				BackpackItem val = default(BackpackItem);
				if (backpack2.TryGetBackpackItem(slot, ref val))
				{
					ItemEquippable val2 = ((Il2CppObjectBase)val.Instance).Cast<ItemEquippable>();
					InventorySlotAmmo inventorySlotAmmo = storage.GetInventorySlotAmmo(slot);
					if (inventorySlotAmmo.BulletClipSize != 0)
					{
						if (putInReserves)
						{
							inventorySlotAmmo.AmmoInPack += (float)val2.GetCurrentClip() * inventorySlotAmmo.CostOfBullet;
						}
						else
						{
							int num = Math.Min(inventorySlotAmmo.BulletsInPack, val2.GetCurrentClip());
							val2.SetCurrentClip(num);
							inventorySlotAmmo.AmmoInPack -= (float)num * inventorySlotAmmo.CostOfBullet;
						}
					}
				}
			}
		}

		public static void OnLevelStart()
		{
			Enumerator<SNet_Player> enumerator = SNet.SessionHub.PlayersInSession.GetEnumerator();
			while (enumerator.MoveNext())
			{
				SNet_Player current = enumerator.Current;
				_playerLookups.Add(current.Lookup);
			}
		}

		public static void OnLevelCleanup()
		{
			_playerLookups.Clear();
		}
	}
	internal static class DinoLogger
	{
		private static ManualLogSource logger = Logger.CreateLogSource("SpreadStartingAmmo");

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)8, (object)str);
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)32, (object)str);
			}
		}
	}
	[BepInPlugin("Dinorush.SpreadStartingAmmo", "SpreadStartingAmmo", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal sealed class EntryPoint : BasePlugin
	{
		public const string MODNAME = "SpreadStartingAmmo";

		public override void Load()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			Harmony val = new Harmony("SpreadStartingAmmo");
			val.PatchAll();
			if (!ETCWrapper.HasETC)
			{
				val.PatchAll(typeof(ETC_ToolAmmoPatches));
			}
			LevelAPI.OnEnterLevel += AmmoSpreadManager.OnLevelStart;
			LevelAPI.OnLevelCleanup += AmmoSpreadManager.OnLevelCleanup;
			((BasePlugin)this).Log.LogMessage((object)"Loaded SpreadStartingAmmo");
		}
	}
}
namespace SpreadStartingAmmo.Patches
{
	[HarmonyPatch]
	internal static class AmmoStoragePatches
	{
		[HarmonyPatch(typeof(InventorySlotAmmo), "AddAmmo")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static bool FixAmmoOverflow(InventorySlotAmmo __instance, float ammoAmount)
		{
			float ammoInPack = __instance.AmmoInPack;
			float ammoMaxCap = __instance.AmmoMaxCap;
			if (ammoInPack + ammoAmount < ammoMaxCap)
			{
				return true;
			}
			if (ammoAmount > 0f && ammoInPack > 0f)
			{
				if (ammoInPack >= ammoMaxCap)
				{
					return false;
				}
				__instance.AmmoInPack = ammoMaxCap;
			}
			else
			{
				__instance.AmmoInPack += ammoAmount;
			}
			__instance.OnBulletsUpdateCallback?.Invoke(__instance.BulletsInPack);
			return false;
		}

		[HarmonyPatch(typeof(PlayerAmmoStorage), "AddLevelDefaultAmmoModifications")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static bool Pre_SetStorage(PlayerAmmoStorage __instance, PlayerAgent owner)
		{
			if (RundownManager.ActiveExpedition == null)
			{
				return true;
			}
			AmmoSpreadManager.PullStartingAmmo(owner, out List<float> ammoMods);
			Il2CppStructArray<uint> ammoModificationIDs = __instance.m_ammoModificationIDs;
			SpecialExpeditionOverridesData specialOverrideData = RundownManager.ActiveExpedition.SpecialOverrideData;
			if (((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[0] != 0)
			{
				AgentModifierManager.ClearModifierChange(((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[0]);
			}
			((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[0] = AgentModifierManager.AddModifierValue((Agent)(object)owner, (AgentModifier)152, specialOverrideData.StandardAmmoAtExpeditionStart * ammoMods[0] - 1f, 0f);
			if (((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[1] != 0)
			{
				AgentModifierManager.ClearModifierChange(((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[1]);
			}
			((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[1] = AgentModifierManager.AddModifierValue((Agent)(object)owner, (AgentModifier)153, specialOverrideData.SpecialAmmoAtExpeditionStart * ammoMods[1] - 1f, 0f);
			if (((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[2] != 0)
			{
				AgentModifierManager.ClearModifierChange(((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[2]);
			}
			((Il2CppArrayBase<uint>)(object)ammoModificationIDs)[2] = AgentModifierManager.AddModifierValue((Agent)(object)owner, (AgentModifier)154, specialOverrideData.ToolAmmoAtExpeditionStart * ammoMods[2] - 1f, 0f);
			return false;
		}
	}
	internal static class ETC_ToolAmmoPatches
	{
		[HarmonyPatch(typeof(PlayerAmmoStorage), "UpdateBulletsInPack")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static bool Unclamp_UpdateBullets(PlayerAmmoStorage __instance, AmmoType ammoType, int bulletCount, ref float __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if ((int)ammoType != 2)
			{
				return true;
			}
			InventorySlotAmmo inventorySlotAmmo = __instance.GetInventorySlotAmmo(ammoType);
			float ammoInPack = inventorySlotAmmo.AmmoInPack;
			float ammoMaxCap = inventorySlotAmmo.AmmoMaxCap;
			float num = (float)bulletCount * inventorySlotAmmo.CostOfBullet;
			if (ammoInPack + num < ammoMaxCap)
			{
				return true;
			}
			float num4;
			if (num > 0f && ammoInPack > 0f)
			{
				if (ammoInPack >= ammoMaxCap || num >= ammoMaxCap)
				{
					float num3 = (inventorySlotAmmo.AmmoInPack = Math.Max(ammoInPack, num));
					num4 = num3;
				}
				else
				{
					float num3 = (inventorySlotAmmo.AmmoInPack = ammoMaxCap);
					num4 = num3;
				}
			}
			else
			{
				float num3 = (inventorySlotAmmo.AmmoInPack += num);
				num4 = num3;
			}
			inventorySlotAmmo.OnBulletsUpdateCallback?.Invoke(inventorySlotAmmo.BulletsInPack);
			__instance.NeedsSync = true;
			__instance.UpdateSlotAmmoUI(inventorySlotAmmo, 0);
			__result = num4;
			return false;
		}

		[HarmonyPatch(typeof(PlayerAmmoStorage), "UpdateAmmoInPack")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static bool Unclamp_UpdateAmmo(PlayerAmmoStorage __instance, AmmoType ammoType, float delta, ref float __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if ((int)ammoType != 2)
			{
				return true;
			}
			InventorySlotAmmo inventorySlotAmmo = __instance.GetInventorySlotAmmo(ammoType);
			float ammoInPack = inventorySlotAmmo.AmmoInPack;
			float ammoMaxCap = inventorySlotAmmo.AmmoMaxCap;
			if (ammoInPack + delta < ammoMaxCap)
			{
				return true;
			}
			float num3;
			if (delta > 0f && ammoInPack > 0f)
			{
				if (ammoInPack >= ammoMaxCap || delta >= ammoMaxCap)
				{
					float num2 = (inventorySlotAmmo.AmmoInPack = Math.Max(ammoInPack, delta));
					num3 = num2;
				}
				else
				{
					float num2 = (inventorySlotAmmo.AmmoInPack = ammoMaxCap);
					num3 = num2;
				}
			}
			else
			{
				float num2 = (inventorySlotAmmo.AmmoInPack += delta);
				num3 = num2;
			}
			inventorySlotAmmo.OnBulletsUpdateCallback?.Invoke(inventorySlotAmmo.BulletsInPack);
			__instance.NeedsSync = true;
			__instance.UpdateSlotAmmoUI(inventorySlotAmmo, 0);
			__result = num3;
			return false;
		}
	}
}
namespace SpreadStartingAmmo.Dependencies
{
	internal static class ETCWrapper
	{
		public const string GUID = "Dinorush.ExtraToolCustomization";

		public static bool HasETC { get; private set; }

		static ETCWrapper()
		{
			HasETC = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.ContainsKey("Dinorush.ExtraToolCustomization");
		}
	}
}