Decompiled source of Budgeting v1.0.0

BudgetingPlugin.dll

Decompiled 2 days ago
using System;
using System.Collections;
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 BudgetingPlugin.Config;
using BudgetingPlugin.Core;
using BudgetingPlugin.Network;
using BudgetingPlugin.UI;
using ExitGames.Client.Photon;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Modules;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("znore")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+42a0c10c3661ea9a72e5743cbf29f87044a80c78")]
[assembly: AssemblyProduct("BudgetingPlugin")]
[assembly: AssemblyTitle("BudgetingPlugin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BudgetingPlugin
{
	[BepInPlugin("znore.Budgeting", "Budgeting", "1.0.0")]
	public class BudgetingPlugin : BaseUnityPlugin
	{
		internal static BudgetingPlugin Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			PluginConfig.Initialize(((BaseUnityPlugin)this).Config);
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		private void Update()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.RunIsShop())
			{
				BudgetWidget.Destroy();
			}
			else if (Input.GetKeyDown(PluginConfig.OpenMenuKey.Value))
			{
				BudgetSharePopup.TogglePopup();
			}
		}

		internal void Patch()
		{
			//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_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace BudgetingPlugin.UI
{
	internal static class BudgetSharePopup
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Action<int> <>9__2_2;

			public static ScrollViewBuilderDelegate <>9__2_1;

			internal void <InitPopupPage>b__2_2(int i)
			{
				SetMoneyToDrop(i);
			}

			internal RectTransform <InitPopupPage>b__2_1(Transform scrollView)
			{
				//IL_0024: 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)
				REPOButton val = MenuAPI.CreateREPOButton("DROP THE BAG", (Action)ActionSubmit, scrollView, default(Vector2));
				return ((REPOElement)val).rectTransform;
			}
		}

		private static REPOPopupPage? _page;

		private static int _moneyToDrop;

		internal static void InitPopupPage()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			_moneyToDrop = 0;
			int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
			int playerMax = BudgetingStats.Instance.getShare(actorNumber) / 1000;
			if (playerMax <= 0)
			{
				PlayerBudgetLines.SaySomethingStupid(PlayerBudgetLines.GetRandomLine(PlayerBudgetLines.LineTypes.NotEnoughMoneyToGive));
				return;
			}
			_page = MenuAPI.CreateREPOPopupPage("How much money to share?", (PresetSide)0, false, true, 1.5f);
			_page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_002d: 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)
				REPOSlider val2 = MenuAPI.CreateREPOSlider(string.Empty, string.Empty, (Action<int>)delegate(int i)
				{
					SetMoneyToDrop(i);
				}, scrollView, default(Vector2), 0, playerMax, 0, "$", "K", (BarBehavior)0);
				return ((REPOElement)val2).rectTransform;
			}, 0f, 0f);
			REPOPopupPage? page = _page;
			object obj = <>c.<>9__2_1;
			if (obj == null)
			{
				ScrollViewBuilderDelegate val = delegate(Transform scrollView)
				{
					//IL_0024: 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)
					REPOButton val2 = MenuAPI.CreateREPOButton("DROP THE BAG", (Action)ActionSubmit, scrollView, default(Vector2));
					return ((REPOElement)val2).rectTransform;
				};
				<>c.<>9__2_1 = val;
				obj = (object)val;
			}
			page.AddElementToScrollView((ScrollViewBuilderDelegate)obj, 0f, 0f);
		}

		private static void SetMoneyToDrop(int inMoney)
		{
			_moneyToDrop = inMoney;
		}

		private static void ActionSubmit()
		{
			if (_moneyToDrop <= 0)
			{
				Close();
				return;
			}
			BudgetingNetwork.Instance?.SpawnMoneyBag(_moneyToDrop * 1000);
			Close();
		}

		internal static void TogglePopup()
		{
			if (IsOpen())
			{
				Close();
			}
			else
			{
				Open();
			}
		}

		private static void Open()
		{
			InitPopupPage();
			_page.OpenPage(true);
		}

		private static void Close()
		{
			_page.ClosePage(true);
			_page = null;
		}

		private static bool IsOpen()
		{
			return _page != null;
		}
	}
	internal static class BudgetWidget
	{
		private const string TextTemplate = "Your wallet: ${0}K";

		private static readonly Vector2 PositionOffset = new Vector2(PluginConfig.WalletOffsetX.Value, PluginConfig.WalletOffsetY.Value);

		private static TextMeshProUGUI? _widgetText;

		internal static void Initialize()
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_widgetText != (Object)null)
			{
				return;
			}
			CurrencyUI instance = CurrencyUI.instance;
			if ((Object)(object)instance == (Object)null)
			{
				BudgetingPlugin.Logger.LogWarning((object)"BudgetWidget.Initialize: CurrencyUI.instance is null; widget not created.");
				return;
			}
			TextMeshProUGUI text = instance.Text;
			BudgetingPlugin.Logger.LogDebug((object)$"CurrencyUI font size: {((TMP_Text)text).fontSize}");
			if ((Object)(object)text == (Object)null)
			{
				BudgetingPlugin.Logger.LogWarning((object)"BudgetWidget.Initialize: CurrencyUI.Text is null; widget not created.");
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)text).gameObject, ((TMP_Text)text).transform.parent);
			((Object)val).name = "BudgetWidget";
			RectTransform component = ((Component)text).GetComponent<RectTransform>();
			RectTransform component2 = val.GetComponent<RectTransform>();
			component2.anchoredPosition = component.anchoredPosition + PositionOffset;
			MonoBehaviour[] components = val.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val2 in components)
			{
				if (!(val2 is TextMeshProUGUI))
				{
					((Behaviour)val2).enabled = false;
				}
			}
			_widgetText = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)_widgetText).fontSize = ((TMP_Text)text).fontSize * 0.6f;
			((Graphic)_widgetText).color = Color.yellow;
			SetValue(0);
		}

		internal static void Destroy()
		{
			if (!((Object)(object)_widgetText == (Object)null))
			{
				Object.Destroy((Object)(object)((Component)_widgetText).gameObject);
				_widgetText = null;
			}
		}

		internal static void SetValue(int amount)
		{
			amount /= 1000;
			if ((Object)(object)_widgetText == (Object)null)
			{
				BudgetingPlugin.Logger.LogWarning((object)"BudgetWidget.SetValue called before the widget was initialized.");
			}
			else
			{
				((TMP_Text)_widgetText).text = $"Your wallet: ${amount}K";
			}
		}
	}
}
namespace BudgetingPlugin.Patches
{
	[HarmonyPatch(typeof(ShopManager))]
	public static class BudgetingPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("ShopInitialize")]
		private static void ShopInitialize_Postfix(ShopManager __instance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if ((Object)(object)BudgetingNetwork.Instance == (Object)null)
			{
				GameObject val = new GameObject("BudgetingNetwork");
				Object.DontDestroyOnLoad((Object)(object)val);
				val.AddComponent<BudgetingNetwork>();
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			int num = __instance.totalCurrency * 1000;
			if (num == 0)
			{
				return;
			}
			List<PlayerAvatar> list = SemiFunc.PlayerGetList();
			BudgetingStats.Instance.setPlayers(list);
			double[] weights = GetWeights();
			Dictionary<int, int> shares = BudgetingStats.Instance.getShares();
			int num2 = 0;
			foreach (int value2 in shares.Values)
			{
				num2 += value2;
			}
			int total = num - num2;
			int[] array = BudgetDistribution.Distribute(total, weights);
			Dictionary<int, int> dictionary = new Dictionary<int, int>(list.Count);
			for (int i = 0; i < list.Count; i++)
			{
				PhotonView photonView = list[i].photonView;
				int? obj;
				if (photonView == null)
				{
					obj = null;
				}
				else
				{
					Player owner = photonView.Owner;
					obj = ((owner != null) ? new int?(owner.ActorNumber) : ((int?)null));
				}
				int num3 = obj ?? i;
				int share = BudgetingStats.Instance.getShare(num3);
				int value = share + array[i];
				dictionary[num3] = value;
				BudgetingPlugin.Logger.LogDebug((object)$"===== Player [{num3}] | Existing: {share} | Added On: {array[i]} | TotalShare : ({dictionary[num3]}) =====");
			}
			BudgetingStats.Instance.setShares(dictionary);
			BudgetingNetwork.Instance?.SendShares(dictionary);
		}

		private static double[] GetWeights()
		{
			return BudgetWeights.GetWeights(BudgetingStats.Instance.getPlayers());
		}
	}
	[HarmonyPatch(typeof(ItemAttributes))]
	public static class DiscountPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("GetValue")]
		private static void GetValue_Postfix(ItemAttributes __instance)
		{
			if (!__instance.shopItem || SemiFunc.IsNotMasterClient() || __instance.value < 10)
			{
				return;
			}
			int value = PluginConfig.ShopDiscountPercent.Value;
			if (value > 0)
			{
				int num = __instance.value * 1000;
				int num2 = num * (100 - value) / 100 / 1000;
				BudgetingPlugin.Logger.LogDebug((object)$"[BudgetingPlugin] Discounted {((Object)__instance).name} by {value}% for a resulting value of ${num2 * 1000} (from {num})");
				__instance.value = num2;
				if (GameManager.Multiplayer() && __instance.photonView.ViewID != 0)
				{
					__instance.photonView.RPC("GetValueRPC", (RpcTarget)1, new object[1] { __instance.value });
				}
			}
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint))]
	public static class ExtractionPointPatch
	{
		private static bool _purchaseMade;

		private static int _approvedCartTotal;

		[HarmonyPrefix]
		[HarmonyPatch("OnShopClick")]
		private static bool OnShopClick_Prefix(ExtractionPoint __instance)
		{
			_purchaseMade = false;
			int lastShopButtonPresserActorNumber = BudgetingNetwork.LastShopButtonPresserActorNumber;
			BudgetingPlugin.Logger.LogDebug((object)$"================== Pressed: {lastShopButtonPresserActorNumber} ==================");
			int share = BudgetingStats.Instance.getShare(lastShopButtonPresserActorNumber);
			int haulCurrent = __instance.haulCurrent;
			if (share >= haulCurrent && haulCurrent > 0)
			{
				_purchaseMade = true;
				return true;
			}
			if (haulCurrent == 0)
			{
				return true;
			}
			BudgetingNetwork.TriggerPlayerTalk(lastShopButtonPresserActorNumber);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("DestroyAllPhysObjectsInShoppingList")]
		private static bool DestroyAllPhysObjectsInShoppingList_Prefix(ExtractionPoint __instance)
		{
			if (!_purchaseMade || !__instance.isShop)
			{
				return true;
			}
			int lastShopButtonPresserActorNumber = BudgetingNetwork.LastShopButtonPresserActorNumber;
			int num = SemiFunc.ShopGetTotalCost() * 1000;
			if (BudgetingStats.Instance.getShare(lastShopButtonPresserActorNumber) < num)
			{
				_purchaseMade = false;
				ShopManager.instance.isThief = true;
				__instance.isThief = true;
				return false;
			}
			_approvedCartTotal = num;
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch("DestroyAllPhysObjectsInShoppingList")]
		private static void DestroyAllPhysObjectsInShoppingList_Postfix(ExtractionPoint __instance)
		{
			if (_purchaseMade && __instance.isShop)
			{
				int lastShopButtonPresserActorNumber = BudgetingNetwork.LastShopButtonPresserActorNumber;
				int amount = BudgetingStats.Instance.deductAmountFromPlayerShare(lastShopButtonPresserActorNumber, _approvedCartTotal);
				_purchaseMade = false;
				BudgetingNetwork.LastShopButtonPresserActorNumber = -1;
				BudgetingNetwork.TriggerMoneyDeductedEvent(lastShopButtonPresserActorNumber, amount);
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabber))]
	public class PhysGrabberPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(PhysGrabber), "StartGrabbingPhysObject")]
		private static void StartGrabbingPhysObject_Prefix(PhysGrabber __instance)
		{
			if (SemiFunc.RunIsShop())
			{
				BudgetingNetwork.NotifyShopButtonPressed();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PhysGrabber), "StartGrabbingPhysObject")]
		private static void StartGrabbingPhysObject_Postfix(PhysGrabber __instance)
		{
			PhysGrabObject grabbedPhysGrabObject = __instance.grabbedPhysGrabObject;
			if (!((Object)(object)grabbedPhysGrabObject == (Object)null))
			{
				int viewID = ((Component)grabbedPhysGrabObject).GetComponent<PhotonView>().ViewID;
				BudgetingNetwork.NotifyBagPickedUp(viewID);
			}
		}
	}
}
namespace BudgetingPlugin.Network
{
	public class BudgetingNetwork : MonoBehaviour, IInRoomCallbacks
	{
		private const string SharesKey = "BudgetShares";

