Decompiled source of BalancedInstanceBasedLoot v2.0.8

InstanceLootPlugin.dll

Decompiled 4 months 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 System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HG.Reflection;
using Microsoft.CodeAnalysis;
using On.RoR2;
using On.RoR2.Artifacts;
using On.RoR2.Networking;
using R2API.Networking;
using R2API.Networking.Interfaces;
using RoR2;
using RoR2.Artifacts;
using RoR2.Networking;
using RoR2.UI;
using Unity;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("InstanceLootPlugin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("InstanceLootPlugin")]
[assembly: AssemblyTitle("InstanceLootPlugin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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;
		}
	}
}
namespace InstanceLootPlugin
{
	public class DropRateManager
	{
		private ConfigEntry<bool> EnableBadLuckProtection;

		private ConfigEntry<bool> EnableSwarmsScaling;

		private ConfigEntry<float> DropChanceMultiplier;

		private ConfigEntry<float> BaseDropChance;

		private ConfigEntry<float> MinimumDropChance;

		public DropRateManager(ConfigEntry<bool> enableBadLuckProtection, ConfigEntry<bool> enableSwarmsScaling, ConfigEntry<float> dropChanceMultiplier, ConfigEntry<float> baseDropChance, ConfigEntry<float> minimumDropChance)
		{
			EnableBadLuckProtection = enableBadLuckProtection;
			EnableSwarmsScaling = enableSwarmsScaling;
			DropChanceMultiplier = dropChanceMultiplier;
			BaseDropChance = baseDropChance;
			MinimumDropChance = minimumDropChance;
		}

		public float GetPlayerAwareBaseDropChance(int playerCount, float dropChance)
		{
			float num = 1f / (float)playerCount;
			float num2 = num * DropChanceMultiplier.Value;
			float num3 = Math.Max(BaseDropChance.Value * num2, MinimumDropChance.Value);
			if (!dropChance.Equals(num3))
			{
				dropChance = num3;
				Log.Debug($"Using dropRate of {dropChance}% (base={BaseDropChance.Value}, multiplier={DropChanceMultiplier.Value}, playerCount={playerCount}, minimumDropChance={MinimumDropChance.Value}");
			}
			return dropChance;
		}

		public float ComputeDropChance(bool isSwarmEnabled, float nativeDropChance, float nativeBaseDropChance, float dropChance)
		{
			float num = ((!(EnableSwarmsScaling.Value && isSwarmEnabled) || nativeDropChance == 0f) ? nativeDropChance : ((nativeDropChance - nativeBaseDropChance) * 0.6f + nativeBaseDropChance));
			float num2 = nativeBaseDropChance / 5f;
			float num3 = num / nativeBaseDropChance;
			return dropChance * num2 * num3;
		}

		public bool NeedsBadLuckProtection(float actualDropChance, float time)
		{
			if (EnableBadLuckProtection.Value && DropRateTracker.cumulativeDropChance >= 100f && actualDropChance > 0f)
			{
				bool flag = DropRateTracker.expectedItems > (float)DropRateTracker.totalItemDrops;
				float num = (float)DropRateTracker.totalItemDrops / (time / 60f);
				return flag || (double)num < 0.8;
			}
			return false;
		}

		public float GetBadLuckProtectedDropChance(float dropChance)
		{
			float num = DropRateTracker.cumulativeDropChance - 100f;
			float num2 = Math.Min(dropChance + num, 90f);
			Log.Debug($"Bad Luck Protection triggered! ({dropChance}% => {num2}%)");
			return num2;
		}
	}
	public static class DropRateTracker
	{
		private static Dictionary<float, long> DropRateReport = new Dictionary<float, long>();

		public static long totalItemDrops { get; private set; } = 0L;


		public static float cumulativeDropChance { get; private set; } = 0f;


		public static float expectedItems { get; private set; } = 0f;


		public static void ResetTracker()
		{
			DropRateReport = new Dictionary<float, long>();
			totalItemDrops = 0L;
			cumulativeDropChance = 0f;
			expectedItems = 0f;
		}

		public static void RegisterDropOpportunity(float dropChance)
		{
			cumulativeDropChance += dropChance;
			expectedItems += (float)Math.Round(dropChance / 100f, 2);
			if (DropRateReport.TryGetValue(dropChance, out var _))
			{
				DropRateReport[dropChance]++;
			}
			else
			{
				DropRateReport.Add(dropChance, 1L);
			}
		}

