Decompiled source of SharedSpoils v1.0.0

plugins/SharedSpoils/SharedSpoils.dll

Decompiled 17 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.ScavBackpack;
using HarmonyLib;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.Artifacts;
using RoR2.Networking;
using Unity;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SynT")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Shares items and gold between players in Risk of Rain 2 while keeping the game balanced.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SharedSpoils")]
[assembly: AssemblyTitle("SharedSpoils")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SharedSpoils;

internal static class Balance
{
	private static int PlayerCount
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)Run.instance))
			{
				return 1;
			}
			return Math.Max(1, Run.instance.participatingPlayerCount);
		}
	}

	internal static void OnPrePopulateScene(SceneDirector director)
	{
		//IL_0101: 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_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		if (!ModConfig.IsOn || !NetworkServer.active || !Object.op_Implicit((Object)(object)Run.instance) || !Object.op_Implicit((Object)(object)director))
		{
			return;
		}
		InteractableScaling value = ModConfig.InteractableMode.Value;
		float value2 = ModConfig.InteractableMultiplier.Value;
		if ((value == InteractableScaling.Off && Math.Abs(value2 - 1f) < 0.001f) || Run.instance is InfiniteTowerRun)
		{
			return;
		}
		ClassicStageInfo val = (Object.op_Implicit((Object)(object)SceneInfo.instance) ? ((Component)SceneInfo.instance).GetComponent<ClassicStageInfo>() : null);
		int interactableCredit = director.interactableCredit;
		if (!Object.op_Implicit((Object)(object)val) || interactableCredit <= 0)
		{
			return;
		}
		int playerCount = PlayerCount;
		float num = 0.5f + 0.5f * (float)playerCount;
		float num2;
		float num3;
		switch (value)
		{
		case InteractableScaling.VanillaParity:
			num2 = 1f / (float)playerCount;
			num3 = 1f / (float)playerCount;
			break;
		case InteractableScaling.Singleplayer:
			num2 = 1f / num;
			num3 = 1f;
			break;
		default:
			num2 = 1f;
			num3 = 1f;
			break;
		}
		int num4 = 0;
		if (val.bonusInteractibleCreditObjects != null)
		{
			BonusInteractibleCreditObject[] bonusInteractibleCreditObjects = val.bonusInteractibleCreditObjects;
			foreach (BonusInteractibleCreditObject val2 in bonusInteractibleCreditObjects)
			{
				if (Object.op_Implicit((Object)(object)val2.objectThatGrantsPointsIfEnabled) && val2.objectThatGrantsPointsIfEnabled.activeSelf)
				{
					num4 += val2.points;
				}
			}
		}
		num4 = Math.Min(num4, interactableCredit);
		int val3 = (int)((float)(interactableCredit - num4) * num2 * value2 + (float)num4 * num3 * value2);
		director.interactableCredit = Math.Max(0, val3);
		Log.Info($"Interactable budget {interactableCredit} -> {director.interactableCredit} ({playerCount} player(s), {value}, x{value2:0.##}).");
	}
}
[HarmonyPatch(typeof(BossGroup), "DropRewards")]
internal static class BossLootPatch
{
	internal struct State
	{
		public bool changed;

		public int bonusRewardCount;
	}

	private static void Prefix(BossGroup __instance, out State __state)
	{
		__state = default(State);
		if (ShareRules.Active && ModConfig.ScaleBossLoot.Value && __instance.scaleRewardsByPlayerCount)
		{
			__state.changed = true;
			__state.bonusRewardCount = __instance.bonusRewardCount;
			int num = Math.Max(1, ModConfig.BossLootCredit.Value);
			__instance.scaleRewardsByPlayerCount = false;
			__instance.bonusRewardCount = num * (1 + __state.bonusRewardCount) - 1;
		}
	}

	private static void Finalizer(BossGroup __instance, State __state)
	{
		if (__state.changed && Object.op_Implicit((Object)(object)__instance))
		{
			__instance.scaleRewardsByPlayerCount = true;
			__instance.bonusRewardCount = __state.bonusRewardCount;
		}
	}
}
[HarmonyPatch(typeof(Opening), "OnEnter")]
internal static class ScavengerBagPatch
{
	private static int _vanillaMaxDrops;

	private static void Prefix(Opening __instance)
	{
		if (_vanillaMaxDrops <= 0)
		{
			_vanillaMaxDrops = Opening.maxItemDropCount;
		}
		if (_vanillaMaxDrops <= 0)
		{
			return;
		}
		int maxItemDropCount = _vanillaMaxDrops;
		int num = ((!Object.op_Implicit((Object)(object)Run.instance)) ? 1 : Math.Max(1, Run.instance.participatingPlayerCount));
		if (ShareRules.Active && ModConfig.ScaleScavengerBags.Value && num > 1)
		{
			ChestBehavior val = (Object.op_Implicit((Object)(object)((EntityState)__instance).outer) ? ((Component)((EntityState)__instance).outer).GetComponent<ChestBehavior>() : null);
			if (Object.op_Implicit((Object)(object)val) && val.tier1Chance > 0f)
			{
				maxItemDropCount = Math.Min(_vanillaMaxDrops, Math.Max(2, (int)Math.Ceiling((double)_vanillaMaxDrops / (double)num)));
			}
		}
		Opening.maxItemDropCount = maxItemDropCount;
	}
}
[HarmonyPatch(typeof(SacrificeArtifactManager), "OnServerCharacterDeath")]
internal static class SacrificeScopePatch
{
	internal static int Depth;

	private static void Prefix()
	{
		Depth++;
	}

	private static void Finalizer()
	{
		Depth--;
	}
}
[HarmonyPatch(typeof(Util), "GetExpAdjustedDropChancePercent")]
internal static class SacrificeDropChancePatch
{
	private static void Prefix(ref float baseChancePercent)
	{
		if (SacrificeScopePatch.Depth > 0 && ShareRules.Active && ModConfig.ScaleSacrificeDrops.Value && Object.op_Implicit((Object)(object)Run.instance))
		{
			baseChancePercent /= Math.Max(1, Run.instance.participatingPlayerCount);
		}
	}
}
internal static class ItemSharing
{
	internal static void ShareItem(CharacterMaster picker, UniquePickup pickup, Vector3 origin)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			ShareItemCore(picker, pickup, origin);
		}
		catch (Exception arg)
		{
			Log.Error($"Sharing a pickup failed: {arg}");
		}
	}

	private static void ShareItemCore(CharacterMaster picker, UniquePickup pickup, Vector3 origin)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: 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_0016: Invalid comparison between Unknown and I4
		//IL_001a: 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_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		PickupDef pickupDef = PickupCatalog.GetPickupDef(pickup.pickupIndex);
		if (pickupDef == null || (int)pickupDef.itemIndex == -1)
		{
			return;
		}
		ItemIndex itemIndex = pickupDef.itemIndex;
		List<SkippedPlayer> list = new List<SkippedPlayer>();
		List<CharacterMaster> list2 = new List<CharacterMaster>();
		foreach (CharacterMaster item in ShareRules.Recipients(picker, list))
		{
			Inventory inventory = item.inventory;
			ItemDef val = ShareRules.ExclusiveGroupBlocker(inventory, itemIndex);
			if (Object.op_Implicit((Object)(object)val))
			{
				list.Add(new SkippedPlayer(item, "already carries " + Language.GetString(val.nameToken)));
				continue;
			}
			if (pickup.isRental)
			{
				inventory.GiveItemRented(itemIndex, 1);
			}
			else if (((UniquePickup)(ref pickup)).isTempItem)
			{
				inventory.GiveItemTemp(itemIndex, pickup.decayValue);
			}
			else
			{
				inventory.GiveItemPermanent(itemIndex, 1);
			}
			PickupNotifier.NotifyRecipient(item, new UniquePickup(pickup.pickupIndex)
			{
				decayValue = pickup.decayValue,
				isRental = pickup.isRental
			});
			PickupNotifier.ShowOrb(origin, item, itemIndex);
			list2.Add(item);
		}
		Log.Debug(string.Format("{0} picked up {1}; shared with {2}, skipped {3}.", Object.op_Implicit((Object)(object)picker) ? ((Object)picker).name : "?", pickupDef.internalName, list2.Count, list.Count));
		ShareChat.Shared(picker, pickupDef, list2, list);
	}

	internal static CharacterMaster MasterOf(CharacterBody body)
	{
		if (!Object.op_Implicit((Object)(object)body))
		{
			return null;
		}
		if (Object.op_Implicit((Object)(object)body.master))
		{
			return body.master;
		}
		if (!Object.op_Implicit((Object)(object)body.inventory))
		{
			return null;
		}
		return ((Component)body.inventory).GetComponent<CharacterMaster>();
	}

	internal static string PersonalReasonOf(GenericPickupController controller)
	{
		PersonalPickupMarker personalPickupMarker = PersonalDrops.MarkerOf((Component)(object)controller);
		if (Object.op_Implicit((Object)(object)personalPickupMarker))
		{
			return personalPickupMarker.Describe();
		}
		if (controller.Duplicated && ModConfig.PersonalExchanges.Value)
		{
			return PersonalDrops.Describe(PersonalReason.Printed, (CostTypeIndex)0);
		}
		return null;
	}

	internal static bool IsHiddenItem(PickupDef def)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		ItemDef itemDef = ItemCatalog.GetItemDef(def.itemIndex);
		if (Object.op_Implicit((Object)(object)itemDef))
		{
			return itemDef.hidden;
		}
		return false;
	}
}
[HarmonyPatch(typeof(GenericPickupController), "AttemptGrant")]
internal static class GenericPickupGrantPatch
{
	internal struct State
	{
		public bool tracked;