		internal static readonly Dictionary<int, int> BudgetBags = new Dictionary<int, int>();

		internal static int LastShopButtonPresserActorNumber = -1;

		private static readonly Durability InvincibleDurability = CreateInvincibleDurability();

		private NetworkedEvent _spawnBagEvent = null;

		private NetworkedEvent _pickupBagEvent = null;

		private NetworkedEvent _makePlayerTalk = null;

		private NetworkedEvent _shopButtonPressedEvent = null;

		private NetworkedEvent _moneyDeductedEvent = null;

		public static BudgetingNetwork? Instance { get; private set; }

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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
			Instance = this;
			PhotonNetwork.AddCallbackTarget((object)this);
			_spawnBagEvent = new NetworkedEvent("BudgetBag_Spawn", (Action<EventData>)OnSpawnBagEvent);
			_pickupBagEvent = new NetworkedEvent("BudgetBag_Pickup", (Action<EventData>)OnPickupBagEvent);
			_makePlayerTalk = new NetworkedEvent("MakePlayerTalk", (Action<EventData>)OnMakePlayerTalk);
			_shopButtonPressedEvent = new NetworkedEvent("ShopButtonPressed", (Action<EventData>)OnShopButtonPressed);
			_moneyDeductedEvent = new NetworkedEvent("MoneyDeductedFromPlayers", (Action<EventData>)OnMoneyDeducted);
		}

