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 BuyDvergrExtractorNeedle v1.1.0
BuyExtractorNeedle.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using ConditionalConfigSync; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Buy Dvergr Extractor Needle")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Buy Dvergr Extractor Needle")] [assembly: AssemblyCopyright("Copyright © 2024-2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("1bd1a4b7-cfc5-48c2-b443-1c91bd448dba")] [assembly: AssemblyFileVersion("1.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.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 BuyExtractorNeedle { public class BuyAndDestroy : MonoBehaviour, Hoverable, Interactable { internal sealed class PaymentItem { internal readonly string PrefabName; internal readonly string SharedName; internal int Amount; internal PaymentItem(string prefabName, string sharedName, int amount) { PrefabName = prefabName; SharedName = sharedName; Amount = amount; } internal PaymentItem Clone(int amount) { return new PaymentItem(PrefabName, SharedName, amount); } } internal sealed class PurchaseData { internal readonly string BuyerName; internal readonly string PurchasedPrefabName; internal readonly List<PaymentItem> Payment; internal PurchaseData(string buyerName, string purchasedPrefabName, List<PaymentItem> payment) { BuyerName = buyerName; PurchasedPrefabName = purchasedPrefabName; Payment = payment ?? new List<PaymentItem>(); } } internal const float DvergrSearchRadius = 30f; private const string PurchaseRpc = "BEN_BuyAndRemove"; private static readonly int PurchaseProcessedZdoKey = StringExtensionMethods.GetStableHashCode("shudnal.BuyExtractorNeedle.PurchaseProcessed"); public string m_text = ""; public Destructible m_destructible; public WearNTear m_wnt; public ZNetView m_nview; public string m_requirements; public string m_description; public int m_myIndex = -1; public static readonly List<BuyAndDestroy> s_allInstances = new List<BuyAndDestroy>(); public static readonly List<string> s_randomBuy = new List<string> { "$npc_haldor_random_buy1", "$npc_haldor_random_buy3", "$npc_haldor_random_buy4", "$npc_haldor_random_buy5", "$npc_haldor_random_sell1", "$npc_haldor_random_sell2", "$npc_haldor_random_greet4", "$npc_haldor_random_sell4" }; public static EffectList s_randomSellFX; public void Awake() { EnsureSellEffects(); IDestructible component = ((Component)this).GetComponent<IDestructible>(); m_destructible = (Destructible)(object)((component is Destructible) ? component : null); m_wnt = (WearNTear)(object)((component is WearNTear) ? component : null); s_allInstances.Add(this); m_myIndex = s_allInstances.Count - 1; m_requirements = BuyExtractorNeedle.requirements.Value; m_nview = (((Object)(object)m_destructible != (Object)null) ? m_destructible.m_nview : (((Object)(object)m_wnt != (Object)null) ? m_wnt.m_nview : null)); if ((Object)(object)m_nview != (Object)null && m_nview.GetZDO() != null) { m_nview.Register<ZPackage>("BEN_BuyAndRemove", (Action<long, ZPackage>)RPC_BuyAndRemove); } } public void OnDestroy() { if (m_myIndex >= 0 && m_myIndex < s_allInstances.Count) { int index = s_allInstances.Count - 1; s_allInstances[m_myIndex] = s_allInstances[index]; s_allInstances[m_myIndex].m_myIndex = m_myIndex; s_allInstances.RemoveAt(index); m_myIndex = -1; } } public string GetHoverText() { if ((Object)(object)m_destructible == (Object)null && (Object)(object)m_wnt == (Object)null) { return GetHoverName(); } if (string.IsNullOrWhiteSpace(m_description) && !string.IsNullOrWhiteSpace(m_requirements)) { m_description = GetDescription(m_requirements); } string text = (string.IsNullOrWhiteSpace(m_description) ? "$piece_itemstand_take" : ("$store_buy " + m_description)); return Localization.instance.Localize(m_text + "\n[<color=yellow><b>$KEY_Use</b></color>] " + text); } public string GetHoverName() { return Localization.instance.Localize(m_text); } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) if (hold || alt || ((Object)(object)m_destructible == (Object)null && (Object)(object)m_wnt == (Object)null) || (Object)(object)user == (Object)null) { return false; } if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return false; } string buyerName = GetBuyerName(user); List<PaymentItem> requirements = GetRequirements(m_requirements); if (!HasNearbyDvergr(((Component)this).transform.position)) { Remove(Array.Empty<PaymentItem>(), buyerName); return true; } Inventory inventory = user.GetInventory(); if (requirements.Count > 0 && requirements.Any((PaymentItem item) => inventory.CountItems(item.SharedName, -1, true) < item.Amount)) { PrivateArea.OnObjectDamaged(((Component)this).transform.position, (Character)(object)user, false); return true; } foreach (PaymentItem item in requirements) { inventory.RemoveItem(item.SharedName, item.Amount, -1, true); } if (requirements.Count > 0 && (Object)(object)StoreGui.instance != (Object)null) { StoreGui.instance.m_sellEffects.Create(((Component)this).transform.position, Quaternion.identity, (Transform)null, 1f, -1); } Remove(requirements, buyerName); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } private void Remove(IEnumerable<PaymentItem> payment, string buyerName) { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { string prefabName = m_nview.GetPrefabName(); m_nview.InvokeRPC("BEN_BuyAndRemove", new object[1] { CreatePurchasePackage(buyerName, prefabName, payment) }); } } private void RPC_BuyAndRemove(long sender, ZPackage package) { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid() || !m_nview.IsOwner()) { return; } PurchaseData purchaseData = ReadPurchasePackage(package); List<PaymentItem> payment = purchaseData.Payment; ZDO zDO = m_nview.GetZDO(); if (zDO == null) { return; } if (zDO.GetBool(PurchaseProcessedZdoKey, false)) { RefundPayment(payment); if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning("A repeated purchase of '" + purchaseData.PurchasedPrefabName + "' by player '" + purchaseData.BuyerName + "' was rejected and its payment was refunded: " + FormatPayment(payment) + "."); } return; } zDO.Set(PurchaseProcessedZdoKey, true); DvergrPaidItemStorage dvergrPaidItemStorage = DvergrPaidItemStorage.FindClosest(((Component)this).transform.position, 30f); if ((Object)(object)dvergrPaidItemStorage == (Object)null) { RefundPayment(payment); if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogInfo("Player '" + purchaseData.BuyerName + "' obtained '" + purchaseData.PurchasedPrefabName + "' for free because no Dvergr was available to accept payment."); } DestroyPurchasedObject(); } else if (!dvergrPaidItemStorage.AcceptPurchase(purchaseData)) { RefundPayment(payment); if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning("Purchase of '" + purchaseData.PurchasedPrefabName + "' by player '" + purchaseData.BuyerName + "' could not be assigned to " + dvergrPaidItemStorage.GetLogDescription() + ". Refunded payment: " + FormatPayment(payment) + "."); } DestroyPurchasedObject(); } else { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogInfo("Player '" + purchaseData.BuyerName + "' bought '" + purchaseData.PurchasedPrefabName + "' for " + FormatPayment(payment) + ". Primary payment recipient: " + dvergrPaidItemStorage.GetLogDescription() + "."); } DestroyPurchasedObject(); } } private void DestroyPurchasedObject() { if ((Object)(object)m_destructible != (Object)null) { m_destructible.Destroy((HitData)null); } else if ((Object)(object)m_wnt != (Object)null) { m_wnt.Destroy((HitData)null, false); } } private void RefundPayment(IEnumerable<PaymentItem> payment) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) foreach (PaymentItem item in payment) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(item.PrefabName) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); if (!((Object)(object)val2 == (Object)null) && val2.m_itemData != null && val2.m_itemData.m_shared != null) { int val3 = Math.Max(1, val2.m_itemData.m_shared.m_maxStackSize); int num = item.Amount; while (num > 0) { int num2 = Math.Min(val3, num); DropItemStack(val, val2, num2, ((Component)this).transform.position + Vector3.up, Quaternion.identity); num -= num2; } } } } internal static ItemDrop DropItemStack(GameObject prefab, ItemDrop itemDrop, int amount, Vector3 position, Quaternion rotation) { //IL_0042: 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) if ((Object)(object)prefab == (Object)null || (Object)(object)itemDrop == (Object)null || itemDrop.m_itemData == null || amount <= 0) { return null; } ItemData val = itemDrop.m_itemData.Clone(); val.m_dropPrefab = prefab; return ItemDrop.DropItem(val, amount, position, rotation); } internal static void PlaySaleResponse(NpcTalk npcTalk, int lineIndex) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)npcTalk == (Object)null) && s_randomBuy.Count != 0) { EnsureSellEffects(); s_randomSellFX.Create(((Component)npcTalk).transform.position, Quaternion.identity, (Transform)null, 1f, -1); int index = Mathf.Clamp(lineIndex, 0, s_randomBuy.Count - 1); npcTalk.Say(s_randomBuy[index], "Talk"); } } private static void EnsureSellEffects() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (s_randomSellFX == null) { object obj; if (!((Object)(object)ZNetScene.instance != (Object)null)) { obj = null; } else { GameObject prefab = ZNetScene.instance.GetPrefab("Haldor"); obj = ((prefab != null) ? prefab.GetComponent<Trader>() : null); } Trader val = (Trader)obj; s_randomSellFX = (EffectList)(((Object)(object)val != (Object)null) ? ((object)val.m_randomSellFX) : ((object)new EffectList())); } } private static bool HasNearbyDvergr(Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return (Object)(object)DvergrPaidItemStorage.FindClosest(position, 30f) != (Object)null; } private static string GetBuyerName(Humanoid user) { Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val != (Object)null) { string playerName = val.GetPlayerName(); if (!string.IsNullOrWhiteSpace(playerName)) { return playerName; } } return (!string.IsNullOrWhiteSpace(((Object)user).name)) ? ((Object)user).name : "Unknown player"; } private static string GetDescription(string requirements) { return string.Join(", ", (from item in GetRequirements(requirements) select item.SharedName + " x" + item.Amount).ToArray()); } private static List<PaymentItem> GetRequirements(string requirements) { List<PaymentItem> list = new List<PaymentItem>(); Dictionary<string, PaymentItem> dictionary = new Dictionary<string, PaymentItem>(StringComparer.Ordinal); if (string.IsNullOrWhiteSpace(requirements) || (Object)(object)ObjectDB.instance == (Object)null) { return list; } string[] array = requirements.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length != 2 || !int.TryParse(array2[1].Trim(), out var result) || result <= 0) { continue; } string text2 = array2[0].Trim(); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text2); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); string text3 = (((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null) ? val.m_itemData.m_shared.m_name : null); if (!string.IsNullOrEmpty(text3)) { if (dictionary.TryGetValue(text2, out var value)) { value.Amount = (int)Math.Min(2147483647L, (long)value.Amount + (long)result); continue; } PaymentItem paymentItem = new PaymentItem(text2, text3, result); dictionary.Add(text2, paymentItem); list.Add(paymentItem); } } return list; } internal static ZPackage CreatePurchasePackage(string buyerName, string purchasedPrefabName, IEnumerable<PaymentItem> payment) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(buyerName ?? "Unknown player"); val.Write(purchasedPrefabName ?? "Unknown prefab"); WritePayment(val, payment); return val; } internal static PurchaseData ReadPurchasePackage(ZPackage package) { if (package == null) { return new PurchaseData("Unknown player", "Unknown prefab", new List<PaymentItem>()); } try { string buyerName = package.ReadString(); string purchasedPrefabName = package.ReadString(); return new PurchaseData(buyerName, purchasedPrefabName, ReadPayment(package)); } catch (Exception ex) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning("Failed to read purchase package: " + ex.Message); } return new PurchaseData("Unknown player", "Unknown prefab", new List<PaymentItem>()); } } internal static string FormatPayment(IEnumerable<PaymentItem> payment) { if (payment == null) { return "nothing"; } string[] array = (from item in payment where item != null && item.Amount > 0 select item.PrefabName + " x" + item.Amount).ToArray(); return (array.Length != 0) ? string.Join(", ", array) : "nothing"; } private static void WritePayment(ZPackage package, IEnumerable<PaymentItem> payment) { List<PaymentItem> list = ((payment != null) ? payment.Where((PaymentItem item) => item != null && item.Amount > 0).ToList() : new List<PaymentItem>()); package.Write(list.Count); foreach (PaymentItem item in list) { package.Write(item.PrefabName); package.Write(item.Amount); } } private static List<PaymentItem> ReadPayment(ZPackage package) { List<PaymentItem> list = new List<PaymentItem>(); int num = Mathf.Clamp(package.ReadInt(), 0, 64); for (int i = 0; i < num; i++) { string text = package.ReadString(); int num2 = package.ReadInt(); GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(text) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); string text2 = (((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null) ? val2.m_itemData.m_shared.m_name : null); if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2) && num2 > 0) { list.Add(new PaymentItem(text, text2, num2)); } } return list; } public static List<BuyAndDestroy> GetAllInstances() { return s_allInstances; } public static void UpdateDescription() { foreach (BuyAndDestroy s_allInstance in s_allInstances) { s_allInstance.m_requirements = BuyExtractorNeedle.requirements.Value; s_allInstance.m_description = ""; } } } [BepInPlugin("shudnal.BuyExtractorNeedle", "Buy Dvergr Extractor Needle", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class BuyExtractorNeedle : BaseUnityPlugin { [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetSceneAwakePatch { private static void Postfix(ZNetScene __instance) { ApplyConfiguredPrefabs(__instance); } } public const string pluginID = "shudnal.BuyExtractorNeedle"; public const string pluginName = "Buy Dvergr Extractor Needle"; public const string pluginVersion = "1.1.0"; private readonly Harmony harmony = new Harmony("shudnal.BuyExtractorNeedle"); internal static readonly ConfigSync configSync = new ConfigSync("shudnal.BuyExtractorNeedle") { DisplayName = "Buy Dvergr Extractor Needle", CurrentVersion = "1.1.0", MinimumRequiredVersion = "1.1.0", ModRequired = true }; public static BuyExtractorNeedle instance; public static ConfigEntry<bool> configLocked; public static ConfigEntry<string> requirements; public static ConfigEntry<string> targetPrefabs; public static ConfigEntry<bool> loggingEnabled; private static readonly Dictionary<string, string> managedPrefabTexts = new Dictionary<string, string>(StringComparer.Ordinal); private void Awake() { instance = this; ConfigInit(); ((ConditionalConfigSync)configSync).AddLockingConfigEntry<bool>(configLocked); harmony.PatchAll(); Game.isModded = true; } private void ConfigInit() { configLocked = BindConfig("General", "Lock Configuration", defaultValue: true, "Configuration is locked and can be changed by server admins only."); requirements = BindConfig("General", "Required items", "Coins:4000", "Items required to buy a configured crate. Use prefab names separated by commas, for example Coins:4000 or Coins:2000,BlackCore:1."); targetPrefabs = BindConfig("General", "Target prefabs", "dvergrprops_crate_long", "Prefab names that should become purchasable, separated by commas."); loggingEnabled = BindConfig("General", "Enable logging", defaultValue: false, "Enable logging for interaction events.", synchronizedSetting: false); requirements.SettingChanged += delegate { BuyAndDestroy.UpdateDescription(); }; targetPrefabs.SettingChanged += delegate { ApplyConfiguredPrefabs(ZNetScene.instance); }; } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); instance = null; harmony.UnpatchSelf(); } public static void LogInfo(object data) { if (loggingEnabled.Value) { ((BaseUnityPlugin)instance).Logger.LogInfo(data); } } public static void LogWarning(object data) { ((BaseUnityPlugin)instance).Logger.LogWarning(data); } private ConfigEntry<T> BindConfig<T>(string group, string name, T defaultValue, ConfigDescription description, bool synchronizedSetting = true) { ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, defaultValue, description); SyncedConfigEntry<T> val2 = ((ConditionalConfigSync)configSync).AddConfigEntry<T>(val); ((OwnConfigEntryBase)val2).SynchronizedConfig = synchronizedSetting; return val; } private ConfigEntry<T> BindConfig<T>(string group, string name, T defaultValue, string description, bool synchronizedSetting = true) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return BindConfig(group, name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } private static IEnumerable<string> GetTargetPrefabNames() { HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); string text = ((targetPrefabs != null) ? targetPrefabs.Value : "dvergrprops_crate_long"); string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { string text3 = text2.Trim(); if (!string.IsNullOrEmpty(text3)) { hashSet.Add(text3); } } return hashSet; } internal static void ApplyConfiguredPrefabs(ZNetScene scene) { if ((Object)(object)scene == (Object)null) { return; } HashSet<string> hashSet = new HashSet<string>(GetTargetPrefabNames(), StringComparer.Ordinal); foreach (string item in new List<string>(managedPrefabTexts.Keys)) { if (!hashSet.Contains(item)) { GameObject prefab = scene.GetPrefab(item); BuyAndDestroy buyAndDestroy = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<BuyAndDestroy>() : null); if ((Object)(object)buyAndDestroy != (Object)null) { HoverText val = prefab.GetComponent<HoverText>() ?? prefab.AddComponent<HoverText>(); val.m_text = managedPrefabTexts[item]; Object.Destroy((Object)(object)buyAndDestroy); } managedPrefabTexts.Remove(item); } } foreach (string item2 in hashSet) { GameObject prefab2 = scene.GetPrefab(item2); if ((Object)(object)prefab2 == (Object)null) { if ((Object)(object)instance != (Object)null) { LogWarning("Target prefab was not found: " + item2); } continue; } BuyAndDestroy component = prefab2.GetComponent<BuyAndDestroy>(); if ((Object)(object)component != (Object)null) { managedPrefabTexts[item2] = component.m_text; continue; } HoverText component2 = prefab2.GetComponent<HoverText>(); if ((Object)(object)component2 == (Object)null) { if ((Object)(object)instance != (Object)null) { LogWarning("Target prefab does not have HoverText and cannot be made purchasable: " + item2); } } else { managedPrefabTexts[item2] = component2.m_text; BuyAndDestroy buyAndDestroy2 = prefab2.AddComponent<BuyAndDestroy>(); buyAndDestroy2.m_text = component2.m_text; Object.Destroy((Object)(object)component2); } } } } internal sealed class DvergrPaidItemStorage : MonoBehaviour { [HarmonyPatch(typeof(Character), "Awake")] private static class CharacterAwakePatch { private static void Postfix(Character __instance) { if (IsDvergr(__instance) && (Object)(object)((Component)__instance).GetComponent<DvergrPaidItemStorage>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<DvergrPaidItemStorage>(); } } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] private static class CharacterDropGenerateDropListPatch { private static void Postfix(CharacterDrop __instance) { DropPaidItems(__instance); } } private static readonly int PaidItemsZdoKey = StringExtensionMethods.GetStableHashCode("shudnal.BuyExtractorNeedle.PaidItems"); private const string AcceptPurchaseRpc = "BEN_AcceptPurchase"; private const string StorePaymentRpc = "BEN_StorePayment"; private const string PlayResponseRpc = "BEN_PlayResponse"; private NpcTalk npcTalk; internal ZNetView nview; private bool initialized; private void Awake() { Initialize(); } private bool Initialize() { if (initialized) { return true; } Character component = ((Component)this).GetComponent<Character>(); npcTalk = ((Component)this).GetComponent<NpcTalk>(); nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || (Object)(object)npcTalk == (Object)null || (Object)(object)nview == (Object)null || nview.GetZDO() == null) { return false; } nview.Register<ZPackage>("BEN_AcceptPurchase", (Action<long, ZPackage>)RPC_AcceptPurchase); nview.Register<ZPackage>("BEN_StorePayment", (Action<long, ZPackage>)RPC_StorePayment); nview.Register<int>("BEN_PlayResponse", (Action<long, int>)RPC_PlayResponse); initialized = true; return true; } internal bool AcceptPurchase(BuyAndDestroy.PurchaseData purchase) { if (!Initialize() || !nview.IsValid() || purchase == null) { return false; } nview.InvokeRPC("BEN_AcceptPurchase", new object[1] { BuyAndDestroy.CreatePurchasePackage(purchase.BuyerName, purchase.PurchasedPrefabName, purchase.Payment) }); return true; } private bool StorePayment(BuyAndDestroy.PurchaseData purchase) { if (!Initialize() || !nview.IsValid() || purchase == null) { return false; } nview.InvokeRPC("BEN_StorePayment", new object[1] { BuyAndDestroy.CreatePurchasePackage(purchase.BuyerName, purchase.PurchasedPrefabName, purchase.Payment) }); return true; } private void RPC_AcceptPurchase(long sender, ZPackage package) { if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner()) { BuyAndDestroy.PurchaseData purchase = BuyAndDestroy.ReadPurchasePackage(package); DistributeAndStorePayment(purchase, 30f); int num = Random.Range(0, BuyAndDestroy.s_randomBuy.Count); nview.InvokeRPC(ZRoutedRpc.Everybody, "BEN_PlayResponse", new object[1] { num }); } } private void RPC_StorePayment(long sender, ZPackage package) { if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner()) { BuyAndDestroy.PurchaseData purchaseData = BuyAndDestroy.ReadPurchasePackage(package); StoreItems(purchaseData.Payment, purchaseData); } } private void RPC_PlayResponse(long sender, int lineIndex) { BuyAndDestroy.PlaySaleResponse(npcTalk, lineIndex); } private void DistributeAndStorePayment(BuyAndDestroy.PurchaseData purchase, float radius) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) List<BuyAndDestroy.PaymentItem> list = ClonePayment(purchase.Payment); List<DvergrPaidItemStorage> list2 = FindNearby(((Component)this).transform.position, radius, this); List<string> list3 = new List<string>(); int num = 0; foreach (BuyAndDestroy.PaymentItem item in list) { int maxStackSize = GetMaxStackSize(item.PrefabName); while (item.Amount > maxStackSize && num < list2.Count) { DvergrPaidItemStorage dvergrPaidItemStorage = list2[num++]; List<BuyAndDestroy.PaymentItem> payment = new List<BuyAndDestroy.PaymentItem> { item.Clone(maxStackSize) }; BuyAndDestroy.PurchaseData purchase2 = new BuyAndDestroy.PurchaseData(purchase.BuyerName, purchase.PurchasedPrefabName, payment); if (dvergrPaidItemStorage.StorePayment(purchase2)) { item.Amount -= maxStackSize; list3.Add(dvergrPaidItemStorage.GetLogDescription() + " <- " + BuyAndDestroy.FormatPayment(payment)); } else if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning("Could not assign " + BuyAndDestroy.FormatPayment(payment) + " from player '" + purchase.BuyerName + "' to " + dvergrPaidItemStorage.GetLogDescription() + ". The main Dvergr will keep it instead."); } } } StoreItems(list, purchase); list3.Insert(0, GetLogDescription() + " <- " + BuyAndDestroy.FormatPayment(list)); if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogInfo("Payment distribution for player '" + purchase.BuyerName + "' buying '" + purchase.PurchasedPrefabName + "': " + string.Join("; ", list3.ToArray()) + "."); } } private void StoreItems(IEnumerable<BuyAndDestroy.PaymentItem> payment, BuyAndDestroy.PurchaseData purchase) { ZDO val = (((Object)(object)nview != (Object)null) ? nview.GetZDO() : null); if (val == null) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning("Could not store payment on " + GetLogDescription() + " because its ZDO is unavailable."); } return; } List<BuyAndDestroy.PaymentItem> list = ClonePayment(payment); Dictionary<string, int> dictionary = ReadStoredItems(val); foreach (BuyAndDestroy.PaymentItem item in list) { dictionary.TryGetValue(item.PrefabName, out var value); dictionary[item.PrefabName] = (int)Math.Min(2147483647L, (long)value + (long)item.Amount); } WriteStoredItems(val, dictionary); if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogInfo("Stored payment from player '" + purchase.BuyerName + "' for '" + purchase.PurchasedPrefabName + "' on " + GetLogDescription() + ": added " + BuyAndDestroy.FormatPayment(list) + "; total stored " + FormatStoredItems(dictionary) + "."); } } private static List<BuyAndDestroy.PaymentItem> ClonePayment(IEnumerable<BuyAndDestroy.PaymentItem> payment) { List<BuyAndDestroy.PaymentItem> list = new List<BuyAndDestroy.PaymentItem>(); if (payment == null) { return list; } foreach (BuyAndDestroy.PaymentItem item in payment) { if (item != null && item.Amount > 0) { list.Add(item.Clone(item.Amount)); } } return list; } private static int GetMaxStackSize(string prefabName) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); return ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null) ? Math.Max(1, val2.m_itemData.m_shared.m_maxStackSize) : int.MaxValue; } internal static DvergrPaidItemStorage FindClosest(Vector3 position, float radius) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) List<DvergrPaidItemStorage> list = FindNearby(position, radius, null); return (list.Count > 0) ? list[0] : null; } private static List<DvergrPaidItemStorage> FindNearby(Vector3 position, float radius, DvergrPaidItemStorage excluded) { //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_0015: Unknown result type (might be due to invalid IL or missing references) List<Character> list = new List<Character>(); Character.GetCharactersInRange(position, radius, list); List<DvergrPaidItemStorage> list2 = new List<DvergrPaidItemStorage>(); foreach (Character item in list) { if (IsDvergr(item)) { DvergrPaidItemStorage dvergrPaidItemStorage = ((Component)item).GetComponent<DvergrPaidItemStorage>(); if ((Object)(object)dvergrPaidItemStorage == (Object)null) { dvergrPaidItemStorage = ((Component)item).gameObject.AddComponent<DvergrPaidItemStorage>(); } if (!((Object)(object)dvergrPaidItemStorage == (Object)(object)excluded) && dvergrPaidItemStorage.Initialize() && dvergrPaidItemStorage.nview.IsValid()) { list2.Add(dvergrPaidItemStorage); } } } list2.Sort(delegate(DvergrPaidItemStorage left, DvergrPaidItemStorage right) { //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) //IL_0012: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)left).transform.position - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = ((Component)right).transform.position - position; float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude; return sqrMagnitude.CompareTo(sqrMagnitude2); }); return list2; } internal static bool IsDvergr(Character candidate) { if ((Object)(object)candidate == (Object)null || (Object)(object)((Component)candidate).GetComponent<NpcTalk>() == (Object)null) { return false; } ZNetView component = ((Component)candidate).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || component.GetZDO() == null) { return false; } string prefabName = component.GetPrefabName(); return !string.IsNullOrEmpty(prefabName) && prefabName.StartsWith("Dverger", StringComparison.Ordinal); } internal string GetLogDescription() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) string text = (((Object)(object)nview != (Object)null) ? nview.GetPrefabName() : ((Object)((Component)this).gameObject).name); if (string.IsNullOrEmpty(text)) { text = ((Object)((Component)this).gameObject).name; } string text2 = text; Vector3 position = ((Component)this).transform.position; return "'" + text2 + "' at " + ((Vector3)(ref position)).ToString("F1"); } private static string GetLogDescription(Character character, ZNetView characterView) { //IL_0066: 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_006b: Unknown result type (might be due to invalid IL or missing references) string text = (((Object)(object)characterView != (Object)null) ? characterView.GetPrefabName() : (((Object)(object)character != (Object)null) ? ((Object)((Component)character).gameObject).name : "Unknown Dvergr")); if (string.IsNullOrEmpty(text) && (Object)(object)character != (Object)null) { text = ((Object)((Component)character).gameObject).name; } Vector3 val = (((Object)(object)character != (Object)null) ? ((Component)character).transform.position : Vector3.zero); return "'" + text + "' at " + ((Vector3)(ref val)).ToString("F1"); } private static Dictionary<string, int> ReadStoredItems(ZDO zdo) { Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); if (zdo == null) { return dictionary; } string text = zdo.GetString(PaidItemsZdoKey, ""); if (string.IsNullOrEmpty(text)) { return dictionary; } string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { int num = text2.LastIndexOf(':'); if (num > 0 && num < text2.Length - 1) { string key = text2.Substring(0, num); if (int.TryParse(text2.Substring(num + 1), out var result) && result > 0) { dictionary.TryGetValue(key, out var value); dictionary[key] = (int)Math.Min(2147483647L, (long)value + (long)result); } } } return dictionary; } private static void WriteStoredItems(ZDO zdo, Dictionary<string, int> items) { if (zdo == null) { return; } List<string> list = new List<string>(); foreach (KeyValuePair<string, int> item in items) { if (!string.IsNullOrEmpty(item.Key) && item.Value > 0) { list.Add(item.Key + ":" + item.Value); } } list.Sort(StringComparer.Ordinal); zdo.Set(PaidItemsZdoKey, string.Join(";", list.ToArray())); } private static string FormatStoredItems(IDictionary<string, int> items) { if (items == null || items.Count == 0) { return "nothing"; } return string.Join(", ", (from item in items.Where((KeyValuePair<string, int> item) => !string.IsNullOrEmpty(item.Key) && item.Value > 0).OrderBy<KeyValuePair<string, int>, string>((KeyValuePair<string, int> item) => item.Key, StringComparer.Ordinal) select item.Key + " x" + item.Value).ToArray()); } private static void DropPaidItems(CharacterDrop characterDrop) { //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) Character val = (((Object)(object)characterDrop != (Object)null) ? ((Component)characterDrop).GetComponent<Character>() : null); if ((Object)(object)val == (Object)null && (Object)(object)characterDrop != (Object)null) { val = ((Component)characterDrop).GetComponentInParent<Character>(); } if ((Object)(object)val == (Object)null) { return; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); ZDO val2 = (((Object)(object)component != (Object)null) ? component.GetZDO() : null); string text = ((val2 != null) ? val2.GetString(PaidItemsZdoKey, "") : ""); if (string.IsNullOrEmpty(text)) { return; } string logDescription = GetLogDescription(val, component); if (!IsDvergr(val)) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning(logDescription + " has stored payment but was not recognized as a Dvergr at death. Raw stored value: " + text + "."); } return; } if ((Object)(object)component == (Object)null || !component.IsValid()) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning(logDescription + " died with stored payment, but its ZNetView was not valid. Raw stored value: " + text + "."); } return; } if (!component.IsOwner()) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogInfo("Stored payment drop for " + logDescription + " was skipped on this peer because it is not the ZDO owner. Raw stored value: " + text + "."); } return; } Dictionary<string, int> dictionary = ReadStoredItems(val2); if (dictionary.Count == 0) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning(logDescription + " died with an unreadable stored payment value: " + text + "."); } return; } if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogInfo(logDescription + " died with stored payment: " + FormatStoredItems(dictionary) + "."); } Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.Ordinal); int num = 0; foreach (KeyValuePair<string, int> item in dictionary) { GameObject val3 = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(item.Key) : null); ItemDrop val4 = (((Object)(object)val3 != (Object)null) ? val3.GetComponent<ItemDrop>() : null); if ((Object)(object)val4 == (Object)null || val4.m_itemData == null || val4.m_itemData.m_shared == null) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning("Cannot drop stored payment from " + logDescription + " because item prefab was not found: " + item.Key + " x" + item.Value + "."); } continue; } int val5 = Math.Max(1, val4.m_itemData.m_shared.m_maxStackSize); int num2 = item.Value; while (num2 > 0) { int num3 = Math.Min(val5, num2); Vector3 position = ((Component)val).transform.position + Vector3.up + Random.insideUnitSphere * 0.4f; ItemDrop val6; try { val6 = BuyAndDestroy.DropItemStack(val3, val4, num3, position, Random.rotation); } catch (Exception ex) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning("Failed to drop " + item.Key + " x" + num3 + " from " + logDescription + ": " + ex?.ToString() + "."); } break; } if ((Object)(object)val6 == (Object)null) { if ((Object)(object)BuyExtractorNeedle.instance != (Object)null) { BuyExtractorNeedle.LogWarning("Failed to create dropped item " + item.Key + " x" + num3 + " for " + logDescription + "."); } break; } dictionary2.TryGetValue(item.Key, out var value); dictionary2[item.Key] = value + num3; num++; num2 -= num3; } } val2.Set(PaidItemsZdoKey, ""); if (!((Object)(object)BuyExtractorNeedle.instance == (Object)null)) { int num4 = dictionary.Sum((KeyValuePair<string, int> item) => item.Value); int num5 = dictionary2.Sum((KeyValuePair<string, int> item) => item.Value); if (num5 == num4) { BuyExtractorNeedle.LogInfo(logDescription + " dropped stored payment: " + FormatStoredItems(dictionary2) + " in " + num + " stack(s)."); } else { BuyExtractorNeedle.LogWarning(logDescription + " dropped only " + FormatStoredItems(dictionary2) + " in " + num + " stack(s); expected " + FormatStoredItems(dictionary) + "."); } } } } }