		public bool isEquipment;

		public ShareDecision decision;

		public PickupDef def;

		public UniquePickup pickup;

		public CharacterMaster picker;

		public EquipmentIndex pickerPreviousEquipment;

		public int pickerEquipmentCopiesBefore;
	}

	private static readonly FieldRef<GenericPickupController, bool> ConsumedRef = AccessTools.FieldRefAccess<GenericPickupController, bool>("consumed");

	private static void Prefix(GenericPickupController __instance, CharacterBody body, out State __state)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: 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_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Invalid comparison between Unknown and I4
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Invalid comparison between Unknown and I4
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		__state = default(State);
		if (!ShareRules.Active || !Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.inventory) || ConsumedRef.Invoke(__instance))
		{
			return;
		}
		UniquePickup pickup = __instance.pickup;
		PickupDef pickupDef = PickupCatalog.GetPickupDef(pickup.pickupIndex);
		if (pickupDef == null)
		{
			return;
		}
		string text = ItemSharing.PersonalReasonOf(__instance);
		if ((int)pickupDef.itemIndex != -1)
		{
			if (ItemSharing.IsHiddenItem(pickupDef))
			{
				return;
			}
			__state.decision = ((text != null) ? ShareDecision.No(text) : ShareRules.EvaluatePickup(in pickup));
		}
		else
		{
			if ((int)pickupDef.equipmentIndex == -1)
			{
				return;
			}
			Inventory inventory = body.inventory;
			__state.isEquipment = true;
			__state.decision = ((text != null) ? ShareDecision.No(text) : ShareRules.EvaluateEquipment(pickupDef.equipmentIndex));
			__state.pickerEquipmentCopiesBefore = EquipmentSharing.CountEquipment(inventory, pickupDef.equipmentIndex);
			EquipmentLocation val = inventory.FindBestEquipmentLocationOrCurrent(ref EquipmentLocationQueryArgs.defaultPickup);
			__state.pickerPreviousEquipment = inventory.GetEquipmentIndex(ref val);
		}
		__state.tracked = true;
		__state.def = pickupDef;
		__state.pickup = pickup;
		__state.picker = ItemSharing.MasterOf(body);
	}

	private static void Postfix(GenericPickupController __instance, CharacterBody body, State __state)
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: 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)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		if (!__state.tracked)
		{
			return;
		}
		int num;
		if (!__state.isEquipment)
		{
			num = (ConsumedRef.Invoke(__instance) ? 1 : 0);
		}
		else
		{
			if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.inventory))
			{
				return;
			}
			num = ((EquipmentSharing.CountEquipment(body.inventory, __state.def.equipmentIndex) > __state.pickerEquipmentCopiesBefore) ? 1 : 0);
		}
		if (num != 0)
		{
			if (!__state.decision.Share)
			{
				ShareChat.NotShared(__state.picker, __state.def, __state.decision.Reason);
			}
			else if (__state.isEquipment)
			{
				EquipmentSharing.ShareEquipment(__state.picker, __state.def.equipmentIndex, __state.pickerPreviousEquipment);
			}
			else
			{
				ItemSharing.ShareItem(__state.picker, __state.pickup, ((Component)__instance).transform.position);
			}
		}
	}
}
[HarmonyPatch(typeof(PickupPickerController), "AttemptGrantPickupDirectly")]
internal static class PickerDirectGrantPatch
{
	internal struct State
	{
		public CharacterMaster chooser;

		public ShareDecision decision;

		public PickupDef def;
	}

	private static readonly FieldRef<PickupPickerController, NetworkUIPromptController> PromptRef = AccessTools.FieldRefAccess<PickupPickerController, NetworkUIPromptController>("networkUIPromptController");

	private static void Prefix(PickupPickerController __instance, UniquePickup pickupState, out State __state)
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Invalid comparison between Unknown and I4
		__state = default(State);
		if (!ShareRules.Active)
		{
			return;
		}
		NetworkUIPromptController val = PromptRef.Invoke(__instance);
		CharacterMaster val2 = (Object.op_Implicit((Object)(object)val) ? val.currentParticipantMaster : null);
		if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.GetBody()))
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupState.pickupIndex);
			if (pickupDef != null && (int)pickupDef.itemIndex != -1 && !ItemSharing.IsHiddenItem(pickupDef))
			{
				PersonalPickupMarker personalPickupMarker = PersonalDrops.MarkerOf((Component)(object)__instance);
				__state.chooser = val2;
				__state.def = pickupDef;
				__state.decision = (Object.op_Implicit((Object)(object)personalPickupMarker) ? ShareDecision.No(personalPickupMarker.Describe()) : ShareRules.EvaluatePickup(in pickupState));
			}
		}
	}

	private static void Postfix(PickupPickerController __instance, UniquePickup pickupState, State __state)
	{
		//IL_0021: 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)
		if (Object.op_Implicit((Object)(object)__state.chooser))
		{
			if (__state.decision.Share)
			{
				ItemSharing.ShareItem(__state.chooser, pickupState, ((Component)__instance).transform.position);
			}
			else
			{
				ShareChat.NotShared(__state.chooser, __state.def, __state.decision.Reason);
			}
		}
	}
}
internal static class EquipmentSharing
{
	internal static int CountEquipment(Inventory inventory, EquipmentIndex equipment)
	{
		//IL_000c: 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)
		//IL_0024: 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_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		for (uint num2 = 0u; num2 < inventory.equipmentSlotCount; num2++)
		{
			for (uint num3 = 0u; num3 < inventory.equipmentSetCount; num3++)
			{
				EquipmentLocation val = new EquipmentLocation
				{
					slot = num2,
					set = num3
				};
				if (inventory.GetEquipment(ref val).equipmentIndex == equipment)
				{
					num++;
				}
			}
		}
		return num;
	}

	internal static List<EquipmentIndex> Snapshot(Inventory inventory)
	{
		//IL_0010: 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_0028: 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_0031: 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_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Invalid comparison between Unknown and I4
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		List<EquipmentIndex> list = new List<EquipmentIndex>();
		for (uint num = 0u; num < inventory.equipmentSlotCount; num++)
		{
			for (uint num2 = 0u; num2 < inventory.equipmentSetCount; num2++)
			{
				EquipmentLocation val = new EquipmentLocation
				{
					slot = num,
					set = num2
				};
				EquipmentIndex equipmentIndex = inventory.GetEquipment(ref val).equipmentIndex;
				if ((int)equipmentIndex != -1)
				{
					list.Add(equipmentIndex);
				}
			}
		}
		return list;
	}

	internal static void ShareEquipment(CharacterMaster picker, EquipmentIndex equipment, EquipmentIndex pickerPrevious)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			ShareEquipmentCore(picker, equipment, pickerPrevious);
		}
		catch (Exception arg)
		{
			Log.Error($"Sharing equipment failed: {arg}");
		}
	}

	private static void ShareEquipmentCore(CharacterMaster picker, EquipmentIndex equipment, EquipmentIndex pickerPrevious)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: 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_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Invalid comparison between Unknown and I4
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: 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)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		PickupIndex val = PickupCatalog.FindPickupIndex(equipment);
		List<SkippedPlayer> list = new List<SkippedPlayer>();
		List<CharacterMaster> list2 = new List<CharacterMaster>();
		foreach (CharacterMaster item in ShareRules.Recipients(picker, list))
		{
			Inventory inventory = item.inventory;
			if (CountEquipment(inventory, equipment) > 0)
			{
				list.Add(new SkippedPlayer(item, "already has it"));
				continue;
			}
			EquipmentLocation val2 = inventory.FindBestEquipmentLocationOrCurrent(ref EquipmentLocationQueryArgs.defaultPickup);
			EquipmentIndex equipmentIndex = inventory.GetEquipmentIndex(ref val2);
			if ((int)equipmentIndex != -1)
			{
				if (!ShareRules.IsEquipmentShareable(equipmentIndex))
				{
					EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
					list.Add(new SkippedPlayer(item, "keeps " + (Object.op_Implicit((Object)(object)equipmentDef) ? Language.GetString(equipmentDef.nameToken) : "their equipment")));
					continue;
				}
				if (equipmentIndex != pickerPrevious)
				{
					CharacterBody body = item.GetBody();
					if (!Object.op_Implicit((Object)(object)body))
					{
						list.Add(new SkippedPlayer(item, "keeps their own equipment"));
						continue;
					}
					PickupDropletController.CreatePickupDroplet(new UniquePickup(PickupCatalog.FindPickupIndex(equipmentIndex)), body.corePosition, Vector3.up * 15f, false);
				}
			}
			inventory.SetEquipmentIndex(equipment, ref val2);
			PickupNotifier.NotifyRecipient(item, new UniquePickup(val));
			list2.Add(item);
		}
		Log.Debug($"Equipment {equipment} shared with {list2.Count}, skipped {list.Count}.");
		ShareChat.Shared(picker, PickupCatalog.GetPickupDef(val), list2, list);
	}

	internal static void RemoveFromOthers(CharacterMaster exclude, EquipmentIndex equipment)
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: 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)
		foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
		{
			CharacterMaster val = (Object.op_Implicit((Object)(object)instance) ? instance.master : null);
			if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val == (Object)(object)exclude || !Object.op_Implicit((Object)(object)val.inventory))
			{
				continue;
			}
			Inventory inventory = val.inventory;
			for (uint num = 0u; num < inventory.equipmentSlotCount; num++)
			{
				for (uint num2 = 0u; num2 < inventory.equipmentSetCount; num2++)
				{
					EquipmentLocation val2 = new EquipmentLocation
					{
						slot = num,
						set = num2
					};
					if (inventory.GetEquipment(ref val2).equipmentIndex == equipment)
					{
						inventory.SetEquipmentIndex((EquipmentIndex)(-1), ref val2);
					}
				}
			}
		}
	}
}
[HarmonyPatch(typeof(PurchaseInteraction), "OnInteractionBegin")]
internal static class EquipmentPaymentPatch
{
	internal struct State
	{
		public CharacterMaster buyer;