		private void OnDestroy()
		{
			PhotonNetwork.RemoveCallbackTarget((object)this);
			BudgetWidget.Destroy();
			Instance = null;
		}

		public unsafe void OnRoomPropertiesUpdate(Hashtable changedProps)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//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)
			if (!((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"BudgetShares"))
			{
				return;
			}
			Hashtable val = (Hashtable)changedProps[(object)"BudgetShares"];
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			DictionaryEntryEnumerator enumerator = val.GetEnumerator();
			try
			{
				while (((DictionaryEntryEnumerator)(ref enumerator)).MoveNext())
				{
					var (obj3, obj4) = (DictionaryEntry)(ref ((DictionaryEntryEnumerator)(ref enumerator)).Current);
					dictionary[(int)obj3] = (int)obj4;
				}
			}
			finally
			{
				((IDisposable)(*(DictionaryEntryEnumerator*)(&enumerator))/*cast due to .constrained prefix*/).Dispose();
			}
			BudgetingStats.Instance.setShares(dictionary);
			int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
			if (!((Dictionary<object, object>)(object)val).ContainsKey((object)actorNumber))
			{
				BudgetingPlugin.Logger.LogWarning((object)$"No share found for player with ActorNumber {actorNumber}");
				return;
			}
			BudgetWidget.Initialize();
			BudgetWidget.SetValue((int)val[(object)actorNumber]);
		}