		public static void RegisterItemDrop(CreatePickupInfo createPickupInfo)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			PickupIndex pickupIndex = ((CreatePickupInfo)(ref createPickupInfo)).pickupIndex;
			if (((PickupIndex)(ref pickupIndex)).pickupDef != null)
			{
				pickupIndex = ((CreatePickupInfo)(ref createPickupInfo)).pickupIndex;
				PickupDef pickupDef = ((PickupIndex)(ref pickupIndex)).pickupDef;
				if (pickupDef.coinValue == 0 && pickupDef.nameToken != "PICKUP_LUNAR_COIN")
				{
					cumulativeDropChance = 0f;
					totalItemDrops++;
				}
			}
		}

		public static void LogReport()
		{
			if (Run.instance == null || !((Behaviour)Run.instance).isActiveAndEnabled)
			{
				return;
			}
			long num = DropRateReport.Values.Aggregate(0L, (long i, long l) => i + l);
			if (num != 0)
			{
				string text = DropRateReport.Keys.OrderByDescending((float f) => f).Aggregate("Kills by Drop Rate", (string s, float f) => $"{s}\n  {f}%: {DropRateReport[f]} kills");
				float runStopwatch = Run.instance.GetRunStopwatch();
				float num2 = runStopwatch / 60f;
				float num3 = DropRateReport.Keys.Aggregate(0f, (float f, float f1) => f + (float)DropRateReport[f1] * f1) / (float)num;
				string text2 = "------ DROP RATE RUN REPORT -----\n";
				text2 += $"Stage: {Run.instance.stageClearCount + 1}\n";
				text2 += $"Run Duration: {runStopwatch}s\n";
				text2 += $"Total kills: {num}\n";
				text2 += $"Total items: {totalItemDrops}\n";
				text2 += $"Theoretical Average Drop Rate: {num3}%\n";
				text2 += $"Actual Average Drop Rate: {(float)totalItemDrops / (float)num * 100f}%\n";
				text2 += $"Drops per Minute: {Math.Round((float)totalItemDrops / num2, 2)}\n";
				text2 = text2 + text + "\n";
				text2 += "------ END OF REPORT -----";
				Log.Info(text2);
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("programit.BalancedInstanceBasedLoot", "BalancedInstanceBasedLoot", "2.0.8")]
	public class InstanceLootPlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_GetExpAdjustedDropChancePercent <0>__Util_GetExpAdjustedDropChancePercent;

			public static NetworkMessageDelegate <1>__HandlePickupMessage;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static hook_DropRewards <>9__36_0;

			public static Func<PlayerCharacterMasterController, bool> <>9__51_0;

			internal void <OnEnable>b__36_0(orig_DropRewards orig, BossGroup self)
			{
				if (EnablePlayerDropRateScaling.Value && IsModHooked)
				{
					self.scaleRewardsByPlayerCount = false;
				}
				orig.Invoke(self);
			}

			internal bool <GetPlayerCount>b__51_0(PlayerCharacterMasterController pc)
			{
				return pc.isConnected;
			}
		}

		public const string PluginGUID = "programit.BalancedInstanceBasedLoot";

		public const string PluginAuthor = "programit";

		public const string PluginName = "BalancedInstanceBasedLoot";

		public const string PluginVersion = "2.0.8";

		public static float dropChance = 5f;

		private static bool IsModHooked = false;

		private bool forceDisabled = false;

		private static bool useManualDropRate = false;

		private static DropRateManager dropRateManager;

		private static ConfigEntry<float> DropChanceMultiplier { get; set; }

		private static ConfigEntry<float> MinimumDropChance { get; set; }

		private static ConfigEntry<float> BaseDropChance { get; set; }

		private static ConfigEntry<bool> EnablePlayerDropRateScaling { get; set; }

		private static ConfigEntry<bool> EnableSwarmsScaling { get; set; }

		private static ConfigEntry<bool> EnableBadLuckProtection { get; set; }