		public List<EquipmentIndex> before;
	}

	private static void Prefix(PurchaseInteraction __instance, Interactor activator, out State __state)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Invalid comparison between Unknown and I4
		__state = default(State);
		if (ShareRules.Active && ModConfig.ShareEquipment.Value && (int)__instance.costType == 7 && Object.op_Implicit((Object)(object)activator))
		{
			CharacterBody component = ((Component)activator).GetComponent<CharacterBody>();
			if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.inventory))
			{
				__state.buyer = ItemSharing.MasterOf(component);
				__state.before = EquipmentSharing.Snapshot(component.inventory);
			}
		}
	}

	private static void Postfix(State __state)
	{
		//IL_0049: 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_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: 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)
		if (__state.before == null || !Object.op_Implicit((Object)(object)__state.buyer) || !Object.op_Implicit((Object)(object)__state.buyer.inventory))
		{
			return;
		}
		List<EquipmentIndex> list = EquipmentSharing.Snapshot(__state.buyer.inventory);
		foreach (EquipmentIndex item in __state.before)
		{
			if (!list.Remove(item) && ShareRules.IsEquipmentShareable(item))
			{
				EquipmentSharing.RemoveFromOthers(__state.buyer, item);
			}
		}
	}
}
internal static class Log
{
	private static ManualLogSource _source;

	internal static void Init(ManualLogSource source)
	{
		_source = source;
	}

	internal static void Info(object message)
	{
		ManualLogSource source = _source;
		if (source != null)
		{
			source.LogInfo(message);
		}
	}

	internal static void Warning(object message)
	{
		ManualLogSource source = _source;
		if (source != null)
		{
			source.LogWarning(message);
		}
	}

	internal static void Error(object message)
	{
		ManualLogSource source = _source;
		if (source != null)
		{
			source.LogError(message);
		}
	}

	internal static void Debug(object message)
	{
		if (ModConfig.VerboseLogging != null && ModConfig.VerboseLogging.Value)
		{
			ManualLogSource source = _source;
			if (source != null)
			{
				source.LogInfo((object)("[debug] " + message));
			}
		}
	}
}
public enum InteractableScaling
{
	VanillaParity,
	Singleplayer,
	Off
}
internal static class ModConfig
{
	internal const string DefaultItemBlacklist = "BeetleGland,TreasureCache,TreasureCacheVoid,TitanGoldDuringTP,TPHealingNova,ArtifactKey,FreeChest,RoboBallBuddy,MinorConstructOnKill,ScrapWhite,ScrapGreen,ScrapRed,ScrapYellow,DronesDropDynamite,PhysicsProjectile,PowerPyramid,PowerCube,MasterBattery,MasterCore,BonusHealthBoost,CookedSteak,Stew,UltimateMeal,WyrmOnHit,LowerPricedChests,ItemDropChanceOnKill,BarrageOnBoss,OnLevelUpFreeUnlock,BlightZone";

	internal static ConfigEntry<bool> Enabled;

	internal static bool ConflictDetected;

	internal static ConfigEntry<bool> ShareWhite;

	internal static ConfigEntry<bool> ShareGreen;

	internal static ConfigEntry<bool> ShareRed;

	internal static ConfigEntry<bool> ShareBoss;

	internal static ConfigEntry<bool> ShareLunar;

	internal static ConfigEntry<bool> ShareVoid;

	internal static ConfigEntry<bool> ShareFood;

	internal static ConfigEntry<bool> ShareOtherTiers;

	internal static ConfigEntry<bool> ShareTemporaryItems;

	internal static ConfigEntry<bool> DeadPlayersGetItems;

	internal static ConfigEntry<string> ItemBlacklist;

	internal static ConfigEntry<bool> ShowShareOrbs;

	internal static ConfigEntry<bool> PickupChatMessages;

	internal static ConfigEntry<bool> ShareEquipment;

	internal static ConfigEntry<bool> ShareLunarEquipment;

	internal static ConfigEntry<bool> ShareEliteAspects;

	internal static ConfigEntry<string> EquipmentBlacklist;

	internal static ConfigEntry<bool> ShareMoney;

	internal static ConfigEntry<float> MoneyScalar;

	internal static ConfigEntry<InteractableScaling> InteractableMode;

	internal static ConfigEntry<float> InteractableMultiplier;

	internal static ConfigEntry<bool> ScaleBossLoot;

	internal static ConfigEntry<int> BossLootCredit;

	internal static ConfigEntry<bool> PersonalPerPlayerRewards;

	internal static ConfigEntry<bool> PersonalExchanges;

	internal static ConfigEntry<bool> ScaleScavengerBags;

	internal static ConfigEntry<bool> ScaleSacrificeDrops;

	internal static ConfigEntry<bool> VerboseLogging;

	internal static bool IsOn
	{
		get
		{
			if (Enabled.Value)
			{
				return !ConflictDetected;
			}
			return false;
		}
	}