		public void OnPlayerEnteredRoom(Player newPlayer)
		{
		}

		public void OnPlayerLeftRoom(Player otherPlayer)
		{
		}

		public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
		{
		}

		public void OnMasterClientSwitched(Player newMasterClient)
		{
		}

		private void OnMakePlayerTalk(EventData photonEvent)
		{
			object[] array = (object[])photonEvent.CustomData;
			if (PhotonNetwork.LocalPlayer.ActorNumber == (int)array[0])
			{
				string randomLine = PlayerBudgetLines.GetRandomLine((PlayerBudgetLines.LineTypes)array[1]);
				PlayerBudgetLines.SaySomethingStupid(randomLine);
			}
		}

		private void OnMoneyDeducted(EventData photonEvent)
		{
			object[] array = (object[])photonEvent.CustomData;
			if (PhotonNetwork.LocalPlayer.ActorNumber == (int)array[0])
			{
				BudgetWidget.SetValue((int)array[1]);
			}
		}

		private void OnShopButtonPressed(EventData photonEvent)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				LastShopButtonPresserActorNumber = photonEvent.Sender;
			}
		}

		internal static void NotifyShopButtonPressed()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsMasterClient)
			{
				LastShopButtonPresserActorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
				return;
			}
			BudgetingNetwork? instance = Instance;
			if (instance != null)
			{
				instance._shopButtonPressedEvent.RaiseEvent((object)PhotonNetwork.LocalPlayer.ActorNumber, NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable);
			}
		}

		internal static void TriggerPlayerTalk(int actorNumber, PlayerBudgetLines.LineTypes lineType = PlayerBudgetLines.LineTypes.NotEnoughMoney)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			BudgetingNetwork? instance = Instance;
			if (instance != null)
			{
				instance._makePlayerTalk.RaiseEvent((object)new object[2] { actorNumber, lineType }, NetworkingEvents.RaiseAll, SendOptions.SendReliable);
			}
		}

		internal static void TriggerMoneyDeductedEvent(int actorNumber, int amount)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			BudgetingNetwork? instance = Instance;
			if (instance != null)
			{
				instance._moneyDeductedEvent.RaiseEvent((object)new object[2] { actorNumber, amount }, NetworkingEvents.RaiseAll, SendOptions.SendReliable);
			}
		}

		private void OnSpawnBagEvent(EventData photonEvent)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsMasterClient)
			{
				object[] array = (object[])photonEvent.CustomData;
				ProcessSpawnRequest(photonEvent.Sender, (int)array[0], (Vector3)array[1]);
			}
		}

		private void OnPickupBagEvent(EventData photonEvent)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				ProcessBagPickup((int)photonEvent.CustomData, photonEvent.Sender);
			}
		}

		public void SpawnMoneyBag(int amount)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0078: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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)
			if (!SemiFunc.RunIsShop())
			{
				return;
			}
			int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
			int share = BudgetingStats.Instance.getShare(actorNumber);
			if (amount > 0)
			{
				if (amount > share)
				{
					TriggerPlayerTalk(actorNumber, PlayerBudgetLines.LineTypes.NotEnoughMoneyToGive);
					return;
				}
				Transform transform = ((Component)PlayerAvatar.instance).transform;
				Vector3 val = transform.position + transform.forward * PluginConfig.BagSpawnForwardOffset.Value + transform.up * PluginConfig.BagSpawnHeightOffset.Value;
				_spawnBagEvent.RaiseEvent((object)new object[2] { amount, val }, NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable);
			}
		}

		private void ProcessSpawnRequest(int requesterActor, int amount, Vector3 spawnPos)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			int share = BudgetingStats.Instance.getShare(requesterActor);
			if (share >= amount)
			{
				SpawnBag(requesterActor, amount, spawnPos);
			}
		}

		private void SpawnBag(int ownerActor, int amount, Vector3 spawnPos)
		{
			//IL_001c: 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)
			GameObject surplusValuableSmall = AssetManager.instance.surplusValuableSmall;
			GameObject val = PhotonNetwork.InstantiateRoomObject("Valuables/" + ((Object)surplusValuableSmall).name, spawnPos, Quaternion.identity, (byte)0, (object[])null);
			val.GetComponent<ValuableObject>().dollarValueOverride = amount;
			val.GetComponent<ValuableObject>().durabilityPreset = InvincibleDurability;
			int viewID = val.GetComponent<PhotonView>().ViewID;
			BudgetBags[viewID] = amount;
			BudgetingStats.Instance.deductAmountFromPlayerShare(ownerActor, amount);
			SendShares(BudgetingStats.Instance.getShares());
		}

		private void ProcessBagPickup(int bagViewId, int pickerActor)
		{
			if (BudgetBags.TryGetValue(bagViewId, out var value))
			{
				BudgetBags.Remove(bagViewId);
				BudgetingStats.Instance.addAmountToPlayerShare(pickerActor, value);
				SendShares(BudgetingStats.Instance.getShares());
				PhotonView val = PhotonView.Find(bagViewId);
				if ((Object)(object)val != (Object)null)
				{
					PhotonNetwork.Destroy(((Component)val).gameObject);
				}
			}
		}

		internal static void NotifyBagPickedUp(int bagViewId)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.RunIsShop())
			{
				BudgetingNetwork? instance = Instance;
				if (instance != null)
				{
					instance._pickupBagEvent.RaiseEvent((object)bagViewId, NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable);
				}
			}
		}

		public void SendShares(Dictionary<int, int> shares)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_006e: 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_007f: Expected O, but got Unknown
			//IL_0087: Expected O, but got Unknown
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			Hashtable val = new Hashtable();
			foreach (var (num3, num4) in shares)
			{
				((Dictionary<object, object>)(object)val).Add((object)num3, (object)num4);
			}
			Room currentRoom = PhotonNetwork.CurrentRoom;
			Hashtable val2 = new Hashtable();
			((Dictionary<object, object>)val2).Add((object)"BudgetShares", (object)val);
			currentRoom.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null);
		}

		private static Durability CreateInvincibleDurability()
		{
			Durability val = ScriptableObject.CreateInstance<Durability>();
			val.durability = 100f;
			val.fragility = 0f;
			return val;
		}
	}
}
namespace BudgetingPlugin.Core
{
	public enum DistributionMethod
	{
		Even,
		Manual,
		Upgrades
	}
	public static class BudgetDistribution
	{
		public static int[] Distribute(int total, double[] weights)
		{
			if (weights == null || weights.Length == 0)
			{
				return Array.Empty<int>();
			}
			if (total < 0)
			{
				total = 0;
			}
			int num = weights.Length;
			double num2 = 0.0;
			for (int i = 0; i < num; i++)
			{
				num2 += Math.Max(0.0, weights[i]);
			}
			if (num2 <= 0.0)
			{
				return DistributeEven(total, num);
			}
			int[] array = new int[num];
			int num3 = 0;
			for (int j = 0; j < num; j++)
			{
				double num4 = (double)total * (Math.Max(0.0, weights[j]) / num2);
				num4 = Math.Floor(num4 / 1000.0);
				num4 *= 1000.0;
				array[j] = (int)num4;
				num3 += (int)num4;
			}
			int num5 = total - num3;
			double value = weights.Max();
			int num6 = Array.IndexOf(weights, value);
			int num7 = Array.LastIndexOf(weights, value);
			if (num6 != num7)
			{
				int num8 = array.Length;
				int num9 = 0;
				while (num5 > 0)
				{
					if (num9 >= num8)
					{
						num9 = 0;
					}
					array[num9] += 1000;
					num5 -= 1000;
					num9++;
				}
			}
			else
			{
				array[num6] += num5;
			}
			return array;
		}

