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 RunicStorageNetwork v0.5.6
plugins\RunicStorageNetwork\RunicStorageNetwork.dll
Decompiled 6 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using RunicStorageNetwork.Logic; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("RunicStorageNetwork")] [assembly: AssemblyFileVersion("0.5.6.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.5.6.0")] namespace RunicStorageNetwork { internal static class Actions { internal sealed class Pending { internal Operation Op; internal Player Player; internal InventoryGui Gui; internal Recipe Recipe; internal Piece Piece; internal ItemData Upgrade; internal ItemData Tool; internal int UpgradeQuality; internal int Variant; internal bool Multi; internal bool Output; internal bool Cancelled; internal bool Prepared; internal Vector3 Position; internal Quaternion Rotation; internal float Started; internal float LastPoll; internal bool Warned; internal RecoveryAttempt Recovery; internal string RollbackFailure; internal List<Debit> Plan; internal InventoryDelta Delta; } internal static Pending Waiting; internal static Pending Active; private static readonly OutcomeReceipts Outcomes = new OutcomeReceipts(); internal static bool Locked(Inventory inv) { if (Waiting != null && Object.op_Implicit((Object)(object)Waiting.Player)) { return ((Humanoid)Waiting.Player).GetInventory() == inv; } return false; } internal static void Clear() { Waiting = null; Active = null; Outcomes.Clear(); Stockroom.ClearObservations(); CraftPreparation.Clear(); RecipeIndex.Invalidate(); Plugin.ClearCritical(); } internal static PieceTable BuildTable(Player p) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)p) || (Object)(object)p != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)ObjectDB.instance)) { return null; } ItemData val = (ItemData)R.Call(p, "GetRightItem", Type.EmptyTypes); PieceTable val2 = val?.m_shared?.m_buildPieces; if (!Object.op_Implicit((Object)(object)val2) || !((Object)(object)p.GetBuildTool() == (Object)(object)val2) || !BuildToolPolicy.Tool(val)) { return null; } return val2; } internal static bool BuildPiece(Player p, Piece piece) { PieceTable val = BuildTable(p); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)piece) || piece.m_repairPiece || piece.m_removePiece) { return false; } GameObject val2 = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(R.Id(((Component)piece).gameObject)) : ((Component)piece).gameObject); if (Object.op_Implicit((Object)(object)val2) && val.m_pieces != null && val.m_pieces.Contains(val2)) { return BuildToolPolicy.PieceReason(val2) == null; } return false; } internal static bool LocalBuildMaterials(Player p, Piece piece, RequirementMode mode) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)piece)) { return false; } Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (Object.op_Implicit((Object)(object)val.m_resItem) && val.m_amount > 0) { int num = (((int)mode == 2) ? 1 : val.m_amount); if (((Humanoid)p).GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true) < num) { return false; } } } return true; } internal static bool BuildToolUsable(Player p, ItemData tool) { if (tool != null && (!tool.m_shared.m_useDurability || tool.m_durability > 0f)) { return ((Character)p).HaveStamina(tool.m_shared.m_attack.m_attackStamina); } return false; } internal static Core Context(Player p, bool craft) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)p) || (Object)(object)p != (Object)(object)Player.m_localPlayer || !Plugin.Enabled || (!craft && !Object.op_Implicit((Object)(object)BuildTable(p)))) { return null; } CraftingStation currentCraftingStation = p.GetCurrentCraftingStation(); if (craft && (!Object.op_Implicit((Object)(object)currentCraftingStation) || currentCraftingStation.m_upgrader)) { return null; } return Core.Choose(craft ? ((Component)currentCraftingStation).transform.position : ((Component)p).transform.position, p.GetPlayerID()); } internal static bool Craft(InventoryGui gui, Player p) { if (Active != null) { return true; } if (Waiting != null) { return false; } if (CraftPreparation.Claimed) { return CraftPreparation.Execute(gui, p); } Recipe obj = R.Get<Recipe>(gui, "m_craftRecipe"); Core core = Context(p, craft: true); if (!Object.op_Implicit((Object)(object)obj) || !Object.op_Implicit((Object)(object)core) || p.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25)) { return true; } return CraftPreparation.Execute(gui, p); } internal static bool Build(Player p, Piece piece) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Expected O, but got Unknown //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) if (Active != null || !BuildPiece(p, piece)) { return true; } if (Waiting != null) { return false; } if (LocalBuildMaterials(p, piece, (RequirementMode)0)) { return true; } Core core = Context(p, craft: false); if (!Object.op_Implicit((Object)(object)core) || p.NoCostCheat() || R.Get<bool>(p, "m_noPlacementCost") || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey())) { return true; } Operation operation = Create(p, core, build: true, R.Id(((Component)piece).gameObject), 0, 1); if (Object.op_Implicit((Object)(object)piece.m_craftingStation)) { CraftingStation val = CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)p).transform.position); if (Object.op_Implicit((Object)(object)val) && R.Valid(R.View((Component)(object)val))) { operation.Station = R.View((Component)(object)val).GetZDO().m_uid; } } if (!operation.Validate(out var _, out var _, out var _)) { return false; } List<Debit> list = Planner.Plan(operation.Needs, Stockroom.Available(p, core, operation.Needs), compact: true); if (list == null) { return false; } if (list.All((Debit d) => d.Source == "player")) { return true; } R.Call(p, "UpdatePlacementGhost", new Type[1] { typeof(bool) }, false); if (R.Get<object>(p, "m_placementStatus").ToString() != "Valid") { return true; } GameObject val2 = R.Get<GameObject>(p, "m_placementGhost"); if (!Object.op_Implicit((Object)(object)val2)) { return true; } Start(new Pending { Op = operation, Player = p, Piece = piece, Tool = (ItemData)R.Call(p, "GetRightItem", Type.EmptyTypes), Position = val2.transform.position, Rotation = val2.transform.rotation }, list); return false; } internal static Operation Create(Player p, Core core, bool build, string target, int quality, int multiplier) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) return new Operation { Id = Guid.NewGuid().ToString("N"), Target = target, Build = build, Quality = quality, Multiplier = multiplier, Actor = ((Character)p).GetZDOID(), Station = (build ? ZDOID.None : R.View((Component)(object)p.GetCurrentCraftingStation()).GetZDO().m_uid), Core = core.Id, Network = ((Component)core).GetComponent<NetworkMember>().SavedNetwork, Peer = ZNet.GetUID(), PlayerId = p.GetPlayerID() }; } internal static bool Propose(Pending pending, List<Debit> preview) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) Core core = Operation.CoreObject(pending.Op.Core); string network = (Object.op_Implicit((Object)(object)core) ? ((Component)core).GetComponent<NetworkMember>().Network : ""); pending.Op.Nodes = (from m in Topology.Members where Object.op_Implicit((Object)(object)m) && m.Valid && m.Network == network select m.View.GetZDO().m_uid).Distinct().ToArray(); if (pending.Op.Nodes.Length == 0 || pending.Op.Nodes.Length > 4096) { return false; } pending.Op.Sources = SourceSelection.Sources(preview); if (pending.Op.Sources == null) { return false; } pending.Op.PlayerStock = Stockroom.Snapshot(((Humanoid)pending.Player).GetInventory(), "player", pending.Op.Needs, chest: false); return true; } private static void Start(Pending pending, List<Debit> preview) { if (!Propose(pending, preview)) { if (Waiting == pending) { Waiting = null; } return; } Waiting = pending; if (pending.Recovery == null) { pending.Started = Time.unscaledTime; pending.Recovery = new RecoveryAttempt(pending.Started); } pending.Recovery.Sent(); pending.LastPoll = Time.unscaledTime; try { Transport.Instance.Begin(pending.Op); } catch (Exception ex) { Plugin.Debug(pending.Op.Id + " request; will replay same ID: " + ex.Message); } } internal static void RecoverCraft(Pending pending) { pending.Prepared = false; pending.Started = Time.unscaledTime; pending.Recovery = new RecoveryAttempt(pending.Started); pending.Recovery.Retry("offer expired", pending.Started); Waiting = pending; Topology.Dirty(); } internal static void Tick() { Pending waiting = Waiting; if (waiting == null) { return; } float unscaledTime = Time.unscaledTime; if (!Intent(waiting, out var reason)) { waiting.Cancelled = true; } if (!waiting.Warned && unscaledTime - waiting.Started > 10f) { waiting.Warned = true; Plugin.Critical(waiting.Op.Id, "Craft/build acknowledgement unresolved after 10 seconds; replaying the existing operation"); } if (waiting.Recovery.InFlight) { if (!(unscaledTime - waiting.LastPoll >= 2f)) { return; } waiting.LastPoll = unscaledTime; try { if (waiting.Prepared) { Transport.Instance.UseQuote(waiting.Op.Id); } else { Transport.Instance.Begin(waiting.Op); } return; } catch (Exception ex) { Plugin.Debug(waiting.Op.Id + " waiting for coordinator: " + ex.Message); return; } } if (!((double)unscaledTime < waiting.Recovery.Due) && !CraftPreparation.Releasing) { if (!Intent(waiting, out reason) || waiting.Recovery.Expired(unscaledTime)) { Waiting = null; Topology.Dirty(); } else { Retry(waiting); } } } internal static void Cancel() { if (Waiting != null) { Waiting.Cancelled = true; } } internal static void Refused(string id, string reason) { Plugin.Debug(id + " terminal refusal (resources released): " + reason); Pending waiting = Waiting; if (waiting?.Op.Id != id || !waiting.Recovery.InFlight) { return; } waiting.Prepared = false; if (waiting.Recovery.Retry(reason, Time.unscaledTime) && Intent(waiting, out var _)) { Topology.Dirty(); Plugin.Debug(id + " rebuilding supply and retrying automatically"); return; } if (!waiting.Cancelled && waiting.Recovery.Expired(Time.unscaledTime) && RecoveryAttempt.Transient(reason) && !reason.Contains("insufficient")) { Plugin.Critical(id, "Automatic recovery exhausted: " + reason); } Waiting = null; Topology.Dirty(); } private static void Retry(Pending p) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) try { Topology.Dirty(); Topology.Refresh(force: true); Core core = Context(p.Player, !p.Op.Build); if (!Object.op_Implicit((Object)(object)core)) { if (!p.Recovery.Retry("network path or coverage changed", Time.unscaledTime)) { Waiting = null; } return; } Operation operation = Create(p.Player, core, p.Op.Build, p.Op.Target, p.Op.Quality, p.Op.Multiplier); operation.Station = p.Op.Station; if (!operation.Validate(out var _, out var _, out var reason)) { if (!p.Recovery.Retry(reason, Time.unscaledTime)) { Waiting = null; } return; } Stockroom.Refresh(core, p.Op.Sources); List<Stock> stock = Stockroom.Available(p.Player, core, operation.Needs); List<Debit> list = (operation.SelectNeeds(stock) ? Planner.Plan(operation.Needs, stock, compact: true) : null); if (list == null) { if (!p.Recovery.Retry("insufficient fresh resources", Time.unscaledTime)) { Waiting = null; } return; } Plugin.Debug(p.Op.Id + " retry -> " + operation.Id + " attempt=" + (p.Recovery.Attempts + 1)); p.Op = operation; p.Plan = null; p.Delta = null; Start(p, list); } catch (Exception e) { Plugin.Error(p.Op.Id + " recovery", e); Waiting = null; } } private static bool Intent(Pending p, out string reason) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Invalid comparison between Unknown and O //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: 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_016d: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown reason = "player context changed"; if (p.Cancelled || !Object.op_Implicit((Object)(object)p.Player) || (Object)(object)p.Player != (Object)(object)Player.m_localPlayer || ((Character)p.Player).IsDead() || p.Player.NoCostCheat()) { return false; } if (p.Op.Build) { reason = "build tool context changed"; if (!BuildPiece(p.Player, p.Piece) || !((Character)p.Player).InPlaceMode() || (Object)(object)p.Player.GetSelectedPiece() != (Object)(object)p.Piece || (object)(ItemData)R.Call(p.Player, "GetRightItem", Type.EmptyTypes) != p.Tool) { return false; } goto IL_021d; } reason = "recipe changed or disabled"; if (!RecipeIndex.Matches(p.Recipe, p.Op.Target)) { return false; } reason = "craft cancelled/changed"; if (Object.op_Implicit((Object)(object)p.Gui) && InventoryGui.IsVisible()) { CraftingStation currentCraftingStation = p.Player.GetCurrentCraftingStation(); ZDOID? val = ((currentCraftingStation == null) ? ((ZDOID?)null) : ((Component)currentCraftingStation).GetComponent<ZNetView>().GetZDO()?.m_uid); ZDOID station = p.Op.Station; if (val.HasValue && (!val.HasValue || !(val.GetValueOrDefault() != station)) && !((Object)(object)R.Get<Recipe>(p.Gui, "m_craftRecipe") != (Object)(object)p.Recipe) && R.Get<ItemData>(p.Gui, "m_craftUpgradeItem") == p.Upgrade) { object obj = R.Get<object>(p.Gui, "m_selectedRecipe"); if ((Object)(Recipe)obj.GetType().GetProperty("Recipe").GetValue(obj, null) != (Object)(object)p.Recipe) { return false; } if (p.Upgrade != null && (!((Humanoid)p.Player).GetInventory().ContainsItem(p.Upgrade) || p.Upgrade.m_quality != p.UpgradeQuality)) { return false; } goto IL_021d; } } return false; IL_021d: reason = "ok"; return true; } internal static void Ready(string id, List<Debit> plan) { //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Invalid comparison between Unknown and O //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_044b: Expected O, but got Unknown //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) if (Outcomes.TryGet(id, out var result)) { Transport.Instance.Result(id, result.Success, result.Reason); return; } Pending waiting = Waiting; if (waiting == null || waiting.Op.Id != id) { Transport.Instance.Result(id, success: false, "no pending action"); return; } if (waiting.RollbackFailure != null) { Transport.InternalMutation++; try { waiting.Delta.Restore(); } catch (Exception e) { Plugin.Error(id + " retrying local rollback", e); return; } finally { Transport.InternalMutation--; } Outcomes.Record(id, result: false, waiting.RollbackFailure); Transport.Instance.Result(id, success: false, waiting.RollbackFailure); return; } bool flag = false; string text = "action not completed"; try { if (!Intent(waiting, out var reason)) { throw new InvalidOperationException(reason); } if (!waiting.Op.Validate(out var _, out var core, out var reason2)) { throw new InvalidOperationException(reason2); } core.Scan(); foreach (Debit debit in plan.Where((Debit d) => d.Source != "player")) { Container val = ((IEnumerable<Container>)core.Pool).FirstOrDefault((Func<Container, bool>)((Container source) => Object.op_Implicit((Object)(object)source) && R.Valid(R.View((Component)(object)source)) && R.Key(R.View((Component)(object)source).GetZDO().m_uid) == debit.Source)); if (!Object.op_Implicit((Object)(object)val) || !Access.Container(val, waiting.Op.PlayerId, core, out var _, ownLease: true)) { throw new InvalidOperationException("source path/access changed before result: " + debit.Source); } } if (!Object.op_Implicit((Object)(object)waiting.Player) || (Object)(object)waiting.Player != (Object)(object)Player.m_localPlayer || ((Character)waiting.Player).IsDead() || waiting.Player.NoCostCheat()) { throw new InvalidOperationException("player context changed"); } if (waiting.Op.Build) { if (!BuildPiece(waiting.Player, waiting.Piece) || R.Get<bool>(waiting.Player, "m_noPlacementCost") || !((Character)waiting.Player).InPlaceMode() || (Object)(object)waiting.Player.GetSelectedPiece() != (Object)(object)waiting.Piece || (object)(ItemData)R.Call(waiting.Player, "GetRightItem", Type.EmptyTypes) != waiting.Tool || !BuildToolUsable(waiting.Player, waiting.Tool)) { throw new InvalidOperationException("build tool context changed"); } R.Call(waiting.Player, "UpdatePlacementGhost", new Type[1] { typeof(bool) }, false); GameObject val2 = R.Get<GameObject>(waiting.Player, "m_placementGhost"); if (!Object.op_Implicit((Object)(object)val2) || R.Get<object>(waiting.Player, "m_placementStatus").ToString() != "Valid" || Vector3.Distance(val2.transform.position, waiting.Position) > 0.05f || Quaternion.Angle(val2.transform.rotation, waiting.Rotation) > 0.5f) { throw new InvalidOperationException("placement moved/cancelled"); } goto IL_0496; } if (Object.op_Implicit((Object)(object)waiting.Gui) && InventoryGui.IsVisible()) { CraftingStation currentCraftingStation = waiting.Player.GetCurrentCraftingStation(); ZDOID? val3 = ((currentCraftingStation != null) ? new ZDOID?(((Component)currentCraftingStation).GetComponent<ZNetView>().GetZDO().m_uid) : ((ZDOID?)null)); ZDOID station = waiting.Op.Station; if (val3.HasValue && (!val3.HasValue || !(val3.GetValueOrDefault() != station)) && !((Object)(object)R.Get<Recipe>(waiting.Gui, "m_craftRecipe") != (Object)(object)waiting.Recipe) && R.Get<ItemData>(waiting.Gui, "m_craftUpgradeItem") == waiting.Upgrade) { object obj = R.Get<object>(waiting.Gui, "m_selectedRecipe"); if ((Object)(Recipe)obj.GetType().GetProperty("Recipe").GetValue(obj, null) != (Object)(object)waiting.Recipe) { throw new InvalidOperationException("recipe selection changed"); } if (waiting.Upgrade != null && (!((Humanoid)waiting.Player).GetInventory().ContainsItem(waiting.Upgrade) || waiting.Upgrade.m_quality != waiting.UpgradeQuality)) { throw new InvalidOperationException("upgrade item changed"); } goto IL_0496; } } throw new InvalidOperationException("craft cancelled/changed"); IL_0496: waiting.Plan = plan; waiting.Delta = new InventoryDelta(((Humanoid)waiting.Player).GetInventory(), plan.Where((Debit d) => d.Source == "player"), chest: false); Active = waiting; Transport.InternalMutation++; try { waiting.Delta.Apply(); Plugin.Debug(id + " player debit confirmed"); if (waiting.Op.Build) { if (waiting.Player.TryPlacePiece(waiting.Piece)) { waiting.Output = true; FinishBuild(waiting); } } else { R.Set(waiting.Gui, "m_craftVariant", waiting.Variant); R.Set(waiting.Gui, "m_multiCrafting", waiting.Multi); waiting.Gui.m_multiCraftAmount = waiting.Op.Multiplier; R.Call(waiting.Gui, "DoCrafting", new Type[1] { typeof(Player) }, waiting.Player); } flag = waiting.Output; if (!flag) { waiting.Delta.Restore(); Plugin.Debug(id + " player delta restored: no result"); } } finally { Transport.InternalMutation--; Active = null; } } catch (Exception ex) { text = ex.Message; if (ex is InvalidOperationException) { Plugin.Debug(id + " action postponed: " + ex.Message); } else { Plugin.Error(id + " action", ex); } flag = waiting.Output; if (!flag) { InventoryDelta delta = waiting.Delta; if (delta != null && delta.Applied) { Transport.InternalMutation++; try { waiting.Delta.Restore(); } catch (Exception e2) { waiting.RollbackFailure = text; Plugin.Error(id + " local rollback unresolved", e2); return; } finally { Transport.InternalMutation--; } } } } Outcomes.Record(id, flag, flag ? "result observed" : text); if (flag) { Waiting = null; Stockroom.ClearObservations(); CraftInspection.Clear(); CraftOverview.Rescan(); Topology.Dirty(); } Transport.Instance.Result(id, flag, flag ? "result observed" : text); } private static void FinishBuild(Pending p) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) R.Set(p.Player, "m_lastToolUseTime", Time.time); ((Character)p.Player).UseStamina((float)R.Call(p.Player, "GetBuildStamina", Type.EmptyTypes)); PieceTable val = R.Get<PieceTable>(p.Player, "m_buildPieces"); if ((int)val.m_skill != 0) { int num = R.Get<int>(p.Player, "m_buildRemoveDebt"); if (num > 0) { R.Set(p.Player, "m_buildRemoveDebt", num - 1); } else { ((Character)p.Player).RaiseSkill(val.m_skill, 1f); } } if (p.Tool.m_shared.m_useDurability) { ItemData tool = p.Tool; tool.m_durability -= (float)R.Call(p.Player, "GetPlaceDurability", new Type[1] { typeof(ItemData) }, p.Tool) * Game.m_durabilityRate; } p.Tool.m_shared.m_buildEffect.Create(((Component)p.Player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, ((Character)p.Player).GetZDOID()); } internal static bool PaidRequirements(Player p, Recipe recipe) { if (Active != null && (Object)(object)Active.Player == (Object)(object)p) { return (Object)(object)Active.Recipe == (Object)(object)recipe; } return false; } internal static bool HaveCraft(Player player, Recipe recipe, int quality, int amount, out bool result) { result = false; if (PaidRequirements(player, recipe)) { result = true; return true; } if (!Object.op_Implicit((Object)(object)Context(player, craft: true))) { return false; } result = CraftPreparation.Available(player, recipe, quality, amount); return true; } internal static bool FirstIngredient(Player p, Recipe recipe, int quality, int multiplier, out ItemData item, out int amount, out int extra) { item = null; amount = (extra = 0); if (!Object.op_Implicit((Object)(object)Context(p, craft: true))) { return false; } List<Need> list = Stockroom.Requirements(recipe.m_resources, quality, multiplier); List<Stock> stock = ((!((Object)(object)Active?.Recipe == (Object)(object)recipe)) ? CraftPreparation.IngredientStock(p, recipe, quality, multiplier, list) : Active.Plan.Select((Debit d) => new Stock(d.Source, d.Item, d.Quality, d.Amount)).ToList()); foreach (Need n in list) { if (Stockroom.Qualities(new List<Need> { n }, stock, craft: true)) { Requirement val = recipe.m_resources.First((Requirement r) => Object.op_Implicit((Object)(object)r.m_resItem) && ((Object)r.m_resItem).name == n.Item); item = val.m_resItem.m_itemData.Clone(); item.m_quality = n.Quality; amount = n.Amount; extra = val.m_extraAmountOnlyOneIngredient; return true; } } return false; } } internal static class BuildToolPolicy { private static readonly Dictionary<GameObject, string> components = new Dictionary<GameObject, string>(); private static BuildToolRules rules; private static ObjectDB database; internal static BuildToolRules Rules { get { if ((Object)(object)database != (Object)(object)ObjectDB.instance) { Invalidate(); database = ObjectDB.instance; } if (rules == null) { rules = new BuildToolRules(Text(Plugin.AllowedBuildTools), Text(Plugin.DeniedBuildTools), Text(Plugin.DeniedPieceComponents)); } return rules; } } internal static void Invalidate() { database = null; rules = null; components.Clear(); } private static string Text(ConfigEntry<string> entry) { object obj; if (entry != null) { obj = entry.Value; if (obj == null) { return ""; } } else { obj = ""; } return (string)obj; } internal static bool Table(PieceTable table) { return Object.op_Implicit((Object)(object)table); } internal static bool Tool(ItemData tool) { if (tool != null && tool.m_shared != null && Object.op_Implicit((Object)(object)tool.m_dropPrefab) && Table(tool.m_shared.m_buildPieces)) { return Rules.Tool(R.Id(tool.m_dropPrefab)); } return false; } internal static string PieceReason(GameObject prefab) { if (!Object.op_Implicit((Object)(object)prefab)) { return "invalid build piece"; } Piece component = prefab.GetComponent<Piece>(); if (!Object.op_Implicit((Object)(object)component) || !component.m_enabled || component.m_repairPiece || component.m_removePiece) { return "invalid build piece"; } BuildToolRules buildToolRules = Rules; if (!components.TryGetValue(prefab, out var value)) { value = (buildToolRules.Piece(R.Components(prefab)) ? null : "excluded build piece"); components[prefab] = value; } return value; } internal static string Reason(GameObject prefab) { string text = PieceReason(prefab); if (text != null) { return text; } if (!Object.op_Implicit((Object)(object)ObjectDB.instance) || ObjectDB.instance.m_items == null) { return "supply unavailable"; } foreach (GameObject item in ObjectDB.instance.m_items) { ItemDrop val = (Object.op_Implicit((Object)(object)item) ? item.GetComponent<ItemDrop>() : null); PieceTable val2 = ((!Object.op_Implicit((Object)(object)val)) ? null : val.m_itemData?.m_shared?.m_buildPieces); if (Table(val2) && Rules.Tool(((Object)item).name) && val2.m_pieces != null && val2.m_pieces.Contains(prefab)) { return null; } } return "excluded build tool"; } internal static bool Eligible(GameObject prefab) { return Reason(prefab) == null; } } internal static class ContainerHover { private static Container target; private static Player player; private static int frame; private static float next; private static string text = ""; private static readonly DisplayAccessCache access = new DisplayAccessCache(); internal static string Text(Container container) { if (!Plugin.Enabled || !Object.op_Implicit((Object)(object)container) || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return ""; } if ((Object)(object)target != (Object)(object)container || (Object)(object)player != (Object)(object)Player.m_localPlayer) { Clear(); target = container; player = Player.m_localPlayer; } frame = Time.frameCount; return text; } internal static void Clear() { target = null; player = null; text = ""; next = 0f; access.Clear(); } internal static void Tick() { if (!Plugin.Enabled || !Object.op_Implicit((Object)(object)target) || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || frame < Time.frameCount - 1) { Clear(); } else { if (Time.unscaledTime < next) { return; } next = Time.unscaledTime + 0.25f; access.Clear(); List<string> list = new List<string>(); foreach (string item2 in Topology.ContainerNetworks(target)) { Core core = Topology.RootSnapshot(item2); if (Object.op_Implicit((Object)(object)core) && Access.Container(target, player.GetPlayerID(), core, out var _, ownLease: true, null, access)) { string text = NetworkName.Read(Topology.LabelRootSnapshot(item2)); string item = ((text.Length == 0) ? RsnLocalization.Text("chest_connected") : RsnLocalization.Text("chest_connected_named", text)); if (!list.Contains(item)) { list.Add(item); } } } ContainerHover.text = string.Join("\n", list); } } } internal static class ContainerPolicy { private static readonly Dictionary<string, string> verdicts = new Dictionary<string, string>(StringComparer.Ordinal); private static ContainerRules rules; private static ZNetScene scene; internal static readonly List<string> Excluded = new List<string>(); internal static int Supported { get; private set; } internal static ContainerRules Rules { get { if (rules == null) { rules = new ContainerRules(Text(Plugin.AllowedContainers), Text(Plugin.DeniedContainers), Text(Plugin.DeniedComponents)); } return rules; } } internal static void Invalidate() { scene = null; rules = null; } private static string Text(ConfigEntry<string> entry) { object obj; if (entry != null) { obj = entry.Value; if (obj == null) { return ""; } } else { obj = ""; } return (string)obj; } internal static string Reason(string prefab) { if (!Object.op_Implicit((Object)(object)ZNetScene.instance)) { return "unloaded"; } if ((Object)(object)scene != (Object)(object)ZNetScene.instance) { Catalog(); } if (string.IsNullOrEmpty(prefab)) { return "unsupported prefab"; } if (!verdicts.TryGetValue(prefab, out var value)) { return "unsupported prefab"; } return value; } internal static bool Eligible(string prefab) { return Reason(prefab) == null; } internal static void Ensure() { Reason(""); } private static void Catalog() { scene = ZNetScene.instance; rules = null; verdicts.Clear(); Excluded.Clear(); int num = 0; foreach (GameObject prefab in scene.m_prefabs) { if (!Object.op_Implicit((Object)(object)prefab) || verdicts.ContainsKey(((Object)prefab).name)) { continue; } string text = Evaluate(prefab); if (!(text == "unsupported prefab")) { num++; verdicts[((Object)prefab).name] = text; if (text != null) { Excluded.Add(((Object)prefab).name); } } } Supported = num - Excluded.Count; Excluded.Sort(StringComparer.Ordinal); Plugin.Info("Container policy: " + Supported + " of " + num + " container prefabs supported; " + Rules.Summary); if (Excluded.Count > 0) { Plugin.Info("Containers excluded: " + string.Join(", ", Excluded.ToArray())); } Plugin.Debug("Containers supported: " + string.Join(", ", (from p in verdicts where p.Value == null select p.Key).OrderBy<string, string>((string n) => n, StringComparer.Ordinal).ToArray())); } private static string Evaluate(GameObject prefab) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 Container component = prefab.GetComponent<Container>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)prefab.GetComponent<Piece>()) || !Object.op_Implicit((Object)(object)prefab.GetComponent<ZNetView>())) { return "unsupported prefab"; } if ((int)component.m_privacy != 2 || Object.op_Implicit((Object)(object)component.m_wagon) || Object.op_Implicit((Object)(object)component.m_rootObjectOverride) || Object.op_Implicit((Object)(object)prefab.GetComponent<Ship>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<Rigidbody>())) { return "moving/private"; } return Rules.Verdict(((Object)prefab).name, R.Components(prefab)); } } public sealed class Core : MonoBehaviour, Hoverable { private sealed class Cached { internal float Until; internal List<Stock> Items; } internal static readonly HashSet<Core> Live = new HashSet<Core>(); internal readonly List<Container> Pool = new List<Container>(); private readonly HashSet<Inventory> subscribed = new HashSet<Inventory>(); private readonly Dictionary<long, Cached> cached = new Dictionary<long, Cached>(); private ZNetView view; private bool registered; internal bool Valid { get { if (R.Valid(view)) { return ((Component)this).GetComponent<Piece>().IsPlacedByPlayer(); } return false; } } internal ZDOID Id => view.GetZDO().m_uid; private void Awake() { view = ((Component)this).GetComponent<ZNetView>(); } private void Update() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (!Valid) { if (registered) { Live.Remove(this); registered = false; Pool.Clear(); } } else if (!registered) { Live.Add(this); registered = true; Plugin.Debug("Core active " + R.Key(Id)); } } internal void Scan() { //IL_01d1: Unknown result type (might be due to invalid IL or missing references) int count = Pool.Count; Pool.Clear(); if (!Valid) { return; } Pool.AddRange(from c in Topology.Pool(this) where Object.op_Implicit((Object)(object)c) && R.Valid(R.View((Component)(object)c)) select c); Pool.Sort((Container a, Container b) => string.CompareOrdinal(R.Key(R.View((Component)(object)a).GetZDO().m_uid), R.Key(R.View((Component)(object)b).GetZDO().m_uid))); HashSet<Inventory> inventories = new HashSet<Inventory>(from c in Pool select c.GetInventory() into i where i != null select i); Inventory[] array = subscribed.Where((Inventory i) => !inventories.Contains(i)).ToArray(); foreach (Inventory val in array) { val.m_onChanged = (Action)Delegate.Remove(val.m_onChanged, new Action(Invalidate)); subscribed.Remove(val); } foreach (Inventory item in inventories) { if (subscribed.Add(item)) { item.m_onChanged = (Action)Delegate.Combine(item.m_onChanged, new Action(Invalidate)); } } Invalidate(); if (count != Pool.Count) { Plugin.Debug("Core " + R.Key(Id) + " candidate containers=" + Pool.Count); } } internal void Invalidate() { cached.Clear(); } internal List<Stock> Stock(long player) { if (cached.TryGetValue(player, out var value) && Time.unscaledTime < value.Until) { return value.Items; } List<Stock> list = new List<Stock>(); foreach (Container item in Pool) { if (Access.Container(item, player, this, out var _, ownLease: false, null, null, preview: true)) { list.AddRange(Stockroom.Preview(item)); } } cached[player] = new Cached { Until = Time.unscaledTime + 0.25f, Items = list }; return list; } private void OnDestroy() { Live.Remove(this); Pool.Clear(); foreach (Inventory item in subscribed) { item.m_onChanged = (Action)Delegate.Remove(item.m_onChanged, new Action(Invalidate)); } subscribed.Clear(); cached.Clear(); if (registered) { Plugin.Debug("Core removed"); } } internal static Core Choose(Vector3 point, long player) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Enabled) { return null; } return Topology.Choose(point, player); } public string GetHoverName() { return Localization.instance.Localize("$rsn_name"); } public float GetHoverOffset() { return 1.5f; } public string GetHoverText() { return HoverInfo.Text(((Component)this).GetComponent<NetworkMember>()); } internal static void Diagnose(Terminal terminal) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { terminal.AddString("[RSN] " + RsnLocalization.Text("diag_no_player")); return; } Core core = Choose(((Component)localPlayer).transform.position, localPlayer.GetPlayerID()); string text = "[RSN] supply=" + Plugin.Enabled + " core=" + (Object.op_Implicit((Object)(object)core) ? R.Key(core.Id) : "none"); terminal.AddString("[RSN] " + RsnLocalization.Text("diag_supply", RsnLocalization.Text(Plugin.Enabled ? "enabled" : "disabled"), Object.op_Implicit((Object)(object)core) ? R.Key(core.Id) : RsnLocalization.Text("none"))); Plugin.Info(text); if (!Object.op_Implicit((Object)(object)core)) { return; } core.Scan(); foreach (Container item in core.Pool) { string reason; bool flag = Access.Container(item, localPlayer.GetPlayerID(), core, out reason); string text2 = R.Key(R.View((Component)(object)item).GetZDO().m_uid); text = text2 + " " + (flag ? "available" : reason); terminal.AddString(RsnLocalization.Text("diag_chest", text2, RsnLocalization.Reason(flag ? "available" : reason))); Plugin.Info(text); } } } internal static class Access { internal static bool Ward(Vector3 point, long player) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) bool flag = false; bool flag2 = false; foreach (PrivateArea item in R.Get<List<PrivateArea>>(typeof(PrivateArea), "m_allAreas")) { if (Object.op_Implicit((Object)(object)item) && (bool)R.Call(item, "IsEnabled", Type.EmptyTypes) && (bool)R.Call(item, "IsInside", new Type[2] { typeof(Vector3), typeof(float) }, point, 0f)) { if (((Component)item).GetComponent<Piece>().GetCreator() == player || (bool)R.Call(item, "IsPermitted", new Type[1] { typeof(long) }, player)) { flag2 = true; } else { flag = true; } } } if (!flag2) { return !flag; } return true; } internal static bool Container(Container c, long player, Core core, out string reason, bool ownLease = false, string reservation = null, DisplayAccessCache display = null, bool preview = false) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Invalid comparison between Unknown and I4 //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) reason = "unloaded"; ZNetView val = R.View((Component)(object)c); if (!Object.op_Implicit((Object)(object)c) || !R.Valid(val) || !Object.op_Implicit((Object)(object)core) || !core.Valid) { return false; } reason = ContainerPolicy.Reason(R.Id(((Component)c).gameObject)); if (reason != null) { return false; } Piece component = ((Component)c).GetComponent<Piece>(); reason = "not player built"; if (!Object.op_Implicit((Object)(object)component) || !component.IsPlacedByPlayer()) { return false; } reason = "moving/private"; if ((int)c.m_privacy != 2 || Object.op_Implicit((Object)(object)c.m_wagon) || Object.op_Implicit((Object)(object)c.m_rootObjectOverride) || Object.op_Implicit((Object)(object)((Component)c).GetComponentInParent<Ship>()) || Object.op_Implicit((Object)(object)((Component)c).GetComponentInParent<Rigidbody>())) { return false; } reason = "network path/storage coverage unavailable"; if (!(display?.Covers(core, ((Component)c).transform.position, player) ?? Topology.Covers(core, ((Component)c).transform.position, player))) { return false; } reason = "unconfirmed loaded area"; if (!(display?.Ready(((Component)c).transform.position) ?? ZNetScene.instance.IsAreaReady(((Component)c).transform.position))) { return false; } reason = "access denied"; if (!(bool)R.Call(c, "CheckAccess", new Type[1] { typeof(long) }, player) || !(display?.Ward(((Component)c).transform.position, player) ?? Ward(((Component)c).transform.position, player)) || !(display?.Ward(((Component)core).transform.position, player) ?? Ward(((Component)core).transform.position, player))) { return false; } reason = "inventory unavailable"; if (c.GetInventory() == null) { return false; } bool flag = preview && (val.GetZDO().GetString("rsn_lease", "") != "" || Transport.Reserved(val.GetZDO())); reason = "busy/reserved"; if (!ownLease && !flag && (c.IsInUse() || val.GetZDO().GetInt(ZDOVars.s_inUse, 0) != 0 || Transport.Reserved(val.GetZDO(), reservation) || Integrations.IsBusy(c.GetInventory()))) { return false; } reason = "available"; return true; } } internal static class Stockroom { private sealed class Observation { internal byte[] Data; internal float Until; internal List<Stock> Items; } private static readonly Dictionary<string, Observation> observed = new Dictionary<string, Observation>(); internal static void ClearObservations() { observed.Clear(); } internal static void Observe(string key, List<Stock> items) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) ZDO val = RemoteContext.Source(key); if (val == null) { return; } observed[key] = new Observation { Data = (byte[])(val.GetByteArray(ZDOVars.s_items, (byte[])null) ?? Array.Empty<byte>()).Clone(), Until = Time.unscaledTime + 10f, Items = items }; foreach (Core item in Core.Live) { if (Object.op_Implicit((Object)(object)item)) { item.Invalidate(); } } CraftOverview.Fresh(key, items); if (val.GetOwner() != ZNet.GetUID()) { ZDOMan.instance.RequestZDO(val.m_uid); } } internal static List<Stock> Preview(Container c) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = R.View((Component)(object)c).GetZDO(); string text = R.Key(zDO.m_uid); List<Stock> list = Snapshot(c.GetInventory(), text, null, chest: true); if (observed.TryGetValue(text, out var value)) { if (!value.Data.SequenceEqual(zDO.GetByteArray(ZDOVars.s_items, (byte[])null) ?? Array.Empty<byte>()) || Time.unscaledTime >= value.Until) { observed.Remove(text); } else { HashSet<string> names = new HashSet<string>(value.Items.Select((Stock s) => s.Item)); list.RemoveAll((Stock s) => names.Contains(s.Item)); list.AddRange(value.Items); } } return list; } internal static void Refresh(Core core, IEnumerable<string> sources) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) HashSet<string> hashSet = new HashSet<string>(sources); int num = 0; core.Scan(); foreach (Container item in core.Pool) { ZNetView val = R.View((Component)(object)item); if (R.Valid(val) && hashSet.Contains(R.Key(val.GetZDO().m_uid)) && !Transport.Reserved(val.GetZDO()) && !Transport.Locked(item.GetInventory())) { R.Call(item, "Load"); if (!val.IsOwner() && num++ < 32) { ZDOMan.instance.RequestZDO(val.GetZDO().m_uid); } } } core.Invalidate(); } internal static bool Ingredient(ItemData item, bool chest) { if (item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab) || item.m_stack <= 0 || item.m_worldLevel < Game.m_worldLevel) { return false; } if (chest) { return !item.m_equipped; } return true; } internal static List<Stock> Snapshot(Inventory inventory, string source, IEnumerable<Need> needs, bool chest) { HashSet<string> ids = ((needs == null) ? null : new HashSet<string>(needs.Select((Need n) => n.Item))); return (from i in inventory.GetAllItems() where Ingredient(i, chest) && (ids == null || ids.Contains(((Object)i.m_dropPrefab).name)) group i by new { Id = ((Object)i.m_dropPrefab).name, m_quality = i.m_quality } into g select new Stock(source, g.Key.Id, g.Key.m_quality, g.Sum((ItemData i) => i.m_stack))).ToList(); } internal static List<Need> Requirements(Requirement[] requirements, int quality, int multiplier) { return (from r in requirements where Object.op_Implicit((Object)(object)r.m_resItem) && !r.m_upgraderResource && r.GetAmount(quality) > 0 select new Need(((Object)r.m_resItem).name, checked(r.GetAmount(quality) * multiplier))).ToList(); } internal static List<Stock> Available(Player player, Core core, List<Need> needs) { List<Stock> list = Snapshot(((Humanoid)player).GetInventory(), "player", needs, chest: false); if (Object.op_Implicit((Object)(object)core)) { HashSet<string> ids = new HashSet<string>(needs.Select((Need n) => n.Item)); list.AddRange(from s in core.Stock(player.GetPlayerID()) where ids.Contains(s.Item) select s); } return list; } internal static bool Qualities(List<Need> needs, List<Stock> stock, bool craft) { if (!craft) { return true; } foreach (Need n in needs) { IGrouping<int, Stock> grouping = (from s in stock where s.Item == n.Item && s.Allowed group s by s.Quality into g orderby g.Key select g).FirstOrDefault((IGrouping<int, Stock> g) => g.Sum((Stock s) => s.Amount) >= n.Amount); if (grouping == null) { return false; } n.Quality = grouping.Key; } return true; } } internal sealed class InventoryDelta { internal sealed class Part { internal ItemData Item; internal int Amount; internal int Removed; internal Vector2i Position; } internal readonly Inventory Inventory; internal readonly List<Part> Parts = new List<Part>(); internal bool Applied; internal InventoryDelta(Inventory inventory, IEnumerable<Debit> debits, bool chest) { //IL_0112: 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) Inventory = inventory; Dictionary<ItemData, int> dictionary = new Dictionary<ItemData, int>(); foreach (Debit d in debits) { int num = d.Amount; foreach (ItemData item in from i in inventory.GetAllItems() where Stockroom.Ingredient(i, chest) && ((Object)i.m_dropPrefab).name == d.Item && i.m_quality == d.Quality select i) { dictionary.TryGetValue(item, out var value); int num2 = Math.Min(num, item.m_stack - value); if (num2 > 0) { Part part = Parts.FirstOrDefault((Part x) => x.Item == item); if (part == null) { part = new Part { Item = item, Position = item.m_gridPos }; Parts.Add(part); } part.Amount += num2; dictionary[item] = value + num2; num -= num2; if (num == 0) { break; } } } if (num != 0) { throw new InvalidOperationException("Fresh stock insufficient: " + d.Item); } } } internal void Apply() { if (Applied) { return; } foreach (Part part in Parts) { if (!Inventory.ContainsItem(part.Item) || part.Item.m_stack < part.Amount) { throw new InvalidOperationException("Stale inventory"); } } Applied = true; try { foreach (Part part2 in Parts) { int stack = part2.Item.m_stack; try { if (!Inventory.RemoveItem(part2.Item, part2.Amount)) { throw new InvalidOperationException("RemoveItem refused"); } } finally { part2.Removed = stack - (Inventory.ContainsItem(part2.Item) ? part2.Item.m_stack : 0); } if (part2.Removed != part2.Amount) { throw new InvalidOperationException("Unexpected debit amount"); } } } catch { Restore(); throw; } } internal void Restore() { if (!Applied) { return; } foreach (Part item2 in Parts.Where((Part x) => x.Removed > 0)) { int num = (Inventory.ContainsItem(item2.Item) ? item2.Item.m_stack : 0); int removed = item2.Removed; try { if (Inventory.ContainsItem(item2.Item)) { ItemData item = item2.Item; item.m_stack += removed; continue; } if (Inventory.GetItemAt(item2.Position.x, item2.Position.y) != null) { throw new InvalidOperationException("Reserved rollback slot occupied"); } ItemData val = item2.Item.Clone(); val.m_stack = removed; try { if (!(bool)R.Call(Inventory, "AddItem", new Type[5] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) }, val, removed, item2.Position.x, item2.Position.y, false)) { throw new InvalidOperationException("Delta restoration refused"); } } finally { ItemData itemAt = Inventory.GetItemAt(item2.Position.x, item2.Position.y); if (itemAt != null && (Object)(object)itemAt.m_dropPrefab == (Object)(object)item2.Item.m_dropPrefab && itemAt.m_quality == item2.Item.m_quality) { item2.Item = itemAt; } } } finally { int val2 = (Inventory.ContainsItem(item2.Item) ? item2.Item.m_stack : 0) - num; item2.Removed -= Math.Max(0, Math.Min(removed, val2)); } } Applied = Parts.Any((Part p) => p.Removed > 0); R.Call(Inventory, "Changed", new Type[2] { typeof(bool), typeof(bool) }, false, false); } } internal static class CoreMaterials { private static readonly string[] Slots = new string[4] { "SNC_Stone", "SNC_Timber", "SNC_Iron", "SNC_Plinth" }; private static readonly string[] Donors = new string[4] { "stone_wall_2x1", "wood_door", "iron_floor_1x1", "stone_wall_2x1" }; private static readonly string[] Names = new string[4] { "stone_mat", "door_wood", "metalwall", "stone_mat" }; private const string Prefix = "RSN_Vanilla_"; internal static void Apply(GameObject core, bool relay = false) { //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Expected O, but got Unknown //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) string[] array = ((!relay) ? Slots : new string[3] { "RR_Stone", "RR_Timber", "RR_Iron" }); if (!Object.op_Implicit((Object)(object)core)) { throw new InvalidOperationException("Core prefab unavailable"); } MeshRenderer[] componentsInChildren = core.GetComponentsInChildren<MeshRenderer>(true); MeshRenderer[] array2 = (MeshRenderer[])(object)new MeshRenderer[array.Length]; int num = 0; MeshRenderer[] array3 = componentsInChildren; foreach (MeshRenderer val in array3) { Material sharedMaterial = ((Renderer)val).sharedMaterial; if (!Object.op_Implicit((Object)(object)sharedMaterial)) { throw new InvalidOperationException("Missing core material"); } for (int j = 0; j < array.Length; j++) { if (((Object)sharedMaterial).name == "RSN_Vanilla_" + array[j]) { num++; } if (((Object)sharedMaterial).name == array[j]) { if (Object.op_Implicit((Object)(object)array2[j])) { throw new InvalidOperationException("Duplicate core material slot " + array[j]); } array2[j] = val; } } } if (num == array.Length) { return; } if (num != 0) { throw new InvalidOperationException("Partial native material assignment"); } List<Material> list = new List<Material>(); try { for (int k = 0; k < array.Length; k++) { if (!Object.op_Implicit((Object)(object)array2[k])) { throw new InvalidOperationException("Core material slot missing: " + array[k]); } GameObject prefab = PrefabManager.Instance.GetPrefab(Donors[k]); if (!Object.op_Implicit((Object)(object)prefab)) { throw new InvalidOperationException("Material donor missing: " + Donors[k]); } Material val2 = null; Renderer[] componentsInChildren2 = prefab.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Material[] sharedMaterials = componentsInChildren2[i].sharedMaterials; foreach (Material val3 in sharedMaterials) { if (Object.op_Implicit((Object)(object)val3) && ((Object)val3).name == Names[k] && Object.op_Implicit((Object)(object)val3.shader) && ((Object)val3.shader).name == "Custom/Piece") { val2 = val3; break; } } } if (!Object.op_Implicit((Object)(object)val2)) { throw new InvalidOperationException("Native material missing: " + Donors[k] + "/" + Names[k]); } Material val4 = new Material(val2) { name = "RSN_Vanilla_" + array[k] }; list.Add(val4); string[] array4 = new string[6] { "_TriplanarMap", "_TriplanarLocalPos", "_TriplanarScale", "_Cull", "_Cutoff", "_TwoSidedNormals" }; foreach (string text in array4) { if (!val4.HasProperty(text)) { throw new InvalidOperationException("Native shader property missing: " + text); } } val4.SetFloat("_TriplanarMap", 1f); val4.SetFloat("_TriplanarLocalPos", 1f); val4.SetFloat("_TriplanarScale", 1f); val4.SetFloat("_Cull", 0f); val4.SetFloat("_TwoSidedNormals", 1f); val4.SetFloat("_Cutoff", 0f); if (k != 2) { val4.SetFloat("_RippleDistance", 0f); val4.SetFloat("_MoveableObject", 1f); } if (k == 3) { val4.SetTexture("_BumpMap", (Texture)null); val4.SetFloat("_BumpScale", 0f); val4.SetFloat("_ValueNoise", 0f); } if (k < 2 || k == 3) { if (k < 2 && !Object.op_Implicit((Object)(object)val4.GetTexture("_BumpMap"))) { throw new InvalidOperationException("Native normal map missing: " + Names[k]); } val4.SetFloat("_TriplanarMap", 0f); array4 = new string[2] { "_MainTex", "_BumpMap" }; foreach (string text2 in array4) { val4.SetTextureScale(text2, Vector2.one); val4.SetTextureOffset(text2, Vector2.zero); } val4.SetVector("_MainTex_ST", new Vector4(1f, 1f, 0f, 0f)); val4.SetFloat("_BumpScale", (k == 3) ? 0f : ((!relay) ? ((k == 0) ? 1.15f : 1.25f) : ((k == 0) ? 0.55f : 0.65f))); } } } catch { foreach (Material item in list) { Object.Destroy((Object)(object)item); } throw; } for (int m = 0; m < array.Length; m++) { ((Renderer)array2[m]).sharedMaterial = list[m]; Plugin.Info((relay ? "Relay" : "Core") + " material " + array[m] + " <- " + Donors[m] + "/" + Names[m] + "; shader=Custom/Piece; " + ((m < 2) ? ("engraved surface UV; normal=" + ((Object)list[m].GetTexture("_BumpMap")).name + " strength=" + list[m].GetFloat("_BumpScale")) : ((m == 2) ? "local triplanar (unchanged since 0.1.2)" : "textured flat stone; surface UV; normal/noise disabled"))); } } } internal static class CraftInspection { private sealed class Source { internal string Key; internal long Owner; internal ZDOID Id; internal float Sent; internal float FirstSent = -1f; internal bool Delivered; } private static Operation operation; private static Recipe recipe; private static ItemData upgrade; private static readonly Dictionary<string, Source> sources = new Dictionary<string, Source>(); private static float nextRefresh; private static string rejectedTarget; private static float retryAt; internal static bool Ready { get; private set; } internal static void Clear() { operation = null; recipe = null; upgrade = null; sources.Clear(); Ready = false; nextRefresh = 0f; rejectedTarget = null; retryAt = 0f; } internal static void Ensure(Actions.Pending selected, Core core) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) if ((rejectedTarget == selected.Op.Target && Time.unscaledTime < retryAt) || (CraftInspection.operation != null && CraftInspection.operation.Target == selected.Op.Target && (Object)(object)recipe == (Object)(object)selected.Recipe && upgrade == selected.Upgrade && CraftInspection.operation.Core == core.Id && CraftInspection.operation.Station == selected.Op.Station && CraftInspection.operation.Quality == selected.Op.Quality && CraftInspection.operation.Multiplier == selected.Op.Multiplier && (!Ready || Time.unscaledTime < nextRefresh))) { return; } Clear(); recipe = selected.Recipe; upgrade = selected.Upgrade; Operation operation = Actions.Create(selected.Player, core, build: false, selected.Op.Target, selected.Op.Quality, selected.Op.Multiplier); if (!operation.ReadRequirements(out var reason)) { rejectedTarget = selected.Op.Target; retryAt = Time.unscaledTime + 1f; } else { if (!Actions.Propose(new Actions.Pending { Op = operation, Player = selected.Player }, new List<Debit>())) { return; } CraftInspection.operation = operation; foreach (Container item in core.Pool) { if (Access.Container(item, operation.PlayerId, core, out reason, ownLease: true)) { ZDO zDO = R.View((Component)(object)item).GetZDO(); string key = R.Key(zDO.m_uid); sources[key] = new Source { Key = key, Owner = zDO.GetOwner(), Id = zDO.m_uid, Sent = -100f }; } } if (sources.Count == 0) { Ready = true; nextRefresh = Time.unscaledTime + 2f; } } } internal static void Tick() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) if (operation == null || Ready) { return; } float now = Time.unscaledTime; foreach (Source item in sources.Values.Where((Source s) => !s.Delivered)) { ZDO val = RemoteContext.Data(item.Id); if (val != null && val.GetOwner() != item.Owner) { item.Owner = val.GetOwner(); item.Sent = -100f; item.FirstSent = -1f; } } Source[] array = sources.Values.Where((Source s) => !s.Delivered && s.FirstSent >= 0f && now - s.FirstSent > 6f).ToArray(); foreach (Source source in array) { Apply(source, new List<Stock>()); Plugin.Debug("Selected ingredient inspection timed out; unconfirmed source counts cleared: " + source.Key); } if (sources.Values.All((Source s) => s.Delivered)) { Ready = true; nextRefresh = now + 2f; return; } Source first = sources.Values.FirstOrDefault((Source s) => !s.Delivered && now - s.Sent >= 2f); if (first == null) { return; } Source[] array2 = sources.Values.Where((Source s) => !s.Delivered && s.Owner == first.Owner && now - s.Sent >= 2f).Take(16).ToArray(); ZPackage val2 = operation.Write(); val2.Write(array2.Length); array = array2; foreach (Source source2 in array) { source2.Sent = now; if (source2.FirstSent < 0f) { source2.FirstSent = now; } val2.Write(source2.Id); } try { Transport.Send(first.Owner, "inspect", val2); } catch (Exception ex) { Plugin.Debug("Ingredient inspection retry: " + ex.Message); } } internal static void Request(long sender, ZPackage p) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown Operation operation = Operation.Read(p); int num = p.ReadInt(); if (num < 1 || num > 16 || operation.Build || operation.Quote || operation.Peer != sender || !operation.ReadRequirements(out var reason) || !RemoteContext.Actor(operation.Actor, sender, operation.PlayerId, out var _, out reason)) { return; } RemoteContext remoteContext = new RemoteContext(operation); for (int i = 0; i < num; i++) { ZDOID val = p.ReadZDOID(); string text = R.Key(val); GameObject obj = ZNetScene.instance.FindInstance(val); Container val2 = ((obj != null) ? obj.GetComponent<Container>() : null); List<Stock> items = new List<Stock>(); if (remoteContext.OwnerSource(val2, out reason, ownLease: true)) { Inventory inventory = val2.GetInventory(); ZNetView val3 = R.View((Component)(object)val2); if (!Transport.Locked(inventory) && !Integrations.IsBusy(inventory) && !val2.IsInUse() && val3.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 0) { R.Call(val2, "Load"); } items = Stockroom.Snapshot(inventory, text, operation.Needs, chest: true); } ZPackage val4 = new ZPackage(); val4.Write(operation.Id); val4.Write(text); Wire.Stocks(val4, items); Transport.Send(sender, "inspected", val4); } } internal static void Response(long sender, ZPackage p) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) string text = p.ReadString(); string key = p.ReadString(); List<Stock> list = Wire.Stocks(p); if (operation?.Id != text || !sources.TryGetValue(key, out var value) || value.Owner != sender || value.Delivered) { return; } ZDO val = RemoteContext.Data(value.Id); if (val != null && val.GetOwner() == sender && !list.Any((Stock s) => s.Source != key || !operation.Needs.Any((Need n) => n.Item == s.Item))) { Apply(value, list); if (sources.Values.All((Source s) => s.Delivered)) { Ready = true; nextRefresh = Time.unscaledTime + 2f; } } } private static void Apply(Source source, List<Stock> items) { foreach (Need need in operation.Needs) { if (!items.Any((Stock s) => s.Item == need.Item)) { items.Add(new Stock(source.Key, need.Item, 1, 0)); } } source.Delivered = true; Stockroom.Observe(source.Key, items); } } internal static class CraftOverview { private static readonly StockCatalog<Container> catalog = new StockCatalog<Container>(); private static InventoryGui gui; private static Player player; private static CraftingStation station; private static Core core; private static float nextScan; private static bool requestRecords; private static bool rowsDirty; private static object[] rowQueue; private static int rowIndex; internal static void Clear() { catalog.Clear(); gui = null; player = null; station = null; core = null; nextScan = 0f; requestRecords = (rowsDirty = false); rowQueue = null; } internal static void Rescan() { catalog.CancelScan(); nextScan = 0f; } internal static void Open(InventoryGui current, Player actor) { CraftingStation val = (Object.op_Implicit((Object)(object)actor) ? actor.GetCurrentCraftingStation() : null); if (!Object.op_Implicit((Object)(object)actor) || !Object.op_Implicit((Object)(object)current) || !Object.op_Implicit((Object)(object)val) || val.m_upgrader || !Plugin.Enabled) { Clear(); } else if (!((Object)(object)gui == (Object)(object)current) || !((Object)(object)player == (Object)(object)actor) || !((Object)(object)station == (Object)(object)val)) { Clear(); gui = current; player = actor; station = val; requestRecords = true; RecipeIndex.Ensure(); } } internal static void Tick() { if (!Object.op_Implicit((Object)(object)gui)) { return; } if (!InventoryGui.IsVisible() || !Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || (Object)(object)player.GetCurrentCraftingStation() != (Object)(object)station || !Plugin.Enabled) { Clear(); return; } if (!catalog.Running) { if (Time.unscaledTime < nextScan) { return; } Core core = Actions.Context(player, craft: true); if ((Object)(object)CraftOverview.core != (Object)(object)core) { CraftOverview.core = core; catalog.Clear(); requestRecords = true; rowsDirty = true; } if (!Object.op_Implicit((Object)(object)CraftOverview.core)) { nextScan = Time.unscaledTime + 0.5f; return; } CraftOverview.core.Scan(); catalog.Begin(CraftOverview.core.Pool.ToArray()); } Stopwatch clock = Stopwatch.StartNew(); int revision = catalog.Revision; try { catalog.Step(Read, 16, () => clock.Elapsed.TotalMilliseconds >= 0.75); } catch (Exception e) { catalog.Clear(); nextScan = Time.unscaledTime + 2f; rowsDirty = true; Plugin.Error("craft-overview", e); return; } if (!catalog.Running) { rowsDirty |= revision != catalog.Revision; requestRecords = false; nextScan = Time.unscaledTime + 1f; Plugin.Debug("Craft overview refreshed; containers=" + CraftOverview.core.Pool.Count + "; revision=" + catalog.Revision + "; no reservations acquired"); } } private static IEnumerable<Stock> Read(Container container) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)core) || !Object.op_Implicit((Object)(object)player) || !Access.Container(container, player.GetPlayerID(), core, out var _, ownLease: true)) { return Array.Empty<Stock>(); } ZNetView val = R.View((Component)(object)container); Inventory inventory = container.GetInventory(); if (requestRecords && !val.IsOwner()) { ZDOMan.instance.RequestZDO(val.GetZDO().m_uid); } if (!Transport.Locked(inventory) && !Integrations.IsBusy(inventory) && !container.IsInUse() && val.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 0) { R.Call(container, "Load"); } return Stockroom.Preview(container); } internal static List<Stock> Stock(Player actor, IEnumerable<Need> requirements) { List<Need> list = requirements.ToList(); List<Stock> list2 = Stockroom.Snapshot(((Humanoid)actor).GetInventory(), "player", list, chest: false); if ((Object)(object)actor == (Object)(object)player && Object.op_Implicit((Object)(object)core) && catalog.Ready) { list2.AddRange(catalog.ForItems(list.Select((Need n) => n.Item))); } return list2; } internal static bool Ready(Player actor) { if ((Object)(object)actor == (Object)(object)player && Object.op_Implicit((Object)(object)core)) { return catalog.Ready; } return false; } internal static void Fresh(string key, List<Stock> items) { if (Object.op_Implicit((Object)(object)core)) { int revision = catalog.Revision; catalog.Replace(key, items.Select((Stock s) => s.Item), items); rowsDirty |= catalog.Revision != revision; } } internal static void RefreshRows(InventoryGui current) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gui != (Object)(object)current || !Object.op_Implicit((Object)(object)player) || Actions.Active != null) { return; } if (rowQueue == null) { if (!rowsDirty) { return; } rowsDirty = false; rowQueue = ((IList)R.Get<object>(gui, "m_availableRecipes")).Cast<object>().ToArray(); rowIndex = 0; } Stopwatch stopwatch = Stopwatch.StartNew(); int num = 32; while (rowIndex < rowQueue.Length && num-- > 0) { object obj = rowQueue[rowIndex++]; Type type = obj.GetType(); Recipe val = (Recipe)type.GetProperty("Recipe").GetValue(obj, null); ItemData val2 = (ItemData)type.GetProperty("ItemData").GetValue(obj, null); GameObject val3 = (GameObject)type.GetProperty("InterfaceElement").GetValue(obj, null); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val3)) { int num2 = ((val2 == null) ? 1 : (val2.m_quality + 1)); bool flag = num2 <= val.m_item.m_itemData.m_shared.m_maxQuality && (player.HaveRequirements(val, false, num2, 1) || player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25)); Transform obj2 = val3.transform.Find("icon"); Image val4 = ((obj2 != null) ? ((Component)obj2).GetComponent<Image>() : null); Transform obj3 = val3.transform.Find("name"); TMP_Text val5 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null); if (Object.op_Implicit((Object)(object)val4)) { ((Graphic)val4).color = (Color)(flag ? Color.white : new Color(1f, 0f, 1f, 0f)); } if (Object.op_Implicit((Object)(object)val5)) { ((Graphic)val5).color = (Color)(flag ? Color.white : new Color(0.66f, 0.66f, 0.66f, 1f)); } if (stopwatch.Elapsed.TotalMilliseconds >= 0.75) { break; } } } if (rowIndex == rowQueue.Length) { rowQueue = null; } } } internal static class CraftPreparation { private sealed class Release { internal float Since; internal float Sent; } private static Actions.Pending desired; private static Actions.Pending offer; private static Actions.Pending lostClaim; private static OfferWindow window; private static float nextProbe; private static float lastSend; private static float nextValidation; private static float failureSince = -1f; private static string failure; private static bool queued; private static readonly Dictionary<string, Release> retiring = new Dictionary<string, Release>(); internal static bool Releasing => retiring.Count > 0; internal static bool Claimed { get { OfferWindow offerWindow = window; if (offerWindow == null || !offerWindow.Claimed) { return lostClaim != null; } return true; } } internal static void Clear() { desired = (offer = (lostClaim = null)); CraftOverview.Clear(); CraftInspection.Clear(); window = null; retiring.Clear(); nextProbe = (lastSend = 0f); failureSince = -1f; failure = null; } private static bool Free(Player p) { if (!p.NoCostCheat()) { return ZoneSystem.instance.GetGlobalKey((GlobalKeys)25); } return true; } private static bool Same(Actions.Pending a, Actions.Pending b) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (a != null && b != null && (Object)(object)a.Player == (Object)(object)b.Player && (Object)(object)a.Gui == (Object)(object)b.Gui && (Object)(object)a.Recipe == (Object)(object)b.Recipe && a.Op.Target == b.Op.Target && a.Upgrade == b.Upgrade && a.UpgradeQuality == b.UpgradeQuality && a.Op.Station == b.Op.Station && a.Op.Quality == b.Op.Quality && a.Op.Multiplier == b.Op.Multiplier) { return a.Variant == b.Variant; } return false; } internal static void Selection(InventoryGui gui, Player player) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) if (Actions.Active != null) { return; } CraftOverview.Open(gui, player); if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)gui) || !InventoryGui.IsVisible() || ((Character)player).IsDead() || Free(player)) { Cancel(); return; } object obj = R.Get<object>(gui, "m_selectedRecipe"); Type type = obj.GetType(); Recipe val = (Recipe)type.GetProperty("Recipe").GetValue(obj, null); ItemData val2 = (ItemData)type.GetProperty("ItemData").GetValue(obj, null); CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)currentCraftingStation) || currentCraftingStation.m_upgrader || !Plugin.Enabled) { Cancel(); return; } OfferWindow offerWindow = window; Actions.Pending pending = ((offerWindow != null && offerWindow.Claimed) ? offer : lostClaim); if (pending != null && (Object)(object)pending.Recipe == (Object)(object)val && pending.Upgrade == val2) { ZDOID station = pending.Op.Station; ZNetView obj2 = R.View((Component)(object)currentCraftingStation); ZDOID? val3 = ((obj2 == null) ? ((ZDOID?)null) : obj2.GetZDO()?.m_uid); if (val3.HasValue && station == val3.GetValueOrDefault()) { return; } } bool flag = val2 == null && (ZInput.GetButton("AltPlace") || ZInput.GetButton("JoyLStick") || R.Get<bool>(gui, "m_touchMultiCrafting")); Actions.Pending obj3 = new Actions.Pending { Player = player, Gui = gui, Recipe = val, Upgrade = val2, UpgradeQuality = (val2?.m_quality ?? 0), Variant = R.Get<int>(gui, "m_selectedVariant"), Multi = flag }; Operation obj4 = new Operation { Target = RecipeIndex.Key(val), Quality = ((val2 == null) ? 1 : (val2.m_quality + 1)), Multiplier = ((!flag) ? 1 : gui.m_multiCraftAmount) }; ZNetView obj5 = R.View((Component)(object)currentCraftingStation); obj4.Station = (ZDOID)(((??)((obj5 == null) ? ((ZDOID?)null) : obj5.GetZDO()?.m_uid)) ?? ZDOID.None); obj3.Op = obj4; Actions.Pending b = obj3; if (!Same(desired, b)) { Cancel(); desired = b; nextProbe = Time.unscaledTime; failureSince = -1f; } } private static bool ContextValid(Actions.Pending p) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (p != null && Object.op_Implicit((Object)(object)p.Player) && (Object)(object)p.Player == (Object)(object)Player.m_localPlayer && !((Character)p.Player).IsDead() && Object.op_Implicit((Object)(object)p.Gui) && InventoryGui.IsVisible()) { CraftingStation currentCraftingStation = p.Player.GetCurrentCraftingStation(); ZDOID? val = ((currentCraftingStation == null) ? ((ZDOID?)null) : ((Component)currentCraftingStation).GetComponent<ZNetView>().GetZDO()?.m_uid); ZDOID station = p.Op.Station; if (val.HasValue && (!val.HasValue || val.GetValueOrDefault() == station)) { if (p.Upgrade != null) { if (((Humanoid)p.Player).GetInventory().ContainsItem(p.Upgrade)) { return p.Upgrade.m_quality == p.UpgradeQuality; } return false; } return true; } } return false; } internal static bool Personal(Player p, Recipe recipe, int quality, int amount) { List<Need> needs = Stockroom.Requirements(recipe.m_resources, quality, amount); List<Stock> stock = Stockroom.Snapshot(((Humanoid)p).GetInventory(), "player", needs, chest: false); return Satisfies(recipe, needs, stock); } private static bool Satisfies(Recipe recipe, List<Need> needs, List<Stock> stock) { if (recipe.m_requireOnlyOneIngredient) { return needs.Any(delegate(Need n) { List<Need> needs2 = new List<Need> { new Need(n.Item, n.Amount) }; return Stockroom.Qualities(needs2, stock, craft: true) && Planner.Plan(needs2, stock) != null; }); } if (Stockroom.Qualities(needs, stock, craft: true)) { return Planner.Plan(needs, stock) != null; } return false; } private static bool PersonalShare(Actions.Pending p) { if (p?.Plan == null || !Object.op_Implicit((Object)(object)p.Player)) { return false; } List<Stock> stock = Stockroom.Snapshot(((Humanoid)p.Player).GetInventory(), "player", p.Op.Needs, chest: false); return Planner.Plan(from d in p.Plan where d.Source == "player" select new Need(d.Item, d.Amount, d.Quality), stock) != null; } private static bool Ready() { if (offer != null && window != null && window.Ready(Time.unscaledTime) && Same(desired, offer) && RecipeIndex.Matches(offer.Recipe, offer.Op.Target) && ContextValid(offer)) { return PersonalShare(offer); } return false; } internal static List<Stock> Stock(Player p, IEnumerable<Need> needs, Recipe recipe = null, int quality = 0, int multiplier = 0) { return CraftOverview.Stock(p, needs); } internal static List<Stock> IngredientStock(Player p, Recipe recipe, int quality, int amount, List<Need> needs) { if (Personal(p, recipe, quality, amount)) { return Stockroom.Snapshot(((Humanoid)p).GetInventory(), "player", needs, chest: false); } if (Ready() && (Object)(object)offer.Player == (Object)(object)p && (Object)(object)offer.Recipe == (Object)(object)recipe && offer.Op.Quality == quality && offer.Op.Multiplier == amount) { return offer.Plan.Select((Debit d) => new Stock(d.Source, d.Item, d.Quality, d.Amount)).ToList(); } return CraftOverview.Stock(p, needs); } internal static bool Available(Player p, Recipe r, int quality, int amount) { List<Need> list = Stockroom.Requirements(r.m_resources, quality, amount); return Satisfies(r, list, CraftOverview.Stock(p, list)); } private static bool CanStart(Actions.Pending p) { if (!Personal(p.Player, p.Recipe, p.Op.Quality, p.Op.Multiplier)) { if (Ready()) { return Same(desired, p); } return false; } return true; } internal static bool Contains(string id, string key) { if (offer?.Op.Id == id) { return offer.Op.Sources.Contains(key); } return false; } internal static bool Locked(Inventory inv) { OfferWindow offerWindow = window; if (offerWindow != null && offerWindow.Claimed && offer != null && Object.op_Implicit((Object)(object)offer.Player)) { return ((Humanoid)offer.Player).GetInventory() == inv; } return false; } internal static bool LockedItem(ItemData item) { OfferWindow offerWindow = window; if (offerWindow != null && offerWindow.Claimed && offer != null && Object.op_Implicit((Object)(object)offer.Player)) { return ((Humanoid)offer.Player).GetInventory().ContainsItem(item); } return false; } private static void Send(Action action) { try { action(); } catch (Exception ex) { Plugin.Debug("preflight transport: " + ex.Message); } } internal static void Cancel() { desired = null; lostClaim = null; CraftInspection.Clear(); if (offer != null) { string id = offer.Op.Id; offer = null; window?.Cancel(); window = null; retiring[id] = new Release { Since = Time.unscaledTime, Sent = Time.unscaledTime }; Send(delegate { Transport.Instance.DropQuote(id); }); } } private static void Retire() { Actions.Pending pending = desired; OfferWindow offerWindow = window; Actions.Pending obj = ((offerWindow != null && offerWindow.Claimed) ? offer : null); Cancel(); desired = pending; lostClaim = obj; nextProbe = Time.unscaledTime + 0.5f; } internal static void Tick() { float unscaledTime = Time.unscaledTime; KeyValuePair<string, Release>[] array = retiring.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair<string, Release> entry = array[i]; if (unscaledTime - entry.Value.Since > 10f) { Plugin.Critical(entry.Key, "Unused craft reservation release unconfirmed after 10 seconds; retrying cancellation"); } if (unscaledTime - entry.Value.Sent >= 2f) { entry.Value.Sent = unscaledTime; Send(delegate { Transport.Instance.DropQuote(entry.Key); }); } } if (Actions.Waiting != null) { return; } if (!ContextValid(desired)) { if (desired != null || offer != null) { Cancel(); } } else { if (lostClaim != null) { return; } Core core = Actions.Context(desired.Player, craft: true); if (Object.op_Implicit((Object)(object)core)) { CraftInspection.Ensure(desired, core); } Player player; Core core2; if (offer != null) { if (window.Confirmed && !Ready()) { Retire(); return; } if (!window.Confirmed && unscaledTime - offer.Started >= 8f) { if (!queued) { Problem("preflight confirmation timeout"); } Retire(); return; } if (window.Confirmed && unscaledTime >= nextValidation) { nextValidation = unscaledTime + 0.5f; if (!offer.Op.Validate(out player, out core2, out var _, forceTopology: false)) { Retire(); return; } } if (window.Claimed && R.Get<float>(offer.Gui, "m_craftTimer") < 0f) { Retire(); lostClaim = null; } else { if (!(unscaledTime - lastSend >= 1f)) { return; } lastSend = unscaledTime; Actions.Pending current = offer; Send(delegate { if (window.Claimed) { Transport.Instance.HoldQuote(current.Op.Id); } else if (!window.Confirmed) { Transport.Instance.Begin(current.Op); } }); } } else { if (retiring.Count > 0 || unscaledTime < nextProbe || !CraftOverview.Ready(desired.Player) || !CraftInspection.Ready) { return; } nextProbe = unscaledTime + 1f; if (!Personal(desired.Player, desired.Recipe, desired.Op.Quality, desired.Op.Multiplier)) { try { Core core3 = core; if (Object.op_Implicit((Object)(object)core3)) { Operation op = Actions.Create(desired.Player, core3, build: false, desired.Op.Target, desired.Op.Quality, desired.Op.Multiplier); op.Quote = true; if (!op.Validate(out player, out core2, out var reason2, forceTopology: false)) { Problem(reason2); } else { List<Stock> stock = CraftOverview.Stock(desired.Player, op.Needs); List<Debit> list = (op.SelectNeeds(stock) ? Planner.Plan(op.Needs, stock, compact: true) : null); if (list == null) { failureSince = -1f; } else { Actions.Pending pending = new Actions.Pending { Player = desired.Player, Gui = desired.Gui, Recipe = desired.Recipe, Upgrade = desired.Upgrade, UpgradeQuality = desired.UpgradeQuality, Variant = desired.Variant, Multi = desired.Multi, Op = op, Started = unscaledTime }; if (!Actions.Propose(pending, list)) { Problem("invalid source proposal"); } else { offer = pending; queued = false; window = new OfferWindow(); lastSend = unscaledTime; Send(delegate { Transport.Instance.Begin(op); }); } } } } return; } catch (Exception ex) { Problem(ex.Message); return; } } failureSince = -1f; } } } internal static void Progress(string id, bool inQueue) { if (offer?.Op.Id == id) { queued = inQueue; } } internal static void Offered(string id, List<Debit> plan, float remaining) { if (offer?.Op.Id != id || window == null || window.Claimed || window.Confirmed) { return; } if (!ContextValid(offer) || !Same(desired, offer) || !RecipeIndex.Matches(offer.Recipe, offer.Op.Target) || remaining <= 0.5f) { Retire(); return; } List<Need> needs = Stockroom.Requirements(offer.Recipe.m_resources, offer.Op.Quality, offer.Op.Multiplier); bool num = !float.IsNaN(remaining) && !float.IsInfinity(remaining) && plan.Count > 0 && plan.All((Debit d) => d.Amount > 0 && d.Quality >= 1 && (d.Source == "player" || offer.Op.Sources.Contains(d.Source)) && needs.Any((Need n) => n.Item == d.Item)) && Satisfies(offer.Recipe, needs, plan.Select((Debit d) => new Stock(d.Source, d.Item, d.Quality, d.Amount)).ToList()); offer.Plan = plan; if (!num || !PersonalShare(offer)) { Problem("preflight plan changed"); Retire(); return; } window.Confirm(Math.Min(offer.Started + 8f, (double)(Time.unscaledTime + remaining) - 0.5)); if (!window.Ready(Time.unscaledTime)) { Retire(); return; } failureSince = -1f; failure = null; } internal static void Refused(string id, string reason) { if (!retiring.Remove(id) && !(offer?.Op.Id != id)) { CraftInspection.Clear(); OfferWindow offerWindow = window; if (offerWindow != null && offerWindow.Claimed) { lostClaim = offer; } offer = null; window = null; nextProbe = Time.unscaledTime + 1f; Topology.Dirty(); Problem(reason); } } private static void Problem(string reason) { string[] obj = new string[6] { "preflight: ", reason, " recipe=", null, null, null }; Actions.Pending pending = desired; object obj2; if (pending == null) { obj2 = null; } else { Recipe recipe = pending.Recipe; obj2 = ((recipe != null) ? ((Object)recipe).name : null); } if (obj2 == null) { obj2 = "none"; } obj[3] = (string)obj2; obj[4] = " target="; obj[5] = desired?.Op.Target ?? "none"; Plugin.Debug(string.Concat(obj)); if (reason.StartsWith("recipe ", StringComparison.Ordinal)) { RecipeIndex.Report(desired?.Op.Target, reason); } if (!(reason == "offer expired") && !(reason == "offer cancelled") && !reason.Contains("insufficient") && !reason.Contains("busy/reserved")) { switch (reason) { default: if (!reason.Contains("access denied")) { failure = reason; if (failureSince < 0f) { failureSince = Time.unscaledTime; } if (Time.unscaledTime - failureSince >= 8f) { Plugin.Critical("preflight-" + desired?.Op.Target, "Cannot confirm selected recipe after background recovery: " + failure); } Topology.Dirty(); return; } break; case "queue timeout": case "station unavailable": case "recipe unavailable": break; } } failureSince = -1f; } private static bool Capacity(Actions.Pending p) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) string dlc = p.Recipe.m_item.m_itemData.m_shared.m_dlc; if (dlc.Length > 0 && !DLCMan.instance.IsDLCInstalled(dlc)) { return false; } if (p.Upgrade != null) { return true; } int num2 = default(int); ItemData val = default(ItemData); int num = p.Recipe.GetAmount(p.Op.Quality, ref num2, ref val, p.Op.Multiplier); CraftingStation currentCraftingStation = p.Player.GetCurrentCraftingStation(); if (Object.op_Implicit((Object)(object)currentCraftingStation) && (int)currentCraftingStation.m_craftingSkill != 0 && ((Character)p.Player).GetSkillFactor(currentCraftingStation.m_craftingSkill) > 0f && p.Gui.m_craftBonusChance > 0f && p.Recipe.m_item.m_itemData.m_shared.m_maxStackSize > 1) { num = CraftCapacity.Maximum(num, p.Op.Multiplier, p.Gui.m_craftBonusAmount); } if (num > 0) { return ((Humanoid)p.Player).GetInventory().CanAddItem(((Component)p.Recipe.m_item).gameObject, num); } return false; } internal static void Button(InventoryGui gui) { if (Actions.Active == null) { if (Actions.Waiting != null) { ((Selectable)gui.m_craftButton).interactable = false; } if ((Object)(object)desired?.Gui == (Object)(object)gui && ((Selectable)gui.m_craftButton).interactable && (!CanStart(desired) || !Capacity(desired))) { ((Selectable)gui.m_craftButton).interactable = false; } CraftOverview.RefreshRows(gui); } } internal static bool Press(InventoryGui gui) { if (Actions.Waiting == null) { OfferWindow offerWindow = window; if ((offerWindow == null || !offerWindow.Claimed) && lostClaim == null) { Selection(gui, Player.m_localPlayer); Actions.Pending pending = desired; if (pending == null) { return true; } if (!((Selectable)gui.m_craftButton).interactable || !Capacity(pending)) { return false; } if (Personal(pending.Player, pending.Recipe, pending.Op.Quality, pending.Op.Multiplier)) { Cancel(); return true; } if (!Ready() || !offer.Op.Validate(out var _, out var _, out var _, forceTopology: false)) { return false; } if (!window.Claim(Time.unscaledTime)) { return false; } lastSend = Time.unscaledTime; Send(delegate { Transport.Instance.HoldQuote(offer.Op.Id); }); return true; } } return false; } internal static void Pressed(InventoryGui gui) { OfferWindow offerWindow = window; if (offerWindow != null && offerWindow.Claimed && R.Get<float>(gui, "m_craftTimer") < 0f) { Retire(); lostClaim = null; } } internal static bool Execute(InventoryGui gui, Player player) { Recipe val = R.Get<Recipe>(gui, "m_craftRecipe"); ItemData val2 = R.Get<ItemData>(gui, "m_craftUpgradeItem"); int num = ((val2 == null) ? 1 : (val2.m_quality + 1)); int num2 = ((!R.Get<bool>(gui, "m_multiCrafting")) ? 1 : gui.m_multiCraftAmount); if (offer != null) { OfferWindow offerWindow = window; if (offerWindow != null && offerWindow.Claimed) { if (!Ready() || (Object)(object)offer.Gui != (Object)(object)gui || (Object)(object)offer.Player != (Object)(object)player || (Object)(object)offer.Recipe != (Object)(object)val || offer.Upgrade != val2 || offer.Op.Quality != num || offer.Op.Multiplier != num2 || !window.Consume(Time.unscaledTime)) { Actions.Pending pending = offer; Retire(); lostClaim = null; Actions.RecoverCraft(pending); return false; } Actions.Pending pending2 = offer; offer = null; window = null; pending2.Prepared = true; pending2.Started = Time.unscaledTime; pending2.LastPoll = pending2.Started; pending2.Recovery = new RecoveryAttempt(pending2.Started); pending2.Recovery.Sent(); Actions.Waiting = pending2; Send(delegate { Transport.Instance.UseQuote(pending2.Op.Id); }); return false; } } Actions.Pending pending3 = lostClaim; lostClaim = null; if (pending3 != null && (Object)(object)pending3.Gui == (Object)(object)gui && (Object)(object)pending3.Player == (Object)(object)player && (Object)(object)pending3.Recipe == (Object)(object)val && pending3.Upgrade == val2) { Actions.RecoverCraft(pending3); return false; } return Personal(player, val, num, num2); } } internal static class HoverInfo { private static readonly IncrementalCount<Container> count = new IncrementalCount<Container>(); private static readonly DisplayAccessCache access = new DisplayAccessCache(); private static readonly Func<Container, bool> include = Include; private static readonly Func<bool> expired = Expired; private static NetworkMember target; private static Core core; private static Player player; private static long actor; private static long started; private static int requestedFrame; private static int revision; private static float nextCount; private static float nextText; private static bool local; private static string text; internal static string Text(NetworkMember node) { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)node) || !node.Valid || !Object.op_Implicit((Object)(object)localPlayer)) { return Localization.instance.Localize((node is Relay) ? "$rsn_relay_name" : "$rsn_name"); } long playerID = localPlayer.GetPlayerID(); if ((Object)(object)target != (Object)(object)node || (Object)(object)player != (Object)(object)localPlayer || actor != playerID) { Clear(); target = node; player = localPlayer; actor = playerID; local = node is Relay; revision = Topology.DisplayRevision; Render(); } requestedFrame = Time.frameCount; return text; } internal static void Clear() { target = null; core = null; player = null; count.Reset(); access.Clear(); text = null; nextCount = (nextText = 0f); } internal static void Tick() { if (!Object.op_Implicit((Object)(object)target) || !target.Valid || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || requestedFrame < Time.frameCount - 1) { Clear(); return; } try { float unscaledTime = Time.unscaledTime; NetworkGraph networkGraph = Topology.ForActor(actor); object obj; if (!networkGraph.Nodes.TryGetValue(target.Id, out var value) || !networkGraph.Roots.TryGetValue(value.Network, out var value2)) { obj = null; } else { NetworkMember networkMember = Topology.Member(value2); obj = ((networkMember != null) ? ((Component)networkMember).GetComponent<Core>() : null); } Core core = (Core)obj; if ((Object)(object)HoverInfo.core != (Object)(object)core || revision != Topology.DisplayRevision) { HoverInfo.core = core; revision = Topology.DisplayRevision; count.Reset(); nextCount = (nextText = 0f); } if (!count.Running && unscaledTime >= nextCount) { count.Begin((Object.op_Implicit((Object)(object)HoverInfo.core) && HoverInfo.core.Valid) ? HoverInfo.core.Pool.ToArray() : Array.Empty<Container>()); } if (count.Running) { access.Clear(); started = Stopwatch.GetTimestamp(); count.Step(include, 32, expired); if (!count.Running) { nextCount = unscaledTime + 1f; nextText = 0f; } } if (unscaledTime >= nextText) { Render(); } } catch (Exception e) { count.Rese