	internal static void Bind(ConfigFile cfg)
	{
		//IL_0232: Unknown result type (might be due to invalid IL or missing references)
		//IL_023c: Expected O, but got Unknown
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Expected O, but got Unknown
		//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d6: Expected O, but got Unknown
		Enabled = cfg.Bind<bool>("1. General", "Enabled", true, "Master switch. When off the game behaves like vanilla (takes effect immediately). Every player needs the mod installed; the host's settings are the ones that count.");
		ShareWhite = cfg.Bind<bool>("2. Items", "ShareWhiteItems", true, "Share common (white) items.");
		ShareGreen = cfg.Bind<bool>("2. Items", "ShareGreenItems", true, "Share uncommon (green) items.");
		ShareRed = cfg.Bind<bool>("2. Items", "ShareRedItems", true, "Share legendary (red) items.");
		ShareBoss = cfg.Bind<bool>("2. Items", "ShareBossItems", true, "Share boss (yellow) items.");
		ShareLunar = cfg.Bind<bool>("2. Items", "ShareLunarItems", false, "Share lunar (blue) items. Off by default: lunars are a personal risk/reward choice.");
		ShareVoid = cfg.Bind<bool>("2. Items", "ShareVoidItems", false, "Share void (purple) items. Off by default: a void item corrupts its normal counterpart in every inventory it lands in.");
		ShareFood = cfg.Bind<bool>("2. Items", "ShareFoodItems", false, "Share food tier items (Alloyed Collective).");
		ShareOtherTiers = cfg.Bind<bool>("2. Items", "ShareOtherTiers", false, "Share items from any other tier (cursed, pages, hexes, untiered and modded tiers).");
		ShareTemporaryItems = cfg.Bind<bool>("2. Items", "ShareTemporaryAndRentalItems", false, "Share temporary and rental pickups as well. Off by default since they are tied to the player who earned them.");
		DeadPlayersGetItems = cfg.Bind<bool>("2. Items", "DeadPlayersGetItems", false, "Give shared items to players who are dead and out of extra lives.");
		ItemBlacklist = cfg.Bind<string>("2. Items", "ItemBlacklist", "BeetleGland,TreasureCache,TreasureCacheVoid,TitanGoldDuringTP,TPHealingNova,ArtifactKey,FreeChest,RoboBallBuddy,MinorConstructOnKill,ScrapWhite,ScrapGreen,ScrapRed,ScrapYellow,DronesDropDynamite,PhysicsProjectile,PowerPyramid,PowerCube,MasterBattery,MasterCore,BonusHealthBoost,CookedSteak,Stew,UltimateMeal,WyrmOnHit,LowerPricedChests,ItemDropChanceOnKill,BarrageOnBoss,OnLevelUpFreeUnlock,BlightZone", "Comma separated internal item names that are never shared. Defaults are items whose effect already counts the whole team (Halcyon Seed, Lepton Daisy), spawn one extra chest per holder (Rusted Key, Shipping Request Form), or create loot/allies per holder. Unknown names are reported in the log.");
		ShowShareOrbs = cfg.Bind<bool>("2. Items", "ShowShareOrbs", true, "Show a little item orb flying from the pickup to each teammate who received a copy.");
		PickupChatMessages = cfg.Bind<bool>("2. Items", "PickupChatMessages", true, "Post one chat line for every item or equipment pickup saying whether it was shared, with whom, and if not, why. Only in runs with more than one player.");
		ShareEquipment = cfg.Bind<bool>("3. Equipment", "ShareEquipment", false, "Share equipment: when someone picks one up, every other player gets a copy (their own different equipment is dropped, not lost). Using an equipment drone or similar takes the shared equipment from everyone.");
		ShareLunarEquipment = cfg.Bind<bool>("3. Equipment", "ShareLunarEquipment", false, "Also share lunar equipment.");
		ShareEliteAspects = cfg.Bind<bool>("3. Equipment", "ShareEliteAspects", false, "Also share elite aspects.");
		EquipmentBlacklist = cfg.Bind<string>("3. Equipment", "EquipmentBlacklist", "", "Comma separated internal equipment names that are never shared.");
		ShareMoney = cfg.Bind<bool>("4. Money", "ShareMoney", true, "Everyone shares one wallet. Income from anyone goes into it and anyone can spend from it. Leftover gold still converts to experience at the end of a stage exactly like vanilla.");
		MoneyScalar = cfg.Bind<float>("4. Money", "MoneyScalar", 1f, new ConfigDescription("Multiplier for all gold added to the shared wallet.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
		InteractableMode = cfg.Bind<InteractableScaling>("5. Balance", "InteractableScaling", InteractableScaling.VanillaParity, "How many chests, shrines and barrels spawn now that loot is shared.\nVanillaParity: vanilla multiplayer budget divided by player count, so each player ends up with about as many items as in a normal multiplayer run.\nSingleplayer: what one solo player would get (more loot, similar to classic ShareSuite).\nOff: vanilla multiplayer amount.");
		InteractableMultiplier = cfg.Bind<float>("5. Balance", "InteractableBudgetMultiplier", 1f, new ConfigDescription("Extra multiplier on top of InteractableScaling. 1.2 = 20% more interactables.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 4f), Array.Empty<object>()));
		ScaleBossLoot = cfg.Bind<bool>("5. Balance", "ScaleBossLoot", true, "Teleporter and other boss groups drop BossLootCredit items (times Shrine of the Mountain stacks) instead of one per player. Every drop is shared.");
		BossLootCredit = cfg.Bind<int>("5. Balance", "BossLootCredit", 1, new ConfigDescription("Boss drops per kill when ScaleBossLoot is on.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>()));
		PersonalPerPlayerRewards = cfg.Bind<bool>("5. Balance", "PersonalPerPlayerRewards", true, "Rewards the game already hands out one per player (Void Fields, Simulacrum waves, Halcyon Shrines, Void Seeds, Aurelionite heart, geodes, the DLC bosses and encounters) stay one per player and are NOT copied to everyone, so nobody gets them N times.");
		PersonalExchanges = cfg.Bind<bool>("5. Balance", "PersonalExchanges", true, "Items that someone paid for with their own items, coins or health (3D printers, cauldrons, cleansing pools and other exchanges) only go to the buyer. Turning this off lets one printer use duplicate an item for the whole team.");
		ScaleScavengerBags = cfg.Bind<bool>("5. Balance", "ScaleScavengerBags", true, "Scavenger bags drop fewer (shared) items: roughly the normal amount divided by player count, at least 2.");
		ScaleSacrificeDrops = cfg.Bind<bool>("5. Balance", "ScaleSacrificeDrops", true, "With Artifact of Sacrifice, divide the drop chance by player count since every drop is shared.");
		VerboseLogging = cfg.Bind<bool>("9. Debug", "VerboseLogging", false, "Log every share decision to the BepInEx console.");
	}
}
internal static class MoneySharing
{
	private static readonly HashSet<CharacterMaster> Registered = new HashSet<CharacterMaster>();

	private static Run _run;

	private static long _pool;

	private static bool _initialized;

	private static bool _propagating;

	private static bool _tickErrorLogged;

	private static bool Enabled
	{
		get
		{
			if (ModConfig.IsOn && ModConfig.ShareMoney.Value && NetworkServer.active)
			{
				return Object.op_Implicit((Object)(object)Run.instance);
			}
			return false;
		}
	}

	internal static long Pool => _pool;

	internal static void OnToggled()
	{
		_run = null;
		Registered.Clear();
		_initialized = false;
		_pool = 0L;
		if (Enabled)
		{
			_run = Run.instance;
			InitializeFromRichest();
		}
	}

	private static void EnsureRun()
	{
		if (!((Object)(object)_run == (Object)(object)Run.instance))
		{
			_run = Run.instance;
			Registered.Clear();
			_initialized = false;
			_pool = 0L;
		}
	}

	private static bool IsIncluded(CharacterMaster master)
	{
		if (!Object.op_Implicit((Object)(object)master) || !Object.op_Implicit((Object)(object)master.playerCharacterMasterController) || !Object.op_Implicit((Object)(object)master.inventory))
		{
			return false;
		}
		ItemDef onLevelUpFreeUnlock = Items.OnLevelUpFreeUnlock;
		if (Object.op_Implicit((Object)(object)onLevelUpFreeUnlock))
		{
			return master.inventory.GetItemCountEffective(onLevelUpFreeUnlock) == 0;
		}
		return true;
	}

	private static void InitializeFromRichest()
	{
		long num = 0L;
		foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
		{
			CharacterMaster val = (Object.op_Implicit((Object)(object)instance) ? instance.master : null);
			if (IsIncluded(val))
			{
				num = Math.Max(num, val.money);
				Registered.Add(val);
			}
		}
		_pool = num;
		_initialized = Registered.Count > 0;
		Broadcast();
	}

	internal static void OnMoneyChanged(CharacterMaster master, uint previous)
	{
		if (!_propagating && Enabled)
		{
			EnsureRun();
			if (!IsIncluded(master))
			{
				Registered.Remove(master);
			}
			else if (!Registered.Contains(master))
			{
				Register(master);
			}
			else
			{
				Apply((long)master.money - (long)previous);
			}
		}
	}

	internal static void Tick()
	{
		try
		{
			TickInternal();
		}
		catch (Exception arg)
		{
			if (!_tickErrorLogged)
			{
				_tickErrorLogged = true;
				Log.Error($"Shared wallet sync failed: {arg}");
			}
		}
	}

	private static void TickInternal()
	{
		if (!Enabled)
		{
			return;
		}
		EnsureRun();
		foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
		{
			CharacterMaster val = (Object.op_Implicit((Object)(object)instance) ? instance.master : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				if (!IsIncluded(val))
				{
					Registered.Remove(val);
				}
				else if (!Registered.Contains(val))
				{
					Register(val);
				}
				else if (val.money != _pool)
				{
					Apply(val.money - _pool);
				}
			}
		}
	}

	private static void Register(CharacterMaster master)
	{
		Registered.Add(master);
		if (!_initialized)
		{
			_initialized = true;
			_pool = master.money;
			Log.Debug($"Shared wallet started at {_pool} gold.");
		}
		else
		{
			SetMoney(master, _pool);
		}
	}

	private static void Apply(long delta)
	{
		if (delta > 0)
		{
			float value = ModConfig.MoneyScalar.Value;
			if (Math.Abs(value - 1f) > 0.0001f)
			{
				delta = (long)Math.Floor((double)delta * (double)value);
			}
		}
		_pool = Math.Max(0L, Math.Min(4294967295L, _pool + delta));
		Broadcast();
	}

	private static void Broadcast()
	{
		Registered.RemoveWhere((CharacterMaster m) => !Object.op_Implicit((Object)(object)m));
		foreach (CharacterMaster item in Registered)
		{
			if (item.money != _pool)
			{
				SetMoney(item, _pool);
			}
		}
	}

	private static void SetMoney(CharacterMaster master, long value)
	{
		_propagating = true;
		try
		{
			master.money = (uint)value;
		}
		finally
		{
			_propagating = false;
		}
	}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class MoneySetterPatch
{
	private static void Prefix(CharacterMaster __instance, out uint __state)
	{
		__state = __instance.money;
	}

	private static void Postfix(CharacterMaster __instance, uint __state)
	{
		if (__instance.money == __state)
		{
			return;
		}
		try
		{
			MoneySharing.OnMoneyChanged(__instance, __state);
		}
		catch (Exception arg)
		{
			Log.Error($"Shared wallet update failed: {arg}");
		}
	}
}
internal enum PersonalReason
{
	None,
	PerPlayerReward,
	Printed,
	Exchange
}
internal sealed class PersonalPickupMarker : MonoBehaviour
{
	internal PersonalReason reason;

	internal CostTypeIndex cost;

	internal string Describe()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		return PersonalDrops.Describe(reason, cost);
	}
}
internal static class PersonalDrops
{
	private readonly struct Scope
	{
		internal readonly PersonalReason Reason;

		internal readonly CostTypeIndex Cost;

		internal Scope(PersonalReason reason, CostTypeIndex cost)
		{
			//IL_0008: 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)
			Reason = reason;
			Cost = cost;
		}
	}

	private const int ReasonShift = 14;

	private const int ReasonMask = 49152;

	private const int CostShift = 16;

	private const int CostMask = 4128768;

	private static readonly List<Scope> Scopes = new List<Scope>();

	private static readonly (string type, string method)[] PerPlayerRewardSources = new(string, string)[12]
	{
		("RoR2.ArenaMissionController", "EndRound"),
		("RoR2.InfiniteTowerWaveController", "DropRewards"),
		("RoR2.HalcyoniteShrineInteractable", "DropRewards"),
		("EntityStates.VoidCamp.Deactivate", "OnEnter"),
		("EntityStates.AurelioniteHeart.AurelioniteHeartActivationState", "FixedUpdate"),
		("EntityStates.Geode.GeodeShatter", "OnEnter"),
		("EntityStates.Missions.GeodeSecretMission.GeodeSecretMissionRewardState", "DropRewards"),
		("EntityStates.FalseSonBoss.SkyJumpDeathState", "GiveColossusItem"),
		("EntityStates.SolusHeart.Death.SolusHeartFinaleSequence+Death", "OnEnter"),
		("EntityStates.Missions.ProvidenceBossEncounter.EncounterFinished", "CreatePotentialServer"),
		("EntityStates.Reaper.DeathState", "DropCursedItems"),
		("EntityStates.Wake.Deactivate", "OnEnter")
	};

	internal static bool InScope => Scopes.Count > 0;

	internal static void Enter(PersonalReason reason, CostTypeIndex cost = (CostTypeIndex)0)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		Scopes.Add(new Scope(reason, cost));
	}

	internal static void Exit()
	{
		if (Scopes.Count > 0)
		{
			Scopes.RemoveAt(Scopes.Count - 1);
		}
	}

	internal static void ScopeFinalizer(bool __state)
	{
		if (__state)
		{
			Exit();
		}
	}

	internal static PickupArtifactFlag Encode(PickupArtifactFlag flags)
	{
		//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_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: 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)
		if (!InScope)
		{
			return flags;
		}
		Scope scope = Scopes[Scopes.Count - 1];
		return (PickupArtifactFlag)((flags & -4177921) | (((int)scope.Reason << 14) & 0xC000) | ((scope.Cost << 16) & 0x3F0000));
	}

	internal static bool TryDecode(PickupArtifactFlag flags, out PersonalReason reason, out CostTypeIndex cost)
	{
		//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)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected I4, but got Unknown
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected I4, but got Unknown
		reason = (PersonalReason)((flags & 0xC000) >> 14);
		cost = (CostTypeIndex)((flags & 0x3F0000) >> 16);
		return reason != PersonalReason.None;
	}

	internal static PersonalPickupMarker MarkerOf(Component component)
	{
		if (!Object.op_Implicit((Object)(object)component))
		{
			return null;
		}
		return component.GetComponent<PersonalPickupMarker>();
	}

	internal static bool IsPersonal(Component component)
	{
		return Object.op_Implicit((Object)(object)MarkerOf(component));
	}

	internal static void Mark(GameObject gameObject, PersonalReason reason, CostTypeIndex cost)
	{
		//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)
		if (Object.op_Implicit((Object)(object)gameObject) && reason != PersonalReason.None && !Object.op_Implicit((Object)(object)gameObject.GetComponent<PersonalPickupMarker>()))
		{
			PersonalPickupMarker personalPickupMarker = gameObject.AddComponent<PersonalPickupMarker>();
			personalPickupMarker.reason = reason;
			personalPickupMarker.cost = cost;
		}
	}

	internal static void MarkFromScope(GameObject gameObject)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		if (InScope)
		{
			Scope scope = Scopes[Scopes.Count - 1];
			Mark(gameObject, scope.Reason, scope.Cost);
		}
	}

	internal static string Describe(PersonalReason reason, CostTypeIndex cost)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		return reason switch
		{
			PersonalReason.PerPlayerReward => "everyone gets their own copy of this reward", 
			PersonalReason.Printed => "printed items stay with whoever paid for them", 
			PersonalReason.Exchange => "it was paid for with " + CostName(cost) + ", so it stays with the buyer", 
			_ => "it belongs to one player", 
		};
	}

	private static string CostName(CostTypeIndex cost)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Expected I4, but got Unknown
		switch (cost - 2)
		{
		case 2:
		case 3:
		case 4:
		case 8:
			return "items";
		case 7:
			return "lunar items";
		case 5:
			return "equipment";
		case 1:
			return "lunar coins";
		case 12:
			return "void coins";
		case 0:
			return "health";
		case 9:
		case 10:
		case 11:
			return "a key";
		case 13:
		case 15:
			return "souls";
		case 16:
			return "a hex";
		default:
			return "a personal cost";
		}
	}

	internal static int ApplyRewardScopes(Harmony harmony)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		Assembly assembly = typeof(Run).Assembly;
		HarmonyMethod val = new HarmonyMethod(typeof(PersonalDrops), "RewardScopePrefix", (Type[])null);
		HarmonyMethod val2 = new HarmonyMethod(typeof(PersonalDrops), "ScopeFinalizer", (Type[])null);
		int num = 0;
		(string, string)[] perPlayerRewardSources = PerPlayerRewardSources;
		for (int i = 0; i < perPlayerRewardSources.Length; i++)
		{
			var (text, text2) = perPlayerRewardSources[i];
			try
			{
				Type type = assembly.GetType(text, throwOnError: false);
				MethodInfo methodInfo = ((type == null) ? null : AccessTools.DeclaredMethod(type, text2, (Type[])null, (Type[])null));
				if (methodInfo == null)
				{
					Log.Warning("Per-player reward source " + text + "." + text2 + " not found in this game version; its rewards will be shared normally.");
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null);
					num++;
				}
			}
			catch (Exception arg)
			{
				Log.Error($"Failed to patch {text}.{text2}: {arg}");
			}
		}
		return num;
	}

