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 EquivalentExchange v0.39.0
EquivalentExchange.dll
Decompiled 2 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.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EquivalentExchange.Commands; using EquivalentExchange.Core; using EquivalentExchange.Drops; using EquivalentExchange.Economy; using EquivalentExchange.InventoryUi; using EquivalentExchange.Portals; using EquivalentExchange.World; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("EquivalentExchange")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.39.0.0")] [assembly: AssemblyInformationalVersion("0.39.0+786e3d5178fc1ed5ea3bb704df11654f7e08d736")] [assembly: AssemblyProduct("EquivalentExchange")] [assembly: AssemblyTitle("EquivalentExchange")] [assembly: AssemblyVersion("0.39.0.0")] [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 EquivalentExchange { internal static class Patches { internal static void Apply(Harmony harmony, ManualLogSource log) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown Patch(harmony, log, typeof(ZNet), "SaveWorld"); Patch(harmony, log, typeof(ZNet), "SaveWorldAndPlayerProfiles"); Patch(harmony, log, typeof(ZNet), "Save"); Patch(harmony, log, typeof(ZNet), "RPC_SavePlayerProfile"); PatchSavePrefix(harmony, log); MethodInfo methodInfo = AccessTools.Method(typeof(ObjectDB), "Awake", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "OnObjectDbReady", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { log.LogWarning((object)"Harmony: ObjectDB.Awake не найден — автопрайсинг рецептов отключён."); } PatchPostfix(harmony, log, typeof(InventoryGui), "Awake", typeof(EmcInventoryUi), "OnInventoryGuiAwake"); PatchPostfix(harmony, log, typeof(InventoryGui), "Show", typeof(EmcInventoryUi), "OnInventoryGuiShow"); PatchPostfix(harmony, log, typeof(InventoryGui), "Show", typeof(EmcInventoryUi), "OnShowContainerPostfix"); PatchPostfix(harmony, log, typeof(InventoryGui), "Hide", typeof(EmcInventoryUi), "OnInventoryGuiHide"); PatchPrefix(harmony, log, typeof(InventoryGui), "OnSelectedItem", typeof(EmcInventoryUi), "OnSelectedItemPrefix"); PatchPrefix(harmony, log, typeof(InventoryGui), "UpdateContainer", typeof(EmcInventoryUi), "UpdateContainerPrefix"); PatchPostfix(harmony, log, typeof(Inventory), "GetTotalWeight", typeof(EmcInventoryUi), "GetTotalWeightPostfix"); PatchPostfix(harmony, log, typeof(InventoryGrid), "UpdateGui", typeof(EmcInventoryUi), "UpdateGuiPostfix"); PatchPostfix(harmony, log, typeof(InventoryGui), "UpdateRecipe", typeof(EmcInventoryUi), "UpdateRecipePostfix"); PatchPostfix(harmony, log, typeof(InventoryGui), "OnCraftPressed", typeof(EmcInventoryUi), "OnCraftPressedPostfix"); PatchFinalizer(harmony, log, typeof(InventoryGui), "OnCraftPressed", typeof(EmcInventoryUi), "OnCraftPressedFinalizer"); PatchPrefix(harmony, log, typeof(InventoryGui), "OnCraftCancelPressed", typeof(EmcInventoryUi), "OnCraftCancelPressedPrefix"); PatchPrefix(harmony, log, typeof(InventoryGui), "DoCrafting", typeof(EmcInventoryUi), "DoCraftingPrefix"); PatchPostfix(harmony, log, typeof(InventoryGui), "DoCrafting", typeof(EmcInventoryUi), "DoCraftingPostfix"); PatchFinalizer(harmony, log, typeof(InventoryGui), "DoCrafting", typeof(EmcInventoryUi), "DoCraftingFinalizer"); PatchPrefix(harmony, log, typeof(Player), "ConsumeResources", typeof(EmcInventoryUi), "ConsumeResourcesPrefix"); PatchPrefix(harmony, log, typeof(Player), "UpdatePlacement", typeof(EmcInventoryUi), "UpdatePlacementPrefix"); PatchFinalizer(harmony, log, typeof(Player), "UpdatePlacement", typeof(EmcInventoryUi), "UpdatePlacementFinalizer"); PatchPostfix(harmony, log, typeof(Hud), "SetupPieceInfo", typeof(EmcInventoryUi), "SetupPieceInfoPostfix"); PatchPostfix(harmony, log, typeof(TeleportWorld), "GetHoverText", typeof(PortalHoverPatch), "OnGetHoverTextPostfix"); PatchPrefix(harmony, log, typeof(TeleportWorld), "Teleport", typeof(PortalTeleportPatch), "OnPortalTeleportPrefix"); PatchFinalizer(harmony, log, typeof(TeleportWorld), "Teleport", typeof(PortalTeleportPatch), "OnPortalTeleportFinalizer"); PatchPrefix(harmony, log, typeof(Player), "TeleportTo", typeof(PortalTeleportPatch), "OnPlayerTeleportToPrefix"); PatchPostfix(harmony, log, typeof(Player), "TeleportTo", typeof(PortalTeleportPatch), "OnPlayerTeleportToPostfix"); PatchPrefix(harmony, log, typeof(Inventory), "RemoveItem", typeof(EmcInventoryUi), "RemoveItemPrefix", new Type[4] { typeof(string), typeof(int), typeof(int), typeof(bool) }); PatchPrefix(harmony, log, typeof(InventoryGui), "RepairOneItem", typeof(EmcRepair), "BlockVanillaRepair"); PatchPostfix(harmony, log, typeof(InventoryGui), "UpdateRepair", typeof(EmcRepair), "OnUpdateRepairPostfix"); PatchPrefix(harmony, log, typeof(Player), "Repair", typeof(EmcRepair), "StructureRepairPrefix"); PatchFinalizer(harmony, log, typeof(Player), "Repair", typeof(EmcRepair), "StructureRepairFinalizer"); PatchPostfix(harmony, log, typeof(WearNTear), "Repair", typeof(EmcRepair), "PieceRepairPostfix"); PatchPostfix(harmony, log, typeof(Hud), "UpdateCrosshair", typeof(EmcRepairHud), "OnUpdateCrosshairPostfix"); PatchPrefix(harmony, log, typeof(Character), "OnDeath", typeof(MobLootDrop), "OnCharacterDeathPrefix"); PatchPostfix(harmony, log, typeof(Character), "OnDeath", typeof(MobLootDrop), "OnCharacterDeathPostfix"); PatchPostfix(harmony, log, typeof(ItemDrop), "Awake", typeof(DropParticlesPatch), "OnItemDropAwakePostfix"); PatchPrefix(harmony, log, typeof(TombStone), "UpdateDespawn", typeof(TombstonePinCleanup), "OnTombstoneUpdateDespawnPrefix"); } private static void PatchPrefix(Harmony harmony, ManualLogSource log, Type type, string methodName, Type patchType, string prefixName, Type[] paramTypes = null) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, methodName, paramTypes, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(patchType, prefixName, (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { log.LogWarning((object)("Harmony: " + type.Name + "." + methodName + " или " + patchType.Name + "." + prefixName + " не найдены.")); } else { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)("Harmony: " + type.Name + "." + methodName + " перехвачен (" + patchType.Name + "." + prefixName + ").")); } } private static void PatchFinalizer(Harmony harmony, ManualLogSource log, Type type, string methodName, Type patchType, string finalizerName) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(patchType, finalizerName, (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { log.LogWarning((object)("Harmony: " + type.Name + "." + methodName + " или " + patchType.Name + "." + finalizerName + " не найдены.")); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null); log.LogInfo((object)("Harmony: " + type.Name + "." + methodName + " финалайзер (" + patchType.Name + "." + finalizerName + ").")); } } private static void PatchPostfix(Harmony harmony, ManualLogSource log, Type type, string methodName, Type patchType, string postfixName) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(patchType, postfixName, (Type[])null, (Type[])null); if (methodInfo == null) { log.LogWarning((object)("Harmony: " + type.Name + "." + methodName + " не найден.")); } else if (methodInfo2 == null) { log.LogWarning((object)("Harmony: постфикс " + patchType.Name + "." + postfixName + " не найден.")); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)("Harmony: " + type.Name + "." + methodName + " -> " + patchType.Name + "." + postfixName)); } } private static void OnObjectDbReady() { Plugin instance = Plugin.Instance; if ((Object)(object)instance == (Object)null) { return; } int num = ValuablePricing.Apply(instance.Registry, instance.CoinEmcValue); if (num > 0) { ManualLogSource log = instance.Log; if (log != null) { log.LogInfo((object)$"ValuablePricing: {num} ценностей оценены по курсу 1 монета = {instance.CoinEmcValue} EMC."); } } int num2 = RecipePricing.ComputeFromRecipes(); if (num2 > 0) { ManualLogSource log2 = instance.Log; if (log2 != null) { log2.LogInfo((object)$"RecipePricing: рассчитано {num2} новых предметов по рецептам. Всего в реестре: {instance.Registry.Count}"); } } } private static void Patch(Harmony harmony, ManualLogSource log, Type type, string methodName) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); if (methodInfo == null) { log.LogWarning((object)("Harmony: " + type.Name + "." + methodName + " не найден — часть моментов сохранения может не покрываться снимком данных.")); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "OnGameSave", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)("Harmony: снимок данных привязан к " + type.Name + "." + methodName)); } } private static void PatchSavePrefix(Harmony harmony, ManualLogSource log) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Player), "Save", (Type[])null, (Type[])null); if (methodInfo == null) { log.LogWarning((object)"Harmony: Player.Save не найден — таймеры не будут попадать в сейв."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches), "OnGameSave", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"Harmony: снимок данных привязан к Player.Save (prefix)"); } private static void OnGameSave() { Plugin.Instance?.Data?.WriteSnapshot(); } } [BepInPlugin("equivalentexchange", "EquivalentExchange", "0.39.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "equivalentexchange"; public const string PluginName = "EquivalentExchange"; public const string PluginVersion = "0.39.0"; private static Plugin _instance; private Harmony _harmony; private ConfigEntry<long> _legacyBalance; private ConfigEntry<float> _pieceRepairPerHealth; private ConfigEntry<float> _buyPriceMultiplier; private ConfigEntry<float> _sellPriceMultiplier; private ConfigEntry<bool> _allowDirectBuy; private ConfigEntry<int> _coinEmcValue; private float _nextLanguageCheck; private readonly HashSet<string> _customValueNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); public static Plugin Instance => _instance; internal ManualLogSource Log => ((BaseUnityPlugin)this).Logger; public EmcRegistry Registry { get; private set; } public PlayerEmcData Data { get; private set; } public long EmcBalance => Data.Balance; public bool AllowDirectBuy => _allowDirectBuy != null && _allowDirectBuy.Value; public float PieceRepairEmcPerHealth => _pieceRepairPerHealth.Value; public double BuyPriceMultiplier => (_buyPriceMultiplier != null) ? Math.Max(1.0, _buyPriceMultiplier.Value) : 1.0; public double SellPriceMultiplier => (_sellPriceMultiplier != null) ? Math.Min(1.0, Math.Max(0.0, _sellPriceMultiplier.Value)) : 1.0; public int CoinEmcValue => (_coinEmcValue == null) ? 1 : Math.Max(1, _coinEmcValue.Value); public bool HasCustomValue(string prefabName) { return !string.IsNullOrEmpty(prefabName) && _customValueNames.Contains(prefabName); } public void AddEmc(long amount) { Data.AddEmc(amount); } public bool TrySpendEmc(long amount, out long remaining) { return Data.TrySpendEmc(amount, out remaining); } private void Awake() { //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Expected O, but got Unknown _instance = this; Loc.Init(ResolveGameLanguage); Loc.LanguageChanged += OnLanguageChanged; Registry = new EmcRegistry(); Registry.RegisterDefaults(); _legacyBalance = ((BaseUnityPlugin)this).Config.Bind<long>("Economy", "EmcBalance", 0L, "Легаси (v0.2.x): баланс EMC из конфига. При первом входе персонажа переносится в его данные и обнуляется."); _pieceRepairPerHealth = ((BaseUnityPlugin)this).Config.Bind<float>("Economy", "PieceRepairEmcPerHealth", 0.02f, "Запасная цена ремонта строений, если EMC-стоимость постройки неизвестна (не оценён хотя бы один ресурс): недостающая прочность × это значение, минимум 1 EMC. Основной расчёт — потерянная доля EMC-стоимости постройки."); _buyPriceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Economy", "BuyPriceMultiplier", 1f, "Наценка ee_buy относительно реестровой цены. 1 — курс 1:1; >1 — покупка дороже."); _sellPriceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Economy", "SellPriceMultiplier", 1f, "Доля реестровой цены для ee_sell и ячейки. 1 — курс 1:1; <1 — продажа дешевле."); _allowDirectBuy = ((BaseUnityPlugin)this).Config.Bind<bool>("Economy", "AllowDirectBuy", false, "Разрешить ee_buy (прямая покупка предметов за EMC). По умолчанию выключено: EMC тратится только на крафт, постройку, ремонт и порталы."); _coinEmcValue = ((BaseUnityPlugin)this).Config.Bind<int>("Economy", "CoinEmcValue", 1, "Сколько EMC стоит 1 монета. Ценности (янтарь, жемчуг, рубины, ожерелья, самоцветы и новые ценности 1.0) оцениваются как торговая стоимость × это значение."); PortalEmcConfig.Bind(((BaseUnityPlugin)this).Config); MobLootConfig.Bind(((BaseUnityPlugin)this).Config); Data = new PlayerEmcData(_legacyBalance, Log); ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Economy", "CustomValues", string.Empty, "Дополнительные предметы в формате Имя=EMC, через ';' (например: Resin=8;BoneFragments=16)."); ApplyCustomValues(val.Value); RegisterCommands(); _harmony = new Harmony("equivalentexchange"); Patches.Apply(_harmony, Log); Log.LogInfo((object)string.Format("{0} {1} загружен. Предметов в реестре EMC: {2}", "EquivalentExchange", "0.39.0", Registry.Count)); } private void Update() { if (Time.unscaledTime >= _nextLanguageCheck) { _nextLanguageCheck = Time.unscaledTime + 5f; Loc.Refresh(); } Data.TrackPlayer(Player.m_localPlayer); EmcInventoryUi.Tick(); EmcPassiveCycle.Tick(); } private static string ResolveGameLanguage() { try { Localization instance = Localization.instance; if (instance != null) { return instance.GetSelectedLanguage() ?? "English"; } } catch { } try { return PlatformPrefs.GetString("language", "English") ?? "English"; } catch { } return "English"; } private static void OnLanguageChanged() { CommandTexts.ApplyLanguage(); EmcInventoryUi.OnLanguageChanged(); } private void ApplyCustomValues(string raw) { if (string.IsNullOrWhiteSpace(raw)) { return; } string[] array = raw.Split(new char[1] { ';' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { '=' }); if (array2.Length != 2 || string.IsNullOrWhiteSpace(array2[0]) || !long.TryParse(array2[1].Trim(), out var result)) { Log.LogWarning((object)("Не удалось разобрать запись CustomValues: '" + text + "'")); continue; } string text2 = array2[0].Trim(); try { Registry.Register(text2, result); _customValueNames.Add(text2); } catch (ArgumentException ex) { Log.LogWarning((object)("CustomValues '" + text + "': " + ex.Message)); } } } private void RegisterCommands() { ValueCommand.Register(); BalanceCommand.Register(); AddEmcCommand.Register(); SpendEmcCommand.Register(); SellCommand.Register(); BuyCommand.Register(); InventoryCommand.Register(); MissingCommand.Register(); TrinketsCommand.Register(); } } } namespace EquivalentExchange.World { public static class TombstonePinCleanup { private const float PinRadius = 10f; private static FieldInfo _containerField; private static FieldInfo _pinsField; public static void OnTombstoneUpdateDespawnPrefix(TombStone __instance) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) try { Minimap instance = Minimap.instance; if (!((Object)(object)instance == (Object)null) && IsEmptied(__instance)) { RemoveDeathPinNear(instance, ((Component)__instance).transform.position); } } catch (Exception ex) { Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogWarning((object)("Метка смерти: " + ex.Message)); } } } private static bool IsEmptied(TombStone tombstone) { if ((Object)(object)tombstone == (Object)null) { return false; } if (_containerField == null) { _containerField = AccessTools.Field(typeof(TombStone), "m_container"); } object? obj = _containerField?.GetValue(tombstone); Container val = (Container)((obj is Container) ? obj : null); return val != null && !val.IsInUse() && val.GetInventory().NrOfItems() <= 0; } private static void RemoveDeathPinNear(Minimap minimap, Vector3 position) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Invalid comparison between Unknown and I4 //IL_008c: 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) if (_pinsField == null) { _pinsField = AccessTools.Field(typeof(Minimap), "m_pins"); } if (!(_pinsField?.GetValue(minimap) is List<PinData> list)) { return; } PinData val = null; float num = 10f; foreach (PinData item in list) { if (item != null && (int)item.m_type == 4) { float num2 = Utils.DistanceXZ(position, item.m_pos); if (!(num2 >= num)) { num = num2; val = item; } } } if (val != null) { minimap.RemovePin(val); Plugin instance = Plugin.Instance; if (instance != null) { instance.Log.LogInfo((object)"Метка смерти убрана с карты: надгробие опустошено."); } } } } } namespace EquivalentExchange.Portals { public static class PortalCostCalculator { public static long Calculate(float distance, float weight) { return PortalCost.Calculate(distance, weight, PortalEmcConfig.BaseCost, PortalEmcConfig.CostPerMeter, PortalEmcConfig.WeightFactor, PortalEmcConfig.MinimumCost); } public static float GetCarriedWeight(Player player) { Inventory val = (((Object)(object)player != (Object)null) ? ((Humanoid)player).GetInventory() : null); if (val == null) { return 0f; } float num = 0f; foreach (ItemData allItem in val.GetAllItems()) { if (allItem != null) { num += allItem.GetWeight(-1); } } return num + EmcCell.TotalWeight; } } public static class PortalDistance { public static bool TryGetDestination(TeleportWorld portal, out Vector3 position) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //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) position = default(Vector3); if ((Object)(object)portal == (Object)null) { return false; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO == null) { return false; } ZDOID connectionZDOID = zDO.GetConnectionZDOID((ConnectionType)1); if (connectionZDOID == ZDOID.None) { return false; } ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(connectionZDOID) : null); if (val == null) { return false; } position = val.GetPosition(); return true; } public static float Between(Vector3 from, Vector3 to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(from, to); } } public static class PortalEmcConfig { private static ConfigEntry<bool> _enabled; private static ConfigEntry<float> _baseCost; private static ConfigEntry<float> _costPerMeter; private static ConfigEntry<float> _weightFactor; private static ConfigEntry<long> _minimumCost; public static bool Enabled => _enabled != null && _enabled.Value; public static float BaseCost => (_baseCost != null) ? Math.Max(0f, _baseCost.Value) : 10f; public static float CostPerMeter => (_costPerMeter != null) ? Math.Max(0f, _costPerMeter.Value) : 0.05f; public static float WeightFactor => (_weightFactor != null) ? Math.Max(0f, _weightFactor.Value) : 0.01f; public static long MinimumCost => (_minimumCost != null) ? Math.Max(0L, _minimumCost.Value) : 10; public static void Bind(ConfigFile config) { _enabled = config.Bind<bool>("Portals", "Enabled", true, "Плата за переход через портал: цена показывается в подсказке и списывается перед телепортацией."); _baseCost = config.Bind<float>("Portals", "BaseCost", 10f, "Базовая стоимость перехода, EMC."); _costPerMeter = config.Bind<float>("Portals", "CostPerMeter", 0.05f, "Стоимость одного метра расстояния между порталами, EMC."); _weightFactor = config.Bind<float>("Portals", "WeightFactor", 0.01f, "Влияние веса снаряжения: множитель цены = 1 + вес × значение. Вес — весь инвентарь игрока, включая надетую экипировку."); _minimumCost = config.Bind<long>("Portals", "MinimumCost", 10L, "Минимальная стоимость перехода, EMC."); } } public static class PortalHoverPatch { public static void OnGetHoverTextPostfix(TeleportWorld __instance, ref string __result) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) if (!PortalEmcConfig.Enabled) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)32))) { return; } Plugin instance = Plugin.Instance; if (instance != null && instance.Data?.IsAvailable == true && PortalDistance.TryGetDestination(__instance, out var position)) { float num = PortalDistance.Between(((Component)__instance).transform.position, position); float carriedWeight = PortalCostCalculator.GetCarriedWeight(localPlayer); long num2 = PortalCostCalculator.Calculate(num, carriedWeight); long emcBalance = instance.EmcBalance; string text = __instance.GetText(); StringBuilder stringBuilder = new StringBuilder(__result); stringBuilder.Append('\n').Append(Loc.Tr("Пункт назначения:", "Destination:")).Append(' ') .Append(string.IsNullOrEmpty(text) ? "—" : text); stringBuilder.Append('\n').Append(Loc.Fmt($"Расстояние: {num:0} м", $"Distance: {num:0} m")); stringBuilder.Append('\n').Append(Loc.Fmt($"Вес с ячейкой: {carriedWeight:0.#}", $"Weight incl. cell: {carriedWeight:0.#}")); stringBuilder.Append('\n').Append(Loc.Fmt($"Стоимость перемещения: {num2} EMC", $"Travel cost: {num2} EMC")); if (emcBalance < num2) { stringBuilder.Append('\n').Append(Loc.Fmt($"<color=#ff8080>Недостаточно EMC! Ваш баланс: {emcBalance} EMC</color>", $"<color=#ff8080>Not enough EMC! Your balance: {emcBalance} EMC</color>")); } __result = stringBuilder.ToString(); } } } public static class PortalTeleportPatch { private sealed class PendingTeleport { public TeleportWorld Portal; public Player Player; public Vector3 Destination; public long Cost; public long BalanceAfter; public bool Charged; public bool Settled; } private static PendingTeleport _pending; public static bool OnPortalTeleportPrefix(TeleportWorld __instance, Player player) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) if (!PortalEmcConfig.Enabled) { return true; } if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return true; } if (!PortalDistance.TryGetDestination(__instance, out var position)) { return true; } Plugin instance = Plugin.Instance; if (instance == null || instance.Data?.IsAvailable != true) { return true; } float distance = PortalDistance.Between(((Component)__instance).transform.position, position); float carriedWeight = PortalCostCalculator.GetCarriedWeight(player); long num = PortalCostCalculator.Calculate(distance, carriedWeight); if (num <= 0) { return true; } if (instance.EmcBalance < num) { Message(Loc.Fmt($"Портал: нужно {num} EMC — недостаточно (баланс {instance.EmcBalance})", $"Portal: {num} EMC required — not enough (balance {instance.EmcBalance})")); return false; } _pending = new PendingTeleport { Portal = __instance, Player = player, Destination = position, Cost = num }; return true; } public static bool OnPlayerTeleportToPrefix(Player __instance, bool distantTeleport) { //IL_0086: 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) PendingTeleport pending = _pending; if (pending == null || (Object)(object)pending.Player != (Object)(object)__instance || !distantTeleport) { return true; } Plugin instance = Plugin.Instance; if (instance == null || instance.Data?.IsAvailable != true) { pending.Settled = true; return true; } float distance = PortalDistance.Between(((Component)pending.Portal).transform.position, pending.Destination); float carriedWeight = PortalCostCalculator.GetCarriedWeight(__instance); pending.Cost = PortalCostCalculator.Calculate(distance, carriedWeight); if (pending.Cost <= 0) { pending.Settled = true; return true; } if (instance.EmcBalance < pending.Cost) { Message(Loc.Fmt($"Портал: нужно {pending.Cost} EMC — недостаточно (баланс {instance.EmcBalance})", $"Portal: {pending.Cost} EMC required — not enough (balance {instance.EmcBalance})")); pending.Settled = true; return false; } if (!instance.TrySpendEmc(pending.Cost, out var remaining)) { Message(Loc.Fmt($"Портал: не удалось списать {pending.Cost} EMC", $"Portal: failed to charge {pending.Cost} EMC")); pending.Settled = true; return false; } pending.Charged = true; pending.BalanceAfter = remaining; return true; } public static void OnPlayerTeleportToPostfix(Player __instance, bool __result) { PendingTeleport pending = _pending; if (pending == null || (Object)(object)pending.Player != (Object)(object)__instance || pending.Settled) { return; } pending.Settled = true; if (pending.Charged) { if (__result) { Message(Loc.Fmt($"Портал: −{pending.Cost} EMC (баланс {pending.BalanceAfter})", $"Portal: −{pending.Cost} EMC (balance {pending.BalanceAfter})")); return; } if (!((Character)__instance).IsOwner()) { Message(Loc.Fmt($"Портал: −{pending.Cost} EMC (через RPC, баланс {pending.BalanceAfter})", $"Portal: −{pending.Cost} EMC (via RPC, balance {pending.BalanceAfter})")); return; } Plugin.Instance?.AddEmc(pending.Cost); Message(Loc.Fmt($"Портал: телепорт не начался — возвращено {pending.Cost} EMC", $"Portal: teleport did not start — {pending.Cost} EMC refunded")); } } public static void OnPortalTeleportFinalizer(TeleportWorld __instance) { PendingTeleport pending = _pending; if (pending != null && !((Object)(object)pending.Portal != (Object)(object)__instance)) { _pending = null; if (pending.Charged && !pending.Settled) { Plugin.Instance?.AddEmc(pending.Cost); Message(Loc.Fmt($"Портал: телепорт не выполнен — возвращено {pending.Cost} EMC", $"Portal: teleport failed — {pending.Cost} EMC refunded")); } } } private static void Message(string text) { try { MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true); } } catch { } Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogInfo((object)text); } } } } namespace EquivalentExchange.InventoryUi { public static class EmcCell { public enum CellBlock { Feed, Repair, Convert } private const float ConvertInterval = 30f; private const float RepairInterval = 60f; private const int RepairCostPerUnit = 1; private const float RepairDurabilityPerCycle = 1f; private const float DamagedEpsilon = 0.01f; private static readonly Inventory[] _blocks = (Inventory[])(object)new Inventory[3]; private static Player _owner; private static float _nextConvert; private static float _nextRepair; private static bool _restorePending; private static float _nextRestoreAttempt; private static bool _syncPaused; private static bool _enforcing; private static int _lastSyncedStacks = -1; private static MethodInfo _inventoryChanged; private static bool _addItemAtMissingLogged; private static readonly MethodInfo AddItemAtMethod = AccessTools.Method(typeof(Inventory), "AddItem", new Type[5] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) }, (Type[])null); private static readonly MethodInfo AddItemAtPosMethod = AccessTools.Method(typeof(Inventory), "AddItem", new Type[2] { typeof(ItemData), typeof(Vector2i) }, (Type[])null); public static Inventory FeedInventory => GetInventory(CellBlock.Feed); public static Inventory RepairInventory => GetInventory(CellBlock.Repair); public static Inventory ConvertInventory => GetInventory(CellBlock.Convert); public static float TotalWeight { get { float num = 0f; foreach (CellBlock value in Enum.GetValues(typeof(CellBlock))) { num += GetInventory(value).GetTotalWeight(); } return num; } } public static Inventory GetInventory(CellBlock block) { return _blocks[(int)block] ?? (_blocks[(int)block] = CreateBlockInventory(block)); } public static CellBlock? BlockOf(Inventory inv) { int num = Array.IndexOf(_blocks, inv); return (num >= 0) ? new CellBlock?((CellBlock)num) : ((CellBlock?)null); } public static string BlockName(CellBlock block) { return block switch { CellBlock.Feed => Loc.Tr("Кормление", "Feed"), CellBlock.Repair => Loc.Tr("Ремонт", "Repair"), _ => Loc.Tr("Извлечение EMC", "EMC Extraction"), }; } public static string BlockHint(CellBlock block) { return block switch { CellBlock.Feed => Loc.Tr("Раз в минуту съедает одну единицу еды из блока за 1 EMC.", "Eats one food item from the block once a minute for 1 EMC."), CellBlock.Repair => Loc.Tr("Раз в минуту чинит снаряжение из блока и всё надетое: +1 прочность за 1 EMC.", "Once a minute repairs block gear and everything equipped: +1 durability for 1 EMC."), _ => Loc.Tr("Раз в 30 секунд извлекает EMC из одного предмета блока. Работает и при закрытой панели.", "Extracts EMC from one item in the block every 30 seconds. Works while the panel is closed."), }; } private static Inventory CreateBlockInventory(CellBlock block) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown Inventory val = new Inventory(BlockName(block), (Sprite)null, 2, 2); FieldInfo fieldInfo = AccessTools.Field(typeof(Inventory), "m_onChanged"); Action a = fieldInfo?.GetValue(val) as Action; fieldInfo?.SetValue(val, (Action)Delegate.Combine(a, (Action)delegate { OnBlockInventoryChanged(block); })); return val; } public static bool IsFeedable(ItemData item) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 return item?.m_shared != null && (int)item.m_shared.m_itemType == 2 && (item.m_shared.m_food > 0f || item.m_shared.m_foodStamina > 0f || item.m_shared.m_foodEitr > 0f); } public static bool IsRepairable(ItemData item) { return item?.m_shared != null && item.m_shared.m_useDurability && item.GetMaxDurability() > 0f; } public static bool IsConvertible(ItemData item) { if (item?.m_shared == null || item.m_shared.m_questItem) { return false; } EmcRegistry emcRegistry = Plugin.Instance?.Registry; long emc; return emcRegistry != null && emcRegistry.TryGetValue(TransmutationService.PrefabName(item), out emc) && PricingPolicy.IsTradable(emc); } public static bool Fits(CellBlock block, ItemData item) { return block switch { CellBlock.Feed => IsFeedable(item), CellBlock.Repair => IsRepairable(item), _ => IsConvertible(item), }; } public static string DescribeRejection(CellBlock block, ItemData item) { string text = TransmutationService.PrefabName(item); if (item?.m_shared != null && item.m_shared.m_questItem) { return Loc.Fmt(text + " — квестовый предмет, вложение запрещено", text + " is a quest item — depositing is not allowed"); } return block switch { CellBlock.Feed => Loc.Fmt(text + ": в блок «Кормление» кладётся только еда", text + ": the Feed block accepts only food"), CellBlock.Repair => Loc.Fmt(text + ": в блок «Ремонт» — только снаряжение с прочностью", text + ": the Repair block accepts only gear with durability"), _ => Loc.Fmt(text + " не имеет EMC и не может быть вложен", text + " has no EMC value and cannot be deposited"), }; } public static bool HasFeedItems() { foreach (ItemData allItem in FeedInventory.GetAllItems()) { if (IsFeedable(allItem)) { return true; } } return false; } public static bool MoveItemFromPlayer(Inventory playerInv, CellBlock block, ItemData item, bool announce = true) { if (playerInv == null || item == null) { return false; } if (!Fits(block, item)) { if (announce) { Message(DescribeRejection(block, item)); } return false; } Inventory inventory = GetInventory(block); string b = TransmutationService.PrefabName(item); int num = Math.Max(1, item.m_shared.m_maxStackSize); bool flag = false; foreach (ItemData item2 in inventory.GetAllItems().ToList()) { if (item.m_stack <= 0) { break; } if (item2.m_stack < num && string.Equals(TransmutationService.PrefabName(item2), b, StringComparison.OrdinalIgnoreCase) && item2.m_quality == item.m_quality && item2.m_worldLevel == item.m_worldLevel) { int num2 = Math.Min(num - item2.m_stack, item.m_stack); if (!playerInv.RemoveItem(item, num2)) { break; } item2.m_stack += num2; flag = true; } } if (item.m_stack > 0) { bool flag2 = false; for (int i = 0; i < 2; i++) { if (flag2) { break; } for (int j = 0; j < 2; j++) { if (flag2) { break; } if (inventory.GetItemAt(j, i) == null) { int stack = item.m_stack; if (!playerInv.RemoveItem(item, stack)) { break; } item.m_stack = stack; if (AddItemAtSlot(inventory, item, j, i) || inventory.AddItem(item)) { flag2 = true; flag = true; } else { playerInv.AddItem(item); } } } } if (!flag2 && !flag && announce) { Message(Loc.Fmt("В блоке «" + BlockName(block) + "» нет свободного места.", "No free space in the \"" + BlockName(block) + "\" block.")); } } if (flag) { SyncCellToData(); } return flag; } private static void ReturnToPlayer(CellBlock block, ItemData item) { Player localPlayer = Player.m_localPlayer; Inventory val = ((localPlayer != null) ? ((Humanoid)localPlayer).GetInventory() : null); if (val != null) { val.MoveItemToThis(GetInventory(block), item); } } private static void EnforceBlockRules(CellBlock block) { Player localPlayer = Player.m_localPlayer; Inventory val = ((localPlayer != null) ? ((Humanoid)localPlayer).GetInventory() : null); if (val == null) { return; } Inventory inventory = GetInventory(block); foreach (ItemData item in inventory.GetAllItems().ToList()) { if (!Fits(block, item)) { string text = TransmutationService.PrefabName(item); val.MoveItemToThis(inventory, item); if (!inventory.ContainsItem(item)) { Message(Loc.Fmt(text + ": предмет не подходит блоку «" + BlockName(block) + "» — возвращён", text + ": item does not belong to the \"" + BlockName(block) + "\" block — returned")); } } } } private static void OnBlockInventoryChanged(CellBlock block) { if (_syncPaused) { return; } if (!_enforcing && (Object)(object)Player.m_localPlayer != (Object)null) { _enforcing = true; _syncPaused = true; try { EnforceBlockRules(block); } finally { _syncPaused = false; _enforcing = false; } } SyncCellToData(); } private static void ResetTimers() { _nextConvert = Time.time + 30f; _nextRepair = Time.time + 60f; } public static void Tick() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { return; } if ((Object)(object)_owner != (Object)(object)localPlayer) { if (Plugin.Instance?.Data?.IsAvailable != true) { return; } _owner = localPlayer; Plugin instance = Plugin.Instance; if (instance != null) { instance.Log.LogInfo((object)"Ячейка: перезаход — восстановление содержимого из файла."); } _syncPaused = true; try { ClearAllBlocks(); } finally { _syncPaused = false; } if (!ApplyPending(Plugin.Instance?.Data?.CellContents)) { _restorePending = true; _nextRestoreAttempt = Time.time + 5f; Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogWarning((object)"Ячейка: восстановление отложено — данные сохранены."); } return; } _restorePending = false; EnforceAllBlocks(); SyncCellToData(); ResetTimers(); } else if (_restorePending && Time.time >= _nextRestoreAttempt) { if (AllBlocksEmpty() && !ApplyPending(Plugin.Instance?.Data?.CellContents)) { return; } _restorePending = false; } if (_restorePending) { return; } Plugin instance3 = Plugin.Instance; if (instance3?.Data == null || !instance3.Data.IsAvailable) { return; } float time = Time.time; if (time >= _nextRepair) { _nextRepair = time + 60f; RepairGear(instance3); } if (time < _nextConvert) { return; } _nextConvert = time + 30f; List<ItemData> list = ConvertInventory.GetAllItems().ToList(); if (list.Count == 0) { return; } ItemData val = list[Random.Range(0, list.Count)]; string text = TransmutationService.PrefabName(val); if (!instance3.Registry.TryGetValue(text, out var emc) || !PricingPolicy.IsTradable(emc) || val.m_shared.m_questItem) { ReturnToPlayer(CellBlock.Convert, val); return; } long num = ItemPricing.SellValue(val, instance3.Registry, instance3.SellPriceMultiplier); if (num <= 0) { ReturnToPlayer(CellBlock.Convert, val); return; } ConvertInventory.RemoveItem(val, 1); instance3.AddEmc(num); Message($"{text} → +{num} EMC"); } private static bool AllBlocksEmpty() { foreach (CellBlock value in Enum.GetValues(typeof(CellBlock))) { if (GetInventory(value).GetAllItems().Count > 0) { return false; } } return true; } private static void ClearAllBlocks() { foreach (CellBlock value in Enum.GetValues(typeof(CellBlock))) { Inventory inventory = GetInventory(value); foreach (ItemData item in inventory.GetAllItems().ToList()) { inventory.RemoveItem(item, item.m_stack); } } } private static void EnforceAllBlocks() { foreach (CellBlock value in Enum.GetValues(typeof(CellBlock))) { EnforceBlockRules(value); } } private static void RepairGear(Plugin plugin) { int num = 0; bool flag = false; long remaining; foreach (ItemData item in RepairInventory.GetAllItems().ToList()) { if (!IsRepairable(item)) { continue; } float maxDurability = item.GetMaxDurability(); if (!(item.m_durability >= maxDurability - 0.01f)) { if (!plugin.TrySpendEmc(1L, out remaining)) { flag = true; break; } item.m_durability = Mathf.Min(maxDurability, item.m_durability + 1f); num++; } } if (num > 0) { SyncCellToData(); } int num2 = 0; Player localPlayer = Player.m_localPlayer; Inventory val = ((localPlayer != null) ? ((Humanoid)localPlayer).GetInventory() : null); if (!flag && val != null) { foreach (ItemData equippedItem in val.GetEquippedItems()) { if (equippedItem?.m_shared == null || !equippedItem.m_shared.m_useDurability) { continue; } float maxDurability2 = equippedItem.GetMaxDurability(); if (!(equippedItem.m_durability >= maxDurability2 - 0.01f)) { if (!plugin.TrySpendEmc(1L, out remaining)) { break; } equippedItem.m_durability = Mathf.Min(maxDurability2, equippedItem.m_durability + 1f); num2++; } } if (num2 > 0) { RefreshInventoryUi(val); } } int num3 = num + num2; if (num3 > 0) { Message(Loc.Fmt($"Ремонт: +1 прочность у {num3} предм. (−{num3} EMC)", $"Repair: +1 durability on {num3} item(s) (−{num3} EMC)")); } } private static void RefreshInventoryUi(Inventory inventory) { try { if (_inventoryChanged == null) { _inventoryChanged = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null); } _inventoryChanged?.Invoke(inventory, new object[2] { false, false }); } catch (Exception ex) { Plugin instance = Plugin.Instance; if (instance != null) { instance.Log.LogWarning((object)("Не удалось обновить UI после ремонта: " + ex.Message)); } } } private static bool ApplyPending(List<CellItem> pending) { if (pending == null || pending.Count == 0) { return true; } ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogWarning((object)"Ячейка: ObjectDB ещё не готова — восстановление отложено."); } return false; } List<(CellItem, GameObject)> list = new List<(CellItem, GameObject)>(); foreach (CellItem item in pending) { if (item == null || string.IsNullOrEmpty(item.Prefab) || item.Stack <= 0) { continue; } GameObject itemPrefab = instance.GetItemPrefab(item.Prefab); if ((Object)(object)itemPrefab == (Object)null) { Plugin instance3 = Plugin.Instance; if (instance3 != null) { instance3.Log.LogWarning((object)("Ячейка: префаб '" + item.Prefab + "' не найден — восстановление отложено, данные сохранены.")); } return false; } list.Add((item, itemPrefab)); } _syncPaused = true; bool flag = true; try { foreach (var entry in list) { ItemDrop component = entry.Item2.GetComponent<ItemDrop>(); int maxStackSize = ((!((Object)(object)component != (Object)null)) ? 1 : Math.Max(1, component.m_itemData.m_shared.m_maxStackSize)); int num = ItemGrant.AddAll(entry.Item1.Stack, maxStackSize, (int batch) => AddClone(entry.Item2, entry.Item1, batch)); if (num != entry.Item1.Stack) { flag = false; break; } } if (!flag) { ClearAllBlocks(); } } finally { _syncPaused = false; } if (!flag) { Plugin instance4 = Plugin.Instance; if (instance4 != null) { instance4.Log.LogWarning((object)"Ячейка: не удалось восстановить содержимое — данные сохранены."); } return false; } SyncCellToData(); ResetTimers(); Plugin instance5 = Plugin.Instance; if (instance5 != null) { instance5.Log.LogInfo((object)"Ячейка: содержимое восстановлено по блокам."); } return true; } private static bool AddClone(GameObject prefab, CellItem source, int stack) { ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { return false; } ItemData val2 = val.m_itemData.Clone(); val2.m_dropPrefab = prefab; val2.m_stack = stack; val2.m_quality = Math.Max(1, source.Quality); val2.m_variant = Math.Max(0, source.Variant); float maxDurability = val2.GetMaxDurability(); val2.m_durability = ((source.Durability < 0f) ? maxDurability : Mathf.Clamp(source.Durability, 0f, maxDurability)); val2.m_worldLevel = source.WorldLevel; val2.m_crafterID = source.CrafterId; val2.m_crafterName = source.CrafterName ?? ""; val2.m_pickedUp = source.PickedUp; val2.m_cheated = source.Cheated; val2.m_equipped = false; val2.m_customData = ((source.CustomData != null) ? new Dictionary<string, string>(source.CustomData) : new Dictionary<string, string>()); CellLayout.Resolve(source.GridX, source.GridY, out var block, out var localX, out var localY); Inventory inventory = GetInventory((CellBlock)block); if (localX >= 0 && localY >= 0 && inventory.GetItemAt(localX, localY) == null && AddItemAtSlot(inventory, val2, localX, localY)) { return true; } if (AddFirstFree(inventory, val2)) { return true; } return block != 2 && AddFirstFree(ConvertInventory, val2); } private static bool AddFirstFree(Inventory inv, ItemData item) { for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { if (inv.GetItemAt(j, i) == null && AddItemAtSlot(inv, item, j, i)) { return true; } } } return false; } private static bool AddItemAtSlot(Inventory inv, ItemData item, int x, int y) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) if (AddItemAtMethod != null) { try { object obj = AddItemAtMethod.Invoke(inv, new object[5] { item, item.m_stack, x, y, true }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch (Exception ex) { Plugin instance = Plugin.Instance; if (instance != null) { instance.Log.LogWarning((object)$"Ячейка: не удалось положить предмет в слот {x},{y}: {ex.Message}"); } return false; } } if (AddItemAtPosMethod != null) { try { object obj = AddItemAtPosMethod.Invoke(inv, new object[2] { item, (object)new Vector2i(x, y) }); bool flag2 = default(bool); int num2; if (obj is bool) { flag2 = (bool)obj; num2 = 1; } else { num2 = 0; } return (byte)((uint)num2 & (flag2 ? 1u : 0u)) != 0; } catch (Exception ex2) { Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogWarning((object)$"Ячейка: не удалось положить предмет в слот {x},{y}: {ex2.Message}"); } return false; } } if (!_addItemAtMissingLogged) { _addItemAtMissingLogged = true; Plugin instance3 = Plugin.Instance; if (instance3 != null) { instance3.Log.LogWarning((object)"Ячейка: позиционная укладка Inventory.AddItem не найдена — слоты заполняются автоматически."); } } return false; } private static void SyncCellToData() { if (_syncPaused) { return; } Plugin instance = Plugin.Instance; if (instance?.Data == null) { return; } List<CellItem> list = new List<CellItem>(); foreach (CellBlock value in Enum.GetValues(typeof(CellBlock))) { int num = CellLayout.StartColumn((int)value); foreach (ItemData allItem in GetInventory(value).GetAllItems()) { list.Add(new CellItem { Prefab = TransmutationService.PrefabName(allItem), Stack = allItem.m_stack, Quality = allItem.m_quality, Variant = allItem.m_variant, Durability = allItem.m_durability, WorldLevel = (byte)Math.Max(0, Math.Min(255, allItem.m_worldLevel)), CrafterId = allItem.m_crafterID, CrafterName = (allItem.m_crafterName ?? ""), PickedUp = allItem.m_pickedUp, Cheated = allItem.m_cheated, GridX = num + allItem.m_gridPos.x, GridY = allItem.m_gridPos.y, CustomData = ((allItem.m_customData != null) ? new Dictionary<string, string>(allItem.m_customData) : new Dictionary<string, string>()) }); } } instance.Data.CellContents = list; if (list.Count != _lastSyncedStacks) { _lastSyncedStacks = list.Count; Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogInfo((object)$"Ячейка: содержимое синхронизировано ({list.Count} стеков)."); } } } private static void Message(string text) { try { MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true); } } catch { } Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogInfo((object)text); } } } public static class EmcInventoryUi { private sealed class CellTab { public EmcCell.CellBlock Block; public Button Button; public Image ButtonImage; public Color ButtonBaseColor = Color.white; public TMP_Text Label; public TMP_Text Badge; public GameObject Panel; public RectTransform SlideRt; public float SlideHeight; public InventoryGrid Grid; public float Anim; public bool TargetOpen; public bool LastActive; public int LastCount = -1; } [CompilerGenerated] private static class <>O { public static UnityAction <0>__OnEmcCraftButtonClicked; } private static bool _emcBuildActive; private static Recipe _paidRecipe; private static ItemData _paidUpgrade; private static int _paidMultiplier = 1; private static MethodInfo _haveRequirements; private static object _haveRequirementsMode; private static bool _haveRequirementsEnumMode; private static bool _haveRequirementsHasAmount; private static bool _haveRequirementsResolved; private static Button _emcCraftButton; private static TMP_Text _emcCraftLabel; private static TMP_Text _vanillaCraftLabel; private static RectTransform _vanillaCraftRt; private static RectTransform _emcCraftRt; private static Vector2 _craftOrigSize; private static Vector2 _craftOrigPos; private static float _craftOrigWidth; private static float _craftOrigPivotX; private static float _craftSplitVanillaWidth; private static bool _craftGeomCaptured; private static bool _craftSplitApplied; private static bool _craftUnderLayoutGroup; private const float CraftButtonGap = 6f; private const float CraftVanillaShare = 0.4f; private static float _emcLabelBaseFont = -1f; private static string _fittedText; private static float _fittedWidth; private static float _fittedSize; private static string _vanillaCraftAuthor = string.Empty; private static bool _emcCraftRequested; private static bool _emcCraftActive; private static long _prepaidCraftCost; private static bool _prepaidCraftConsumed; private static float _craftStoppedAt = -1f; private static readonly FieldInfo CraftRecipeField = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe"); private static readonly FieldInfo CraftUpgradeItemField = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem"); private static readonly FieldInfo CraftTimerField = AccessTools.Field(typeof(InventoryGui), "m_craftTimer"); private static readonly FieldInfo MultiCraftingField = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting"); private static readonly FieldInfo SelectedRecipeField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe"); private static readonly PropertyInfo PairRecipeProperty = AccessTools.Property(AccessTools.Inner(typeof(InventoryGui), "RecipeDataPair"), "Recipe"); private static readonly PropertyInfo PairItemDataProperty = AccessTools.Property(AccessTools.Inner(typeof(InventoryGui), "RecipeDataPair"), "ItemData"); private static readonly FieldInfo TouchMultiCraftingField = AccessTools.Field(typeof(InventoryGui), "m_touchMultiCrafting"); private static readonly FieldInfo TextMarginWidthField = AccessTools.Field(typeof(TMP_Text), "m_marginWidth"); private static float _nextTextRefresh; private static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements"); private static readonly PropertyInfo ElementPositionProperty = AccessTools.Property(typeof(InventoryElement), "Position"); private static readonly Dictionary<GameObject, (GameObject Root, TMP_Text Label, RectTransform Backing)> _emcLabels = new Dictionary<GameObject, (GameObject, TMP_Text, RectTransform)>(); private static TMP_FontAsset _emcFont; private static bool _emcLabelDiagLogged; private static Sprite _pillSprite; private static bool _built; private static bool _iconApplied; private static GameObject _statBox; private static TMP_Text _statText; private static Image _statIconImage; private static Image _vanillaIconImage; private static RectTransform _playerPanel; private static bool _repositionPending; private const float TabHeight = 24f; private const float TabGap = 8f; private const float PanelPad = 14f; private const float PanelTopPad = 20f; private const float HandleTopMargin = 2f; private const float HandleBottomMargin = 12f; private const float OpenLift = 4f; private const float FrameOverhang = 10f; private const float OpenDuration = 0.25f; private const float CloseDuration = 0.2f; private const float ContainerGap = 12f; private static readonly Vector3[] _worldCorners = (Vector3[])(object)new Vector3[4]; private static readonly MethodInfo CloseContainerMethod = AccessTools.Method(typeof(InventoryGui), "CloseContainer", (Type[])null, (Type[])null); private static readonly CellTab[] _cellTabs = new CellTab[3]; private static bool _cellTabsBuilt; private static int _activeCellTab = -1; private static readonly FieldInfo DragItemField = AccessTools.Field(typeof(InventoryGui), "m_dragItem"); private static readonly FieldInfo CurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); private static readonly Color FeedColor = new Color(0.7f, 0.95f, 0.6f); private static readonly Color RepairColor = new Color(1f, 0.72f, 0.42f); private static readonly Color ConvertColor = new Color(1f, 0.85f, 0.4f); private static float TabStripHeight => 48f; internal static bool AnyCellPanelOpen => _activeCellTab >= 0; internal static EmcCell.CellBlock? ActiveCellBlock => (_activeCellTab >= 0) ? new EmcCell.CellBlock?((EmcCell.CellBlock)_activeCellTab) : ((EmcCell.CellBlock?)null); public static bool ConsumeResourcesPrefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { if (__instance.NoCostCheat()) { return true; } if (_emcCraftActive) { if (_prepaidCraftCost <= 0) { return true; } _prepaidCraftConsumed = true; return false; } if (!_emcBuildActive) { return true; } Plugin instance = Plugin.Instance; if (instance?.Registry == null || instance.Data == null || !instance.Data.IsAvailable) { return true; } long? num = ComputeCost(requirements, qualityLevel, multiplier, __instance.GetCurrentCraftingStation(), instance.Registry); if (!num.HasValue || num.Value <= 0 || instance.EmcBalance < num.Value) { return true; } instance.TrySpendEmc(num.Value, out var _); ShowMessage(Loc.Fmt($"Постройка за {num.Value} EMC — ресурсы сохранены", $"Built for {num.Value} EMC — resources preserved")); return false; } public static void UpdatePlacementPrefix(bool takeInput) { _emcBuildActive = takeInput; } public static void UpdatePlacementFinalizer() { _emcBuildActive = false; } public static void SetupPieceInfoPostfix(Hud __instance, Piece piece) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece == (Object)null) { return; } TMP_Text buildSelection = __instance.m_buildSelection; if ((Object)(object)buildSelection == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !localPlayer.NoCostCheat() && (!((Object)(object)ZoneSystem.instance != (Object)null) || !ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey()))) { long? pieceCost = GetPieceCost(piece); string text = ((!pieceCost.HasValue) ? buildSelection.text : ((Plugin.Instance.EmcBalance < pieceCost.Value) ? $"{buildSelection.text} <color=#FF6A6A>({pieceCost.Value} EMC)</color>" : $"{buildSelection.text} ({pieceCost.Value} EMC)")); if (buildSelection.text != text) { buildSelection.text = text; } } } internal static long? GetPieceCost(Piece piece) { Plugin instance = Plugin.Instance; if (instance?.Registry == null || instance.Data == null || !instance.Data.IsAvailable) { return null; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || piece.m_resources == null) { return null; } long? num = ComputeCost(piece.m_resources, 0, 1, localPlayer.GetCurrentCraftingStation(), instance.Registry); return (num.HasValue && num.Value > 0) ? num : ((long?)null); } private static void RememberPaidCraft(Recipe recipe, ItemData upgrade, int multiplier) { _paidRecipe = recipe; _paidUpgrade = upgrade; _paidMultiplier = Mathf.Max(1, multiplier); } private static void ForgetPaidCraft() { _paidRecipe = null; _paidUpgrade = null; _paidMultiplier = 1; } private static int GetStartedCraftMultiplier(InventoryGui gui) { return (MultiCraftingField?.GetValue(gui) as bool? != true) ? 1 : Mathf.Max(1, gui.m_multiCraftAmount); } private static bool HaveCraftResources(Player player, Recipe recipe, ItemData upgrade, int multiplier) { if ((Object)(object)player == (Object)null || recipe?.m_resources == null) { return false; } if (player.NoCostCheat()) { return true; } int multiplier2 = Mathf.Max(1, multiplier); int qualityLevel = ((upgrade == null) ? 1 : (upgrade.m_quality + 1)); if (upgrade == null && TryVanillaRequirementCheck(player, recipe, qualityLevel, multiplier2, out var result)) { return result; } return CountIngredients(player, recipe, qualityLevel, multiplier2); } private static bool TryVanillaRequirementCheck(Player player, Recipe recipe, int qualityLevel, int multiplier, out bool result) { result = false; ResolveHaveRequirements(); if (_haveRequirements == null) { return false; } try { object[] parameters = (_haveRequirementsEnumMode ? new object[3] { recipe, _haveRequirementsMode, multiplier } : ((!_haveRequirementsHasAmount) ? new object[3] { recipe, false, qualityLevel } : new object[4] { recipe, false, qualityLevel, multiplier })); object obj = _haveRequirements.Invoke(player, parameters); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } result = (byte)((uint)num & (flag ? 1u : 0u)) != 0; return true; } catch (Exception ex) { Plugin instance = Plugin.Instance; if (instance != null) { instance.Log.LogWarning((object)("Крафт за EMC: HaveRequirements бросил исключение (" + ex.Message + ") — считаем по инвентарю.")); } _haveRequirements = null; return false; } } private static void ResolveHaveRequirements() { if (_haveRequirementsResolved) { return; } _haveRequirementsResolved = true; MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name != "HaveRequirements" || methodInfo.ReturnType != typeof(bool)) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length < 3 || parameters.Length > 4 || parameters[0].ParameterType != typeof(Recipe)) { continue; } if (parameters[1].ParameterType == typeof(bool) && parameters[2].ParameterType == typeof(int)) { if (parameters.Length == 3) { _haveRequirementsHasAmount = false; } else { if (!(parameters[3].ParameterType == typeof(int))) { continue; } _haveRequirementsHasAmount = true; } _haveRequirementsEnumMode = false; _haveRequirements = methodInfo; Plugin instance = Plugin.Instance; if (instance != null) { instance.Log.LogInfo((object)"Крафт за EMC: проверка ресурсов через Player.HaveRequirements(Recipe, bool discover, ...)."); } return; } if (parameters.Length != 3 || !parameters[1].ParameterType.IsEnum || !(parameters[2].ParameterType == typeof(int))) { continue; } Type parameterType = parameters[1].ParameterType; string[] names = Enum.GetNames(parameterType); string value = Array.Find(names, (string n) => n.IndexOf("CanCraft", StringComparison.OrdinalIgnoreCase) >= 0) ?? names[0]; _haveRequirementsMode = Enum.Parse(parameterType, value); _haveRequirementsEnumMode = true; _haveRequirementsHasAmount = false; _haveRequirements = methodInfo; Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogInfo((object)$"Крафт за EMC: проверка ресурсов через Player.HaveRequirements({parameterType.Name}={_haveRequirementsMode})."); } return; } Plugin instance3 = Plugin.Instance; if (instance3 != null) { instance3.Log.LogWarning((object)"Крафт за EMC: Player.HaveRequirements не найден — наличие ингредиентов считается по инвентарю."); } } private static bool CountIngredients(Player player, Recipe recipe, int qualityLevel, int multiplier) { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); bool flag = (Object)(object)currentCraftingStation != (Object)null && currentCraftingStation.m_upgrader; List<CraftStock> list = new List<CraftStock>(); Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val?.m_resItem == (Object)null) && (recipe.m_requireOnlyOneIngredient || ((!((Object)(object)currentCraftingStation != (Object)null) || flag == val.m_upgraderResource) && (!((Object)(object)currentCraftingStation == (Object)null) || !val.m_upgraderResource)))) { int amount = val.GetAmount(qualityLevel); if (amount > 0) { string text = val.m_resItem.m_itemData?.m_shared?.m_name; int num = ((!string.IsNullOrEmpty(text)) ? inventory.CountItems(text, -1, true) : 0); list.Add(new CraftStock((long)amount * (long)multiplier, num)); } } } return recipe.m_requireOnlyOneIngredient ? CraftResourceGate.HasAny(list) : CraftResourceGate.HasAll(list); } private static void GuardPrepaidCraft() { if (_prepaidCraftCost <= 0) { return; } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null) { RefundPrepaidCraft(); return; } if (!IsCraftRunning(instance)) { if (_craftStoppedAt < 0f) { _craftStoppedAt = Time.time; } else if (Time.time - _craftStoppedAt >= 0.5f) { RefundPrepaidCraft(); } return; } _craftStoppedAt = -1f; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)_paidRecipe == (Object)null) && !HaveCraftResources(localPlayer, _paidRecipe, _paidUpgrade, _paidMultiplier)) { RefundPrepaidCraft(); AbortCraft(instance, Loc.Tr("Крафт за EMC отменён: ингредиентов больше нет в инвентаре", "EMC craft cancelled: ingredients are no longer in the inventory")); } } private static void EnsureEmcCraftButton(InventoryGui gui) { //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown if ((Object)(object)_emcCraftButton != (Object)null) { return; } Button craftButton = gui.m_craftButton; if ((Object)(object)craftButton == (Object)null) { return; } try { Transform parent = ((Component)craftButton).transform.parent; GameObject val = Object.Instantiate<GameObject>(((Component)craftButton).gameObject, parent); ((Object)val).name = "EEV_CraftEmcButton"; val.transform.SetSiblingIndex(((Component)craftButton).transform.GetSiblingIndex() + 1); Button component = val.GetComponent<Button>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val); return; } Component component2 = val.GetComponent("UITooltip"); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } try { object obj = AccessTools.Field(typeof(UnityEventBase), "m_PersistentCalls")?.GetValue(component.onClick); obj?.GetType().GetMethod("Clear", Type.EmptyTypes)?.Invoke(obj, null); } catch { } ((UnityEventBase)component.onClick).RemoveAllListeners(); ButtonClickedEvent onClick = component.onClick; object obj3 = <>O.<0>__OnEmcCraftButtonClicked; if (obj3 == null) { UnityAction val2 = OnEmcCraftButtonClicked; <>O.<0>__OnEmcCraftButtonClicked = val2; obj3 = (object)val2; } ((UnityEvent)onClick).AddListener((UnityAction)obj3); Navigation navigation = ((Selectable)component).navigation; ((Navigation)(ref navigation)).mode = (Mode)3; ((Selectable)component).navigation = navigation; _emcCraftButton = component; _emcCraftLabel = val.GetComponentInChildren<TMP_Text>(true); _vanillaCraftLabel = ((Component)craftButton).GetComponentInChildren<TMP_Text>(true); _vanillaCraftRt = ((Component)craftButton).GetComponent<RectTransform>(); _emcCraftRt = val.GetComponent<RectTransform>(); _craftUnderLayoutGroup = (Object)(object)parent != (Object)null && (Object)(object)((Component)parent).GetComponent<LayoutGroup>() != (Object)null; _craftGeomCaptured = false; _craftSplitApplied = false; _vanillaCraftAuthor = string.Empty; _emcLabelBaseFont = -1f; _fittedText = null; val.SetActive(false); Plugin instance = Plugin.Instance; if (instance != null) { instance.Log.LogInfo((object)(_craftUnderLayoutGroup ? "EmcInventoryUi: кнопка «за EMC» встала в layout-группу ванильной кнопки." : "EmcInventoryUi: кнопка «за EMC» создана справа от ванильной.")); } } catch (Exception ex) { Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogWarning((object)("EmcInventoryUi: не удалось создать кнопку крафта за EMC: " + ex.Message)); } } } private static void CaptureCraftGeometry() { //IL_0021: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //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_0069: Unknown result type (might be due to invalid IL or missing references) if (!_craftGeomCaptured && !((Object)(object)_vanillaCraftRt == (Object)null)) { Rect rect = _vanillaCraftRt.rect; float width = ((Rect)(ref rect)).width; if (!(width <= 1f)) { _craftOrigSize = _vanillaCraftRt.sizeDelta; _craftOrigPos = _vanillaCraftRt.anchoredPosition; _craftOrigWidth = width; _craftOrigPivotX = _vanillaCraftRt.pivot.x; _craftGeomCaptured = true; } } } private static void LayoutCraftButtons(bool split) { //IL_002b: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (!_craftGeomCaptured || _craftUnderLayoutGroup) { return; } if (_craftSplitApplied == split) { if (!split) { return; } Rect rect = _vanillaCraftRt.rect; if (Mathf.Abs(((Rect)(ref rect)).width - _craftSplitVanillaWidth) < 0.5f) { return; } } _craftSplitApplied = split; if (!split) { _vanillaCraftRt.sizeDelta = _craftOrigSize; _vanillaCraftRt.anchoredPosition = _craftOrigPos; return; } float craftOrigWidth = _craftOrigWidth; float craftOrigPivotX = _craftOrigPivotX; float num = Mathf.Max(40f, (craftOrigWidth - 6f) * 0.4f); float num2 = Mathf.Max(60f, craftOrigWidth - 6f - num); _craftSplitVanillaWidth = num; _vanillaCraftRt.sizeDelta = _craftOrigSize - new Vector2(craftOrigWidth - num, 0f); _vanillaCraftRt.anchoredPosition = _craftOrigPos - new Vector2((craftOrigWidth - num) * craftOrigPivotX, 0f); _emcCraftRt.sizeDelta = _craftOrigSize - new Vector2(craftOrigWidth - num2, 0f); _emcCraftRt.anchoredPosition = _craftOrigPos + new Vector2(num + 6f + craftOrigPivotX * num2 - craftOrigPivotX * craftOrigWidth, 0f); } public static void UpdateRecipePostfix(InventoryGui __instance) { RefreshEmcCraftButton(__instance); } private static void RefreshEmcCraftButton(InventoryGui gui) { if ((Object)(object)gui == (Object)null) { return; } Button craftButton = gui.m_craftButton; if ((Object)(object)craftButton == (Object)null) { return; } EnsureEmcCraftButton(gui); if ((Object)(object)_emcCraftButton == (Object)null) { return; } CaptureCraftGeometry(); if ((Object)(object)_vanillaCraftLabel == (Object)null) { _vanillaCraftLabel = ((Component)craftButton).GetComponentInChildren<TMP_Text>(true); } string text = (((Object)(object)_vanillaCraftLabel != (Object)null) ? (_vanillaCraftLabel.text ?? string.Empty) : string.Empty); if (!CraftButtonLabel.IsOwn(text)) { _vanillaCraftAuthor = CraftButtonLabel.StripPrice(text); } ItemData upgrade; Recipe selectedRecipe = GetSelectedRecipe(gui, out upgrade); int craftMultiplier = GetCraftMultiplier(gui, upgrade); bool flag = ((Component)craftButton).gameObject.activeInHierarchy && ((Object)(object)selectedRecipe != (Object)null || !string.IsNullOrWhiteSpace(text)) && !IsCraftRunning(gui) && !IsFreeCraft(); if (((Component)_emcCraftButton).gameObject.activeSelf != flag) { ((Component)_emcCraftButton).gameObject.SetActive(flag); } LayoutCraftButtons(flag); if (!flag) { if ((Object)(object)_vanillaCraftLabel != (Object)null && !string.IsNullOrEmpty(_vanillaCraftAuthor) && _vanillaCraftLabel.text != _vanillaCraftAuthor) { _vanillaCraftLabel.text = _vanillaCraftAuthor; } return; } long? labelCost = GetLabelCost(gui); bool flag2 = labelCost.HasValue && Plugin.Instance.EmcBalance >= labelCost.Value; ((Selectable)_emcCraftButton).interactable = ((Selectable)craftButton).interactable && flag2; string text2 = CraftButtonLabel.Count(craftMultiplier); if ((Object)(object)_vanillaCraftLabel != (Object)null && _vanillaCraftLabel.text != text2) { _vanillaCraftLabel.text = text2; } string text3 = CraftButtonLabel.CountWithPrice(craftMultiplier, labelCost, flag2); if ((Object)(object)_emcCraftLabel != (Object)null && _emcCraftLabel.text != text3) { _emcCraftLabel.text = text3; } ApplyCraftLabelFont(); } private static bool IsCraftRunning(InventoryGui gui) { return CraftTimerField?.GetValue(gui) is float num && num >= 0f; } private static bool IsFreeCraft() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return true; } if (localPlayer.NoCostCheat()) { return true; } return (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)25); } private static Recipe GetSelectedRecipe(InventoryGui gui, out ItemData upgrade) { upgrade = null; object obj = SelectedRecipeField?.GetValue(gui); if (obj == null) { return null; } object? obj2 = PairItemDataProperty?.GetValue(obj); upgrade = (ItemData)((obj2 is ItemData) ? obj2 : null); object? obj3 = PairRecipeProperty?.GetValue(obj); return (Recipe)((obj3 is Recipe) ? obj3 : null); } private static void OnEmcCraftButtonClicked() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || IsCraftRunning(instance)) { return; } Button craftButton = instance.m_craftButton; if ((Object)(object)craftButton == (Object)null || !((Selectable)craftButton).interactable || !((Component)craftButton).gameObject.activeInHierarchy) { return; } Plugin instance2 = Plugin.Instance; if (instance2?.Data == null || !instance2.Data.IsAvailable) { return; } long? labelCost = GetLabelCost(instance); if (!labelCost.HasValue) { ShowMessage(Loc.Tr("Рецепт не оценён в EMC — крафтуйте за ресурсы", "The recipe has no EMC price — craft with resources")); return; } Player localPlayer = Player.m_localPlayer; ItemData upgrade; Recipe selectedRecipe = GetSelectedRecipe(instance, out upgrade); if ((Object)(object)selectedRecipe == (Object)null || !HaveCraftResources(localPlayer, selectedRecipe, upgrade, GetCraftMultiplier(instance, upgrade))) { ShowMessage(Loc.Tr("Крафт за EMC недоступен: не хватает ингредиентов", "EMC craft unavailable: missing ingredients")); return; } if (instance2.EmcBalance < labelCost.Value) { ShowMessage(Loc.Fmt($"Недостаточно EMC: нужно {labelCost.Value}, есть {instance2.EmcBalance}", $"Not enough EMC: {labelCost.Value} needed, you have {instance2.EmcBalance}")); return; } _emcCraftRequested = true; try { ((UnityEvent)craftButton.onClick).Invoke(); } catch (Exception ex) { _emcCraftRequested = false; Plugin instance3 = Plugin.Instance; if (instance3 != null) { instance3.Log.LogWarning((object)("Крафт за EMC: ошибка запуска — " + ex.Message)); } } } public static void OnCraftPressedPostfix(InventoryGui __instance) { bool emcCraftRequested = _emcCraftRequested; _emcCraftRequested = false; RefundPrepaidCraft(); if (!emcCraftRequested || !IsCraftRunning(__instance)) { return; } Plugin instance = Plugin.Instance; if (instance?.Data == null || !instance.Data.IsAvailable) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } object? obj = CraftRecipeField?.GetValue(__instance); Recipe val = (Recipe)((obj is Recipe) ? obj : null); if ((Object)(object)val == (Object)null) { AbortCraft(__instance, Loc.Tr("Крафт за EMC: рецепт не выбран", "EMC craft: no recipe selected")); return; } object? obj2 = CraftUpgradeItemField?.GetValue(__instance); ItemData upgrade = (ItemData)((obj2 is ItemData) ? obj2 : null); int startedCraftMultiplier = GetStartedCraftMultiplier(__instance); if (!HaveCraftResources(localPlayer, val, upgrade, startedCraftMultiplier)) { AbortCraft(__instance, Loc.Tr("Крафт за EMC отменён: не хватает ингредиентов", "EMC craft cancelled: missing ingredients")); return; } long? num = ComputeCraftCost(localPlayer, val, upgrade, startedCraftMultiplier); if (!num.HasValue || num.Value <= 0) { AbortCraft(__instance, Loc.Tr("Крафт за EMC отменён: рецепт не оценён", "EMC craft cancelled: the recipe is not priced")); return; } if (!instance.TrySpendEmc(num.Value, out var _)) { AbortCraft(__instance, Loc.Fmt($"Крафт за EMC отменён: нужно {num.Value} EMC", $"EMC craft cancelled: {num.Value} EMC required")); return; } _prepaidCraftCost = num.Value; _prepaidCraftConsumed = false; _craftStoppedAt = -1f; RememberPaidCraft(val, upgrade, startedCraftMultiplier); ShowMessage(Loc.Fmt($"Крафт за {num.Value} EMC — списано сразу", $"Craft for {num.Value} EMC — charged upfront")); } public static void OnCraftPressedFinalizer() { _emcCraftRequested = false; } private static void AbortCraft(InventoryGui gui, string reason) { try { CraftTimerField?.SetValue(gui, -1f); MultiCraftingField?.SetValue(gui, false); } catch { } ShowMessage(reason); } public static void OnCraftCancelPressedPrefix() { RefundPrepaidCraft(); } public static bool DoCraftingPrefix(InventoryGui __instance) { _emcCraftActive = true; if (_prepaidCraftCost <= 0) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)_paidRecipe == (Object)null || !HaveCraftResources(localPlayer, _paidRecipe, _paidUpgrade, _paidMultiplier)) { RefundPrepaidCraft(); AbortCraft(__instance, Loc.Tr("Крафт за EMC отменён: ингредиентов больше нет в инвентаре", "EMC craft cancelled: ingredients are no longer in the inventory")); return false; } return true; } public static void DoCraftingFinalizer() { _emcCraftActive = false; } public static void DoCraftingPostfix() { if (_prepaidCraftCost > 0) { if (_prepaidCraftConsumed) { _prepaidCraftCost = 0L; _prepaidCraftConsumed = false; ForgetPaidCraft(); } else { RefundPrepaidCraft(); } } } private static void RefundPrepaidCraft() { _craftStoppedAt = -1f; ForgetPaidCraft(); if (_prepaidCraftCost > 0) { long prepaidCraftCost = _prepaidCraftCost; _prepaidCraftCost = 0L; if (_prepaidCraftConsumed) { _prepaidCraftConsumed = false; return; } Plugin.Instance?.AddEmc(prepaidCraftCost); ShowMessage(Loc.Fmt($"Крафт отменён — возвращено {prepaidCraftCost} EMC", $"Craft cancelled — {prepaidCraftCost} EMC refunded")); } } public static bool RemoveItemPrefix(Inventory __instance, string name, int amount, int itemQuality, bool worldLevelBased) { if (!_emcCraftActive || _prepaidCraftCost <= 0) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || __instance != ((Humanoid)localPlayer).GetInventory()) { return true; } _prepaidCraftConsumed = true; return false; } private static void ApplyCraftLabelFont() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Invalid comparison between Unknown and I4 //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_emcCraftLabel == (Object)null) { return; } if (_emcLabelBaseFont <= 0f) { float num = (_emcCraftLabel.enableAutoSizing ? _emcCraftLabel.fontSizeMax : _emcCraftLabel.fontSize); if (num <= 0f) { return; } _emcLabelBaseFont = num; } if (_emcCraftLabel.enableAutoSizing) { _emcCraftLabel.enableAutoSizing = false; } if ((int)_emcCraftLabel.textWrappingMode > 0) { _emcCraftLabel.textWrappingMode = (TextWrappingModes)0; } float num2 = _emcLabelBaseFont; float craftLabelWidth = GetCraftLabelWidth(); string text = _emcCraftLabel.text ?? string.Empty; if (text == _fittedText && Mathf.Abs(craftLabelWidth - _fittedWidth) < 0.5f && Mathf.Abs(_emcCraftLabel.fontSize - _fittedSize) < 0.01f) { return; } if (Mathf.Abs(_emcCraftLabel.fontSize - _emcLabelBaseFont) > 0.01f) { _emcCraftLabel.fontSize = _emcLabelBaseFont; } if (craftLabelWidth > 0f) { float num3 = craftLabelWidth * 0.95f; Vector2 preferredValues = _emcCraftLabel.GetPreferredValues(text); if (preferredValues.x > num3) { num2 = Mathf.Max(4f, _emcLabelBaseFont * num3 / preferredValues.x); } } _fittedText = text; _fittedWidth = craftLabelWidth; _fittedSize = num2; if (Mathf.Abs(_emcCraftLabel.fontSize - num2) > 0.01f) { _emcCraftLabel.fontSize = num2; } } private static float GetCraftLabelWidth() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) float num = ((TextMarginWidthField?.GetValue(_emcCraftLabel) is float num2 && num2 > 0f) ? num2 : 0f); if (num <= 0f && (Object)(object)_emcCraftLabel != (Object)null) { Rect rect = _emcCraftLabel.rectTransform.rect; num = ((Rect)(ref rect)).width; } return (num > 0f) ? num : 0f; } private static long? GetLabelCost(InventoryGui gui) { Plugin instance = Plugin.Instance; if (instance?.Registry == null || instance.Data == null || !instance.Data.IsAvailable) { return null; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || IsFreeCraft()) { return null; } ItemData upgrade; Recipe selectedRecipe = GetSelectedRecipe(gui, out upgrade); if (selectedRecipe?.m_resources == null) { return null; } return ComputeCraftCost(localPlayer, selectedRecipe, upgrade, GetCraftMultiplier(gui, upgrade)); } private static long? ComputeCraftCost(Player player, Recipe recipe, ItemData upgrade, int multiplier) { Plugin instance = Plugin.Instance; if (instance?.Registry == null || recipe?.m_resources == null) { return null; } int num = ((upgrade == null) ? 1 : (upgrade.m_quality + 1)); if (recipe.m_requireOnlyOneIngredient) { int num2 = default(int); int num3 = default(int); ItemData firstRequiredItem = player.GetFirstRequiredItem(((Humanoid)player).GetInventory(), recipe, num, ref num2, ref num3, multiplier); if (firstRequiredItem != null) { string prefabName = TransmutationService.PrefabName(firstRequiredItem); if (!instance.Registry.TryGetValue(prefabName, out var emc) || !PricingPolicy.IsTradable(emc)) { return null; } return num2 * emc; } Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if ((Object)(object)val?.m_resItem == (Object)null) { continue; } int amount = val.GetAmount(num); if (amount > 0) { string prefabName2 = RecipePricing.PrefabNameOf(val.m_resItem); if (!instance.Registry.TryGetValue(prefabName2, out var emc2) || !PricingPolicy.IsTradable(emc2)) { return null; } return (long)amount * (long)multiplier * emc2; } } return null; } long? num4 = ComputeCost(recipe.m_resources, num, multiplier, player.GetCurrentCraftingStation(), instance.Registry); return (num4.HasValue && num4.Value > 0) ? num4 : ((long?)null); } private static int GetCraftMultiplier(InventoryGui gui, ItemData upgrade) { if (upgrade != null) { return 1; } bool valueOrDefault = TouchMultiCraftingField?.GetValue(gui) as bool? == true; if (!(ZInput.GetButton("AltPlace") || ZInput.GetButton("JoyLStick") || valueOrDefault)) { return 1; } return Mathf.Max(1, gui.m_multiCraftAmount); } public static void OnInventoryGuiShow(InventoryGui __instance) { ApplyEmcIcon(); EnsureCellTabs(__instance); UpdateStatText(); _repositionPending = true; } public static void OnInventoryGuiHide(InventoryGui __instance) { CloseCellPanels(immediate: true); _emcCraftActive = false; _emcCraftRequested = false; RefundPrepaidCraft(); } public static void Tick() { EmcCell.Tick(); TickCellTabs(); if (!(Time.time < _nextTextRefresh)) { _nextTextRefresh = Time.time + 0.25f; GuardPrepaidCraft(); ApplyPendingPosition(); UpdateStatText(); SyncEmcIconColor(); RefreshEmcCraftButton(InventoryGui.instance); } } private static long? ComputeCost(Requirement[] requirements, int qualityLevel, int multiplier, CraftingStation station, EmcRegistry registry) { bool flag = (Object)(object)station != (Object)null && station.m_upgrader; List<CraftRequirement> list = new List<CraftRequirement>(); foreach (Requirement val in requirements) { if (!((Object)(object)val?.m_resItem == (Object)null) && (!((Object)(object)station != (Object)null) || flag == val.m_upgraderResource) && (!((Object)(object)station == (Object)null) || !val.m_upgraderResource)) { int amount = val.GetAmount(qualityLevel); if (amount > 0) { list.Add(new CraftRequirement(registry.TryGetValue(RecipePricing.PrefabNameOf(val.m_resItem), out var emc) ? new long?(emc) : ((long?)null), amount)); } } } return CraftCost.Compute(list, multiplier); } private static void ShowMessage(string text) { try { MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true); } } catch { } Plugin instance2 = Plugin.Instance; if (instance2 != null) { instance2.Log.LogInfo((object)text); } } public static void UpdateGuiPostfix(InventoryGrid __instance, Player player) { //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) if (!(ElementsField?.GetValue(__instance) is List<InventoryElement> list)) { return; } EmcRegistry emcRegistry = Plugin.Instance?.Registry; Inventory val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null); Inventory inventory = __instance.GetInventory(); if (!AnyCellPanelOpen || emcRegistry == null || inventory == null || (inventory != val && !EmcCell.BlockOf(inventory).HasValue)) { foreach (KeyValuePair<GameObject, (GameObject, TMP_Text, RectTransform)> emcLabel2 in _emcLabels) { if ((Object)(object)emcLabel2.Value.Item1 != (Object)null && emcLabel2.Value.Item1.activeSelf && emcLabel2.Value.Item1.transform.IsChildOf(((Component)__instance).transform)) { emcLabel2.Value.Item1.SetActive(false); } } return; } foreach (InventoryElement item2 in list) { GameObject val2 = (((Object)(object)item2?.m_button != (Object)null) ? ((Component)item2.m_button).gameObject : null); if ((Object)(object)val2 == (Object)null) { continue; } TMP_Text emcLabel = GetEmcLabel(val2, item2); if ((Object)(object)emcLabel == (Object)null) { break; } (GameObject, TMP_Text, RectTransform) tuple = _emcLabels[val2]; GameObject item = tuple.Item1; ItemData val3 = null; if (item2.m_used && ElementPositionProperty != null) { Vector2i val4 = (Vector2i)ElementPositionProperty.GetValue(item2); val3 = inventory.GetItemAt(val4.x, val4.y); } if (val3 == null || !emcRegistry.TryGetValue(TransmutationService.PrefabName(val3), out var _)) { if (item.activeSelf) { item.SetActive(false); } continue; } if (!item.activeSelf) { item.SetActive(true); } string text = ItemPricing.SellValue(val3, emcRegistry, Plugin.Instance.SellPriceMultiplier).ToString(); if (emcLabel.text != text) { emcLabel.text = text; float num = Mathf.Max(26f, 14f + (float)text.Length * 7.5f); tuple.Item3.sizeDelta = new Vector2(num, 18f); } } } private static Sprite GetPillSprite() { //IL_0021: 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_002f: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_pillSprite != (Object)null) { return _pillSprite; } Texture2D val = new Texture2D(48, 20, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)1 }; for (int i = 0; i < 20; i++) { for (int j = 0; j < 48; j++) { int num = Mathf.Clamp(j, 9, 38); int num2 = Mathf.Clamp(i, 9, 10); int num3 = j - num; int num4 = i - num2; float num5 = Mathf.Sqrt((float)(num3 * num3 + num4 * num4)); float num6 = ((num5 <= 8f) ? 1f : ((num5 < 9f) ? (9f - num5) : 0f)); val.SetPixel(j, i, new Color(1f, 1f, 1f, num6)); } } val.Apply(); _pillSprite = Sprite.Create(val, new Rect(0f, 0f, 48f, 20f), new Vector2(0.5f, 0.5f)); return _pillSprite; } private static TMP_Text GetEmcLabel(GameObject slot, InventoryElement el) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Expected O, but got Unknown //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: 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_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Expected O, but got Unknown //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) if (_emcLabels.TryGetValue(slot, out (GameObject, TMP_Text, RectTransform) value) && (Object)(object)value.Item2 != (Object)null) { return value.Item2; } TMP_FontAsset val = ResolveEmcFont(el); if ((Object)(object)val == (Object)nul