		public void Awake()
		{
			Log.Init(((BaseUnityPlugin)this).Logger);
			DropChanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DropChanceMultiplier", 1f, "Manipulate drop rate. Use `0.5` to halve or `2` to double.");
			MinimumDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MinimumDropChance", 1f, "The lowest possible drop chance when player count scaling is active.");
			EnablePlayerDropRateScaling = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnablePlayerBasedDropRateScaling", true, "Enabling this will reduce drop rates to account for shared loot.");
			EnableSwarmsScaling = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableSwarmsScaling", true, "Enabling this will (correctly) reduce drop rates for Artifact of Swarms.");
			EnableBadLuckProtection = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableBadLuckProtection", true, "Enabling this will increase drop rate consistency with low drop rates.");
			BaseDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "BaseDropChance", 5f, "Base item drop chance. It is recommended to leave this at the default value.");
			dropChance = BaseDropChance.Value;
			dropRateManager = new DropRateManager(EnableBadLuckProtection, EnableSwarmsScaling, DropChanceMultiplier, BaseDropChance, MinimumDropChance);
		}

		private void Update()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if (!Input.GetKeyDown((KeyCode)284) || !IsModHooked)
			{
				return;
			}
			try
			{
				Object.FindObjectsOfType<RuleBookViewer>();
				PickupDisplay[] array = Object.FindObjectsOfType<PickupDisplay>();
				Vector3 position = ((MPEventSystem)EventSystem.current).localUser.cachedMaster.GetBodyObject().transform.position;
				float num = 10f;
				Vector3 position2 = default(Vector3);
				for (int i = 0; i < array.Length; i++)
				{
					PickupDisplay val = array[i];
					if (((Object)val.highlight).name.StartsWith("CommandCube"))
					{
						float num2 = (float)i * MathF.PI * 2f / (float)array.Length;
						((Vector3)(ref position2))..ctor(position.x + Mathf.Cos(num2) * num, position.y, position.z + Mathf.Sin(num2) * num);
						((Component)val).gameObject.transform.position = position2;
					}
				}
			}
			catch (NullReferenceException)
			{
				((BaseUnityPlugin)this).Logger.LogDebug((object)"Failed to pull CommandCubes with F3 - most likely because there were none.");
			}
		}

		private void OnApplicationFocus(bool hasFocus)
		{
			if (hasFocus)
			{
				ReevaluateLifecycle();
			}
		}

		private void OnEnable()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			object obj = <>c.<>9__36_0;
			if (obj == null)
			{
				hook_DropRewards val = delegate(orig_DropRewards orig, BossGroup self)
				{
					if (EnablePlayerDropRateScaling.Value && IsModHooked)
					{
						self.scaleRewardsByPlayerCount = false;
					}
					orig.Invoke(self);
				};
				<>c.<>9__36_0 = val;
				obj = (object)val;
			}
			BossGroup.DropRewards += (hook_DropRewards)obj;
			SceneManager.activeSceneChanged += delegate(Scene oldScene, Scene newScene)
			{
				bool flag = ((Scene)(ref newScene)).name == "loadingbasic" || ((Scene)(ref newScene)).name == "intro" || ((Scene)(ref newScene)).name == "splash" || ((Scene)(ref newScene)).name == "title" || ((Scene)(ref newScene)).name == "eclipseworld" || ((Scene)(ref newScene)).name == "infinitetowerworld" || ((Scene)(ref newScene)).name == "lobby";
				forceDisabled = ((Scene)(ref newScene)).name == "artifactworld" || flag;
				if (flag)
				{
					useManualDropRate = false;
					DropRateTracker.ResetTracker();
				}
				ReevaluateLifecycle();
			};
			NetworkingAPI.RegisterMessageType<SpawnCustomMessage2>();
		}

		private void ReevaluateLifecycle()
		{
			if (EnablePlayerDropRateScaling.Value && IsSacrificeEnabled() && !useManualDropRate)
			{
				dropChance = dropRateManager.GetPlayerAwareBaseDropChance(GetPlayerCount(), dropChance);
			}
			if (forceDisabled)
			{
				if (IsModHooked)
				{
					Log.Warning("Force Disabled: Will remove hooks, even if Artifact of Command is enabled.");
					UnHook();
				}
				else
				{
					Log.Debug("Force Disabled: Will not hook.");
				}
				return;
			}
			bool flag = IsCommandEnabled();
			if (IsModHooked && !flag)
			{
				UnHook();
			}
			else if (!IsModHooked && flag)
			{
				Hook();
			}
		}

		private void Hook()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading hooks");
			object obj = <>O.<0>__Util_GetExpAdjustedDropChancePercent;
			if (obj == null)
			{
				hook_GetExpAdjustedDropChancePercent val = Util_GetExpAdjustedDropChancePercent;
				<>O.<0>__Util_GetExpAdjustedDropChancePercent = val;
				obj = (object)val;
			}
			Util.GetExpAdjustedDropChancePercent += (hook_GetExpAdjustedDropChancePercent)obj;
			NetworkMessageHandlerAttribute.RegisterClientMessages += new hook_RegisterClientMessages(NetworkMessageHandlerAttribute_RegisterClientMessages);
			CommandArtifactManager.OnDropletHitGroundServer += new hook_OnDropletHitGroundServer(CommandArtifactManager_OnDropletHitGroundServer);
			Interactor.AttemptInteraction += new hook_AttemptInteraction(Interactor_AttemptInteraction);
			PickupPickerController.SubmitChoice += new hook_SubmitChoice(PickupPickerController_SubmitChoice);
			GenericPickupController.CreatePickup += new hook_CreatePickup(GenericPickupController_CreatePickup);
			IsModHooked = true;
		}

		private void UnHook()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Unloading hooks");
			object obj = <>O.<0>__Util_GetExpAdjustedDropChancePercent;
			if (obj == null)
			{
				hook_GetExpAdjustedDropChancePercent val = Util_GetExpAdjustedDropChancePercent;
				<>O.<0>__Util_GetExpAdjustedDropChancePercent = val;
				obj = (object)val;
			}
			Util.GetExpAdjustedDropChancePercent -= (hook_GetExpAdjustedDropChancePercent)obj;
			NetworkMessageHandlerAttribute.RegisterClientMessages -= new hook_RegisterClientMessages(NetworkMessageHandlerAttribute_RegisterClientMessages);
			CommandArtifactManager.OnDropletHitGroundServer -= new hook_OnDropletHitGroundServer(CommandArtifactManager_OnDropletHitGroundServer);
			Interactor.AttemptInteraction -= new hook_AttemptInteraction(Interactor_AttemptInteraction);
			PickupPickerController.SubmitChoice -= new hook_SubmitChoice(PickupPickerController_SubmitChoice);
			GenericPickupController.CreatePickup -= new hook_CreatePickup(GenericPickupController_CreatePickup);
			IsModHooked = false;
		}

		private GenericPickupController GenericPickupController_CreatePickup(orig_CreatePickup orig, ref CreatePickupInfo createPickupInfo)
		{
			return null;
		}

		private void PickupPickerController_SubmitChoice(orig_SubmitChoice orig, PickupPickerController self, int choiceIndex)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			if ((ulong)choiceIndex >= (ulong)self.options.Length)
			{
				return;
			}
			ref Option reference = ref self.options[choiceIndex];
			if (reference.available)
			{
				PickupIndexUnityEvent onPickupSelected = self.onPickupSelected;
				if (onPickupSelected != null)
				{
					((UnityEvent<int>)(object)onPickupSelected).Invoke(reference.pickupIndex.value);
					Log.Info($"Sending CreatePickup {self.options[choiceIndex].pickupIndex}");
					NetMessageExtensions.Send((INetMessage)(object)new SpawnCustomMessage2(self.options[choiceIndex].pickupIndex, ((MPEventSystem)EventSystem.current).localUser.cachedMaster.GetBodyObject().transform.position), (NetworkDestination)2);
					self.OnDisplayEnd((NetworkUIPromptController)null, (LocalUser)null, (CameraRigController)null);
				}
			}
		}

		private void Interactor_AttemptInteraction(orig_AttemptInteraction orig, Interactor self, GameObject interactableObject)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (((Object)interactableObject).name.StartsWith("CommandCube"))
			{
				PickupPickerController component = interactableObject.GetComponent<PickupPickerController>();
				component.panelInstance = Object.Instantiate<GameObject>(component.panelPrefab, ((MPEventSystem)EventSystem.current).localUser.cameraRigController.hud.mainContainer.transform);
				component.panelInstanceController = component.panelInstance.GetComponent<PickupPickerPanel>();
				component.panelInstanceController.pickerController = component;
				component.panelInstanceController.SetPickupOptions(component.options);
			}
			else
			{
				orig.Invoke(self, interactableObject);
			}
		}

		private void CommandArtifactManager_OnDropletHitGroundServer(orig_OnDropletHitGroundServer orig, ref CreatePickupInfo createPickupInfo, ref bool shouldSpawn)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			DropRateTracker.RegisterItemDrop(createPickupInfo);
			NetworkServer.SendToAll((short)969, (MessageBase)(object)new SpawnCustomMessage
			{
				position = createPickupInfo.position,
				pickupIndex = ((CreatePickupInfo)(ref createPickupInfo)).pickupIndex
			});
			shouldSpawn = false;
		}

		private void NetworkMessageHandlerAttribute_RegisterClientMessages(orig_RegisterClientMessages orig, NetworkClient client)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			orig.Invoke(client);
			object obj = <>O.<1>__HandlePickupMessage;
			if (obj == null)
			{
				NetworkMessageDelegate val = SpawnCustomController.HandlePickupMessage;
				<>O.<1>__HandlePickupMessage = val;
				obj = (object)val;
			}
			client.RegisterHandler((short)969, (NetworkMessageDelegate)obj);
		}

		private static float Util_GetExpAdjustedDropChancePercent(orig_GetExpAdjustedDropChancePercent orig, float nativeBaseDropChance, GameObject characterBodyObject)
		{
			float num = orig.Invoke(nativeBaseDropChance, characterBodyObject);
			float num2 = dropRateManager.ComputeDropChance(IsSwarmEnabled(), num, nativeBaseDropChance, dropChance);
			Log.Debug($"DropChance: original_base={nativeBaseDropChance} original_final={num}; plugin_base={dropChance}; plugin_final={num2} (Character={((Object)characterBodyObject).name})");
			DropRateTracker.RegisterDropOpportunity(num2);
			if (dropRateManager.NeedsBadLuckProtection(num2, Run.instance.GetRunStopwatch()))
			{
				return dropRateManager.GetBadLuckProtectedDropChance(num2);
			}
			return num2;
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCSetDropRate(ConCommandArgs args)
		{
			dropChance = ((ConCommandArgs)(ref args)).GetArgFloat(0);
			useManualDropRate = true;
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCGetDropRateReport(ConCommandArgs args)
		{
			if (IsModHooked)
			{
				DropRateTracker.LogReport();
			}
		}

		private static bool IsSacrificeEnabled()
		{
			return RunArtifactManager.instance != null && ((Behaviour)RunArtifactManager.instance).isActiveAndEnabled && RunArtifactManager.instance.IsArtifactEnabled(Artifacts.sacrificeArtifactDef);
		}

		private static bool IsCommandEnabled()
		{
			return RunArtifactManager.instance != null && ((Behaviour)RunArtifactManager.instance).isActiveAndEnabled && RunArtifactManager.instance.IsArtifactEnabled(Artifacts.commandArtifactDef);
		}

		private static bool IsSwarmEnabled()
		{
			return RunArtifactManager.instance != null && ((Behaviour)RunArtifactManager.instance).isActiveAndEnabled && RunArtifactManager.instance.IsArtifactEnabled(Artifacts.swarmsArtifactDef);
		}

		private int GetPlayerCount()
		{
			return PlayerCharacterMasterController.instances.Count((PlayerCharacterMasterController pc) => pc.isConnected);
		}
	}
	internal static class Log
	{
		private static ManualLogSource _logSource;

		internal static void Init(ManualLogSource logSource)
		{
			_logSource = logSource;
		}

		internal static void Debug(object data)
		{
			_logSource.LogDebug(data);
		}

		internal static void Error(object data)
		{
			_logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			_logSource.LogFatal(data);
		}

		internal static void Info(object data)
		{
			_logSource.LogInfo(data);
		}

		internal static void Message(object data)
		{
			_logSource.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			_logSource.LogWarning(data);
		}
	}
	public class SpawnCustomController : NetworkBehaviour
	{
		[NetworkMessageHandler(msgType = 969, client = true)]
		public static void HandlePickupMessage(NetworkMessage netMsg)
		{
			//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)
			SpawnCustomMessage spawnCustomMessage = new SpawnCustomMessage();
			netMsg.ReadMessage<SpawnCustomMessage>(spawnCustomMessage);
			Log.Info($"HandlePickupMessage {spawnCustomMessage.pickupIndex.value}");
			CreatePickupDroplet(spawnCustomMessage.pickupIndex, spawnCustomMessage.position);
		}

		public static void CreatePickupDroplet(PickupIndex pickupIndex, Vector3 position)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			CreatePickupInfo val = default(CreatePickupInfo);
			val.rotation = Quaternion.identity;
			((CreatePickupInfo)(ref val)).pickupIndex = pickupIndex;
			CreatePickupInfo val2 = val;
			GameObject val3 = Object.Instantiate<GameObject>(CommandArtifactManager.commandCubePrefab, position, val2.rotation);
			PickupIndexNetworker component = val3.GetComponent<PickupIndexNetworker>();
			PickupPickerController component2 = val3.GetComponent<PickupPickerController>();
			component2.SetOptionsInternal(PickupPickerController.GetOptionsFromPickupIndex(((CreatePickupInfo)(ref val2)).pickupIndex));
			if (!NetworkServer.active)
			{
				((NetworkBehaviour)component2).SetDirtyBit(PickupPickerController.optionsDirtyBit);
			}
			component.NetworkpickupIndex = ((CreatePickupInfo)(ref val2)).pickupIndex;
			if (Object.op_Implicit((Object)(object)component.pickupDisplay))
			{
				component.pickupDisplay.SetPickupIndex(((CreatePickupInfo)(ref val2)).pickupIndex, false);
			}
		}

		public static void CreatePickupItem(PickupIndex pickupIndex, Vector3 position)
		{
			//IL_0017: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			//IL_003c: 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_004c: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active)
			{
				CreatePickupInfo val = default(CreatePickupInfo);
				val.rotation = Quaternion.identity;
				val.position = position;
				((CreatePickupInfo)(ref val)).pickupIndex = pickupIndex;
				CreatePickupInfo val2 = val;
				GameObject val3 = Object.Instantiate<GameObject>(val2.prefabOverride ?? GenericPickupController.pickupPrefab, position, val2.rotation);
				GenericPickupController component = val3.GetComponent<GenericPickupController>();
				if (Object.op_Implicit((Object)(object)component))
				{
					GenericPickupController val4 = component;
					CreatePickupInfo val5 = val2;
					val4.NetworkpickupIndex = ((CreatePickupInfo)(ref val5)).pickupIndex;
				}
				PickupIndexNetworker component2 = val3.GetComponent<PickupIndexNetworker>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					PickupIndexNetworker val6 = component2;
					CreatePickupInfo val7 = val2;
					val6.NetworkpickupIndex = ((CreatePickupInfo)(ref val7)).pickupIndex;
				}
				PickupPickerController component3 = val3.GetComponent<PickupPickerController>();
				if (Object.op_Implicit((Object)(object)component3) && val2.pickerOptions != null)
				{
					component3.SetOptionsServer(val2.pickerOptions);
				}
				NetworkServer.Spawn(val3);
			}
		}
	}
	public class SpawnCustomMessage : MessageBase, INetMessage, ISerializableObject
	{
		public Vector3 position;

		public PickupIndex pickupIndex;

		public override void Serialize(NetworkWriter writer)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			writer.Write(position);
			GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
		}

		public override void Deserialize(NetworkReader reader)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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)
			position = reader.ReadVector3();
			pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
		}

		public void OnReceived()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			SpawnCustomController.CreatePickupItem(pickupIndex, position);
		}
	}
	public struct SpawnCustomMessage2 : INetMessage, ISerializableObject
	{
		public Vector3 position;

		public PickupIndex pickupIndex;

		public void Serialize(NetworkWriter writer)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			writer.Write(position);
			GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
		}

		public void Deserialize(NetworkReader reader)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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)
			position = reader.ReadVector3();
			pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
		}

		public void OnReceived()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			SpawnCustomController.CreatePickupItem(pickupIndex, position);
		}

		public SpawnCustomMessage2(PickupIndex pickupIndex, Vector3 position)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			this.position = position;
			this.pickupIndex = pickupIndex;
		}
	}
}