	private static void RewardScopePrefix(out bool __state)
	{
		__state = ShareRules.Active && ModConfig.PersonalPerPlayerRewards.Value;
		if (__state)
		{
			Enter(PersonalReason.PerPlayerReward, (CostTypeIndex)0);
		}
	}

	internal static bool IsPaidWithPersonalResources(CostTypeIndex costType)
	{
		//IL_0000: 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_0005: Invalid comparison between Unknown and I4
		if ((int)costType != 0)
		{
			return (int)costType != 1;
		}
		return false;
	}
}
[HarmonyPatch(typeof(PickupDropletController), "CreatePickupDroplet", new Type[]
{
	typeof(CreatePickupInfo),
	typeof(Vector3),
	typeof(Vector3)
})]
internal static class PersonalDropletCreatePatch
{
	private static void Prefix(ref CreatePickupInfo pickupInfo)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		if (PersonalDrops.InScope)
		{
			pickupInfo.artifactFlag = PersonalDrops.Encode(pickupInfo.artifactFlag);
		}
	}
}
[HarmonyPatch(typeof(PickupDropletController), "CreatePickup")]
internal static class PersonalDropletLandPatch
{
	private static readonly FieldRef<PickupDropletController, CreatePickupInfo> CreatePickupInfoRef = AccessTools.FieldRefAccess<PickupDropletController, CreatePickupInfo>("createPickupInfo");

	private static void Prefix(PickupDropletController __instance, out bool __state)
	{
		//IL_000c: 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)
		__state = PersonalDrops.TryDecode(CreatePickupInfoRef.Invoke(__instance).artifactFlag, out var reason, out var cost);
		if (__state)
		{
			PersonalDrops.Enter(reason, cost);
		}
	}

	private static void Finalizer(bool __state)
	{
		PersonalDrops.ScopeFinalizer(__state);
	}
}
[HarmonyPatch(typeof(GenericPickupController), "CreatePickup")]
internal static class PersonalPickupCreatePatch
{
	private static void Postfix(ref CreatePickupInfo createPickupInfo, GenericPickupController __result)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)__result))
		{
			if (PersonalDrops.TryDecode(createPickupInfo.artifactFlag, out var reason, out var cost))
			{
				PersonalDrops.Mark(((Component)__result).gameObject, reason, cost);
			}
			else
			{
				PersonalDrops.MarkFromScope(((Component)__result).gameObject);
			}
		}
	}
}
[HarmonyPatch(typeof(PickupPickerController), "SetOptionsFromPickupForCommandArtifact", new Type[] { typeof(UniquePickup) })]
internal static class PersonalCommandCubePatch
{
	private static void Postfix(PickupPickerController __instance)
	{
		PersonalDrops.MarkFromScope(((Component)__instance).gameObject);
	}
}
[HarmonyPatch(typeof(PickupPickerController), "CreatePickup", new Type[] { typeof(UniquePickup) })]
internal static class PersonalPotentialChoicePatch
{
	private static void Prefix(PickupPickerController __instance, out bool __state)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		PersonalPickupMarker personalPickupMarker = PersonalDrops.MarkerOf((Component)(object)__instance);
		__state = Object.op_Implicit((Object)(object)personalPickupMarker);
		if (__state)
		{
			PersonalDrops.Enter(personalPickupMarker.reason, personalPickupMarker.cost);
		}
	}

	private static void Finalizer(bool __state)
	{
		PersonalDrops.ScopeFinalizer(__state);
	}
}
[HarmonyPatch(typeof(ShopTerminalBehavior), "DropPickup", new Type[] { typeof(bool) })]
internal static class PersonalShopTerminalPatch
{
	private static void Prefix(ShopTerminalBehavior __instance, bool isDuplicated, out bool __state)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		__state = false;
		if (ShareRules.Active && ModConfig.PersonalExchanges.Value)
		{
			PurchaseInteraction component = ((Component)__instance).GetComponent<PurchaseInteraction>();
			CostTypeIndex val = (CostTypeIndex)(Object.op_Implicit((Object)(object)component) ? ((int)component.costType) : 0);
			if (isDuplicated)
			{
				__state = true;
				PersonalDrops.Enter(PersonalReason.Printed, val);
			}
			else if (PersonalDrops.IsPaidWithPersonalResources(val))
			{
				__state = true;
				PersonalDrops.Enter(PersonalReason.Exchange, val);
			}
		}
	}

	private static void Finalizer(bool __state)
	{
		PersonalDrops.ScopeFinalizer(__state);
	}
}
[HarmonyPatch(typeof(BaseCreatePickupDroplet), "SpawnPickupsServer")]
internal static class PersonalBaseDropletPatch
{
	private static void Prefix(BaseCreatePickupDroplet __instance, out bool __state)
	{
		__state = ShareRules.Active && ModConfig.PersonalPerPlayerRewards.Value && __instance.scaleWithPlayerCount;
		if (__state)
		{
			PersonalDrops.Enter(PersonalReason.PerPlayerReward, (CostTypeIndex)0);
		}
	}