		private static int[] DistributeEven(int total, int playerCount)
		{
			double[] array = new double[playerCount];
			for (int i = 0; i < playerCount; i++)
			{
				array[i] = 1.0;
			}
			return Distribute(total, array);
		}
	}
	public class BudgetingStats
	{
		private List<PlayerAvatar> _players = new List<PlayerAvatar>();

		private Dictionary<int, int> _shares = new Dictionary<int, int>();

		public static BudgetingStats Instance { get; } = new BudgetingStats();

		public int playerCount => _players.Count;

		public Dictionary<int, int> getShares()
		{
			return _shares;
		}

		public int deductAmountFromPlayerShare(int actorNumber, int amountLost)
		{
			BudgetingPlugin.Logger.LogDebug((object)$"==== deductAmountFromPlayerShare; Actor = {actorNumber}; amountLost = {amountLost};");
			if (!_shares.ContainsKey(actorNumber))
			{
				BudgetingPlugin.Logger.LogWarning((object)$"deductAmountFromPlayerShare: actor {actorNumber} not in shares, skipping deduction.");
				return 0;
			}
			int share = getShare(actorNumber);
			int num = Math.Max(0, share - amountLost);
			_shares[actorNumber] = num;
			return num;
		}

		public int addAmountToPlayerShare(int actorNumber, int amount)
		{
			if (!_shares.ContainsKey(actorNumber))
			{
				BudgetingPlugin.Logger.LogWarning((object)$"addAmountToPlayerShare: actor {actorNumber} not in shares, skipping.");
				return 0;
			}
			int num = _shares[actorNumber] + amount;
			_shares[actorNumber] = num;
			return num;
		}

