Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Budgeting v1.0.0
BudgetingPlugin.dll
Decompiled 2 days agousing 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."); } } }