	private static void Finalizer(bool __state)
	{
		PersonalDrops.ScopeFinalizer(__state);
	}
}
internal static class PickupNotifier
{
	private sealed class SharedPickupMessage : MessageBase
	{
		public GameObject masterGameObject;

		public UniquePickup pickupState;

		public override void Serialize(NetworkWriter writer)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			writer.Write(masterGameObject);
			GeneratedNetworkCode._WriteUniquePickup_None(writer, pickupState);
		}

		public override void Deserialize(NetworkReader reader)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			masterGameObject = reader.ReadGameObject();
			pickupState = GeneratedNetworkCode._ReadUniquePickup_None(reader);
		}
	}

	internal const short SharedPickupMessageId = 10351;

	private static GameObject _orbEffectPrefab;

	private static bool _orbEffectLoadAttempted;

	internal static void RegisterClientHandler(NetworkClient client)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		client.RegisterHandler((short)10351, new NetworkMessageDelegate(HandleSharedPickup));
	}

	private static void HandleSharedPickup(NetworkMessage netMsg)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		SharedPickupMessage sharedPickupMessage = netMsg.ReadMessage<SharedPickupMessage>();
		CharacterMaster val = (Object.op_Implicit((Object)(object)sharedPickupMessage.masterGameObject) ? sharedPickupMessage.masterGameObject.GetComponent<CharacterMaster>() : null);
		if (Object.op_Implicit((Object)(object)val))
		{
			ShowLocally(val, sharedPickupMessage.pickupState);
		}
	}

	private static void ShowLocally(CharacterMaster master, UniquePickup pickup)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		PickupDef pickupDef = PickupCatalog.GetPickupDef(pickup.pickupIndex);
		if (pickupDef == null)
		{
			return;
		}
		ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
		if (!Object.op_Implicit((Object)(object)itemDef) || !itemDef.hidden)
		{
			CharacterMasterNotificationQueue.PushPickupNotification(master, pickup);
			CharacterBody body = master.GetBody();
			if (Object.op_Implicit((Object)(object)body))
			{
				Util.PlaySound("Play_UI_item_pickup", ((Component)body).gameObject);
			}
		}
	}

	internal static void NotifyRecipient(CharacterMaster recipient, UniquePickup pickup)
	{
		//IL_0043: 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_0023: Unknown result type (might be due to invalid IL or missing references)
		NetworkUser val = UserOf(recipient);
		if (!Object.op_Implicit((Object)(object)val))
		{
			return;
		}
		NetworkConnection connectionToClient = ((NetworkBehaviour)val).connectionToClient;
		if (connectionToClient == null)
		{
			if (((NetworkBehaviour)val).isLocalPlayer)
			{
				ShowLocally(recipient, pickup);
			}
			return;
		}
		try
		{
			connectionToClient.SendByChannel((short)10351, (MessageBase)(object)new SharedPickupMessage
			{
				masterGameObject = ((Component)recipient).gameObject,
				pickupState = pickup
			}, QosChannelIndex.chat.intVal);
		}
		catch (Exception ex)
		{
			Log.Debug("Could not notify " + ((Object)recipient).name + ": " + ex.Message);
		}
	}

	internal static void ShowOrb(Vector3 origin, CharacterMaster recipient, ItemIndex itemIndex)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Invalid comparison between Unknown and I4
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: 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)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Expected I4, but got Unknown
		//IL_007b: Expected O, but got Unknown
		if (!ModConfig.ShowShareOrbs.Value || (int)itemIndex == -1)
		{
			return;
		}
		CharacterBody body = recipient.GetBody();
		if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.mainHurtBox))
		{
			if (!_orbEffectLoadAttempted)
			{
				_orbEffectLoadAttempted = true;
				_orbEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OrbEffects/ItemTransferOrbEffect");
			}
			if (Object.op_Implicit((Object)(object)_orbEffectPrefab))
			{
				EffectData val = new EffectData
				{
					origin = origin,
					genericFloat = 0.6f,
					genericUInt = Util.IntToUintPlusOne((int)itemIndex)
				};
				val.SetHurtBoxReference(body.mainHurtBox);
				EffectManager.SpawnEffect(_orbEffectPrefab, val, true);
			}
		}
	}

	internal static NetworkUser UserOf(CharacterMaster master)
	{
		if (!Object.op_Implicit((Object)(object)master) || !Object.op_Implicit((Object)(object)master.playerCharacterMasterController))
		{
			return null;
		}
		return master.playerCharacterMasterController.networkUser;
	}
}
internal static class RiskOfOptionsCompat
{
	[MethodImpl(MethodImplOptions.NoInlining)]
	internal static void Register()
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Expected O, but got Unknown
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: 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_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Expected O, but got Unknown
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Expected O, but got Unknown
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Expected O, but got Unknown
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Expected O, but got Unknown
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Expected O, but got Unknown
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Expected O, but got Unknown
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Expected O, but got Unknown
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Expected O, but got Unknown
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Expected O, but got Unknown
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Expected O, but got Unknown
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Expected O, but got Unknown
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Expected O, but got Unknown
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Expected O, but got Unknown
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Expected O, but got Unknown
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Expected O, but got Unknown
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Expected O, but got Unknown
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Expected O, but got Unknown
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Expected O, but got Unknown
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: Expected O, but got Unknown
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f6: Expected O, but got Unknown
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Expected O, but got Unknown
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0216: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Expected O, but got Unknown
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0227: Expected O, but got Unknown
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Expected O, but got Unknown
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0245: Expected O, but got Unknown
		//IL_024a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Expected O, but got Unknown
		//IL_0259: Unknown result type (might be due to invalid IL or missing references)
		//IL_0263: Expected O, but got Unknown
		//IL_0268: Unknown result type (might be due to invalid IL or missing references)
		//IL_0272: Expected O, but got Unknown
		ModSettingsManager.SetModDescription("Shares items and gold between all players while keeping chest counts, boss drops and per-player rewards balanced. Every player needs the mod; the host's settings apply.", "com.synt.sharedspoils", "SharedSpoils");
		Sprite val = LoadIcon();
		if (Object.op_Implicit((Object)(object)val))
		{
			ModSettingsManager.SetModIcon(val, "com.synt.sharedspoils", "SharedSpoils");
		}
		Add((BaseOption)new CheckBoxOption(ModConfig.Enabled));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareWhite));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareGreen));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareRed));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareBoss));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareLunar));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareVoid));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareFood));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareOtherTiers));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareTemporaryItems));
		Add((BaseOption)new CheckBoxOption(ModConfig.DeadPlayersGetItems));
		Add((BaseOption)new StringInputFieldOption(ModConfig.ItemBlacklist, new InputFieldConfig
		{
			submitOn = (SubmitEnum)6
		}));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShowShareOrbs));
		Add((BaseOption)new CheckBoxOption(ModConfig.PickupChatMessages));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareEquipment));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareLunarEquipment));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareEliteAspects));
		Add((BaseOption)new StringInputFieldOption(ModConfig.EquipmentBlacklist, new InputFieldConfig
		{
			submitOn = (SubmitEnum)6
		}));
		Add((BaseOption)new CheckBoxOption(ModConfig.ShareMoney));
		Add((BaseOption)new StepSliderOption(ModConfig.MoneyScalar, new StepSliderConfig
		{
			min = 0.1f,
			max = 5f,
			increment = 0.05f,
			formatString = "{0:0.00}x"
		}));
		Add((BaseOption)new ChoiceOption((ConfigEntryBase)(object)ModConfig.InteractableMode));
		Add((BaseOption)new StepSliderOption(ModConfig.InteractableMultiplier, new StepSliderConfig
		{
			min = 0.25f,
			max = 4f,
			increment = 0.05f,
			formatString = "{0:0.00}x"
		}));
		Add((BaseOption)new CheckBoxOption(ModConfig.ScaleBossLoot));
		Add((BaseOption)new IntSliderOption(ModConfig.BossLootCredit, new IntSliderConfig
		{
			min = 1,
			max = 8
		}));
		Add((BaseOption)new CheckBoxOption(ModConfig.PersonalPerPlayerRewards));
		Add((BaseOption)new CheckBoxOption(ModConfig.PersonalExchanges));
		Add((BaseOption)new CheckBoxOption(ModConfig.ScaleScavengerBags));
		Add((BaseOption)new CheckBoxOption(ModConfig.ScaleSacrificeDrops));
		Add((BaseOption)new CheckBoxOption(ModConfig.VerboseLogging));
	}

	private static void Add(BaseOption option)
	{
		ModSettingsManager.AddOption(option, "com.synt.sharedspoils", "SharedSpoils");
	}

	private static Sprite LoadIcon()
	{
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Expected O, but got Unknown
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		using Stream stream = typeof(RiskOfOptionsCompat).Assembly.GetManifestResourceStream("SharedSpoils.icon.png");
		if (stream == null)
		{
			Log.Warning("Embedded icon not found; the Mod Options page will show a default icon.");
			return null;
		}
		byte[] array = new byte[stream.Length];
		int num;
		for (int i = 0; i < array.Length; i += num)
		{
			num = stream.Read(array, i, array.Length - i);
			if (num <= 0)
			{
				break;
			}
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
		if (!ImageConversion.LoadImage(val, array))
		{
			Log.Warning("Could not decode the embedded icon; the Mod Options page will show a default icon.");
			return null;
		}
		((Object)val).name = "SharedSpoilsIcon";
		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 ShareChat
{
	private static bool ShouldReport
	{
		get
		{
			if (ModConfig.PickupChatMessages.Value)
			{
				return ShareRules.PlayerCount > 1;
			}
			return false;
		}
	}

	internal static void Shared(CharacterMaster picker, PickupDef def, List<CharacterMaster> receivers, List<SkippedPlayer> skipped)
	{
		if (!ShouldReport || def == null)
		{
			return;
		}
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append(Subject(picker, def));
		if (receivers.Count > 0)
		{
			stringBuilder.Append(" was <style=cIsHealing>shared</style> with ").Append(JoinNames(receivers)).Append('.');
			if (skipped.Count > 0)
			{
				stringBuilder.Append(" Not given to ").Append(JoinSkipped(skipped)).Append('.');
			}
		}
		else
		{
			stringBuilder.Append(" was <style=cDeath>not shared</style>: no teammate could take it");
			if (skipped.Count > 0)
			{
				stringBuilder.Append(" (").Append(JoinSkipped(skipped)).Append(')');
			}
			stringBuilder.Append('.');
		}
		Send(stringBuilder.ToString());
	}

	internal static void NotShared(CharacterMaster picker, PickupDef def, string reason)
	{
		if (ShouldReport && def != null)
		{
			Send(Subject(picker, def) + " was <style=cDeath>not shared</style>: " + reason + ".");
		}
	}

	private static string Subject(CharacterMaster picker, PickupDef def)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		string text = RawPlayerName(picker);
		string text2 = Util.EscapeRichTextForTextMeshPro(text) + (text.EndsWith("s") ? "'" : "'s");
		string text3 = ColorUtility.ToHtmlStringRGB(def.baseColor);
		return text2 + " <color=#" + text3 + ">" + Language.GetString(def.nameToken) + "</color>";
	}

	private static string RawPlayerName(CharacterMaster master)
	{
		NetworkUser val = PickupNotifier.UserOf(master);
		if (!Object.op_Implicit((Object)(object)val) || string.IsNullOrEmpty(val.userName))
		{
			return "A player";
		}
		return val.userName;
	}

	internal static string PlayerName(CharacterMaster master)
	{
		return Util.EscapeRichTextForTextMeshPro(RawPlayerName(master));
	}

	private static string JoinNames(List<CharacterMaster> masters)
	{
		List<string> list = new List<string>(masters.Count);
		foreach (CharacterMaster master in masters)
		{
			list.Add(PlayerName(master));
		}
		return JoinList(list);
	}

	private static string JoinSkipped(List<SkippedPlayer> skipped)
	{
		List<string> list = new List<string>(skipped.Count);
		foreach (SkippedPlayer item in skipped)
		{
			list.Add(PlayerName(item.Master) + " (" + item.Reason + ")");
		}
		return JoinList(list);
	}

	private static string JoinList(List<string> parts)
	{
		return parts.Count switch
		{
			0 => "", 
			1 => parts[0], 
			2 => parts[0] + " and " + parts[1], 
			_ => string.Join(", ", parts.GetRange(0, parts.Count - 1)) + " and " + parts[parts.Count - 1], 
		};
	}

	private static void Send(string text)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
		{
			baseToken = text
		});
	}
}
[BepInPlugin("com.synt.sharedspoils", "SharedSpoils", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class SharedSpoilsPlugin : BaseUnityPlugin
{
	public const string Guid = "com.synt.sharedspoils";

	public const string Name = "SharedSpoils";

	public const string Version = "1.0.0";

	private const string RiskOfOptionsGuid = "com.rune580.riskofoptions";

	private static readonly string[] ConflictingMods = new string[2] { "com.funkfrog_sipondo.sharesuite", "com.tiagoferreira.sharedspoils" };

	private Harmony _harmony;

	private int _patchFailures;

	private void Awake()
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		Log.Init(((BaseUnityPlugin)this).Logger);
		ModConfig.Bind(((BaseUnityPlugin)this).Config);
		_harmony = new Harmony("com.synt.sharedspoils");
		int num = 0;
		Type[] array = new Type[15]
		{
			typeof(GenericPickupGrantPatch),
			typeof(PickerDirectGrantPatch),
			typeof(EquipmentPaymentPatch),
			typeof(MoneySetterPatch),
			typeof(PersonalDropletCreatePatch),
			typeof(PersonalDropletLandPatch),
			typeof(PersonalPickupCreatePatch),
			typeof(PersonalCommandCubePatch),
			typeof(PersonalPotentialChoicePatch),
			typeof(PersonalShopTerminalPatch),
			typeof(PersonalBaseDropletPatch),
			typeof(BossLootPatch),
			typeof(ScavengerBagPatch),
			typeof(SacrificeScopePatch),
			typeof(SacrificeDropChancePatch)
		};
		foreach (Type patchClass in array)
		{
			num += (PatchSafely(patchClass) ? 1 : 0);
		}
		int num2 = PersonalDrops.ApplyRewardScopes(_harmony);
		SceneDirector.onPrePopulateSceneServer += Balance.OnPrePopulateScene;
		RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(ShareRules.OnCatalogsReady));
		RoR2Application.onFixedUpdate += MoneySharing.Tick;
		NetworkManagerSystem.onStartClientGlobal += PickupNotifier.RegisterClientHandler;
		ModConfig.ItemBlacklist.SettingChanged += delegate
		{
			ShareRules.Rebuild();
		};
		ModConfig.EquipmentBlacklist.SettingChanged += delegate
		{
			ShareRules.Rebuild();
		};
		ModConfig.ShareMoney.SettingChanged += delegate
		{
			MoneySharing.OnToggled();
		};
		ModConfig.Enabled.SettingChanged += delegate
		{
			MoneySharing.OnToggled();
		};
		if (Chainloader.PluginInfos.TryGetValue("com.rune580.riskofoptions", out var value) && Object.op_Implicit((Object)(object)value.Instance))
		{
			RegisterRiskOfOptions();
		}
		string text = string.Format("{0} {1} loaded: {2} patch groups, {3} per-player reward sources.", "SharedSpoils", "1.0.0", num, num2);
		if (_patchFailures > 0)
		{
			Log.Error(text + $" {_patchFailures} patch group(s) FAILED, see errors above. The matching feature is disabled.");
		}
		else
		{
			Log.Info(text);
		}
	}

	private void Start()
	{
		string[] conflictingMods = ConflictingMods;
		foreach (string key in conflictingMods)
		{
			if (Chainloader.PluginInfos.TryGetValue(key, out var value))
			{
				Log.Error($"{value.Metadata.Name} {value.Metadata.Version} is also installed. Both mods would share every item twice, " + "so SharedSpoils stays inactive this session. Disable one of them in your mod manager.");
				ModConfig.ConflictDetected = true;
			}
		}
	}

	private static void RegisterRiskOfOptions()
	{
		try
		{
			typeof(SharedSpoilsPlugin).Assembly.GetType("SharedSpoils.RiskOfOptionsCompat", throwOnError: true).GetMethod("Register", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null);
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex is TargetInvocationException { InnerException: not null } ex3) ? ex3.InnerException : ex);
			Log.Warning("Risk Of Options is installed but the settings page could not be added (the config file still works): " + ex2.Message);
		}
	}

	private bool PatchSafely(Type patchClass)
	{
		try
		{
			_harmony.CreateClassProcessor(patchClass).Patch();
			return true;
		}
		catch (Exception arg)
		{
			_patchFailures++;
			Log.Error($"Could not apply {patchClass.Name} (the game code it targets probably changed): {arg}");
			return false;
		}
	}
}
internal readonly struct ShareDecision
{
	internal readonly bool Share;

	internal readonly string Reason;

	internal static readonly ShareDecision Yes = new ShareDecision(share: true, null);

	private ShareDecision(bool share, string reason)
	{
		Share = share;
		Reason = reason;
	}

	internal static ShareDecision No(string reason)
	{
		return new ShareDecision(share: false, reason);
	}
}
internal readonly struct SkippedPlayer
{
	internal readonly CharacterMaster Master;

	internal readonly string Reason;

	internal SkippedPlayer(CharacterMaster master, string reason)
	{
		Master = master;
		Reason = reason;
	}
}
internal static class ShareRules
{
	private static readonly HashSet<ItemIndex> BlacklistedItems = new HashSet<ItemIndex>();