		public int getShare(int actorNumber)
		{
			if (!_shares.TryGetValue(actorNumber, out var value))
			{
				BudgetingPlugin.Logger.LogWarning((object)$"getShare: no share found for actor {actorNumber}, defaulting to 0.");
				return 0;
			}
			return value;
		}

		public void setShares(Dictionary<int, int> shares)
		{
			_shares = shares;
		}

		public List<PlayerAvatar> getPlayers()
		{
			return _players;
		}

		public PlayerAvatar getPlayer(int index)
		{
			return _players[index];
		}

		public void setPlayers(List<PlayerAvatar> players)
		{
			_players = players;
		}
	}
	public static class BudgetWeights
	{
		private static int _playerCount;

		public static double[] GetWeights(List<PlayerAvatar> players)
		{
			_playerCount = players.Count;
			double[] array = new double[_playerCount];
			string value = PluginConfig.DesiredDist.Value;
			string text = value;
			if (text == "Manual")
			{
				GetWeights_Manual(array);
			}
			else
			{
				GetWeights_Even(array);
			}
			return array;
		}

		private static void GetWeights_Even(double[] weights)
		{
			Array.Fill(weights, 1.0);
		}

		private static void GetWeights_Manual(double[] weights)
		{
			weights[0] = 1.0;
			for (int i = 1; i < _playerCount; i++)
			{
				weights[i] = 0.0;
			}
		}

