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 LootVote v1.1.1
plugins/LootVote.dll
Decompiled 19 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates.MealPrep; using EntityStates.Scrapper; using LootVote.Networking; using LootVote.SoftReserve; using LootVote.Ui; using Microsoft.CodeAnalysis; using On.EntityStates.MealPrep; using On.EntityStates.Scrapper; using On.RoR2; using On.RoR2.UI; using R2API.Networking; using R2API.Networking.Interfaces; using R2API.Utils; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.Artifacts; using RoR2.ContentManagement; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.UI; [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("LootVote")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+08916767ff049b814b68d74fab7ec1a247e3e264")] [assembly: AssemblyProduct("LootVote")] [assembly: AssemblyTitle("LootVote")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LootVote { internal static class ExemptionTracker { [CompilerGenerated] private static class <>O { public static hook_DropPickup_bool <0>__OnShopTerminalDropPickup; public static hook_OnEnter <1>__OnScrappingToIdleEnter; public static hook_DropItem <2>__OnMealPrepDropItem; public static hook_ItemDrop <3>__OnChestItemDrop; public static hook_CreatePickup_UniquePickup <4>__OnPickerCreatePickup; public static hook_OnEnable <5>__OnDropletEnable; public static hook_CreatePickup <6>__OnDropletCreatePickup; public static hook_CreatePickup <7>__OnCreatePickup; } private const float _exemptDropUpwardSpeed = 15f; private static ExemptReason _scope; public static void Init() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0050: 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: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown //IL_00b0: 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_00bb: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown object obj = <>O.<0>__OnShopTerminalDropPickup; if (obj == null) { hook_DropPickup_bool val = OnShopTerminalDropPickup; <>O.<0>__OnShopTerminalDropPickup = val; obj = (object)val; } ShopTerminalBehavior.DropPickup_bool += (hook_DropPickup_bool)obj; object obj2 = <>O.<1>__OnScrappingToIdleEnter; if (obj2 == null) { hook_OnEnter val2 = OnScrappingToIdleEnter; <>O.<1>__OnScrappingToIdleEnter = val2; obj2 = (object)val2; } ScrappingToIdle.OnEnter += (hook_OnEnter)obj2; object obj3 = <>O.<2>__OnMealPrepDropItem; if (obj3 == null) { hook_DropItem val3 = OnMealPrepDropItem; <>O.<2>__OnMealPrepDropItem = val3; obj3 = (object)val3; } CookingToIdle.DropItem += (hook_DropItem)obj3; object obj4 = <>O.<3>__OnChestItemDrop; if (obj4 == null) { hook_ItemDrop val4 = OnChestItemDrop; <>O.<3>__OnChestItemDrop = val4; obj4 = (object)val4; } ChestBehavior.ItemDrop += (hook_ItemDrop)obj4; object obj5 = <>O.<4>__OnPickerCreatePickup; if (obj5 == null) { hook_CreatePickup_UniquePickup val5 = OnPickerCreatePickup; <>O.<4>__OnPickerCreatePickup = val5; obj5 = (object)val5; } PickupPickerController.CreatePickup_UniquePickup += (hook_CreatePickup_UniquePickup)obj5; object obj6 = <>O.<5>__OnDropletEnable; if (obj6 == null) { hook_OnEnable val6 = OnDropletEnable; <>O.<5>__OnDropletEnable = val6; obj6 = (object)val6; } PickupDropletController.OnEnable += (hook_OnEnable)obj6; object obj7 = <>O.<6>__OnDropletCreatePickup; if (obj7 == null) { hook_CreatePickup val7 = OnDropletCreatePickup; <>O.<6>__OnDropletCreatePickup = val7; obj7 = (object)val7; } PickupDropletController.CreatePickup += (hook_CreatePickup)obj7; object obj8 = <>O.<7>__OnCreatePickup; if (obj8 == null) { hook_CreatePickup val8 = OnCreatePickup; <>O.<7>__OnCreatePickup = val8; obj8 = (object)val8; } GenericPickupController.CreatePickup += (hook_CreatePickup)obj8; } public static bool IsExempt(GenericPickupController pickupController) { ExemptMarker component = ((Component)pickupController).GetComponent<ExemptMarker>(); if (Object.op_Implicit((Object)(object)component)) { return LootVoteConfig.IsExemptionEnabled(component.Reason); } return false; } public static void Mark(GameObject gameObject, ExemptReason reason) { ExemptMarker exemptMarker = gameObject.GetComponent<ExemptMarker>(); if (!Object.op_Implicit((Object)(object)exemptMarker)) { exemptMarker = gameObject.AddComponent<ExemptMarker>(); } exemptMarker.Reason = reason; } public static void DropExempt(UniquePickup pickup, Vector3 position, ExemptReason reason) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Vector3 velocity = Vector3.up * 15f; RunInScope(reason, delegate { //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_000d: Unknown result type (might be due to invalid IL or missing references) PickupDropletController.CreatePickupDroplet(pickup, position, velocity, false); }); } private static void RunInScope(ExemptReason reason, Action action) { ExemptReason scope = _scope; _scope = reason; try { action(); } finally { _scope = scope; } } private static ExemptReason ReasonForCost(CostTypeIndex costType) { //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_0028: Expected I4, but got Unknown switch (costType - 3) { case 1: case 2: case 3: case 4: case 6: case 7: return ExemptReason.PrinterOrCauldron; case 0: return ExemptReason.LunarPurchase; default: return ExemptReason.None; } } private static void OnShopTerminalDropPickup(orig_DropPickup_bool orig, ShopTerminalBehavior self, bool isDuplicated) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) PurchaseInteraction component = ((Component)self).GetComponent<PurchaseInteraction>(); RunInScope(Object.op_Implicit((Object)(object)component) ? ReasonForCost(component.costType) : ExemptReason.None, delegate { orig.Invoke(self, isDuplicated); }); } private static void OnScrappingToIdleEnter(orig_OnEnter orig, ScrappingToIdle self) { RunInScope(ExemptReason.Scrapper, delegate { orig.Invoke(self); }); } private static void OnMealPrepDropItem(orig_DropItem orig, CookingToIdle self) { RunInScope(ExemptReason.WanderingChef, delegate { orig.Invoke(self); }); } private static void OnChestItemDrop(orig_ItemDrop orig, ChestBehavior self) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 PurchaseInteraction component = ((Component)self).GetComponent<PurchaseInteraction>(); RunInScope((Object.op_Implicit((Object)(object)component) && (int)component.costType == 3) ? ExemptReason.LunarPurchase : ExemptReason.None, delegate { orig.Invoke(self); }); } private static void OnPickerCreatePickup(orig_CreatePickup_UniquePickup orig, PickupPickerController self, UniquePickup pickup) { //IL_0015: 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) RunInScope(ExemptReason.PickerDrop, delegate { //IL_000d: Unknown result type (might be due to invalid IL or missing references) orig.Invoke(self, pickup); }); } private static void OnDropletEnable(orig_OnEnable orig, PickupDropletController self) { orig.Invoke(self); if (NetworkServer.active && _scope != ExemptReason.None) { Mark(((Component)self).gameObject, _scope); } } private static void OnDropletCreatePickup(orig_CreatePickup orig, PickupDropletController self) { ExemptMarker component = ((Component)self).GetComponent<ExemptMarker>(); RunInScope(Object.op_Implicit((Object)(object)component) ? component.Reason : _scope, delegate { orig.Invoke(self); }); } private static GenericPickupController OnCreatePickup(orig_CreatePickup orig, ref CreatePickupInfo createPickupInfo) { GenericPickupController val = orig.Invoke(ref createPickupInfo); if (Object.op_Implicit((Object)(object)val) && _scope != ExemptReason.None) { Mark(((Component)val).gameObject, _scope); } return val; } } internal class ExemptMarker : MonoBehaviour { public ExemptReason Reason; } internal enum ExemptReason { None, PrinterOrCauldron, Scrapper, LunarPurchase, PickerDrop, WanderingChef, AlreadyVoted } internal static class ItemDelivery { public static bool Delivering; public static bool Deliver(GenericPickupController pickupController, NetworkUser recipient) { if (!Object.op_Implicit((Object)(object)pickupController) || !Object.op_Implicit((Object)(object)recipient) || !Object.op_Implicit((Object)(object)recipient.master)) { return false; } CharacterMaster master = recipient.master; CharacterBody body = master.GetBody(); if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.healthComponent) || !body.healthComponent.alive) { GiveToDeadPlayer(pickupController, master); return true; } Delivering = true; try { pickupController.AttemptGrant(body); } finally { Delivering = false; } if (Object.op_Implicit((Object)(object)pickupController)) { MarkFree(pickupController); } return true; } public static void MarkFree(GenericPickupController pickupController) { ExemptionTracker.Mark(((Component)pickupController).gameObject, ExemptReason.AlreadyVoted); } private static void GiveToDeadPlayer(GenericPickupController pickupController, CharacterMaster master) { //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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_0066: Invalid comparison between Unknown and I4 //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_007a: Unknown result type (might be due to invalid IL or missing references) UniquePickup pickup = pickupController.pickup; Inventory inventory = master.inventory; PickupDef pickupDef = PickupCatalog.GetPickupDef(pickup.pickupIndex); if ((int)pickupDef.itemIndex != -1) { inventory.GiveItemPermanent(pickupDef.itemIndex, 1); } else if ((int)pickupDef.equipmentIndex != -1) { EquipmentLocationQueryArgs defaultPickup = EquipmentLocationQueryArgs.defaultPickup; EquipmentLocation val = inventory.FindBestEquipmentLocationOrCurrent(ref defaultPickup); EquipmentIndex equipmentIndex = inventory.GetEquipmentIndex(ref val); inventory.SetEquipmentIndex(pickupDef.equipmentIndex, ref val); if ((int)equipmentIndex != -1) { ExemptionTracker.DropExempt(new UniquePickup(PickupCatalog.FindPickupIndex(equipmentIndex)), ((Component)pickupController).transform.position, ExemptReason.AlreadyVoted); } } GenericPickupController.SendPickupMessage(master, pickup); Object.Destroy((Object)(object)((Component)pickupController).gameObject); } } internal static class ItemSummary { public static string Join(IReadOnlyList<string> names) { List<string> list = new List<string>(); Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (string name in names) { if (dictionary.TryGetValue(name, out var value)) { dictionary[name] = value + 1; continue; } dictionary[name] = 1; list.Add(name); } List<string> list2 = new List<string>(list.Count); foreach (string item in list) { list2.Add((dictionary[item] > 1) ? $"{item} ({dictionary[item]})" : item); } return string.Join(", ", list2); } } internal static class Log { private static ManualLogSource _logSource; public static void Init(ManualLogSource logSource) { _logSource = logSource; } public static void Debug(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) { _logSource.LogDebug((object)Format(data, file, line)); } public static void Error(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) { _logSource.LogError((object)Format(data, file, line)); } public static void Fatal(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) { _logSource.LogFatal((object)Format(data, file, line)); } public static void Info(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) { _logSource.LogInfo((object)Format(data, file, line)); } public static void Message(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) { _logSource.LogMessage((object)Format(data, file, line)); } public static void Warning(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) { _logSource.LogWarning((object)Format(data, file, line)); } private static string Format(object data, string file, int line) { string fileName = Path.GetFileName(file); return $"[{fileName}:{line}] {data}"; } } internal static class LootVoteConfig { public static ConfigEntry<bool> White; public static ConfigEntry<bool> Green; public static ConfigEntry<bool> Red; public static ConfigEntry<bool> Boss; public static ConfigEntry<bool> Lunar; public static ConfigEntry<bool> Void; public static ConfigEntry<bool> Equipment; public static ConfigEntry<bool> LunarEquipment; public static ConfigEntry<bool> OtherTiers; public static ConfigEntry<bool> ExemptPrintersAndCauldrons; public static ConfigEntry<bool> ExemptScrappers; public static ConfigEntry<bool> ExemptLunarPurchases; public static ConfigEntry<bool> ExemptPickerDrops; public static ConfigEntry<bool> ExemptWanderingChef; public static ConfigEntry<TieBreaker> TieBreak; public static ConfigEntry<int> VoteTimerSeconds; public static ConfigEntry<int> FinalCountdownSeconds; public static ConfigEntry<bool> VoidNeedsSelfVote; public static ConfigEntry<bool> LunarNeedsSelfVote; public static ConfigEntry<int> SoftReserveSlots; public static ConfigEntry<bool> SplitTeleporterDrops; public static ConfigEntry<bool> SoloTestMode; public static ConfigEntry<KeyboardShortcut> OpenVoteKey; public static ConfigEntry<bool> NumberKeyVoting; public static ConfigEntry<bool> ShowItemCounts; public static ConfigEntry<KeyboardShortcut> SkipVoteKey; public static ConfigEntry<KeyboardShortcut> DeclineKey; public const int MaxSoftReserveSlots = 10; public const int MaxVoteTimerSeconds = 300; public const int MaxFinalCountdownSeconds = 30; private const string _tiersSection = "Tiers"; private const string _exemptionsSection = "Exemptions"; public static void Init(ConfigFile config) { //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) White = BindTier(config, "White", defaultValue: false, "White (common) items trigger a vote."); Green = BindTier(config, "Green", defaultValue: true, "Green (uncommon) items trigger a vote."); Red = BindTier(config, "Red", defaultValue: true, "Red (legendary) items trigger a vote."); Boss = BindTier(config, "Boss", defaultValue: true, "Yellow (boss) items trigger a vote."); Lunar = BindTier(config, "Lunar", defaultValue: true, "Blue (lunar) items trigger a vote."); Void = BindTier(config, "Void", defaultValue: true, "Void items of every tier (white, green, red and yellow) trigger a vote."); Equipment = BindTier(config, "Equipment", defaultValue: true, "Orange equipment triggers a vote."); LunarEquipment = BindTier(config, "LunarEquipment", defaultValue: true, "Lunar equipment triggers a vote."); OtherTiers = BindTier(config, "OtherTiers", defaultValue: false, "Items of any other tier (e.g. from DLC or other mods) trigger a vote."); ExemptPrintersAndCauldrons = config.Bind<bool>("Exemptions", "PrintersAndCauldrons", true, "Items from printers and cauldrons skip the vote, since the player paid with their own items."); ExemptScrappers = config.Bind<bool>("Exemptions", "Scrappers", true, "Scrap from a scrapper skips the vote."); ExemptLunarPurchases = config.Bind<bool>("Exemptions", "LunarPurchases", true, "Items bought with lunar coins (Bazaar shop and lunar pods) skip the vote."); ExemptPickerDrops = config.Bind<bool>("Exemptions", "PotentialsAndEssences", true, "Items a player chooses from a void potential or Command essence skip the vote. This covers Void Fields and Void Seed rewards, Simulacrum, Halcyon shrines, Encrusted Caches and other pickers."); ExemptWanderingChef = config.Bind<bool>("Exemptions", "WanderingChef", true, "Food cooked by the Wandering Chef from a player's own items skips the vote."); TieBreak = config.Bind<TieBreaker>("Voting", "TieBreaker", TieBreaker.Random, "How a tied vote is decided. Random: a random one of the tied players. Picker: the player who picked the item up, if they're tied; otherwise random. Soft reservers win ties either way."); LunarNeedsSelfVote = config.Bind<bool>("Voting", "LunarNeedsSelfVote", true, "Lunar items and lunar equipment (which have downsides) only go to a player who voted for themselves. If nobody did, the item is left for anyone to pick up."); VoidNeedsSelfVote = config.Bind<bool>("Voting", "VoidNeedsSelfVote", true, "Void items (which corrupt your normal items) only go to a player who voted for themselves. If nobody did, the item is left for anyone to pick up."); VoteTimerSeconds = config.Bind<int>("Voting", "TimerSeconds", 30, new ConfigDescription("Seconds before a vote ends with the votes cast so far. If nobody voted, a soft reserver gets the item, otherwise the player who picked it up. 0 waits for everyone to vote.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 300), Array.Empty<object>())); FinalCountdownSeconds = config.Bind<int>("Voting", "FinalCountdownSeconds", 2, new ConfigDescription("Once everyone has voted, the vote ends after this many seconds (or sooner, if the timer has less left), so players can still change their minds. Changing a vote restarts the countdown. 0 ends it straight away.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 30), Array.Empty<object>())); SplitTeleporterDrops = config.Bind<bool>("Teleporter", "SplitDrops", true, "When the teleporter boss dies, its yellow items are voted on straight away and the rest are shared out with the split card (take your share, give it to someone, or reject it). Off: teleporter items are voted on like any other pickup."); SoftReserveSlots = config.Bind<int>("SoftReserve", "SlotsPerPlayer", 3, new ConfigDescription("How many items each player can soft-reserve with /sr. 0 turns soft reserves off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>())); SoloTestMode = config.Bind<bool>("Debug", "SoloTestMode", false, "Run votes even when you are the only player, and enable debug keys on the host: F2 drops a random green item, F3 a random white, F4 a random equipment, and F5 a fake teleporter reward (3 greens and a boss item), F6 a random void green."); OpenVoteKey = config.Bind<KeyboardShortcut>("Client", "OpenVoteKey", new KeyboardShortcut((KeyCode)118, Array.Empty<KeyCode>()), "Shows the mouse cursor so you can click the vote card. Press again to hide it."); ShowItemCounts = config.Bind<bool>("Client", "ShowItemCounts", true, "Show each player's item counts per tier (white, green, red, yellow, lunar, void) under their name on the vote and split cards."); NumberKeyVoting = config.Bind<bool>("Client", "NumberKeyVoting", true, "Press 1-9 to vote for the player in that position on the vote card, without showing the cursor. Turn off if another mod uses the number keys."); SkipVoteKey = config.Bind<KeyboardShortcut>("Client", "SkipVoteKey", new KeyboardShortcut((KeyCode)96, Array.Empty<KeyCode>()), "Skip the current vote: the vote stops waiting for you and your name is struck through. Voting afterwards replaces the skip. On the teleporter split card it takes your share."); DeclineKey = config.Bind<KeyboardShortcut>("Client", "DeclineKey", new KeyboardShortcut((KeyCode)120, Array.Empty<KeyCode>()), "Say you don't want the item being voted on: it counts as your vote, your name turns red, and nobody can vote for you. Voting afterwards replaces it."); } public static bool IsTierEnabled(PickupDef def) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected I4, but got Unknown //IL_000a: Unknown result type (might be due to invalid IL or missing references) if ((int)def.equipmentIndex != -1) { EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(def.equipmentIndex); if (!Object.op_Implicit((Object)(object)equipmentDef) || !equipmentDef.isLunar) { return Equipment.Value; } return LunarEquipment.Value; } ItemTier itemTier = def.itemTier; switch ((int)itemTier) { case 0: return White.Value; case 1: return Green.Value; case 2: return Red.Value; case 4: return Boss.Value; case 3: return Lunar.Value; case 6: case 7: case 8: case 9: return Void.Value; case 5: return false; default: return OtherTiers.Value; } } public static bool IsVoidItem(PickupDef def) { //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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 ItemTier itemTier = def.itemTier; if (itemTier - 6 <= 3) { return (int)def.itemIndex != -1; } return false; } public static bool IsExemptionEnabled(ExemptReason reason) { return reason switch { ExemptReason.PrinterOrCauldron => ExemptPrintersAndCauldrons.Value, ExemptReason.Scrapper => ExemptScrappers.Value, ExemptReason.LunarPurchase => ExemptLunarPurchases.Value, ExemptReason.PickerDrop => ExemptPickerDrops.Value, ExemptReason.WanderingChef => ExemptWanderingChef.Value, ExemptReason.AlreadyVoted => true, _ => false, }; } private static ConfigEntry<bool> BindTier(ConfigFile config, string key, bool defaultValue, string description) { return config.Bind<bool>("Tiers", key, defaultValue, description); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInPlugin("Lightsage.LootVote", "LootVote", "1.1.1")] public class LootVotePlugin : BaseUnityPlugin { public const string PluginGuid = "Lightsage.LootVote"; public const string PluginAuthor = "Lightsage"; public const string PluginName = "LootVote"; public const string PluginVersion = "1.1.1"; private const float _debugDropHeight = 2f; private const float _debugDropForwardSpeed = 20f; private const float _debugDropUpwardSpeed = 10f; private const float _debugDropSidewaysSpeed = 8f; private const int _fakeTeleporterGreens = 3; public void Awake() { Log.Init(((BaseUnityPlugin)this).Logger); LootVoteConfig.Init(((BaseUnityPlugin)this).Config); NetworkingAPI.RegisterMessageType<VoteStartMessage>(); NetworkingAPI.RegisterMessageType<VoteCastMessage>(); NetworkingAPI.RegisterMessageType<VoteProgressMessage>(); NetworkingAPI.RegisterMessageType<VoteEndedMessage>(); NetworkingAPI.RegisterMessageType<SoftReserveRequestMessage>(); NetworkingAPI.RegisterMessageType<SoftReserveSyncMessage>(); NetworkingAPI.RegisterMessageType<SoftReserveFeedbackMessage>(); NetworkingAPI.RegisterMessageType<SplitStartMessage>(); NetworkingAPI.RegisterMessageType<SplitChoiceMessage>(); NetworkingAPI.RegisterMessageType<SplitProgressMessage>(); NetworkingAPI.RegisterMessageType<SplitEndedMessage>(); ExemptionTracker.Init(); TeleporterDropTracker.Init(); PickupHooks.Init(); VoteManager.Init(); TeleporterSplitManager.Init(); SoftReserveManager.Init(); SoftReserveClientState.Init(); SoftReserveCommands.Init(); VoteClientState.Init(); SplitClientState.Init(); ItemCounts.Init(); LootVoteHud.Init(); SceneExitController.onBeginExit += OnBeginStageExit; if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { RiskOfOptionsCompat.Init(); } } private static void OnBeginStageExit(SceneExitController sceneExitController) { if (NetworkServer.active) { VoteManager.ForceEndAll(); TeleporterSplitManager.ForceResolveAll(); } } private void Update() { if (NetworkServer.active && Object.op_Implicit((Object)(object)Run.instance)) { VoteManager.Tick(); TeleporterSplitManager.Tick(); if (LootVoteConfig.SoloTestMode.Value) { UpdateDebugKeys(); } } } private static void UpdateDebugKeys() { if (Input.GetKeyDown((KeyCode)283)) { DropRandom(Run.instance.availableTier2DropList); } else if (Input.GetKeyDown((KeyCode)284)) { DropRandom(Run.instance.availableTier1DropList); } else if (Input.GetKeyDown((KeyCode)285)) { DropRandom(Run.instance.availableEquipmentDropList); } else if (Input.GetKeyDown((KeyCode)286)) { TeleporterDropTracker.DropAsBatch(DropFakeTeleporterRewards); } else if (Input.GetKeyDown((KeyCode)287)) { DropRandom(Run.instance.availableVoidTier2DropList); } } private static void DropFakeTeleporterRewards() { for (int i = 0; i < 3; i++) { DropRandom(Run.instance.availableTier2DropList, i - 1); } DropRandom(Run.instance.availableBossDropList, 2f); } private static void DropRandom(List<PickupIndex> dropList, float sideways = 0f) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_0097: 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) //IL_009d: Unknown result type (might be due to invalid IL or missing references) LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null); if (Object.op_Implicit((Object)(object)val) && dropList.Count != 0) { PickupIndex val2 = dropList[Random.Range(0, dropList.Count)]; Transform transform = val.transform; Vector3 val3 = transform.position + Vector3.up * 2f; Vector3 val4 = transform.forward * 20f + transform.right * sideways * 8f + Vector3.up * 10f; PickupDropletController.CreatePickupDroplet(new UniquePickup(val2), val3, val4, false); } } } internal static class PickupHooks { [CompilerGenerated] private static class <>O { public static hook_AttemptGrant <0>__OnAttemptGrant; public static hook_GetInteractability <1>__OnGetInteractability; } public static void Init() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown object obj = <>O.<0>__OnAttemptGrant; if (obj == null) { hook_AttemptGrant val = OnAttemptGrant; <>O.<0>__OnAttemptGrant = val; obj = (object)val; } GenericPickupController.AttemptGrant += (hook_AttemptGrant)obj; object obj2 = <>O.<1>__OnGetInteractability; if (obj2 == null) { hook_GetInteractability val2 = OnGetInteractability; <>O.<1>__OnGetInteractability = val2; obj2 = (object)val2; } GenericPickupController.GetInteractability += (hook_GetInteractability)obj2; } private static void OnAttemptGrant(orig_AttemptGrant orig, GenericPickupController self, CharacterBody body) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || ItemDelivery.Delivering) { orig.Invoke(self, body); } else { if (VoteManager.IsPending(self) || TeleporterSplitManager.IsHeld(self)) { return; } NetworkUser val = (Object.op_Implicit((Object)(object)body) ? Util.LookUpBodyNetworkUser(body) : null); if (!Object.op_Implicit((Object)(object)val) || !ShouldVote(self)) { orig.Invoke(self, body); return; } PickupIndex pickupIndex = self.pickup.pickupIndex; List<NetworkUser> list = SoftReserveManager.ConnectedReservers(pickupIndex); if (list.Count == 1 && (Object)(object)list[0] == (Object)(object)val) { AnnounceOwnReserve(val, pickupIndex); orig.Invoke(self, body); } else { VoteManager.Enqueue(self, val); } } } private static void AnnounceOwnReserve(NetworkUser user, PickupIndex pickupIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) SimpleChatMessage val = new SimpleChatMessage(); val.baseToken = "<style=cEvent>{0} took their soft-reserved {1}.</style>"; val.paramTokens = new string[2] { Util.EscapeRichTextForTextMeshPro(user.userName), VoteManager.ColoredPickupName(pickupIndex) }; Chat.SendBroadcastChat((ChatMessageBase)(object)val); } private static Interactability OnGetInteractability(orig_GetInteractability orig, GenericPickupController self, Interactor activator) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active && (VoteManager.IsPending(self) || TeleporterSplitManager.IsHeld(self))) { return (Interactability)0; } return orig.Invoke(self, activator); } private static bool ShouldVote(GenericPickupController pickupController) { //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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0033: 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_0066: Unknown result type (might be due to invalid IL or missing references) UniquePickup pickup = pickupController.pickup; PickupDef pickupDef = PickupCatalog.GetPickupDef(pickup.pickupIndex); if (pickupDef == null || ((int)pickupDef.itemIndex == -1 && (int)pickupDef.equipmentIndex == -1)) { return false; } if (((UniquePickup)(ref pickup)).isTempItem || pickup.isRental) { return false; } if (ExemptionTracker.IsExempt(pickupController)) { return false; } if (Players.ConnectedCount() < 2 && !LootVoteConfig.SoloTestMode.Value) { return false; } if (!LootVoteConfig.IsTierEnabled(pickupDef)) { return SoftReserveManager.IsReservedByConnectedPlayer(pickup.pickupIndex); } return true; } } internal static class Players { public static List<NetworkUser> Connected() { List<NetworkUser> list = new List<NetworkUser>(); foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (IsConnected(instance)) { list.Add(instance.networkUser); } } return list; } public static int ConnectedCount() { return Connected().Count; } public static bool IsConnected(NetworkUser user) { if (Object.op_Implicit((Object)(object)user) && Object.op_Implicit((Object)(object)user.master)) { return IsConnected(user.master.playerCharacterMasterController); } return false; } public static BodyIndex BodyIndexOf(NetworkUser user) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) CharacterMaster master = user.master; CharacterBody val = (Object.op_Implicit((Object)(object)master) ? master.GetBody() : null); if (Object.op_Implicit((Object)(object)val)) { return val.bodyIndex; } if (!Object.op_Implicit((Object)(object)master) || !Object.op_Implicit((Object)(object)master.bodyPrefab)) { return (BodyIndex)(-1); } return BodyCatalog.FindBodyIndex(master.bodyPrefab); } public static VoteCandidate ToCandidate(NetworkUser user, bool isReserver) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0029: Expected I4, but got Unknown return new VoteCandidate { UserNetId = ((NetworkBehaviour)user).netId, Name = user.userName, BodyIndex = (int)BodyIndexOf(user), IsReserver = isReserver }; } private static bool IsConnected(PlayerCharacterMasterController player) { if (Object.op_Implicit((Object)(object)player) && player.isConnected) { return Object.op_Implicit((Object)(object)player.networkUser); } return false; } } internal static class RiskOfOptionsCompat { public const string PluginGuid = "com.rune580.riskofoptions"; [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void Init() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_007c: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown ModSettingsManager.SetModDescription("Players vote on who gets each item. Gameplay settings only take effect for the host."); ModSettingsManager.AddOption((BaseOption)new KeyBindOption(LootVoteConfig.OpenVoteKey)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LootVoteConfig.NumberKeyVoting)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LootVoteConfig.ShowItemCounts)); ModSettingsManager.AddOption((BaseOption)new KeyBindOption(LootVoteConfig.SkipVoteKey)); ModSettingsManager.AddOption((BaseOption)new KeyBindOption(LootVoteConfig.DeclineKey)); ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)LootVoteConfig.TieBreak)); IntSliderConfig val = new IntSliderConfig { min = 0, max = 300 }; ModSettingsManager.AddOption((BaseOption)new IntSliderOption(LootVoteConfig.VoteTimerSeconds, val)); IntSliderConfig val2 = new IntSliderConfig { min = 0, max = 30 }; ModSettingsManager.AddOption((BaseOption)new IntSliderOption(LootVoteConfig.FinalCountdownSeconds, val2)); ConfigEntry<bool>[] array = new ConfigEntry<bool>[18] { LootVoteConfig.White, LootVoteConfig.Green, LootVoteConfig.Red, LootVoteConfig.Boss, LootVoteConfig.Lunar, LootVoteConfig.Void, LootVoteConfig.Equipment, LootVoteConfig.LunarEquipment, LootVoteConfig.OtherTiers, LootVoteConfig.ExemptPrintersAndCauldrons, LootVoteConfig.ExemptScrappers, LootVoteConfig.ExemptLunarPurchases, LootVoteConfig.ExemptPickerDrops, LootVoteConfig.ExemptWanderingChef, LootVoteConfig.SplitTeleporterDrops, LootVoteConfig.VoidNeedsSelfVote, LootVoteConfig.LunarNeedsSelfVote, LootVoteConfig.SoloTestMode }; for (int i = 0; i < array.Length; i++) { ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(array[i])); } IntSliderConfig val3 = new IntSliderConfig { min = 0, max = 10 }; ModSettingsManager.AddOption((BaseOption)new IntSliderOption(LootVoteConfig.SoftReserveSlots, val3)); } } internal static class SplitAllocation { private const double _epsilon = 1E-09; public static int[] Allocate(int splitItemCount, int totalBatchItems, IReadOnlyList<SplitPlayer> players, Random random) { int count = players.Count; if (count == 0 || splitItemCount <= 0) { return null; } double num = (double)totalBatchItems / (double)count; double[] array = new double[count]; bool[] array2 = new bool[count]; bool[] array3 = new bool[count]; double num2 = 0.0; for (int i = 0; i < count; i++) { SplitPlayer splitPlayer = players[i]; double num3 = Math.Max(0.0, num - (double)splitPlayer.YellowsWon); if (!splitPlayer.Connected) { num2 += num3; continue; } switch (splitPlayer.Choice) { case SplitChoice.Reject: num2 += num3; continue; case SplitChoice.Give: if (IsValidGiftTarget(players, i, splitPlayer.GiveTarget)) { array[splitPlayer.GiveTarget] += num3; array3[splitPlayer.GiveTarget] = true; continue; } break; } array[i] += num3; array2[i] = true; } if (!DistributeRejected(array, array2, array3, num2)) { return null; } return ToWholeItems(array, splitItemCount, random); } private static bool IsValidGiftTarget(IReadOnlyList<SplitPlayer> players, int giver, int target) { if (target >= 0 && target < players.Count && target != giver) { return players[target].Connected; } return false; } private static bool DistributeRejected(double[] entitlements, bool[] isTaker, bool[] isRecipient, double rejectedPool) { List<int> list = new List<int>(); for (int i = 0; i < isTaker.Length; i++) { if (isTaker[i]) { list.Add(i); } } if (list.Count == 0) { for (int j = 0; j < isRecipient.Length; j++) { if (isRecipient[j]) { list.Add(j); } } } if (list.Count == 0) { return false; } foreach (int item in list) { entitlements[item] += rejectedPool / (double)list.Count; } return true; } private static int[] ToWholeItems(double[] entitlements, int itemCount, Random random) { double num = 0.0; foreach (double num2 in entitlements) { num += num2; } if (num <= 0.0) { return null; } int[] array = new int[entitlements.Length]; double[] array2 = new double[entitlements.Length]; int num3 = 0; for (int j = 0; j < entitlements.Length; j++) { double num4 = (double)itemCount * entitlements[j] / num; array[j] = (int)Math.Floor(num4 + 1E-09); array2[j] = num4 - (double)array[j]; num3 += array[j]; } List<int> list = new List<int>(); for (int k = 0; k < entitlements.Length; k++) { if (entitlements[k] > 0.0) { list.Add(k); } } Shuffle(list, random); List<int> list2 = StableSortDescending(list, array2); int num5 = 0; while (num3 < itemCount) { array[list2[num5 % list2.Count]]++; num3++; num5++; } return array; } private static void Shuffle(List<int> list, Random random) { for (int num = list.Count - 1; num > 0; num--) { int index = random.Next(num + 1); int value = list[num]; list[num] = list[index]; list[index] = value; } } private static List<int> StableSortDescending(List<int> indices, double[] keys) { List<int> list = new List<int>(indices.Count); foreach (int index in indices) { int num = list.Count; while (num > 0 && keys[list[num - 1]] < keys[index] - 1E-09) { num--; } list.Insert(num, index); } return list; } } internal enum SplitChoice : byte { Undecided, Take, Give, Reject } internal class SplitPlayer { public SplitChoice Choice; public int GiveTarget = -1; public int YellowsWon; public bool Connected = true; } internal class TeleporterDropMarker : MonoBehaviour { public int BatchId; } internal static class TeleporterDropTracker { [CompilerGenerated] private static class <>O { public static hook_DropRewards <0>__OnDropRewards; public static hook_OnEnable <1>__OnDropletEnable; public static hook_CreatePickup <2>__OnDropletCreatePickup; public static hook_CreatePickup <3>__OnCreatePickup; } private static int _droppingBatchId; private static int _landingBatchId; public static void Init() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0050: 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: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown object obj = <>O.<0>__OnDropRewards; if (obj == null) { hook_DropRewards val = OnDropRewards; <>O.<0>__OnDropRewards = val; obj = (object)val; } BossGroup.DropRewards += (hook_DropRewards)obj; object obj2 = <>O.<1>__OnDropletEnable; if (obj2 == null) { hook_OnEnable val2 = OnDropletEnable; <>O.<1>__OnDropletEnable = val2; obj2 = (object)val2; } PickupDropletController.OnEnable += (hook_OnEnable)obj2; object obj3 = <>O.<2>__OnDropletCreatePickup; if (obj3 == null) { hook_CreatePickup val3 = OnDropletCreatePickup; <>O.<2>__OnDropletCreatePickup = val3; obj3 = (object)val3; } PickupDropletController.CreatePickup += (hook_CreatePickup)obj3; object obj4 = <>O.<3>__OnCreatePickup; if (obj4 == null) { hook_CreatePickup val4 = OnCreatePickup; <>O.<3>__OnCreatePickup = val4; obj4 = (object)val4; } GenericPickupController.CreatePickup += (hook_CreatePickup)obj4; } public static void DropAsBatch(Action dropItems) { int num = TeleporterSplitManager.BeginBatch(); int droppingBatchId = _droppingBatchId; _droppingBatchId = num; try { dropItems(); } finally { _droppingBatchId = droppingBatchId; } TeleporterSplitManager.EndBatchDrop(num); } private static bool ShouldSplit(BossGroup bossGroup) { TeleporterInteraction instance = TeleporterInteraction.instance; if (NetworkServer.active && LootVoteConfig.SplitTeleporterDrops.Value && !CommandArtifactManager.IsCommandArtifactEnabled && Object.op_Implicit((Object)(object)instance) && (Object)(object)instance.bossGroup == (Object)(object)bossGroup) { if (Players.ConnectedCount() < 2) { return LootVoteConfig.SoloTestMode.Value; } return true; } return false; } private static void OnDropRewards(orig_DropRewards orig, BossGroup self) { if (ShouldSplit(self)) { DropAsBatch(delegate { orig.Invoke(self); }); } else { orig.Invoke(self); } } private static void OnDropletEnable(orig_OnEnable orig, PickupDropletController self) { orig.Invoke(self); if (NetworkServer.active && _droppingBatchId != 0) { ((Component)self).gameObject.AddComponent<TeleporterDropMarker>().BatchId = _droppingBatchId; TeleporterSplitManager.OnDropletCreated(_droppingBatchId); } } private static void OnDropletCreatePickup(orig_CreatePickup orig, PickupDropletController self) { TeleporterDropMarker component = ((Component)self).GetComponent<TeleporterDropMarker>(); int landingBatchId = _landingBatchId; _landingBatchId = (Object.op_Implicit((Object)(object)component) ? component.BatchId : 0); try { orig.Invoke(self); } finally { _landingBatchId = landingBatchId; } } private static GenericPickupController OnCreatePickup(orig_CreatePickup orig, ref CreatePickupInfo createPickupInfo) { GenericPickupController val = orig.Invoke(ref createPickupInfo); if (Object.op_Implicit((Object)(object)val) && _landingBatchId != 0) { TeleporterSplitManager.OnItemLanded(_landingBatchId, val); } return val; } } internal static class TeleporterSplitManager { private class Batch { public int Id; public int ExpectedCount; public bool DropFinished; public float DroppedAt; public int LandedCount; public bool SplitStarted; public List<GenericPickupController> Held = new List<GenericPickupController>(); public HashSet<GenericPickupController> YellowVotes = new HashSet<GenericPickupController>(); public Dictionary<NetworkUser, int> YellowsWon = new Dictionary<NetworkUser, int>(); } private class Session { public int Id; public Batch Batch; public List<NetworkUser> Candidates; public SplitChoice[] Choices; public int[] Targets; } private const float _landingTimeoutSeconds = 6f; private static readonly List<Batch> _batches = new List<Batch>(); private static readonly List<Batch> _readyQueue = new List<Batch>(); private static readonly HashSet<GenericPickupController> _held = new HashSet<GenericPickupController>(); private static readonly Random _random = new Random(); private static Session _active; private static int _nextBatchId = 1; private static int _nextSplitId = 1; public static void Init() { VoteManager.VoteFinished += OnVoteFinished; Stage.onServerStageBegin += OnServerStageBegin; Run.onRunDestroyGlobal += OnRunDestroyed; } public static bool IsHeld(GenericPickupController pickupController) { return _held.Contains(pickupController); } public static int BeginBatch() { Batch batch = new Batch { Id = _nextBatchId++ }; _batches.Add(batch); return batch.Id; } public static void OnDropletCreated(int batchId) { Batch batch = FindBatch(batchId); if (batch != null) { batch.ExpectedCount++; } } public static void EndBatchDrop(int batchId) { Batch batch = FindBatch(batchId); if (batch != null) { batch.DropFinished = true; batch.DroppedAt = Time.time; if (batch.ExpectedCount == 0) { _batches.Remove(batch); } } } public static void OnItemLanded(int batchId, GenericPickupController pickupController) { //IL_0032: 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) Batch batch = FindBatch(batchId) ?? FindQueuedBatch(batchId); if (batch == null || batch.SplitStarted) { ItemDelivery.MarkFree(pickupController); return; } batch.LandedCount++; PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupController.pickup.pickupIndex); if (pickupDef != null && IsYellow(pickupDef) && LootVoteConfig.IsTierEnabled(pickupDef)) { batch.YellowVotes.Add(pickupController); VoteManager.Enqueue(pickupController, null); } else { batch.Held.Add(pickupController); _held.Add(pickupController); } CheckReady(batch, force: false); } public static void Tick() { for (int num = _batches.Count - 1; num >= 0; num--) { if (num < _batches.Count) { CheckReady(_batches[num], force: false); } } } public static void ReceiveChoice(int splitId, NetworkInstanceId voterNetId, SplitChoice choice, int targetIndex) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) Session active = _active; if (active == null || active.Id != splitId || choice == SplitChoice.Undecided) { return; } int num = active.Candidates.FindIndex((NetworkUser u) => Object.op_Implicit((Object)(object)u) && ((NetworkBehaviour)u).netId == voterNetId); if (num < 0) { Log.Warning($"Ignoring split choice from unknown player {voterNetId}", "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\TeleporterSplitManager.cs", 122); return; } bool flag = targetIndex >= 0 && targetIndex < active.Candidates.Count && targetIndex != num; if (choice != SplitChoice.Give || flag) { active.Choices[num] = choice; active.Targets[num] = ((choice == SplitChoice.Give) ? targetIndex : (-1)); BroadcastProgress(active); if (Array.IndexOf(active.Choices, SplitChoice.Undecided) < 0) { Resolve(active); } } } public static void ForceEnd() { if (NetworkServer.active && _active != null) { Resolve(_active); } } public static void ForceResolveAll() { if (NetworkServer.active) { Batch[] array = _batches.ToArray(); for (int i = 0; i < array.Length; i++) { CheckReady(array[i], force: true); } int num = _readyQueue.Count + 1; while (_active != null && num-- > 0) { Resolve(_active); } } } private static Batch FindBatch(int batchId) { return _batches.Find((Batch b) => b.Id == batchId); } private static Batch FindQueuedBatch(int batchId) { if (_active != null && _active.Batch.Id == batchId) { return _active.Batch; } return _readyQueue.Find((Batch b) => b.Id == batchId); } private static bool IsYellow(PickupDef pickupDef) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if (!pickupDef.isBoss) { return (int)pickupDef.itemTier == 9; } return true; } private static void OnVoteFinished(GenericPickupController pickupController, NetworkUser winner) { Batch batch = _batches.Find((Batch b) => b.YellowVotes.Contains(pickupController)); if (batch != null) { batch.YellowVotes.Remove(pickupController); if (Object.op_Implicit((Object)(object)winner)) { batch.YellowsWon.TryGetValue(winner, out var value); batch.YellowsWon[winner] = value + 1; } CheckReady(batch, force: false); } } private static void CheckReady(Batch batch, bool force) { if (!_batches.Contains(batch)) { return; } if (!force) { bool flag = Time.time - batch.DroppedAt > 6f; bool flag2 = batch.LandedCount >= batch.ExpectedCount || flag; if (!batch.DropFinished || !flag2 || batch.YellowVotes.Count > 0) { return; } } _batches.Remove(batch); if (batch.Held.Count != 0) { _readyQueue.Add(batch); if (_active == null) { StartNext(); } } } private static void StartNext() { while (_readyQueue.Count > 0) { Batch batch = _readyQueue[0]; _readyQueue.RemoveAt(0); batch.SplitStarted = true; batch.Held.RemoveAll((GenericPickupController pickupController) => !Object.op_Implicit((Object)(object)pickupController)); if (batch.Held.Count == 0) { continue; } List<NetworkUser> list = Players.Connected(); if (list.Count == 0) { Release(batch); continue; } Session session = new Session { Id = _nextSplitId++, Batch = batch, Candidates = list, Choices = new SplitChoice[list.Count], Targets = new int[list.Count] }; for (int num = 0; num < session.Targets.Length; num++) { session.Targets[num] = -1; } _active = session; Log.Info($"Split {session.Id} started with {batch.Held.Count} item(s) for " + $"{list.Count} player(s)", "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\TeleporterSplitManager.cs", 243); BroadcastStart(session); break; } } private static int YellowsWonBy(Batch batch, NetworkUser user) { if (!batch.YellowsWon.TryGetValue(user, out var value)) { return 0; } return value; } private static void BroadcastStart(Session session) { //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) List<GenericPickupController> held = session.Batch.Held; int[] array = new int[held.Count]; for (int i = 0; i < held.Count; i++) { array[i] = held[i].pickup.pickupIndex.value; } VoteCandidate[] array2 = new VoteCandidate[session.Candidates.Count]; int[] array3 = new int[session.Candidates.Count]; for (int j = 0; j < array2.Length; j++) { array2[j] = Players.ToCandidate(session.Candidates[j], isReserver: false); array3[j] = YellowsWonBy(session.Batch, session.Candidates[j]); } NetMessageExtensions.Send((INetMessage)(object)new SplitStartMessage { SplitId = session.Id, PickupIndices = array, Candidates = array2, YellowsWon = array3 }, (NetworkDestination)1); } private static void BroadcastProgress(Session session) { NetMessageExtensions.Send((INetMessage)(object)new SplitProgressMessage { SplitId = session.Id, Choices = session.Choices, Targets = session.Targets }, (NetworkDestination)1); } private static void Resolve(Session session) { Batch batch = session.Batch; List<SplitPlayer> list = new List<SplitPlayer>(); for (int i = 0; i < session.Candidates.Count; i++) { NetworkUser user = session.Candidates[i]; list.Add(new SplitPlayer { Choice = session.Choices[i], GiveTarget = session.Targets[i], YellowsWon = YellowsWonBy(batch, user), Connected = Players.IsConnected(user) }); } List<GenericPickupController> list2 = batch.Held.FindAll((GenericPickupController item) => Object.op_Implicit((Object)(object)item)); foreach (GenericPickupController item in batch.Held) { _held.Remove(item); } int[] array = SplitAllocation.Allocate(list2.Count, batch.ExpectedCount, list, _random); if (array == null) { Release(batch); Announce("Nobody took the teleporter items, so they're free for anyone."); } else { DealItems(session, list2, array); } End(session); } private static void DealItems(Session session, List<GenericPickupController> items, int[] counts) { //IL_003a: 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_0044: 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) Shuffle(items); int num = 0; List<string> list = new List<string>(); for (int i = 0; i < counts.Length; i++) { NetworkUser val = session.Candidates[i]; List<string> list2 = new List<string>(); for (int j = 0; j < counts[i]; j++) { if (num >= items.Count) { break; } GenericPickupController obj = items[num++]; PickupIndex pickupIndex = obj.pickup.pickupIndex; if (ItemDelivery.Deliver(obj, val)) { list2.Add(VoteManager.ColoredPickupName(pickupIndex)); } } if (list2.Count > 0) { string text = Util.EscapeRichTextForTextMeshPro(val.userName); list.Add(text + " got " + ItemSummary.Join(list2)); } } Announce("Teleporter split: " + string.Join("; ", list) + "."); Log.Info(string.Format("Split {0} resolved: {1}", session.Id, string.Join(", ", counts)), "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\TeleporterSplitManager.cs", 333); } private static void End(Session session) { NetMessageExtensions.Send((INetMessage)(object)new SplitEndedMessage { SplitId = session.Id }, (NetworkDestination)1); if (_active == session) { _active = null; StartNext(); } } private static void Release(Batch batch) { foreach (GenericPickupController item in batch.Held) { _held.Remove(item); if (Object.op_Implicit((Object)(object)item)) { ItemDelivery.MarkFree(item); } } } private static void Announce(string text) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown SimpleChatMessage val = new SimpleChatMessage(); val.baseToken = "<style=cEvent>{0}</style>"; val.paramTokens = new string[1] { text }; Chat.SendBroadcastChat((ChatMessageBase)(object)val); } private static void Shuffle(List<GenericPickupController> items) { for (int num = items.Count - 1; num > 0; num--) { int index = _random.Next(num + 1); GenericPickupController value = items[num]; items[num] = items[index]; items[index] = value; } } private static void OnServerStageBegin(Stage stage) { Clear(); } private static void OnRunDestroyed(Run run) { if (NetworkServer.active) { Clear(); } } private static void Clear() { if (_active != null) { NetMessageExtensions.Send((INetMessage)(object)new SplitEndedMessage { SplitId = _active.Id }, (NetworkDestination)1); _active = null; } _batches.Clear(); _readyQueue.Clear(); _held.Clear(); } } internal enum TieBreaker { Random, Picker } internal static class VoteManager { private class Candidate { public NetworkUser User; public string Name; public bool IsReserver; } private class Session { public int Id; public GenericPickupController PickupController; public UniquePickup Pickup; public int InitiatorIndex; public bool IsReserved; public bool NeedsSelfVote; public List<Candidate> Candidates; public float Duration; public float Deadline; public float FinalDeadline; public Dictionary<NetworkInstanceId, int> Votes = new Dictionary<NetworkInstanceId, int>(); } private class QueuedPickup { public GenericPickupController PickupController; public NetworkUser Initiator; } public const int SkipVoteIndex = -1; public const int DeclineVoteIndex = -2; private static readonly List<QueuedPickup> _queue = new List<QueuedPickup>(); private static readonly HashSet<GenericPickupController> _pending = new HashSet<GenericPickupController>(); private static readonly Random _random = new Random(); private static Session _active; private static int _nextVoteId = 1; public static event Action<GenericPickupController, NetworkUser> VoteFinished; public static void Init() { Stage.onServerStageBegin += OnServerStageBegin; Run.onRunDestroyGlobal += OnRunDestroyed; } public static bool IsPending(GenericPickupController pickupController) { return _pending.Contains(pickupController); } public static void Enqueue(GenericPickupController pickupController, NetworkUser initiator) { _pending.Add(pickupController); _queue.Add(new QueuedPickup { PickupController = pickupController, Initiator = initiator }); if (_active == null) { StartNext(); } else { BroadcastProgress(); } } public static void ReceiveVote(int voteId, NetworkInstanceId voterNetId, int candidateIndex) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_00ab: Unknown result type (might be due to invalid IL or missing references) Session active = _active; if (active == null || active.Id != voteId || candidateIndex < -2 || candidateIndex >= active.Candidates.Count) { return; } int num = active.Candidates.FindIndex((Candidate c) => Object.op_Implicit((Object)(object)c.User) && ((NetworkBehaviour)c.User).netId == voterNetId); if (num < 0) { Log.Warning($"Ignoring vote from unknown voter {voterNetId}", "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\VoteManager.cs", 91); } else { if (candidateIndex >= 0 && candidateIndex != num && HasDeclined(active, candidateIndex)) { return; } int value; bool flag = active.Votes.TryGetValue(voterNetId, out value) && value != candidateIndex; active.Votes[voterNetId] = candidateIndex; if (candidateIndex == -2) { ClearVotesFor(active, num); } if (active.Votes.Count < active.Candidates.Count) { active.FinalDeadline = 0f; } else if (active.FinalDeadline <= 0f || flag) { float num2 = LootVoteConfig.FinalCountdownSeconds.Value; if (num2 <= 0f) { BroadcastProgress(); Resolve(active); return; } active.FinalDeadline = Time.time + num2; } BroadcastProgress(); } } public static void ForceEnd() { if (NetworkServer.active && _active != null) { Resolve(_active); } } public static void Tick() { Session active = _active; float num = ((active != null) ? EffectiveDeadline(active) : 0f); if (num > 0f && Time.time >= num) { Log.Info($"Vote {active.Id}: time is up", "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\VoteManager.cs", 138); Resolve(active); } } public static void ForceEndAll() { if (NetworkServer.active) { int num = _queue.Count + 1; while (_active != null && num-- > 0) { Resolve(_active); } } } public static string PickupName(PickupIndex pickupIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef == null) { return "???"; } return Language.GetString(pickupDef.nameToken); } public static string ColoredPickupName(PickupIndex pickupIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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) PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef == null) { return "???"; } return Util.GenerateColoredString(Language.GetString(pickupDef.nameToken), Color32.op_Implicit(pickupDef.baseColor)); } private static void OnServerStageBegin(Stage stage) { CancelAll(); } private static void OnRunDestroyed(Run run) { if (NetworkServer.active) { CancelAll(); } } private static void StartNext() { //IL_005f: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) while (_queue.Count > 0) { QueuedPickup next = _queue[0]; _queue.RemoveAt(0); if (!Object.op_Implicit((Object)(object)next.PickupController)) { _pending.Remove(next.PickupController); continue; } UniquePickup pickup = next.PickupController.pickup; List<Candidate> list = new List<Candidate>(); foreach (NetworkUser item in Players.Connected()) { list.Add(CreateCandidate(item, pickup.pickupIndex)); } if (list.Count == 0) { Unlock(next.PickupController); continue; } Session session = new Session { Id = _nextVoteId++, PickupController = next.PickupController, Pickup = pickup, InitiatorIndex = list.FindIndex((Candidate c) => (Object)(object)c.User == (Object)(object)next.Initiator), IsReserved = list.Exists((Candidate c) => c.IsReserver), NeedsSelfVote = RequiresSelfVote(pickup.pickupIndex), Candidates = list, Duration = LootVoteConfig.VoteTimerSeconds.Value }; if (session.Duration > 0f) { session.Deadline = Time.time + session.Duration; } _active = session; Log.Info($"Vote {session.Id} started for {PickupName(pickup.pickupIndex)} with " + $"{list.Count} voter(s)", "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\VoteManager.cs", 215); BroadcastStart(session); break; } } private static Candidate CreateCandidate(NetworkUser user, PickupIndex pickupIndex) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) return new Candidate { User = user, Name = user.userName, IsReserver = SoftReserveManager.IsReservedBy(user, pickupIndex) }; } private static void BroadcastStart(Session session) { VoteCandidate[] array = new VoteCandidate[session.Candidates.Count]; for (int i = 0; i < array.Length; i++) { Candidate candidate = session.Candidates[i]; array[i] = Players.ToCandidate(candidate.User, candidate.IsReserver); } NetMessageExtensions.Send((INetMessage)(object)new VoteStartMessage { VoteId = session.Id, PickupIndex = session.Pickup.pickupIndex.value, InitiatorIndex = session.InitiatorIndex, IsReserved = session.IsReserved, NeedsSelfVote = session.NeedsSelfVote, QueuedCount = _queue.Count, DurationSeconds = session.Duration, Candidates = array }, (NetworkDestination)1); } private static void BroadcastProgress() { //IL_006d: Unknown result type (might be due to invalid IL or missing references) Session active = _active; if (active != null) { bool[] array = new bool[active.Candidates.Count]; bool[] array2 = new bool[active.Candidates.Count]; bool[] array3 = new bool[active.Candidates.Count]; for (int i = 0; i < array.Length; i++) { NetworkUser user = active.Candidates[i].User; int value = -1; array3[i] = Object.op_Implicit((Object)(object)user) && active.Votes.TryGetValue(((NetworkBehaviour)user).netId, out value); array[i] = array3[i] && value == -1; array2[i] = array3[i] && value == -2; } float num = EffectiveDeadline(active); NetMessageExtensions.Send((INetMessage)(object)new VoteProgressMessage { VoteId = active.Id, Counts = Tally(active), Skipped = array, Declined = array2, HasVoted = array3, VotedCount = active.Votes.Count, VoterCount = active.Candidates.Count, QueuedCount = _queue.Count, SecondsLeft = ((num > 0f) ? Mathf.Max(0f, num - Time.time) : (-1f)) }, (NetworkDestination)1); } } private static float EffectiveDeadline(Session session) { if (!(session.FinalDeadline > 0f) || (!(session.Deadline <= 0f) && !(session.FinalDeadline < session.Deadline))) { return session.Deadline; } return session.FinalDeadline; } private static int[] Tally(Session session) { int[] array = new int[session.Candidates.Count]; foreach (int value in session.Votes.Values) { if (value >= 0) { array[value]++; } } return array; } private static int RealVoteCount(Session session) { int num = 0; foreach (int value in session.Votes.Values) { if (value >= 0) { num++; } } return num; } private static bool HasDeclined(Session session, int candidateIndex) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) NetworkUser user = session.Candidates[candidateIndex].User; if (Object.op_Implicit((Object)(object)user) && session.Votes.TryGetValue(((NetworkBehaviour)user).netId, out var value)) { return value == -2; } return false; } private static void ClearVotesFor(Session session, int candidateIndex) { //IL_0011: 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_003f: 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_004f: 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) //IL_008b: Unknown result type (might be due to invalid IL or missing references) NetworkInstanceId netId = ((NetworkBehaviour)session.Candidates[candidateIndex].User).netId; List<NetworkInstanceId> list = new List<NetworkInstanceId>(); foreach (KeyValuePair<NetworkInstanceId, int> vote in session.Votes) { if (vote.Value == candidateIndex && vote.Key != netId) { list.Add(vote.Key); } } foreach (NetworkInstanceId item in list) { session.Votes.Remove(item); } } private static void Resolve(Session session) { //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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) int[] array = Tally(session); List<int> list = new List<int>(); for (int i = 0; i < session.Candidates.Count; i++) { NetworkUser user = session.Candidates[i].User; bool flag = !HasDeclined(session, i) && (!session.NeedsSelfVote || VotedForSelf(session, i)); if (Players.IsConnected(user) && flag) { list.Add(i); } } if (list.Count == 0) { Log.Info($"Vote {session.Id}: nobody can receive the item, unlocking it", "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\VoteManager.cs", 342); PickupIndex pickupIndex = session.Pickup.pickupIndex; if (session.NeedsSelfVote) { AnnounceLeftForAnyone("Nobody claimed {0}, so anyone can pick it up.", pickupIndex); } else if (session.Votes.ContainsValue(-2)) { AnnounceLeftForAnyone("Nobody wanted {0}, so anyone can pick it up.", pickupIndex); } Unlock(session.PickupController); End(session, -1); } else { bool wonTieBreak; int num = PickWinner(session, array, list, out wonTieBreak); Candidate candidate = session.Candidates[num]; if (!ItemDelivery.Deliver(session.PickupController, candidate.User)) { Log.Info($"Vote {session.Id}: the item no longer exists", "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\VoteManager.cs", 357); End(session, -1); } else { string detail = ((RealVoteCount(session) == 0) ? "nobody voted" : ((!wonTieBreak) ? $"{array[num]} of {RealVoteCount(session)} votes" : "won the tie-break")); AnnounceWinner(session, candidate, detail); End(session, num); } } } private static int PickWinner(Session session, int[] counts, List<int> eligible, out bool wonTieBreak) { wonTieBreak = false; if (RealVoteCount(session) == 0) { return NoVoteWinner(session, eligible); } int highest = 0; foreach (int item in eligible) { highest = Mathf.Max(highest, counts[item]); } List<int> list = eligible.FindAll((int i) => counts[i] == highest); List<int> list2 = list.FindAll((int i) => session.Candidates[i].IsReserver); wonTieBreak = list.Count > 1; if (list2.Count > 0) { list = list2; } if (list.Count > 1 && LootVoteConfig.TieBreak.Value == TieBreaker.Picker && list.Contains(session.InitiatorIndex)) { return session.InitiatorIndex; } return list[_random.Next(list.Count)]; } private static bool RequiresSelfVote(PickupIndex pickupIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef == null) { return false; } if (!LootVoteConfig.VoidNeedsSelfVote.Value || !LootVoteConfig.IsVoidItem(pickupDef)) { if (LootVoteConfig.LunarNeedsSelfVote.Value) { return pickupDef.isLunar; } return false; } return true; } private static bool VotedForSelf(Session session, int candidateIndex) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) NetworkUser user = session.Candidates[candidateIndex].User; if (Object.op_Implicit((Object)(object)user) && session.Votes.TryGetValue(((NetworkBehaviour)user).netId, out var value)) { return value == candidateIndex; } return false; } private static void AnnounceLeftForAnyone(string format, PickupIndex pickupIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) SimpleChatMessage val = new SimpleChatMessage(); val.baseToken = "<style=cEvent>" + format + "</style>"; val.paramTokens = new string[1] { ColoredPickupName(pickupIndex) }; Chat.SendBroadcastChat((ChatMessageBase)(object)val); } private static int NoVoteWinner(Session session, List<int> eligible) { List<int> list = eligible.FindAll((int i) => session.Candidates[i].IsReserver); if (list.Count > 0) { if (!list.Contains(session.InitiatorIndex)) { return list[_random.Next(list.Count)]; } return session.InitiatorIndex; } if (eligible.Contains(session.InitiatorIndex)) { return session.InitiatorIndex; } return eligible[_random.Next(eligible.Count)]; } private static void AnnounceWinner(Session session, Candidate winner, string detail) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0034: 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) PickupIndex pickupIndex = session.Pickup.pickupIndex; SimpleChatMessage val = new SimpleChatMessage(); val.baseToken = "<style=cEvent>{0} won {1} ({2}).</style>"; val.paramTokens = new string[3] { Util.EscapeRichTextForTextMeshPro(winner.Name), ColoredPickupName(pickupIndex), detail }; Chat.SendBroadcastChat((ChatMessageBase)(object)val); Log.Info($"Vote {session.Id}: {winner.Name} won {PickupName(pickupIndex)} ({detail})", "C:\\Users\\mattw\\Documents\\ExamplePlugin-main\\LootVote\\VoteManager.cs", 453); } private static void End(Session session, int winnerIndex) { _pending.Remove(session.PickupController); NetMessageExtensions.Send((INetMessage)(object)new VoteEndedMessage { VoteId = session.Id, WinnerIndex = winnerIndex }, (NetworkDestination)1); if (_active == session) { _active = null; } NetworkUser arg = ((winnerIndex >= 0) ? session.Candidates[winnerIndex].User : null); VoteManager.VoteFinished?.Invoke(session.PickupController, arg); if (_active == null) { StartNext(); } } private static void Unlock(GenericPickupController pickupController) { _pending.Remove(pickupController); if (Object.op_Implicit((Object)(object)pickupController)) { ItemDelivery.MarkFree(pickupController); } } private static void CancelAll() { if (_active != null) { Session active = _active; _active = null; NetMessageExtensions.Send((INetMessage)(object)new VoteEndedMessage { VoteId = active.Id, WinnerIndex = -1 }, (NetworkDestination)1); } _queue.Clear(); _pending.Clear(); } } } namespace LootVote.Ui { internal class CardHoverTracker : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { public bool IsPointerOver { get; private set; } public void OnPointerEnter(PointerEventData eventData) { IsPointerOver = true; } public void OnPointerExit(PointerEventData eventData) { IsPointerOver = false; } private void OnDisable() { IsPointerOver = false; } } internal static class CardParts { public const float PanelSpacing = 6f; public const float ButtonHeight = 28f; public static readonly Color BackgroundColor = new Color(0.07f, 0.08f, 0.11f, 0.94f); public static readonly Color BorderColor = new Color(1f, 1f, 1f, 0.18f); public static readonly Color AccentColor = new Color(0.95f, 0.77f, 0.3f); public static readonly Color DividerColor = new Color(1f, 1f, 1f, 0.35f); public static readonly Color SubtleTextColor = new Color(0.68f, 0.7f, 0.74f); public static readonly Color ButtonColor = new Color(0.24f, 0.26f, 0.31f); public static readonly Color SelectedButtonColor = new Color(0.36f, 0.31f, 0.18f); public static readonly Color ForceEndColor = new Color(0.55f, 0.18f, 0.16f); public static readonly Color DoneColor = new Color(0.5f, 0.82f, 0.5f); public static readonly Color WarningColor = new Color(0.88f, 0.48f, 0.42f); private static readonly Color _missingPortraitColor = new Color(1f, 1f, 1f, 0.15f); public static Image CreatePanel(Transform parent, LootVoteHud hud, out Outline border) { //IL_0006: 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) //IL_0048: 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_006a: Expected O, but got Unknown Image val = UiFactory.Image(parent, "Main", BackgroundColor); hud.RegisterHoverTracker(((Component)val).gameObject.AddComponent<CardHoverTracker>()); border = ((Component)val).gameObject.AddComponent<Outline>(); ((Shadow)border).effectColor = BorderColor; ((Shadow)border).effectDistance = new Vector2(2f, -2f); UiFactory.Vertical((Component)(object)val, 6f, new RectOffset(12, 12, 12, 10)); return val; } public static GameObject CreateDivider(Transform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Image obj = UiFactory.Image(parent, "Divider", DividerColor); UiFactory.Layout((Component)(object)obj, -1f, 2f); return ((Component)obj).gameObject; } public static RawImage CreatePortrait(Transform parent, int bodyIndex, float size) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) RawImage obj = ((Component)UiFactory.Create("Portrait", parent)).gameObject.AddComponent<RawImage>(); CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent((BodyIndex)bodyIndex); obj.texture = (Object.op_Implicit((Object)(object)bodyPrefabBodyComponent) ? bodyPrefabBodyComponent.portraitIcon : null); ((Graphic)obj).color = (Object.op_Implicit((Object)(object)obj.texture) ? Color.white : _missingPortraitColor); UiFactory.Layout((Component)(object)obj, size, size); return obj; } public static void CreateNameBlock(Transform row, string label, float fontSize, VoteCandidate candidate, PickupIndex focusPickup) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) RectTransform val = UiFactory.Create("NameBlock", row); ((LayoutGroup)UiFactory.Vertical((Component)(object)val, 0f)).childAlignment = (TextAnchor)3; UiFactory.Layout((Component)(object)val, -1f, -1f, 1f); HGTextMeshProUGUI obj = UiFactory.Text((Transform)(object)val, "Name", fontSize, Color.white, (TextAlignmentOptions)4097); ((TMP_Text)obj).enableWordWrapping = false; ((TMP_Text)obj).overflowMode = (TextOverflowModes)1; ((TMP_Text)obj).text = label; if (LootVoteConfig.ShowItemCounts.Value) { HGTextMeshProUGUI obj2 = UiFactory.Text((Transform)(object)val, "ItemCounts", 12f, Color.white, (TextAlignmentOptions)4097); ((TMP_Text)obj2).enableWordWrapping = false; ItemCounts.Track(obj2, candidate.UserNetId, focusPickup); } } public static Image CreateTextButton(Transform parent, string label, Color color, UnityAction onClick) { //IL_0002: 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) Image val = UiFactory.Image(parent, label, color); UiFactory.Layout((Component)(object)val, -1f, 28f); UiFactory.Button(((Component)val).gameObject, (Graphic)(object)val, onClick); HGTextMeshProUGUI obj = UiFactory.Text(((Component)val).transform, "Text", 15f, Color.white, (TextAlignmentOptions)514); ((TMP_Text)obj).text = label; ((TMP_Text)obj).enableWordWrapping = false; ((TMP_Text)obj).overflowMode = (TextOverflowModes)1; UiFactory.Stretch(((TMP_Text)obj).rectTransform, 4f); return val; } public static string NameWithTags(string name, List<string> tags, bool struckThrough = false, bool declined = false) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) string text = Util.EscapeRichTextForTextMeshPro(name); if (declined) { text = Colored(text, WarningColor); } else if (struckThrough) { text = "<s><color=#8a8f98>" + text + "</color></s>"; } if (tags.Count > 0) { text = text + " <size=75%><color=#aab0bb>(" + string.Join(", ", tags) + ")</color></size>"; } return text; } public static string Colored(string text, Color color) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) return "<color=#" + ColorUtility.ToHtmlStringRGB(color) + ">" + text + "</color>"; } public static bool IsMe(VoteCandidate candidate) { //IL_001b: 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) LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); NetworkUser val = ((firstLocalUser != null) ? firstLocalUser.currentNetworkUser : null); if (Object.op_Implicit((Object)(object)val)) { return candidate.UserNetId == ((NetworkBehaviour)val).netId; } return false; } public static AssetOrDirectReference<Sprite> ShowPickupIcon(Image image, PickupDef pickupDef) { if (Object.op_Implicit((Object)(object)pickupDef.iconSprite)) { image.sprite = pickupDef.iconSprite; return null; } AssetOrDirectReference<Sprite> iconAODR = pickupDef.GetIconAODR(true, (Action<Sprite>)delegate(Sprite sprite) { if (Object.op_Implicit((Object)(object)image)) { image.sprite = sprite; } }, (Action<Sprite>)null); if (iconAODR != null && iconAODR.IsLoaded()) { image.sprite = iconAODR.Result; } return iconAODR; } } internal static class ItemCounts { private class TrackedLabel { public HGTextMeshProUGUI Text; public NetworkInstanceId UserNetId; public PickupIndex FocusPickup; } private const string _zeroAlpha = "55"; private static readonly ItemTier[] _shownTiers; private static readonly ItemTier[] _voidTiers; private static readonly List<TrackedLabel> _labels; public static void Init() { Inventory.onInventoryChangedGlobal += OnInventoryChanged; } public static void Track(HGTextMeshProUGUI text, NetworkInstanceId userNetId, PickupIndex focusPickup) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_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_004f: 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) _labels.RemoveAll((TrackedLabel label) => !Object.op_Implicit((Object)(object)label.Text)); _labels.Add(new TrackedLabel { Text = text, UserNetId = userNetId, FocusPickup = focusPickup }); ((TMP_Text)text).text = Text(userNetId, focusPickup); } public static string Text(NetworkInstanceId userNetId, PickupIndex focusPickup) { //IL_0000: 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_0030: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) Inventory val = FindInventory(userNetId); if (!Object.op_Implicit((Object)(object)val)) { return ""; } List<string> list = new List<string>(); ItemTier[] shownTiers = _shownTiers; foreach (ItemTier val2 in shownTiers) { list.Add(Number(val.GetTotalItemCountOfTier(val2), val2)); } int num = 0; shownTiers = _voidTiers; foreach (ItemTier val3 in shownTiers) { num += val.GetTotalItemCountOfTier(val3); } list.Add(Number(num, (ItemTier)7)); string text = string.Join(" ", list); int num2 = OwnedCount(val, focusPickup); if (num2 > 0) { text += $" <color=#ffffff>has {num2}</color>"; } return text; } private static int OwnedCount(Inventory inventory, PickupIndex pickupIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_0017: 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_0032: Unknown result type (might be due to invalid IL or missing references) PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef == null) { return 0; } if ((int)pickupDef.itemIndex != -1) { return inventory.GetItemCountEffective(pickupDef.itemIndex); } return ((int)pickupDef.equipmentIndex != -1 && inventory.GetEquipmentIndex() == pickupDef.equipmentIndex) ? 1 : 0; } private static string Number(int count, ItemTier colourTier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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) //IL_000f: 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_003d: Unknown result type (might be due to invalid IL or missing references) ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(colourTier); Color val = (Object.op_Implicit((Object)(object)itemTierDef) ? Color32.op_Implicit(ColorCatalog.GetColor(itemTierDef.colorIndex)) : Color.white); string arg = ((count > 0) ? "" : "55"); return $"<color=#{ColorUtility.ToHtmlStringRGB(val)}{arg}>{count}</color>"; } private static Inventory FindInventory(NetworkInstanceId userNetId) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if (Object.op_Implicit((Object)(object)readOnlyInstances) && ((NetworkBehaviour)readOnlyInstances).netId == userNetId) { return Object.op_Implicit((Object)(object)readOnlyInstances.master) ? readOnlyInstances.master.inventory : null; } } return null; } private static void OnInventoryChanged(Inventory inventory) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_00a8: Unknown result type (might be due to invalid IL or missing references) _labels.RemoveAll((TrackedLabel label) => !Object.op_Implicit((Object)(object)label.Text)); if (_labels.Count == 0 || !Object.op_Implicit((Object)(object)inventory)) { return; } CharacterMaster component = ((Component)inventory).GetComponent<CharacterMaster>(); NetworkUser val = ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.playerCharacterMasterController)) ? component.playerCharacterMasterController.networkUser : null); if (!Object.op_Implicit((Object)(object)val)) { return; } foreach (TrackedLabel label in _labels) { if (label.UserNetId == ((NetworkBehaviour)val).netId) { ((TMP_Text)label.Text).text = Text(((NetworkBehaviour)val).netId, label.FocusPickup); } } } static ItemCounts() { ItemTier[] array = new ItemTier[5]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); _shownTiers = (ItemTier[])(object)array; ItemTier[] array2 = new ItemTier[4]; RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); _voidTiers = (ItemTier[])(object)array2; _labels = new List<TrackedLabel>(); } } internal class LootVoteHud : MonoBehaviour { [CompilerGenerated] private static class <>O { public static hook_Awake <0>__OnHudAwake; public static hook_GetUIPassthrough <1>__OnGetUiPassthrough; } private const float _columnWidth = 380f; private const float _columnOffsetX = 24f; private const float _columnOffsetY = 40f; private const float _cardSpacing = 28f; private static readonly List<LootVoteHud> _instances = new List<LootVoteHud>(); private static int _skipKeyUsedFrame = -1; private readonly List<CardHoverTracker> _hoverTrackers = new List<CardHoverTracker>(); private RectTransform _column; private GameObject _cursorOpener; private UIInputPassthrough _movementPassthrough; public bool CursorShown { get { if (Object.op_Implicit((Object)(object)_cursorOpener)) { return _cursorOpener.activeSelf; } return false; } } public event Action CursorChanged; public static void Init() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but