	private static readonly HashSet<EquipmentIndex> BlacklistedEquipment = new HashSet<EquipmentIndex>();

	private static bool _catalogsReady;

	private static readonly Dictionary<string, string> BlacklistReasons = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		["TitanGoldDuringTP"] = "its effect already adds up across the whole team",
		["TPHealingNova"] = "its effect already adds up across the whole team",
		["BlightZone"] = "its effect already adds up across the whole team",
		["TreasureCache"] = "every copy would spawn an extra chest each stage",
		["TreasureCacheVoid"] = "every copy would spawn an extra chest each stage",
		["FreeChest"] = "every copy would spawn an extra chest each stage",
		["OnLevelUpFreeUnlock"] = "it raises prices for the whole team",
		["ItemDropChanceOnKill"] = "it makes enemies drop extra items",
		["BarrageOnBoss"] = "it pays out extra gold",
		["BeetleGland"] = "every copy would summon more allies",
		["RoboBallBuddy"] = "every copy would summon more allies",
		["MinorConstructOnKill"] = "every copy would summon more allies",
		["LowerPricedChests"] = "it is a one-use discount",
		["ArtifactKey"] = "objective items are never shared",
		["PowerCube"] = "objective items are never shared",
		["PowerPyramid"] = "objective items are never shared",
		["CookedSteak"] = "food items are not shared",
		["Stew"] = "food items are not shared",
		["UltimateMeal"] = "food items are not shared"
	};

	internal static bool Active
	{
		get
		{
			if (ModConfig.IsOn && NetworkServer.active)
			{
				return Object.op_Implicit((Object)(object)Run.instance);
			}
			return false;
		}
	}

	internal static int PlayerCount => PlayerCharacterMasterController.instances.Count;

	internal static void OnCatalogsReady()
	{
		_catalogsReady = true;
		Rebuild();
	}

	internal static void Rebuild()
	{
		//IL_0031: 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_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Invalid comparison between Unknown and I4
		//IL_0057: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Invalid comparison between Unknown and I4
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		if (!_catalogsReady)
		{
			return;
		}
		BlacklistedItems.Clear();
		foreach (string item in Split(ModConfig.ItemBlacklist.Value))
		{
			ItemIndex val = ItemCatalog.FindItemIndex(item);
			if ((int)val == -1)
			{
				Log.Warning("ItemBlacklist: no item named '" + item + "' in this game version, ignoring it.");
			}
			else
			{
				BlacklistedItems.Add(val);
			}
		}
		BlacklistedEquipment.Clear();
		foreach (string item2 in Split(ModConfig.EquipmentBlacklist.Value))
		{
			EquipmentIndex val2 = EquipmentCatalog.FindEquipmentIndex(item2);
			if ((int)val2 == -1)
			{
				Log.Warning("EquipmentBlacklist: no equipment named '" + item2 + "' in this game version, ignoring it.");
			}
			else
			{
				BlacklistedEquipment.Add(val2);
			}
		}
		Log.Info($"Share rules ready: {BlacklistedItems.Count} blacklisted items, {BlacklistedEquipment.Count} blacklisted equipment.");
	}

	private static IEnumerable<string> Split(string list)
	{
		if (string.IsNullOrEmpty(list))
		{
			yield break;
		}
		string[] array = list.Split(new char[3] { ',', ';', '\n' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length > 0)
			{
				yield return text;
			}
		}
	}

	internal static bool IsPickupShareable(in UniquePickup pickup)
	{
		return EvaluatePickup(in pickup).Share;
	}

	internal static bool IsEquipmentShareable(EquipmentIndex equipmentIndex)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		return EvaluateEquipment(equipmentIndex).Share;
	}

	internal static ShareDecision EvaluatePickup(in UniquePickup pickup)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Invalid comparison between Unknown and I4
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		if (!((UniquePickup)(ref pickup)).isValid)
		{
			return ShareDecision.No("it is not a valid pickup");
		}
		if (!ModConfig.ShareTemporaryItems.Value)
		{
			if (((UniquePickup)(ref pickup)).isTempItem)
			{
				return ShareDecision.No("temporary items are not shared");
			}
			if (pickup.isRental)
			{
				return ShareDecision.No("rented items are not shared");
			}
		}
		PickupDef pickupDef = PickupCatalog.GetPickupDef(pickup.pickupIndex);
		if (pickupDef == null || (int)pickupDef.itemIndex == -1)
		{
			return ShareDecision.No("only items are shared");
		}
		return EvaluateItem(pickupDef.itemIndex);
	}

	internal static ShareDecision EvaluateItem(ItemIndex itemIndex)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Expected I4, but got Unknown
		ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
		if (!Object.op_Implicit((Object)(object)itemDef))
		{
			return ShareDecision.No("it is not a valid item");
		}
		if (itemDef.hidden)
		{
			return ShareDecision.No("hidden items are not shared");
		}
		if (itemDef.ContainsTag((ItemTag)10))
		{
			return ShareDecision.No("scrap is never shared");
		}
		if (itemDef.ContainsTag((ItemTag)32) || itemDef.ContainsTag((ItemTag)26))
		{
			return ShareDecision.No("objective items are never shared");
		}
		if (Object.op_Implicit((Object)(object)Items.Junk) && itemIndex == Items.Junk.itemIndex)
		{
			return ShareDecision.No("only the Drifter can use junk");
		}
		string value;
		if (BlacklistedItems.Contains(itemIndex))
		{
			return ShareDecision.No(BlacklistReasons.TryGetValue(((Object)itemDef).name, out value) ? value : "it is on the item blacklist");
		}
		ItemTier tier = itemDef.tier;
		switch ((int)tier)
		{
		case 0:
			return TierRule(ModConfig.ShareWhite.Value, "white");
		case 1:
			return TierRule(ModConfig.ShareGreen.Value, "green");
		case 2:
			return TierRule(ModConfig.ShareRed.Value, "red");
		case 4:
			return TierRule(ModConfig.ShareBoss.Value, "boss");
		case 3:
			return TierRule(ModConfig.ShareLunar.Value, "lunar");
		case 6:
		case 7:
		case 8:
		case 9:
			return TierRule(ModConfig.ShareVoid.Value, "void");
		case 10:
			return TierRule(ModConfig.ShareFood.Value, "food");
		case 11:
			return TierRule(ModConfig.ShareOtherTiers.Value, "cursed");
		case 12:
			return TierRule(ModConfig.ShareOtherTiers.Value, "page");
		case 13:
			return TierRule(ModConfig.ShareOtherTiers.Value, "hex");
		case 5:
			return TierRule(ModConfig.ShareOtherTiers.Value, "untiered");
		default:
			return TierRule(ModConfig.ShareOtherTiers.Value, "modded tier");
		}
	}

	private static ShareDecision TierRule(bool enabled, string tierName)
	{
		if (!enabled)
		{
			return ShareDecision.No(tierName + " items are not shared");
		}
		return ShareDecision.Yes;
	}

	internal static ShareDecision EvaluateEquipment(EquipmentIndex equipmentIndex)
	{
		//IL_0000: 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)
		EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
		if (!Object.op_Implicit((Object)(object)equipmentDef))
		{
			return ShareDecision.No("it is not valid equipment");
		}
		if (!ModConfig.ShareEquipment.Value)
		{
			return ShareDecision.No("equipment sharing is turned off");
		}
		if (BlacklistedEquipment.Contains(equipmentIndex))
		{
			return ShareDecision.No("it is on the equipment blacklist");
		}
		if (Object.op_Implicit((Object)(object)equipmentDef.passiveBuffDef) && equipmentDef.passiveBuffDef.isElite && !ModConfig.ShareEliteAspects.Value)
		{
			return ShareDecision.No("elite aspects are not shared");
		}
		if (equipmentDef.isLunar && !ModConfig.ShareLunarEquipment.Value)
		{
			return ShareDecision.No("lunar equipment is not shared");
		}
		return ShareDecision.Yes;
	}

	internal static ItemDef ExclusiveGroupBlocker(Inventory inventory, ItemIndex itemIndex)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		ItemGroupType mutualExclusivity = ItemGroupTypes.MutualExclusivity;
		ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
		if (!Object.op_Implicit((Object)(object)mutualExclusivity) || !Object.op_Implicit((Object)(object)itemDef))
		{
			return null;
		}
		Group val = default(Group);
		ItemDef val2 = default(ItemDef);
		if (ItemCatalog.IsPartOfGroup(itemDef, mutualExclusivity, ref val) && ((Group)(ref val)).IsCarryingItemInGroup(inventory, ref val2, itemDef))
		{
			if (!Object.op_Implicit((Object)(object)val2))
			{
				return itemDef;
			}
			return val2;
		}
		return null;
	}

	internal static List<CharacterMaster> Recipients(CharacterMaster exclude, List<SkippedPlayer> skipped)
	{
		List<CharacterMaster> list = new List<CharacterMaster>();
		foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
		{
			CharacterMaster val = (Object.op_Implicit((Object)(object)instance) ? instance.master : null);
			if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val == (Object)(object)exclude) && Object.op_Implicit((Object)(object)val.inventory))
			{
				if (!ModConfig.DeadPlayersGetItems.Value && val.IsDeadAndOutOfLivesServer())
				{
					skipped?.Add(new SkippedPlayer(val, "dead"));
				}
				else
				{
					list.Add(val);
				}
			}
		}
		return list;
	}
}