		private static int GetWeightPointsForGroup()
		{
			return (int)((double)(float)_playerCount * 1.5);
		}
	}
	public static class PlayerBudgetLines
	{
		public enum LineTypes
		{
			NotEnoughMoney,
			NotEnoughMoneyToGive
		}

		private static readonly Random RandomNumGenerator = new Random();

		private static readonly string[] NotEnoughMoneyLines = new string[12]
		{
			"Nope. I'm outta cash", "No moners!", "Nope, gotta pay for rent this month", "I DON'T HAVE ANY MONEEEEEEEEEEEEEEEEEEEEEY", "NOOOOOOOOOO MONNNNEEEEEEEEY", "Holla holla get $", "Job application incoming", "WHAT DO I DO, MY CREDIT CARD DECLINED", "DID I LOSE MY WALLET", "Mom would be so disappointed",
			"Yeah in retrospect all those crypto investments weren't the right move", "'Put it all on black', they said"
		};

		private static readonly string[] NotEnoughMoneyToGiveLines = new string[2] { "I don't have this much money to give out", "I should probably keep this for myself" };

		public static string GetRandomLine(LineTypes type = LineTypes.NotEnoughMoney)
		{
			string[] array = Array.Empty<string>();
			array = ((type == LineTypes.NotEnoughMoney || type != LineTypes.NotEnoughMoneyToGive) ? NotEnoughMoneyLines : NotEnoughMoneyToGiveLines);
			if (array.Length != 0)
			{
				int num = RandomNumGenerator.Next(0, array.Length);
				return array[num];
			}
			return string.Empty;
		}

		public static void SaySomethingStupid(string message)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			ChatManager.instance.PossessChatScheduleStart(10);
			ChatManager.instance.PossessChat((PossessChatID)0, message, 3f, new Color(0f, 1f, 0f), 0f, false, 0, (UnityEvent)null);
			ChatManager.instance.PossessChatScheduleEnd();
		}
	}
}
namespace BudgetingPlugin.Config
{
	public static class DistributionMethods
	{
		public const string Even = "Even";

		public const string Manual = "Manual";

		public const string Death = "Death";

		public const string DeathReverse = "Death Reverse";

		public const string KillPercent = "Kill %";

		public const string UpgradeCount = "Upgrade Count";
	}
	internal static class PluginConfig
	{
		private static readonly string[] DistributionMethodsList = new string[2] { "Even", "Manual" };

		internal static ConfigEntry<KeyCode> OpenMenuKey { get; private set; } = null;

		internal static ConfigEntry<float> BagSpawnForwardOffset { get; private set; } = null;

		internal static ConfigEntry<float> BagSpawnHeightOffset { get; private set; } = null;

		internal static ConfigEntry<int> ShopDiscountPercent { get; private set; } = null;

		internal static ConfigEntry<string> DesiredDist { get; private set; } = null;

		internal static ConfigEntry<float> WalletOffsetX { get; private set; } = null;

		internal static ConfigEntry<float> WalletOffsetY { get; private set; } = null;

		internal static void Initialize(ConfigFile config)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			OpenMenuKey = config.Bind<KeyCode>("Controls", "ShareMoneyKey", (KeyCode)52, "What key should be pressed to open the 'Share Money' pop up");
			BagSpawnForwardOffset = config.Bind<float>("BagSpawn", "ForwardOffset", 1.5f, "How far in front of the player the money bag spawns (in units).");
			BagSpawnHeightOffset = config.Bind<float>("BagSpawn", "HeightOffset", 1.5f, "How high above the player the money bag spawns (in units).");
			ShopDiscountPercent = config.Bind<int>("Game", "ShopDiscountPercent", 10, new ConfigDescription("Discount applied to all items above $10 in the shop. Caps at 30%", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 30), Array.Empty<object>()));
			DesiredDist = config.Bind<string>("Game", "DistributionMethod", "Even", new ConfigDescription("Even: Money is distributed evenly to all playersManual: Host gets all money, then distributes it with money sharing", (AcceptableValueBase)(object)new AcceptableValueList<string>(DistributionMethodsList), Array.Empty<object>()));
			WalletOffsetX = config.Bind<float>("UI", "WalletOffset_X", 0f, "Where the 'Wallet' text should be displayed during the shop phase (horizontal location). This is relative to the existing money count text.");
			WalletOffsetY = config.Bind<float>("UI", "WalletOffset_Y", -50f, "Where the 'Wallet' text should be displayed during the shop phase (vertical location). This is relative to the existing money count text.");
		}
	}
}