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 Forge Pipes v1.1.4
plugins/ForgePipes.dll
Decompiled a week 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.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("Forge Pipes")] [assembly: AssemblyFileVersion("1.1.4.0")] [assembly: AssemblyInformationalVersion("1.1.4")] [assembly: AssemblyDescription("Forge Pipes for Valheim")] [assembly: AssemblyVersion("1.1.4.0")] namespace ForgePipes; internal static class AutomationScheduler { private static readonly List<Component> work = new List<Component>(); private static int cursor; private static float nextCycle; private static float nextMaintenance; private static ZNetScene scene; internal static void Tick() { //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Expected O, but got Unknown //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Expected O, but got Unknown if ((Object)(object)scene != (Object)(object)ZNetScene.instance) { scene = ZNetScene.instance; work.Clear(); cursor = 0; nextCycle = (nextMaintenance = 0f); InventoryWake.Clear(); Routing.Reset(); } long timestamp = Stopwatch.GetTimestamp(); try { if (Time.time >= nextMaintenance) { nextMaintenance = Time.time + 5f; Plugin.Chests.RemoveWhere((Container c) => !Object.op_Implicit((Object)(object)c)); Plugin.Machines.RemoveWhere((Smelter s) => !Object.op_Implicit((Object)(object)s)); Stations.All.RemoveWhere((Component s) => !Object.op_Implicit((Object)(object)s)); Pieces.AttachHammer(); PortFactory.EnsureAll(); InventoryWake.Prune(); } if (Plugin.RunConnectionChecks.Value && Routing.Dirty) { long timestamp2 = Stopwatch.GetTimestamp(); Routing.Rebuild(); PerformanceStats.Section("graph", timestamp2); } if (!Plugin.RunAutomation.Value) { return; } if (cursor >= work.Count) { if (Time.time < nextCycle) { return; } nextCycle = Time.time + 1f; work.Clear(); cursor = 0; foreach (Smelter machine in Plugin.Machines) { if (Object.op_Implicit((Object)(object)machine)) { work.Add((Component)(object)machine); } } foreach (Container chest in Plugin.Chests) { if (Object.op_Implicit((Object)(object)chest)) { work.Add((Component)(object)chest); } } foreach (Component item in Stations.All) { if (Object.op_Implicit((Object)(object)item) && !(item is Smelter)) { work.Add(item); } } if (Plugin.CollectLooseItems.Value) { work.Add(null); } } int num = 0; double num2 = Math.Max(0.25, Math.Min(8f, Plugin.WorkBudgetMs.Value)); while (cursor < work.Count && num++ < 8 && (num <= 1 || !((double)(Stopwatch.GetTimestamp() - timestamp) * 1000.0 / (double)Stopwatch.Frequency >= num2))) { Component val = work[cursor++]; long timestamp3 = Stopwatch.GetTimestamp(); try { if (object.ReferenceEquals(val, null)) { LoosePickup.Tick(); PerformanceStats.Section("pickup", timestamp3); } else if (val is Smelter) { Smelter val2 = (Smelter)val; if (Object.op_Implicit((Object)(object)val2) && Automation.Supported(val2)) { MachineHandoff.Prepare((Component)(object)val2); Automation.Feed(val2); } PerformanceStats.Section("smelters", timestamp3); } else if (val is Container) { ChestTransfers.Tick((Container)val); PerformanceStats.Section("chests", timestamp3); } else if (Object.op_Implicit((Object)(object)val)) { Stations.Tick(val); PerformanceStats.Section("stations", timestamp3); } } catch (Exception ex) { Plugin.Error("Automation job failed: " + ex); } } } finally { PerformanceStats.Tick(timestamp); } } } public struct PipeRun { public int Node; public Point A; public Point B; public PipeRun(int node, Point a, Point b) { Node = node; A = a; B = b; } } public static class BodyConnections { private static Point Sub(Point a, Point b) { return new Point(a.X - b.X, a.Y - b.Y, a.Z - b.Z); } private static Point At(Point a, Point delta, float t) { return new Point(a.X + delta.X * t, a.Y + delta.Y * t, a.Z + delta.Z * t); } private static float Clamp(float v) { return Math.Max(0f, Math.Min(1f, v)); } public static float DistanceSquared(PipeRun one, PipeRun two) { Point point = Sub(one.B, one.A); Point point2 = Sub(two.B, two.A); Point b = Sub(one.A, two.A); float num = Point.Dot(point, point); float num2 = Point.Dot(point, point2); float num3 = Point.Dot(point2, point2); float num4 = Point.Dot(point, b); float num5 = Point.Dot(point2, b); if (num < 1E-10f && num3 < 1E-10f) { return Point.DistanceSquared(one.A, two.A); } float num6 = ((num < 1E-10f) ? 0f : ((num3 < 1E-10f) ? Clamp((0f - num4) / num) : ((num * num3 - num2 * num2 > 1E-10f) ? Clamp((num2 * num5 - num3 * num4) / (num * num3 - num2 * num2)) : 0f))); float num7 = ((num3 < 1E-10f) ? 0f : ((num2 * num6 + num5) / num3)); if (num7 < 0f) { num7 = 0f; num6 = ((num < 1E-10f) ? 0f : Clamp((0f - num4) / num)); } else if (num7 > 1f) { num7 = 1f; num6 = ((num < 1E-10f) ? 0f : Clamp((num2 - num4) / num)); } return Point.DistanceSquared(At(one.A, point, num6), At(two.A, point2, num7)); } public static void Connect(NetworkGraph graph, IEnumerable<PipeRun> runs) { Dictionary<NetworkGraph.Cell, List<PipeRun>> dictionary = new Dictionary<NetworkGraph.Cell, List<PipeRun>>(); foreach (PipeRun run in runs) { Point point = Sub(run.B, run.A); int num = Math.Max(1, (int)Math.Ceiling(Math.Sqrt(Point.Dot(point, point)) / 0.4)); for (int i = 0; i < num; i++) { PipeRun pipeRun = new PipeRun(run.Node, At(run.A, point, (float)i / (float)num), At(run.A, point, (float)(i + 1) / (float)num)); Point point2 = At(pipeRun.A, Sub(pipeRun.B, pipeRun.A), 0.5f); NetworkGraph.Cell key = new NetworkGraph.Cell { X = (int)Math.Floor(point2.X / 0.5f), Y = (int)Math.Floor(point2.Y / 0.5f), Z = (int)Math.Floor(point2.Z / 0.5f) }; for (int j = -1; j <= 1; j++) { for (int k = -1; k <= 1; k++) { for (int l = -1; l <= 1; l++) { if (!dictionary.TryGetValue(new NetworkGraph.Cell { X = key.X + j, Y = key.Y + k, Z = key.Z + l }, out var value)) { continue; } foreach (PipeRun item in value) { if (item.Node != pipeRun.Node && !graph.Connected(item.Node, pipeRun.Node) && DistanceSquared(item, pipeRun) <= 0.0064f) { graph.Join(item.Node, pipeRun.Node); } } } } } if (!dictionary.TryGetValue(key, out var value2)) { value2 = new List<PipeRun>(); dictionary.Add(key, value2); } value2.Add(pipeRun); } } } } [HarmonyPatch(typeof(PieceTable), "UpdateAvailable")] internal static class BuildMenuPatch { private static readonly MethodInfo AddKnown = AccessTools.Method(typeof(Player), "AddKnownPiece", (Type[])null, (Type[])null); private static Player lastPlayer; private static string lastReport; private static bool IsHammer(PieceTable table) { if (Object.op_Implicit((Object)(object)ObjectDB.instance)) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer"); if (Object.op_Implicit((Object)(object)itemPrefab) && (Object)(object)itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces == (Object)(object)table) { return true; } } return table.m_pieces.Any((GameObject p) => Object.op_Implicit((Object)(object)p) && Native.Name(p) == "wood_beam"); } private static void Prefix(PieceTable __instance, HashSet<string> __0, Player __1) { if (!Object.op_Implicit((Object)(object)__1) || (Object)(object)__1 != (Object)(object)Player.m_localPlayer || !IsHammer(__instance)) { return; } GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab("Copper") : null); ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null); bool flag = Object.op_Implicit((Object)(object)val2) && __1.IsKnownMaterial(val2.m_itemData.m_shared.m_name); int num = 0; foreach (GameObject prefab in Plugin.Prefabs) { if (!__instance.m_pieces.Contains(prefab)) { __instance.m_pieces.Add(prefab); } Piece component = prefab.GetComponent<Piece>(); if (!flag) { __0.Remove(component.m_name); continue; } if (!__0.Contains(component.m_name) && __1.HaveRequirements(component, (RequirementMode)1)) { if (Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)Hud.instance.m_buildUi) && Object.op_Implicit((Object)(object)MessageHud.instance)) { AddKnown.Invoke(__1, new object[1] { component }); } else { __0.Add(component.m_name); } } if (__0.Contains(component.m_name)) { num++; } } string text = "Hammer registration: " + Plugin.Prefabs.Count + " pipes; " + num + " recipes unlocked. Find them under Crafting / Transport or search 'Forge pipe'."; if (num < Plugin.Prefabs.Count) { text += " Discover Wood, a Copper ingot, and a workbench to unlock the recipes."; } if ((Object)(object)lastPlayer != (Object)(object)__1 || lastReport != text) { Plugin.LogInfo(text); lastPlayer = __1; lastReport = text; } } } public enum ChestFlow { Both, SendOnly, ReceiveOnly } public static class ChestFlowRules { public static ChestFlow Read(int value) { if (value < 0 || value > 2) { return ChestFlow.Both; } return (ChestFlow)value; } public static ChestFlow Next(ChestFlow mode) { return (ChestFlow)((int)(mode + 1) % 3); } public static bool Sends(ChestFlow mode) { return mode != ChestFlow.ReceiveOnly; } public static bool Receives(ChestFlow mode) { return mode != ChestFlow.SendOnly; } public static bool Transfer(ChestFlow source, ChestFlow destination) { if (source != ChestFlow.SendOnly || !Receives(destination)) { if (source == ChestFlow.Both) { return destination == ChestFlow.ReceiveOnly; } return false; } return true; } public static string Label(ChestFlow mode) { return mode switch { ChestFlow.ReceiveOnly => "Receive only (input)", ChestFlow.SendOnly => "Send only (output)", _ => "Both (input + output)", }; } } public sealed class ChestPreviewVisibility : MonoBehaviour { private LODGroup[] lods; private void Awake() { lods = ((Component)this).GetComponentsInChildren<LODGroup>(true); Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!(val is LineRenderer)) { val.allowOcclusionWhenDynamic = false; } } Refresh(); } private void LateUpdate() { Refresh(); } private void Refresh() { if (lods == null) { return; } LODGroup[] array = lods; foreach (LODGroup val in array) { if (Object.op_Implicit((Object)(object)val)) { val.RecalculateBounds(); val.ForceLOD(0); } } } } internal static class ChestSettings { private const string ModeKey = "FP_chest_mode_v1"; private static readonly FieldInfo Areas = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly MethodInfo Enabled = AccessTools.Method(typeof(PrivateArea), "IsEnabled", (Type[])null, (Type[])null); private static readonly MethodInfo Inside = AccessTools.Method(typeof(PrivateArea), "IsInside", (Type[])null, (Type[])null); private static readonly MethodInfo Permitted = AccessTools.Method(typeof(PrivateArea), "IsPermitted", (Type[])null, (Type[])null); internal static ChestFlow Mode(Container chest) { if (!Hopper.Is(chest)) { if (!Native.Valid((Component)(object)chest)) { return ChestFlow.Both; } return ChestFlowRules.Read(Native.View((Component)(object)chest).GetZDO().GetInt("FP_chest_mode_v1", 0)); } return ChestFlow.SendOnly; } internal static void SetFromPeer(Container chest, long sender, ZDOID playerId, int value) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) if (Hopper.Is(chest) || !Native.Owner((Component)(object)chest) || !ChestHandoff.Eligible(chest) || ChestHandoff.Busy(chest) || value < 0 || value > 2) { return; } GameObject val = ZNetScene.instance.FindInstance(playerId); Player val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Player>() : null); if (!Object.op_Implicit((Object)(object)val2) || !Native.Valid((Component)(object)val2) || Native.View((Component)(object)val2).GetZDO().GetOwner() != sender || Vector3.Distance(((Component)val2).transform.position, ((Component)chest).transform.position) > val2.m_maxInteractDistance + 1f) { return; } long playerID = val2.GetPlayerID(); foreach (PrivateArea item in (List<PrivateArea>)Areas.GetValue(null)) { if (Object.op_Implicit((Object)(object)item) && (bool)Enabled.Invoke(item, null) && (bool)Inside.Invoke(item, new object[2] { ((Component)chest).transform.position, 0f })) { Piece component = ((Component)item).GetComponent<Piece>(); if ((!Object.op_Implicit((Object)(object)component) || component.GetCreator() != playerID) && !(bool)Permitted.Invoke(item, new object[1] { playerID })) { return; } } } Native.View((Component)(object)chest).GetZDO().Set("FP_chest_mode_v1", value); Routing.Dirty = true; } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ChestModeHoverPatch { private static void Postfix(Container __instance, ref string __result) { if (!Hopper.Is(__instance) && ChestHandoff.Eligible(__instance) && ChestHandoff.Access((Component)(object)__instance)) { __result = __result + "\n<color=#dca06b>Forge Pipes: " + PipeLanguage.Text(ChestFlowRules.Label(ChestSettings.Mode(__instance))) + "</color>"; __result = __result + Localization.instance.Localize("\n[<color=yellow>$KEY_AltPlace + $KEY_Use</color>] ") + PipeLanguage.Text("Change pipe mode"); } } } [HarmonyPatch(typeof(Container), "Interact")] internal static class ChestModeInteractPatch { private static bool Prefix(Container __instance, Humanoid __0, bool __1, bool __2, ref bool __result) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (Hopper.Is(__instance) || !__2 || (Object)(object)__0 != (Object)(object)Player.m_localPlayer || !ChestHandoff.Eligible(__instance)) { return true; } __result = true; if (__1) { return false; } if (!ChestHandoff.Access((Component)(object)__instance)) { return false; } if (ChestHandoff.Busy(__instance)) { ((Character)__0).Message((MessageType)2, PipeLanguage.Text("Close the chest before changing its pipe mode."), 0, (Sprite)null, false); return false; } ChestFlow chestFlow = ChestFlowRules.Next(ChestSettings.Mode(__instance)); Native.View((Component)(object)__instance).InvokeRPC("FP_ChestMode", new object[2] { Native.View((Component)(object)__0).GetZDO().m_uid, (int)chestFlow }); ((Character)__0).Message((MessageType)2, PipeLanguage.Text("Requested pipe mode: ") + PipeLanguage.Text(ChestFlowRules.Label(chestFlow)), 0, (Sprite)null, false); return false; } } internal static class ChestTransfers { internal static void Tick(Container source) { if (!ChestHandoff.Eligible(source) || !Native.Owner((Component)(object)source)) { return; } List<Container> list = Routing.ConnectedChests(source); if (!InventoryWake.ShouldRun(source, list)) { return; } if (OpenChestAccess.Viewing(source)) { foreach (Container item in list) { if (OpenChestRules.MayPull(Native.Owner((Component)(object)source), targetViewed: true, ChestHandoff.Busy(item)) && ChestFlowRules.Transfer(ChestSettings.Mode(item), ChestSettings.Mode(source))) { ChestHandoff component = ((Component)item).GetComponent<ChestHandoff>(); if (Object.op_Implicit((Object)(object)component)) { component.Ready((Component)(object)source); } } } } if (!ChestFlowRules.Sends(ChestSettings.Mode(source))) { return; } ChestHandoff component2 = ((Component)source).GetComponent<ChestHandoff>(); if (!Object.op_Implicit((Object)(object)component2) || !component2.Ready((Component)(object)source)) { return; } int num = 10; try { foreach (Container item2 in list) { if (!ChestFlowRules.Transfer(ChestSettings.Mode(source), ChestSettings.Mode(item2))) { continue; } ChestHandoff component3 = ((Component)item2).GetComponent<ChestHandoff>(); if (!Object.op_Implicit((Object)(object)component3) || !component3.Ready((Component)(object)source)) { continue; } Inventory inventory = source.GetInventory(); Inventory inventory2 = item2.GetInventory(); ItemData[] array = inventory.GetAllItems().ToArray(); foreach (ItemData val in array) { if (OpenChestAccess.Reserved(inventory, val) || !Hopper.Allows(source, item2, val)) { continue; } while (num > 0 && inventory.ContainsItem(val) && StockReserve.Available(inventory, val) > 0 && OpenChestAccess.CanEdit(source) && OpenChestAccess.CanEdit(item2) && ChestFlowRules.Transfer(ChestSettings.Mode(source), ChestSettings.Mode(item2))) { bool flag = false; for (int j = 0; j < inventory2.GetHeight(); j++) { if (flag) { break; } for (int k = 0; k < inventory2.GetWidth(); k++) { if (flag) { break; } ItemData itemAt = inventory2.GetItemAt(k, j); if (itemAt == null || !OpenChestAccess.Reserved(inventory2, itemAt)) { int stack = val.m_stack; inventory2.MoveItemToThis(inventory, val, 1, k, j); flag = val.m_stack < stack; } } } if (!flag) { break; } num--; } if (num == 0) { break; } } if (num == 0) { break; } } } finally { InventoryWake.Completed(source, list, num < 10); } } } internal static class CookingCredit { internal sealed class Snapshot { internal Container Source; internal Inventory From; internal Inventory To; internal Dictionary<string, int> Before; internal Dictionary<string, int> Destination; internal bool Completed; } private static readonly Dictionary<Inventory, Container> containers = new Dictionary<Inventory, Container>(); private static readonly Dictionary<Inventory, Dictionary<string, int>> observed = new Dictionary<Inventory, Dictionary<string, int>>(); private static readonly HashSet<Inventory> credited = new HashSet<Inventory>(); internal static int Moving; internal static void Clear() { containers.Clear(); observed.Clear(); credited.Clear(); Moving = 0; } internal static void Register(Container c) { if (Object.op_Implicit((Object)(object)c) && c.GetInventory() != null) { containers[c.GetInventory()] = c; Refresh(c); } } internal static void Forget(Container c) { if (Object.op_Implicit((Object)(object)c) && c.GetInventory() != null) { containers.Remove(c.GetInventory()); observed.Remove(c.GetInventory()); credited.Remove(c.GetInventory()); } } internal static void Refresh(Container c) { if (Object.op_Implicit((Object)(object)c) && Native.Owner((Component)(object)c) && Native.View((Component)(object)c).GetZDO().GetBool("FP_has_cook_credit", false)) { credited.Add(c.GetInventory()); observed[c.GetInventory()] = Counts(c.GetInventory()); } } internal static void Observe(Inventory inventory) { if (Moving > 0 || inventory == null || !credited.Contains(inventory)) { return; } Container val = Find(inventory); if (Object.op_Implicit((Object)(object)val) && Native.Owner((Component)(object)val)) { if (observed.TryGetValue(inventory, out var value)) { Snapshot snapshot = new Snapshot(); snapshot.Source = val; snapshot.From = inventory; snapshot.Before = value; Finish(snapshot); } else { Refresh(val); } } } private static string Identity(ItemData i) { return (Object.op_Implicit((Object)(object)i.m_dropPrefab) ? ((Object)i.m_dropPrefab).name : i.m_shared.m_name) + ":" + i.m_quality + ":" + i.m_worldLevel; } private static Dictionary<string, int> Counts(Inventory inv) { return inv.GetAllItems().GroupBy(Identity).ToDictionary((IGrouping<string, ItemData> g) => g.Key, (IGrouping<string, ItemData> g) => g.Sum((ItemData i) => i.m_stack)); } private static int Count(Dictionary<string, int> counts, string key) { if (!counts.TryGetValue(key, out var value)) { return 0; } return value; } private static Container Find(Inventory inv) { if (inv == null || !containers.TryGetValue(inv, out var value) || !Object.op_Implicit((Object)(object)value)) { return null; } return value; } internal static void Add(Container c, ItemData item, int amount, SkillType skill) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected I4, but got Unknown if ((int)skill != 0 && amount > 0 && Native.Owner((Component)(object)c) && !(((int)skill == -1) ? (!Plugin.HoneyAchievement.Value) : (!Plugin.CookingCollectionXP.Value))) { Register(c); Add(c, Identity(item), amount, (int)skill); } } private static void Add(Container c, string id, int amount, int skill) { ZDO zDO = Native.View((Component)(object)c).GetZDO(); string text = "FP_cook_credit_" + id; zDO.Set(text, Math.Max(0, zDO.GetInt(text, 0)) + amount); zDO.Set(text + "_skill", skill); zDO.Set("FP_has_cook_credit", true); credited.Add(c.GetInventory()); Refresh(c); } internal static Snapshot Capture(Inventory from, Inventory to = null) { Container val = Find(from); if (!Object.op_Implicit((Object)(object)val) || !Native.Owner((Component)(object)val) || !Native.View((Component)(object)val).GetZDO().GetBool("FP_has_cook_credit", false)) { return null; } Snapshot snapshot = new Snapshot(); snapshot.Source = val; snapshot.From = from; snapshot.To = to; snapshot.Before = Counts(from); snapshot.Destination = ((to == null) ? null : Counts(to)); return snapshot; } internal static void Finish(Snapshot state) { if (state == null || state.Completed || !Object.op_Implicit((Object)(object)state.Source) || !Native.Owner((Component)(object)state.Source)) { return; } state.Completed = true; Dictionary<string, int> dictionary = Counts(state.From); Dictionary<string, int> dictionary2 = ((state.To == null) ? null : Counts(state.To)); Container val = Find(state.To); Player localPlayer = Player.m_localPlayer; bool flag = Object.op_Implicit((Object)(object)localPlayer) && state.To == ((Humanoid)localPlayer).GetInventory() && OpenChestAccess.Viewing(state.Source) && ChestHandoff.Access((Component)(object)state.Source); ZDO z = Native.View((Component)(object)state.Source).GetZDO(); foreach (KeyValuePair<string, int> item in state.Before) { int num = Math.Max(0, item.Value - Count(dictionary, item.Key)); if (num == 0) { continue; } string text = "FP_cook_credit_" + item.Key; int num2 = Math.Min(item.Value, Math.Max(0, z.GetInt(text, 0))); int num3 = Math.Min(num, num2); if (num3 == 0) { continue; } int num4 = z.GetInt(text + "_skill", 0); z.Set(text, num2 - num3); int num5 = ((dictionary2 != null) ? Math.Min(num3, Math.Max(0, Count(dictionary2, item.Key) - Count(state.Destination, item.Key))) : 0); if (num5 == 0 || num4 == 0) { continue; } if (flag) { if (num4 == -1) { if (Plugin.HoneyAchievement.Value && Object.op_Implicit((Object)(object)Game.instance)) { Game.instance.IncrementPlayerStat((PlayerStatType)76, (float)num5, false); } } else if (Plugin.CookingCollectionXP.Value) { for (int i = 0; i < num5; i++) { ((Character)localPlayer).RaiseSkill((SkillType)num4, 0.6f); } } } else if (Object.op_Implicit((Object)(object)val) && Native.Owner((Component)(object)val)) { Add(val, item.Key, num5, num4); } } bool flag2 = dictionary.Any((KeyValuePair<string, int> entry) => entry.Value > 0 && z.GetInt("FP_cook_credit_" + entry.Key, 0) > 0); z.Set("FP_has_cook_credit", flag2); if (flag2) { Refresh(state.Source); } else { credited.Remove(state.Source.GetInventory()); observed.Remove(state.Source.GetInventory()); } if (Object.op_Implicit((Object)(object)val)) { Refresh(val); } } } [HarmonyPatch(typeof(Inventory), "Changed")] internal static class CookingCreditChangedPatch { private static void Postfix(Inventory __instance) { CookingCredit.Observe(__instance); } } [HarmonyPatch(typeof(Container), "Load")] internal static class CookingCreditLoadPatch { private static void Prefix() { CookingCredit.Moving++; } private static void Finalizer(Container __instance) { try { CookingCredit.Refresh(__instance); } finally { CookingCredit.Moving = Math.Max(0, CookingCredit.Moving - 1); } } } [HarmonyPatch] internal static class CookingCreditMovePatch { private static IEnumerable<MethodBase> TargetMethods() { return (from m in typeof(Inventory).GetMethods() where m.Name == "MoveItemToThis" || m.Name == "MoveAll" || m.Name == "StackAll" select m).Cast<MethodBase>(); } private static void Prefix(Inventory __instance, Inventory __0, out CookingCredit.Snapshot __state) { __state = ((CookingCredit.Moving++ == 0) ? CookingCredit.Capture(__0, __instance) : null); } private static void Finalizer(CookingCredit.Snapshot __state) { try { CookingCredit.Finish(__state); } finally { CookingCredit.Moving = Math.Max(0, CookingCredit.Moving - 1); } } } [HarmonyPatch] internal static class CookingCreditRemovePatch { private static IEnumerable<MethodBase> TargetMethods() { return (from m in typeof(Inventory).GetMethods() where m.Name == "RemoveItem" || m.Name == "RemoveOneItem" || m.Name == "RemoveAll" select m).Cast<MethodBase>(); } private static void Prefix(Inventory __instance, out CookingCredit.Snapshot __state) { __state = ((CookingCredit.Moving++ == 0) ? CookingCredit.Capture(__instance) : null); } private static void Finalizer(CookingCredit.Snapshot __state) { try { CookingCredit.Finish(__state); } finally { CookingCredit.Moving = Math.Max(0, CookingCredit.Moving - 1); } } } public static class CopperGrain { public const int Size = 256; private static int Wrap(int n, int size) { return (n % size + size) % size; } private static float Noise(int x, int y, int size) { uint num = (uint)(Wrap(x, size) * 374761393 + Wrap(y, size) * 668265263 + 9021); num = (num ^ (num >> 13)) * 1274126177; num ^= num >> 16; return (float)(num & 0xFFFF) / 65535f; } private static float Broad(int x, int y, int cell) { x = Wrap(x, 256); y = Wrap(y, 256); int num = x / cell; int num2 = y / cell; float num3 = (float)(x % cell) / (float)cell; float num4 = (float)(y % cell) / (float)cell; num3 = num3 * num3 * (3f - 2f * num3); num4 = num4 * num4 * (3f - 2f * num4); float num5 = Noise(num, num2, 256 / cell) * (1f - num3) + Noise(num + 1, num2, 256 / cell) * num3; float num6 = Noise(num, num2 + 1, 256 / cell) * (1f - num3) + Noise(num + 1, num2 + 1, 256 / cell) * num3; return num5 * (1f - num4) + num6 * num4; } public static float Height(int x, int y) { return 0.4f * Noise(x, y, 256) + 0.36f * Broad(x, y, 4) + 0.24f * Broad(x, y, 32); } public static float Tone(int x, int y) { return 0.63f + 0.43f * Height(x, y) + 0.12f * Broad(x, y, 32); } } internal static class CopperMaterial { internal const int AtlasTileSize = 256; internal const int AtlasTiles = 4; internal const int AtlasGutter = 32; private const int AtlasMipCount = 6; private static Material copper; private static Material collar; private static Material pipe; internal static Material Get(Material fallback, bool isCollar) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)copper)) { copper = Create(atlas: false); collar = new Material(copper); ((Object)collar).name = "ForgePipes dark copper collars"; collar.color = new Color(0.87f, 0.83f, 0.78f); } if (!isCollar) { return copper; } return collar; } internal static Material GetPipe() { if (!Object.op_Implicit((Object)(object)pipe)) { return pipe = Create(atlas: true); } return pipe; } internal static float AtlasU(float u, int surface) { int num = Mathf.Clamp(surface, 0, 2); float num2 = 191f; return ((float)(num * 256 + 32) + 0.5f + Mathf.Clamp01(u) * num2) / 1024f; } private static Material Create(bool atlas) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Standard") ?? Shader.Find("Legacy Shaders/Diffuse") ?? Shader.Find("Unlit/Texture"); if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("No non-deforming copper shader is available."); } Material val2 = new Material(val); ((Object)val2).name = (atlas ? "ForgePipes shared copper atlas" : "ForgePipes rough copper"); val2.color = Color.white; bool value = Plugin.MatteCopper.Value; bool flag = !value && val2.HasProperty("_BumpMap"); bool flag2 = !value && val2.HasProperty("_MetallicGlossMap"); int num = 256; int num2 = (atlas ? 1024 : num); Color[] array = (Color[])(object)new Color[num2 * num]; Color[] array2 = (Color[])(object)(flag ? new Color[array.Length] : null); Color[] array3 = (Color[])(object)(flag2 ? new Color[array.Length] : null); for (int i = 0; i < num; i++) { for (int j = 0; j < num2; j++) { int num3 = i * num2 + j; int num4 = (atlas ? (j / 256) : 0); int num5 = (atlas ? ((int)Mathf.Floor((float)(j % 256 - 32) * 256f / 191f)) : j); float num6 = CopperGrain.Tone(num5, i); Color val3 = (Color)(num4 switch { 2 => new Color(0.22f, 0.2f, 0.18f), 1 => new Color(0.76f, 0.72f, 0.68f), _ => Color.white, }); ref Color reference = ref array[num3]; reference = new Color(0.78f * num6 * val3.r, 0.405f * num6 * val3.g, 0.225f * num6 * val3.b, 1f); if (array2 != null) { float num7 = (CopperGrain.Height(num5 - 1, i) - CopperGrain.Height(num5 + 1, i)) * 0.7f; float num8 = (CopperGrain.Height(num5, i - 1) - CopperGrain.Height(num5, i + 1)) * 0.7f; Vector3 val4 = new Vector3(num7, num8, 1f); Vector3 normalized = ((Vector3)(ref val4)).normalized; ref Color reference2 = ref array2[num3]; reference2 = new Color(1f, normalized.y * 0.5f + 0.5f, 1f, normalized.x * 0.5f + 0.5f); } if (array3 != null) { ref Color reference3 = ref array3[num3]; reference3 = new Color((num4 == 2) ? 0.1f : 0.55f, 0f, 0f, 0.18f + CopperGrain.Height(num5, i) * 0.18f); } } } val2.mainTexture = (Texture)(object)Texture(num2, num, linear: false, atlas, array, "grainy copper albedo"); if (array2 != null) { val2.SetTexture("_BumpMap", (Texture)(object)Texture(num2, num, linear: true, atlas, array2, "copper grain normals")); val2.SetFloat("_BumpScale", 0.65f); val2.EnableKeyword("_NORMALMAP"); } if (array3 != null) { val2.SetTexture("_MetallicGlossMap", (Texture)(object)Texture(num2, num, linear: true, atlas, array3, "copper roughness")); val2.EnableKeyword("_METALLICGLOSSMAP"); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", value ? 0f : 0.55f); } if (val2.HasProperty("_Glossiness")) { val2.SetFloat("_Glossiness", value ? 0.08f : 0.26f); } val2.enableInstancing = true; return val2; } private static Texture2D Texture(int width, int height, bool linear, bool atlas, Color[] pixels, string name) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Texture2D val = new Texture2D(width, height, (TextureFormat)4, atlas ? 6 : (-1), linear); Finish(val, pixels, name + (atlas ? " atlas" : "")); if (atlas) { ((Texture)val).wrapModeU = (TextureWrapMode)1; } return val; } private static void Finish(Texture2D texture, Color[] pixels, string name) { ((Object)texture).name = name; ((Texture)texture).wrapMode = (TextureWrapMode)0; ((Texture)texture).filterMode = (FilterMode)2; ((Texture)texture).anisoLevel = 4; texture.SetPixels(pixels); texture.Apply(true, true); } } internal static class CraftingInterop { internal static bool CanYield(Container chest) { MonoBehaviour val = null; MonoBehaviour[] components = ((Component)chest).GetComponents<MonoBehaviour>(); foreach (MonoBehaviour val2 in components) { if (Object.op_Implicit((Object)(object)val2) && ((object)val2).GetType().FullName == "ForgeChestCrafting.CraftChestLease") { val = val2; break; } } if (!Object.op_Implicit((Object)(object)val)) { return true; } MethodInfo methodInfo = AccessTools.Method(((object)val).GetType(), "CanYieldToPipes", (Type[])null, (Type[])null); if (methodInfo == null) { return true; } try { return (bool)methodInfo.Invoke(val, null); } catch (Exception ex) { Plugin.Error("Crafting lease check failed: " + ex); return false; } } } internal static class EitrDamageRules { internal static bool IsSpark(bool hasAttacker, DamageTypes damage) { if (!hasAttacker && damage.m_lightning > 0f && damage.m_poison > 0f && damage.m_damage <= 0f && damage.m_blunt <= 0f && damage.m_slash <= 0f && damage.m_pierce <= 0f && damage.m_chop <= 0f && damage.m_pickaxe <= 0f && damage.m_fire <= 0f && damage.m_frost <= 0f && damage.m_spirit <= 0f) { return damage.m_nonPlayer <= 0f; } return false; } } internal static class EitrProtection { internal static bool Protected(WearNTear wear) { if (!Native.Owner((Component)(object)wear)) { return false; } if (Object.op_Implicit((Object)(object)((Component)wear).GetComponent<PipeNode>())) { return true; } Container componentInChildren = ((Component)wear).GetComponentInChildren<Container>(); if (!ChestHandoff.Eligible(componentInChildren)) { return false; } if (!Routing.Dirty) { return Routing.HasChestAnchor(componentInChildren); } return PipeStructure.Anchored(wear); } } [HarmonyPatch(typeof(WearNTear), "RPC_Damage")] internal static class PipeEitrProtectionPatch { private static bool Prefix(WearNTear __instance, HitData __1) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (__1 != null && EitrDamageRules.IsSpark(__1.HaveAttacker(), __1.m_damage)) { return !EitrProtection.Protected(__instance); } return true; } } public sealed class Hopper : MonoBehaviour { public bool HasLegacyBounds; public Vector3 LegacyCenter; public Vector3 LegacySize; private static readonly HashSet<Inventory> inventories = new HashSet<Inventory>(); private void Awake() { RegisterInventory(((Component)this).GetComponent<Container>()); } internal static void RegisterInventory(Container c) { if (Is(c) && c.GetInventory() != null) { inventories.Add(c.GetInventory()); } } private void OnDestroy() { Container component = ((Component)this).GetComponent<Container>(); if (Object.op_Implicit((Object)(object)component) && component.GetInventory() != null) { inventories.Remove(component.GetInventory()); } } internal static bool InventoryIsHopper(Inventory inventory) { return inventories.Contains(inventory); } internal static bool Is(Container chest) { if (Object.op_Implicit((Object)(object)chest)) { return Object.op_Implicit((Object)(object)((Component)chest).GetComponent<Hopper>()); } return false; } internal static bool Allows(Container source, Container destination, ItemData item) { if (!Is(source)) { return true; } if (Is(destination) || !Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return false; } return destination.GetInventory().GetAllItems().Any((ItemData i) => Object.op_Implicit((Object)(object)i.m_dropPrefab) && i.m_stack > 0 && SortingRules.Matches(((Object)item.m_dropPrefab).name, item.m_quality, item.m_worldLevel, ((Object)i.m_dropPrefab).name, i.m_quality, i.m_worldLevel)); } private static void CaptureLegacySockets(GameObject go, Container chest) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) List<GameObject> list = new List<GameObject>(); for (int i = 0; i < 4; i++) { GameObject val = new GameObject("legacy_hopper_bounds"); val.transform.SetParent(go.transform, false); Quaternion val2 = Quaternion.Euler(0f, (float)(i * 90), 0f); val.transform.localPosition = Vector3.up * 0.95f + val2 * (Vector3.forward * 0.43f); val.transform.localRotation = val2 * Quaternion.Euler(-25f, 0f, 0f); val.transform.localScale = new Vector3(1.15f, 0.65f, 0.065f); val.AddComponent<BoxCollider>(); list.Add(val); } Hopper component = go.GetComponent<Hopper>(); if (PortFactory.TryChestBounds(chest, preview: true, out var bounds)) { component.HasLegacyBounds = true; component.LegacyCenter = ((Bounds)(ref bounds)).center; component.LegacySize = ((Bounds)(ref bounds)).size; } foreach (GameObject item in list) { Object.DestroyImmediate((Object)(object)item); } } internal static void Register(ZNetScene scene) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown if (!Plugin.Prefabs.Any((GameObject p) => ((Object)p).name == "FP_Hopper")) { GameObject prefab = scene.GetPrefab("piece_chest_wood"); GameObject val = Object.Instantiate<GameObject>(prefab, Plugin.PrefabRoot.transform, false); ((Object)val).name = "FP_Hopper"; val.AddComponent<Hopper>(); Container component = val.GetComponent<Container>(); component.m_name = PipeLanguage.Token("Forge sorting hopper"); Piece component2 = val.GetComponent<Piece>(); component2.m_name = "Forge sorting hopper"; component2.m_icon = PipeIcons.Load("Hopper"); component2.m_description = "Drop items into the hopper or open its inventory. Items move only to connected receiving chests already containing the same item. Unmatched items stay here."; component2.m_category = (PieceCategory)1; component2.m_usage = (UsageTagFlags)2050; component2.m_craftingStation = scene.GetPrefab("piece_workbench").GetComponent<CraftingStation>(); Requirement[] array = (Requirement[])(object)new Requirement[2]; Requirement val2 = new Requirement(); val2.m_resItem = scene.GetPrefab("Wood").GetComponent<ItemDrop>(); val2.m_amount = 10; val2.m_recover = true; array[0] = val2; Requirement val3 = new Requirement(); val3.m_resItem = scene.GetPrefab("Copper").GetComponent<ItemDrop>(); val3.m_amount = 4; val3.m_recover = true; array[1] = val3; component2.m_resources = array; MetalPlacement.Apply(component2, scene); CaptureLegacySockets(val, component); HopperModel.Build(val); Plugin.Prefabs.Add(val); val.SetActive(true); } } } internal static class HopperModel { internal static Mesh Create() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown HopperShape hopperShape = HopperShape.Create(); List<Vector3> list = new List<Vector3>(); List<Vector2> list2 = new List<Vector2>(); foreach (Point vertex in hopperShape.Vertices) { list.Add(new Vector3(vertex.X, vertex.Y, vertex.Z)); } foreach (Point item in hopperShape.UV) { list2.Add(new Vector2(item.X, item.Y)); } Mesh val = new Mesh(); ((Object)val).name = "Forge sorting hopper fitted funnel"; Mesh val2 = val; val2.SetVertices(list); val2.SetUVs(0, list2); val2.SetTriangles(hopperShape.Indices, 0); val2.RecalculateNormals(); val2.RecalculateTangents(); val2.RecalculateBounds(); return val2; } internal static void Build(GameObject go) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0163: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0188: 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_019e: 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_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) LODGroup[] componentsInChildren = go.GetComponentsInChildren<LODGroup>(true); foreach (LODGroup val in componentsInChildren) { Object.DestroyImmediate((Object)(object)val); } Renderer[] componentsInChildren2 = go.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren2) { val2.enabled = false; } GameObject val3 = new GameObject("FP_hopper_funnel"); val3.layer = go.layer; val3.transform.SetParent(go.transform, false); val3.AddComponent<MeshFilter>().sharedMesh = Create(); ((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterial = CopperMaterial.GetPipe(); Collider[] componentsInChildren3 = go.GetComponentsInChildren<Collider>(true); foreach (Collider val4 in componentsInChildren3) { Object.DestroyImmediate((Object)(object)val4); } BoxCollider val5 = val3.AddComponent<BoxCollider>(); val5.center = new Vector3(0f, 0.365f, 0f); val5.size = new Vector3(0.76f, 0.43f, 0.76f); for (int l = 0; l < 4; l++) { GameObject val6 = new GameObject("hopper_wall_collider"); val6.layer = go.layer; val6.transform.SetParent(val3.transform, false); Quaternion val7 = Quaternion.Euler(0f, (float)(l * 90), 0f); val6.transform.localPosition = Vector3.up * 0.88f + val7 * (Vector3.forward * 0.515f); val6.transform.localRotation = val7 * Quaternion.FromToRotation(Vector3.up, new Vector3(0f, 0.6f, 0.27f)); val6.AddComponent<BoxCollider>().size = new Vector3(1.28f, 0.658f, 0.055f); } WearNTear component = go.GetComponent<WearNTear>(); if (Object.op_Implicit((Object)(object)component)) { component.m_new = val3; component.m_worn = val3; component.m_broken = val3; component.m_wet = null; } } } public sealed class HopperShape { public readonly List<Point> Vertices = new List<Point>(); public readonly List<Point> UV = new List<Point>(); public readonly List<int> Indices = new List<int>(); public static HopperShape Create() { HopperShape hopperShape = new HopperShape(); Point[] array = new Point[6] { new Point(0.38f, 0.15f, 0f), new Point(0.38f, 0.58f, 0f), new Point(0.65f, 1.18f, 0f), new Point(0.59f, 1.18f, 0f), new Point(0.32f, 0.59f, 0f), new Point(0.32f, 0.19f, 0f) }; for (int i = 0; i < array.Length - 1; i++) { for (int j = 0; j < 4; j++) { int n = (j + 1) % 4; int count = hopperShape.Vertices.Count; hopperShape.Vertices.Add(Corner(j, array[i])); hopperShape.Vertices.Add(Corner(n, array[i])); hopperShape.Vertices.Add(Corner(n, array[i + 1])); hopperShape.Vertices.Add(Corner(j, array[i + 1])); float num = ((i == 2) ? 0.37f : 0.12f); hopperShape.UV.Add(new Point(num - 0.07f, 0.15f, 0f)); hopperShape.UV.Add(new Point(num + 0.07f, 0.15f, 0f)); hopperShape.UV.Add(new Point(num + 0.07f, 0.85f, 0f)); hopperShape.UV.Add(new Point(num - 0.07f, 0.85f, 0f)); hopperShape.Indices.AddRange(new int[6] { count, count + 2, count + 1, count, count + 3, count + 2 }); } } int count2 = hopperShape.Vertices.Count; for (int k = 0; k < 4; k++) { hopperShape.Vertices.Add(Corner(k, array[5])); hopperShape.UV.Add(new Point(0.62f, 0.5f, 0f)); } hopperShape.Indices.AddRange(new int[6] { count2, count2 + 2, count2 + 1, count2, count2 + 3, count2 + 2 }); count2 = hopperShape.Vertices.Count; for (int l = 0; l < 4; l++) { hopperShape.Vertices.Add(Corner(l, array[0])); hopperShape.UV.Add(new Point(0.12f, 0.5f, 0f)); } hopperShape.Indices.AddRange(new int[6] { count2, count2 + 1, count2 + 2, count2, count2 + 2, count2 + 3 }); return hopperShape; } private static Point Corner(int n, Point ring) { return new Point((n == 0 || n == 3) ? (0f - ring.X) : ring.X, ring.Y, (n < 2) ? (0f - ring.X) : ring.X); } } internal static class InventoryWake { private sealed class State { internal ulong Fingerprint; internal float Next; internal int Misses; } private static readonly Dictionary<Inventory, int> revisions = new Dictionary<Inventory, int>(); private static readonly Dictionary<Container, State> idle = new Dictionary<Container, State>(); internal static void Clear() { revisions.Clear(); idle.Clear(); } internal static void Watch(Inventory inventory) { if (inventory != null && !revisions.ContainsKey(inventory)) { revisions.Add(inventory, 0); } } internal static void Changed(Inventory inventory) { if (revisions.TryGetValue(inventory, out var value)) { revisions[inventory] = value + 1; } } private static ulong Fingerprint(Container source, List<Container> peers) { ulong n = (ulong)Routing.Revision; Mix(ref n, source); foreach (Container peer in peers) { if (Object.op_Implicit((Object)(object)peer)) { Mix(ref n, peer); } } return n; } private static void Mix(ref ulong n, Container c) { Inventory inventory = c.GetInventory(); Watch(inventory); revisions.TryGetValue(inventory, out var value); n = n * 1099511628211L + (uint)((Object)c).GetInstanceID(); n = n * 1099511628211L + (uint)value; n = n * 1099511628211L + (uint)ChestSettings.Mode(c); n = n * 1099511628211L + (ulong)(Native.Owner((Component)(object)c) ? 1 : 0); } internal static bool ShouldRun(Container source, List<Container> peers) { if (!idle.TryGetValue(source, out var value)) { idle[source] = new State(); return true; } if (!OpenChestAccess.Viewing(source) && !(Time.time >= value.Next)) { return value.Fingerprint != Fingerprint(source, peers); } return true; } internal static void Completed(Container source, List<Container> peers, bool moved) { if (!idle.TryGetValue(source, out var value)) { value = (idle[source] = new State()); } value.Misses = ((!moved) ? Math.Min(3, value.Misses + 1) : 0); value.Fingerprint = Fingerprint(source, peers); value.Next = Time.time + (float)((!moved) ? value.Misses : 0); } internal static void Prune() { Container[] array = idle.Keys.Where((Container c) => !Object.op_Implicit((Object)(object)c) || !Plugin.Chests.Contains(c)).ToArray(); foreach (Container key in array) { idle.Remove(key); } HashSet<Inventory> live = new HashSet<Inventory>(); foreach (Container chest in Plugin.Chests) { if (Object.op_Implicit((Object)(object)chest)) { live.Add(chest.GetInventory()); } } Inventory[] array2 = revisions.Keys.Where((Inventory i) => !live.Contains(i)).ToArray(); foreach (Inventory key2 in array2) { revisions.Remove(key2); } } } [HarmonyPatch(typeof(Inventory), "Changed")] internal static class InventoryWakePatch { private static void Postfix(Inventory __instance) { InventoryWake.Changed(__instance); } } internal static class LoosePickup { private sealed class Mouth { internal Component Owner; internal Transform Socket; internal List<Container> Chests; internal Vector3 Position { get { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Socket)) { return Owner.transform.TransformPoint(Vector3.up * 1.15f); } return Socket.position; } } } private static readonly Collider[] hits = (Collider[])(object)new Collider[64]; private static readonly HashSet<ItemDrop> seen = new HashSet<ItemDrop>(); private static readonly int itemMask = LayerMask.GetMask(new string[1] { "item" }); private static readonly int wallMask = LayerMask.GetMask(new string[3] { "terrain", "piece", "static_solid" }); private static int cursor; private static int revision = -1; private static readonly List<Mouth> mouths = new List<Mouth>(); internal static void Tick() { //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) if (revision != Routing.Revision) { mouths.Clear(); revision = Routing.Revision; foreach (PipeNode item in PipeNode.All) { if (!Object.op_Implicit((Object)(object)item) || !item.Ready || !Native.Valid((Component)(object)item)) { continue; } foreach (Transform item2 in ((Component)item).transform) { Transform val = item2; if (!(((Object)val).name != "_snap") || (item.Kind == PipeKind.Output && ((Object)val).name == "_fp_dock")) { mouths.Add(new Mouth { Owner = (Component)(object)item, Socket = val }); } } } foreach (Container chest in Plugin.Chests) { if (Hopper.Is(chest) && ChestHandoff.Eligible(chest)) { mouths.Add(new Mouth { Owner = (Component)(object)chest, Chests = new List<Container> { chest } }); } } } if (mouths.Count == 0) { cursor = 0; return; } int num = Math.Min(4, mouths.Count); for (int i = 0; i < num; i++) { Mouth mouth = mouths[cursor++ % mouths.Count]; PipeNode pipeNode = mouth.Owner as PipeNode; if (!Object.op_Implicit((Object)(object)mouth.Owner) || !Native.Owner(mouth.Owner) || !ChestHandoff.Access(mouth.Owner)) { continue; } int num2 = Physics.OverlapSphereNonAlloc(mouth.Position, 0.85f, hits, itemMask, (QueryTriggerInteraction)2); if (num2 == 0) { continue; } if (Object.op_Implicit((Object)(object)pipeNode)) { MachinePort machinePort = SocketIndex.NearbyPorts(mouth.Position).FirstOrDefault((MachinePort p) => Object.op_Implicit((Object)(object)p) && !p.Preview && Object.op_Implicit((Object)(object)p.Target) && Vector3.SqrMagnitude(((Component)p).transform.position - mouth.Position) < 0.0324f); if ((Object.op_Implicit((Object)(object)machinePort) && machinePort.Kind != PipeKind.Output) || (!Object.op_Implicit((Object)(object)machinePort) && (!Object.op_Implicit((Object)(object)mouth.Socket) || PipeSnapping.Occupied(mouth.Socket, pipeNode)))) { continue; } mouth.Chests = Routing.StorageForPipe(pipeNode); } if (mouth.Chests.Count == 0) { continue; } seen.Clear(); int num3 = 10; for (int num4 = 0; num4 < num2; num4++) { if (num3 <= 0) { break; } ItemDrop val2 = (Object.op_Implicit((Object)(object)hits[num4]) ? ((Component)hits[num4]).GetComponentInParent<ItemDrop>() : null); if (!Object.op_Implicit((Object)(object)val2) || !seen.Add(val2) || !val2.m_autoPickup || !Native.Valid((Component)(object)val2) || !ChestHandoff.Access((Component)(object)val2)) { continue; } val2.Load(); if (val2.m_itemData.m_stack <= 0 || Physics.Linecast(mouth.Position, ((Component)val2).transform.position, wallMask, (QueryTriggerInteraction)1)) { continue; } foreach (Container chest2 in mouth.Chests) { ChestHandoff chestHandoff = (Object.op_Implicit((Object)(object)chest2) ? ((Component)chest2).GetComponent<ChestHandoff>() : null); if (!Object.op_Implicit((Object)(object)chestHandoff) || !chestHandoff.Ready(mouth.Owner) || !chest2.GetInventory().CanAddItem(val2.m_itemData, 1)) { continue; } if (!Native.Owner((Component)(object)val2)) { val2.RequestOwn(); break; } if (!val2.CanPickup(true)) { break; } while (Object.op_Implicit((Object)(object)val2) && num3 > 0 && val2.m_itemData.m_stack > 0 && OpenChestAccess.CanEdit(chest2) && Native.Owner((Component)(object)val2)) { ItemData val3 = val2.m_itemData.Clone(); val3.m_stack = 1; if (!chest2.GetInventory().AddItem(val3)) { break; } num3--; if (val2.m_itemData.m_stack == 1) { val2.SetStack(0); ZNetScene.instance.Destroy(((Component)val2).gameObject); break; } val2.SetStack(val2.m_itemData.m_stack - 1); } if (!Object.op_Implicit((Object)(object)val2) || num3 == 0) { break; } } } } if (cursor > 1000000) { cursor %= mouths.Count; } } } public sealed class MachineHandoff : MonoBehaviour { private Component machine; private float nextRequest; private float nextGrant; private void Awake() { machine = Stations.Find(((Component)this).gameObject); Native.View(machine).Register<ZDOID>("FP_RequestMachine", (Action<long, ZDOID>)OnRequest); } private Container PreferredViewer() { return (from c in (from c in Routing.Connected(machine, PipeKind.Output).Concat(Routing.Connected(machine, PipeKind.Input)).Concat(Routing.Connected(machine, PipeKind.Fuel)) where ChestHandoff.Eligible(c) && ChestHandoff.Busy(c) select c).Distinct() orderby ((object)Unsafe.As<ZDOID, ZDOID>(ref Native.View((Component)(object)c).GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString() select c).FirstOrDefault(); } internal static void Prepare(Component s) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (!Native.Valid(s)) { return; } MachineHandoff machineHandoff = s.GetComponent<MachineHandoff>(); if (!Object.op_Implicit((Object)(object)machineHandoff)) { machineHandoff = s.gameObject.AddComponent<MachineHandoff>(); } if (!Native.Owner(s) && !(Time.time < machineHandoff.nextRequest)) { Container val = machineHandoff.PreferredViewer(); if (Object.op_Implicit((Object)(object)val) && Native.Owner((Component)(object)val) && OpenChestAccess.Viewing(val) && ChestHandoff.Access((Component)(object)val) && ChestHandoff.Access(s)) { machineHandoff.nextRequest = Time.time + 3f; Native.View(s).InvokeRPC("FP_RequestMachine", new object[1] { Native.View((Component)(object)val).GetZDO().m_uid }); } } } private void OnRequest(long sender, ZDOID chestId) { //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_009d: Unknown result type (might be due to invalid IL or missing references) if (Native.Owner(machine) && Stations.Supported(machine) && Stations.CanHandoff(machine) && !(Time.time < nextGrant) && ChestHandoff.Access(machine)) { Container val = PreferredViewer(); if (Object.op_Implicit((Object)(object)val) && !(Native.View((Component)(object)val).GetZDO().m_uid != chestId) && Native.View((Component)(object)val).GetZDO().GetOwner() == sender && ChestHandoff.Access((Component)(object)val)) { ZDO zDO = Native.View(machine).GetZDO(); ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid); zDO.SetOwner(sender); nextGrant = Time.time + 3f; } } } } internal static class MetalPlacement { internal static void Apply(Piece piece, ZNetScene scene) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown GameObject val = scene.GetPrefab("sfx_build_hammer_metal"); if (!Object.op_Implicit((Object)(object)val)) { string[] array = new string[3] { "iron_wall_1x1", "iron_floor_1x1", "piece_chest_blackmetal" }; foreach (string text in array) { GameObject prefab = scene.GetPrefab(text); Piece val2 = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Piece>() : null); if (Object.op_Implicit((Object)(object)val2) && val2.m_placeEffect != null) { val = (from e in val2.m_placeEffect.m_effectPrefabs where Object.op_Implicit((Object)(object)e.m_prefab) && ((Object)e.m_prefab).name.IndexOf("metal", StringComparison.OrdinalIgnoreCase) >= 0 && Object.op_Implicit((Object)(object)e.m_prefab.GetComponentInChildren<AudioSource>(true)) select e.m_prefab).FirstOrDefault(); if (Object.op_Implicit((Object)(object)val)) { break; } } } } if (!Object.op_Implicit((Object)(object)val)) { Plugin.Error("Metal placement sound prefab unavailable; keeping native placement effects."); return; } EffectList val3 = new EffectList(); EffectData[] array2 = (EffectData[])(object)new EffectData[1]; EffectData val4 = new EffectData(); val4.m_prefab = val; val4.m_enabled = true; val4.m_scale = true; array2[0] = val4; val3.m_effectPrefabs = array2; piece.m_placeEffect = val3; } } public struct Point { public float X; public float Y; public float Z; public Point(float x, float y, float z) { X = x; Y = y; Z = z; } public static float DistanceSquared(Point a, Point b) { float num = a.X - b.X; float num2 = a.Y - b.Y; float num3 = a.Z - b.Z; return num * num + num2 * num2 + num3 * num3; } public static float Dot(Point a, Point b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } } public struct Socket { public int Node; public Point Position; public Point Direction; public Socket(int node, Point position, Point direction) { Node = node; Position = position; Direction = direction; } } public sealed class NetworkGraph { internal struct Cell : IEquatable<Cell> { internal int X; internal int Y; internal int Z; public bool Equals(Cell c) { if (X == c.X && Y == c.Y) { return Z == c.Z; } return false; } public override bool Equals(object other) { if (other is Cell) { return Equals((Cell)other); } return false; } public override int GetHashCode() { return (X * 73856093) ^ (Y * 19349663) ^ (Z * 83492791); } } private readonly int[] parents; public NetworkGraph(int count, IList<Socket> sockets, float tolerance) { if (count < 0 || tolerance <= 0f) { throw new ArgumentOutOfRangeException(); } parents = new int[count]; for (int i = 0; i < count; i++) { parents[i] = i; } Dictionary<Cell, List<Socket>> dictionary = new Dictionary<Cell, List<Socket>>(); foreach (Socket socket in sockets) { if (socket.Node < 0 || socket.Node >= count) { throw new ArgumentOutOfRangeException("sockets"); } int num = (int)Math.Floor(socket.Position.X / tolerance); int num2 = (int)Math.Floor(socket.Position.Y / tolerance); int num3 = (int)Math.Floor(socket.Position.Z / tolerance); for (int j = -1; j <= 1; j++) { for (int k = -1; k <= 1; k++) { for (int l = -1; l <= 1; l++) { if (!dictionary.TryGetValue(Key(num + j, num2 + k, num3 + l), out var value)) { continue; } foreach (Socket item in value) { if (item.Node != socket.Node && Point.DistanceSquared(socket.Position, item.Position) <= tolerance * tolerance && Point.Dot(socket.Direction, item.Direction) < -0.8f) { parents[Root(socket.Node)] = Root(item.Node); } } } } } Cell key = Key(num, num2, num3); if (!dictionary.TryGetValue(key, out var value2)) { value2 = new List<Socket>(); dictionary.Add(key, value2); } value2.Add(socket); } } private static Cell Key(int x, int y, int z) { return new Cell { X = x, Y = y, Z = z }; } public void Join(int a, int b) { parents[Root(a)] = Root(b); } public int Root(int i) { while (parents[i] != i) { parents[i] = parents[parents[i]]; i = parents[i]; } return i; } public bool Connected(int a, int b) { return Root(a) == Root(b); } } internal static class OpenChestAccess { private static readonly FieldInfo Current = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); private static readonly FieldInfo Drag = AccessTools.Field(typeof(InventoryGui), "m_dragItem"); private static readonly FieldInfo DragInventory = AccessTools.Field(typeof(InventoryGui), "m_dragInventory"); private static readonly FieldInfo DragObject = AccessTools.Field(typeof(InventoryGui), "m_dragGo"); private static readonly FieldInfo Split = AccessTools.Field(typeof(InventoryGui), "m_splitItem"); private static readonly FieldInfo SplitInventory = AccessTools.Field(typeof(InventoryGui), "m_splitInventory"); internal static bool Viewing(Container chest) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)InventoryGui.instance)) { return (Object)(Container)Current.GetValue(InventoryGui.instance) == (Object)(object)chest; } return false; } internal static bool CanEdit(Container chest) { return OpenChestRules.CanEdit(Native.Owner((Component)(object)chest), ChestHandoff.Busy(chest), Viewing(chest)); } internal static bool Reserved(Inventory inventory, ItemData item) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown InventoryGui instance = InventoryGui.instance; if (!Object.op_Implicit((Object)(object)instance)) { return false; } if (!Object.op_Implicit((Object)(GameObject)DragObject.GetValue(instance)) || DragInventory.GetValue(instance) != inventory || Drag.GetValue(instance) != item) { if (Object.op_Implicit((Object)(object)instance.m_splitDialog) && ((Component)instance.m_splitDialog).gameObject.activeInHierarchy && SplitInventory.GetValue(instance) == inventory) { return Split.GetValue(instance) == item; } return false; } return true; } } internal static class OpenChestRules { internal static bool CanEdit(bool owned, bool inUse, bool localViewer) { if (owned) { if (inUse) { return localViewer; } return true; } return false; } internal static bool CanHandoff(bool owned, bool inUse, bool localViewer) { if (owned && !inUse) { return !localViewer; } return false; } internal static bool MayPull(bool targetOwned, bool targetViewed, bool sourceBusy) { if (targetOwned && targetViewed) { return !sourceBusy; } return false; } } internal static class PerformanceConsole { internal static void Register() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown new ConsoleCommand("fpperf", "Forge Pipes: fpperf status | render/automation/connections/groups on/off | reset", (ConsoleEvent)delegate(ConsoleEventArgs args) { if (args.Args.Length == 2 && args.Args[1] == "reset") { ConfigEntry<bool> renderPipes = Plugin.RenderPipes; ConfigEntry<bool> runAutomation = Plugin.RunAutomation; ConfigEntry<bool> runConnectionChecks = Plugin.RunConnectionChecks; bool flag = (Plugin.GroupRendering.Value = true); bool flag3 = (runConnectionChecks.Value = flag); bool value = (runAutomation.Value = flag3); renderPipes.Value = value; Routing.Dirty = true; } else if (args.Args.Length == 3 && (args.Args[2] == "on" || args.Args[2] == "off")) { bool value2 = args.Args[2] == "on"; switch (args.Args[1]) { case "render": Plugin.RenderPipes.Value = value2; break; case "automation": Plugin.RunAutomation.Value = value2; break; case "connections": Plugin.RunConnectionChecks.Value = value2; Routing.Dirty = true; break; case "groups": Plugin.GroupRendering.Value = value2; break; default: args.Context.AddString("Use render, automation, connections or groups."); return; } } string text = "Forge Pipes: render=" + Plugin.RenderPipes.Value + ", automation=" + Plugin.RunAutomation.Value + ", connections=" + Plugin.RunConnectionChecks.Value + ", groups=" + Plugin.GroupRendering.Value + ". Use fpperf reset to restore. Read 30-second FP timing samples in LogOutput.log."; args.Context.AddString(text); Plugin.LogInfo(text); }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } internal static class PerformanceStats { private static readonly Dictionary<string, double[]> sections = new Dictionary<string, double[]>(); private static int frames; private static int ticks; private static int lastRevision; private static float elapsed; private static float worstFrame; private static double tickTotal; private static double tickWorst; internal static void Section(string name, long start) { if (Plugin.PerformanceLogging.Value) { if (!sections.TryGetValue(name, out var value)) { value = (sections[name] = new double[3]); } double num = (double)(Stopwatch.GetTimestamp() - start) * 1000.0 / (double)Stopwatch.Frequency; value[0] += num; value[1] = Math.Max(value[1], num); value[2] += 1.0; } } internal static void Tick(long started) { double num = (double)(Stopwatch.GetTimestamp() - started) * 1000.0 / (double)Stopwatch.Frequency; ticks++; tickTotal += num; tickWorst = Math.Max(tickWorst, num); } internal static void Frame() { if (!Plugin.PerformanceLogging.Value || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { frames = (ticks = 0); elapsed = (worstFrame = 0f); tickTotal = (tickWorst = 0.0); lastRevision = Routing.Revision; return; } frames++; elapsed += Time.unscaledDeltaTime; worstFrame = Mathf.Max(worstFrame, Time.unscaledDeltaTime); if (elapsed < 30f) { return; } int num = 0; int num2 = 0; int num3 = 0; long num4 = 0L; foreach (PipeNode item in PipeNode.All) { if (!Object.op_Implicit((Object)(object)item) || !Native.Valid((Component)(object)item)) { continue; } num++; MeshRenderer[] componentsInChildren = ((Component)item).GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val in componentsInChildren) { if (((Renderer)val).enabled && !((Renderer)val).forceRenderingOff) { num2++; MeshFilter component = ((Component)val).GetComponent<MeshFilter>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sharedMesh)) { num4 += (long)component.sharedMesh.GetIndexCount(0) / 3L; } } } Collider[] componentsInChildren2 = ((Component)item).GetComponentsInChildren<Collider>(); foreach (Collider val2 in componentsInChildren2) { if (val2.enabled) { num3++; } } } num2 += PipeRenderGroups.RendererCount; num4 += PipeRenderGroups.TriangleCount; Plugin.LogInfo($"FP performance 1.1.1: {(float)frames / elapsed:F1} FPS avg, worst frame {worstFrame * 1000f:F1} ms; pipes={num}, enabled renderers={num2}, triangles={num4}, colliders={num3}; automation avg/max={((ticks == 0) ? 0.0 : (tickTotal / (double)ticks)):F2}/{tickWorst:F2} ms; graph rebuilds={Routing.Revision - lastRevision} in {elapsed:F1}s."); foreach (KeyValuePair<string, double[]> section in sections) { Plugin.LogInfo($"FP timing {section.Key}: avg {section.Value[0] / Math.Max(1.0, section.Value[2]):F3} ms, max {section.Value[1]:F3} ms, calls {section.Value[2]}; managed memory {(double)GC.GetTotalMemory(forceFullCollection: false) / 1048576.0:F1} MB"); } sections.Clear(); frames = (ticks = 0); elapsed = (worstFrame = 0f); tickTotal = (tickWorst = 0.0); lastRevision = Routing.Revision; } } public sealed class PipeNode : MonoBehaviour, Hoverable { public PipeKind Kind; public Vector3[] Ends; public Vector3[] Directions; public Vector3[] RunStarts; public Vector3[] RunEnds; private readonly List<LineRenderer> endGuides = new List<LineRenderer>(); internal static readonly HashSet<PipeNode> All = new HashSet<PipeNode>(); internal int VisualRevision; private bool registered; internal bool Terminal { get { if (Kind >= PipeKind.Chest) { return Kind <= PipeKind.Output; } return false; } } internal bool Ready { get { if (Kind == PipeKind.Stretch) { if (Object.op_Implicit((Object)(object)((Component)this).GetComponent<StretchPipe>())) { return ((Component)this).GetComponent<StretchPipe>().Shape != null; } return false; } return true; } } internal Vector3 LocalDock { get { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)this).transform.Find("_fp_dock"); if (!Object.op_Implicit((Object)(object)val)) { return Vector3.back * 0.5f; } return val.localPosition; } } internal Vector3 Dock => ((Component)this).transform.TransformPoint(LocalDock); private void Start() { if (Native.Valid((Component)(object)this)) { registered = true; Routing.Dirty = true; SocketIndex.Invalidate(); } } private void OnEnable() { All.Add(this); SocketIndex.Invalidate(); if (Native.Valid((Component)(object)this)) { registered = true; Routing.Dirty = true; } } private void OnDisable() { All.Remove(this); PipeRenderGroups.Remove(this); SocketIndex.Invalidate(); foreach (LineRenderer endGuide in endGuides) { if (Object.op_Implicit((Object)(object)endGuide)) { ((Renderer)endGuide).enabled = false; } } if (registered) { Routing.Dirty = true; } registered = false; } private void BuildEndGuides() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) if (endGuides.Count > 0 || Ends == null || Ends.Length == 0) { return; } Material guideMaterial = PortFactory.GuideMaterial; if (!Object.op_Implicit((Object)(object)guideMaterial)) { return; } for (int i = 0; i < Ends.Length; i++) { GameObject val = new GameObject("FP_pipe_end_guide"); val.layer = ((Component)this).gameObject.layer; val.transform.SetParent(((Component)this).transform, false); Vector3 localPosition = ((Kind == PipeKind.Chest) ? LocalDock : Ends[i]); Vector3 val2 = ((Kind == PipeKind.Chest) ? Vector3.back : Directions[i]); val.transform.localPosition = localPosition; val.transform.localRotation = Quaternion.FromToRotation(Vector3.forward, val2); LineRenderer val3 = val.AddComponent<LineRenderer>(); val3.useWorldSpace = false; val3.loop = true; val3.positionCount = 24; float startWidth = (val3.endWidth = 0.025f); val3.startWidth = startWidth; ((Renderer)val3).sharedMaterial = guideMaterial; Color startColor = (val3.endColor = Pieces.PortColor(Kind)); val3.startColor = startColor; ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val3).receiveShadows = false; for (int j = 0; j < 24; j++) { float num2 = (float)j * (float)Math.PI / 12f; val3.SetPosition(j, new Vector3(Mathf.Cos(num2) * 0.24f, Mathf.Sin(num2) * 0.24f, 0.025f)); } ((Renderer)val3).enabled = false; endGuides.Add(val3); } } internal void RefreshGuides(bool chest, bool stretch, Vector3 playerPosition) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) if (chest || stretch) { BuildEndGuides(); } for (int i = 0; i < endGuides.Count; i++) { if (Object.op_Implicit((Object)(object)endGuides[i])) { Transform transform = ((Component)endGuides[i]).transform; if (Kind == PipeKind.Stretch || Kind == PipeKind.Chest) { transform.localPosition = ((Kind == PipeKind.Chest && !stretch) ? LocalDock : Ends[i]); transform.localRotation = Quaternion.FromToRotation(Vector3.forward, (Kind == PipeKind.Chest && !stretch) ? Vector3.back : Directions[i]); } ((Renderer)endGuides[i]).enabled = (chest || stretch) && (stretch || !Terminal || Kind == PipeKind.Chest) && Native.Valid((Component)(object)this) && (stretch || SnapGeometry.UprightPort(new Point(transform.forward.x, transform.forward.y, transform.forward.z)) || Mathf.Abs(transform.forward.y) > 0.999f) && !PipeSnapping.Occupied(transform, this); } } } public string GetHoverName() { return PipeLanguage.Text(((Component)this).GetComponent<Piece>().m_name); } public float GetHoverOffset() { return 0.3f; } public string GetHoverText() { string text = Routing.Status(this); return GetHoverName() + "\n<color=#e9ba77>" + text + "</color>"; } } internal static class Pieces { private sealed class FieldInfoCache { internal readonly FieldInfo Named = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs"); } private static readonly FieldInfoCache fields = new FieldInfoCache(); internal static void Register(ZNetScene scene) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown if (Plugin.Prefabs.Count == 0) { GameObject prefab = scene.GetPrefab("wood_beam"); if (!Object.op_Implicit((Object)(object)prefab)) { throw new InvalidOperationException("Vanilla wood_beam prefab not found."); } Plugin.PrefabRoot = new GameObject("ForgePipes_Prefabs"); Plugin.PrefabRoot.SetActive(false); Object.DontDestroyOnLoad((Object)(object)Plugin.PrefabRoot); foreach (PipeKind value in Enum.GetValues(typeof(PipeKind))) { Build(prefab, value, scene); } Hopper.Register(scene); } Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)fields.Named.GetValue(scene); foreach (GameObject prefab2 in Plugin.Prefabs) { dictionary[StringExtensionMethods.GetStableHashCode(((Object)prefab2).name)] = prefab2; if (!scene.m_prefabs.Contains(prefab2)) { scene.m_prefabs.Add(prefab2); } } AttachHammer(); Plugin.LogInfo("Registered " + Plugin.Prefabs.Count + " Forge pipe network prefabs."); } internal static void AttachHammer() { if (!Object.op_Implicit((Object)(object)ObjectDB.instance)) { return; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer"); if (!Object.op_Implicit((Object)(object)itemPrefab)) { return; } PieceTable buildPieces = itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces; bool flag = false; foreach (GameObject prefab in Plugin.Prefabs) { if (!buildPieces.m_pieces.Contains(prefab)) { buildPieces.m_pieces.Add(prefab); flag = true; } } if (flag) { AccessTools.Field(typeof(ObjectDB), "m_buildPieces").SetValue(ObjectDB.instance, null); } } internal static string Label(PipeKind kind) { return kind switch { PipeKind.TightBend => "Forge pipe - tight elbow", PipeKind.TightUpBend => "Forge pipe - tight elbow up", PipeKind.TightDownBend => "Forge pipe - tight elbow down", PipeKind.ShortStraight => "Forge pipe - straight (1m)", PipeKind.Cross => "Forge pipe - four-way junction", PipeKind.SixWay => "Forge pipe - six-way junction", PipeKind.TeeUp => "Forge pipe - tee up", PipeKind.TeeDown => "Forge pipe - tee down", PipeKind.ShortTee => "Forge pipe - short junction", PipeKind.ShortTeeUp => "Forge pipe - short tee up", PipeKind.ShortTeeDown => "Forge pipe - short tee down", PipeKind.ShortCross => "Forge pipe - short four-way junction", PipeKind.ShortSixWay => "Forge pipe - short six-way junction", PipeKind.TeePlusUp => "Forge pipe - four-way tee up", PipeKind.TeePlusDown => "Forge pipe - four-way tee down", PipeKind.ShortTeePlusUp => "Forge pipe - short four-way tee up", PipeKind.ShortTeePlusDown => "Forge pipe - short four-way tee down", PipeKind.CompactChest => "Forge pipe - compact chest connector", PipeKind.CompactInput => "Forge pipe - compact ingredient inlet", PipeKind.CompactFuel => "Forge pipe - compact fuel inlet", PipeKind.CompactOutput => "Forge pipe - compact product outlet", PipeKind.Stretch => "Forge pipe - stretch (0.5-16m)", PipeKind.Straight => "Forge pipe - straight (2m)", PipeKind.Bend => "Forge pipe - elbow", PipeKind.Tee => "Forge pipe - junction", PipeKind.Riser => "Forge pipe - vertical (2m)", PipeKind.UpBend => "Forge pipe - elbow up", PipeKind.DownBend => "Forge pipe - elbow down", PipeKind.Chest => "Forge pipe - chest connector", PipeKind.Input => "Forge pipe - ingredient inlet", PipeKind.Fuel => "Forge pipe - coal inlet", _ => "Forge pipe - product outlet", }; } internal static Color PortColor(PipeKind kind) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) return (Color)(kind switch { PipeKind.Output => new Color(0.95f, 0.7f, 0.2f), PipeKind.Fuel => new Color(0.5f, 0.52f, 0.58f), PipeKind.Input => new Color(0.3f, 0.75f, 0.38f), PipeKind.Chest => new Color(0.2f, 0.6f, 0.85f), _ => new Color(0.62f, 0.36f, 0.18f), }); } private static void Build(GameObject source, PipeKind kind, ZNetScene scene) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Expected O, but got Unknown //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_0428: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Expected O, but got Unknown //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_04a1: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Expected O, but got Unknown //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Unknown result type (might be due to invalid IL or missing references) //IL_04f5: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_052b: Unknown result type (might be due to invalid IL or missing references) //IL_0537: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_0608: Unknown result type (might be due to invalid IL or missing references) //IL_060f: Expected O, but got Unknown //IL_063c: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(source, Plugin.PrefabRoot.transform, false); ((Object)val).name = "FP_" + kind; val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; Renderer componentInChildren = val.GetComponentInChildren<Renderer>(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { _ = componentInChildren.sharedMaterial; } LODGroup[] componentsInChildren = val.GetComponentsInChildren<LODGroup>(true); foreach (LODGroup val2 in componentsInChildren) { Object.DestroyImmediate((Object)(object)val2); } for (int num = val.transform.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)val.transform.GetChild(num)).gameObject); } Rigidbody[] componentsInChildren2 = val.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val3 in componentsInChildren2) { Object.DestroyImmediate((Object)(object)val3); } Collider[] components = val.GetComponents<Collider>(); foreach (Collider val4 in components) { Object.DestroyImmediate((Object)(object)val4); } Renderer[] components2 = val.GetComponents<Renderer>(); foreach (Renderer val5 in components2) { Object.DestroyImmediate((Object)(object)val5); } MeshFilter[] components3 = val.GetComponents<MeshFilter>(); foreach (MeshFilter val6 in components3) { Object.DestroyImmediate((Object)(object)val6); } bool flag = kind >= PipeKind.CompactChest && kind <= PipeKind.CompactOutput; bool flag2 = kind >= PipeKind.TightBend && kind <= PipeKind.TightDownBend; PipeNode pipeNode = val.AddComponent<PipeNode>(); pipeNode.Kind = (flag ? (6 + kind - 16) : kind); bool flag3 = kind == PipeKind.ShortTee || kind == PipeKind.ShortTeeUp || kind == PipeKind.ShortTeeDown || kind == PipeKind.ShortCross || kind == PipeKind.ShortSixWay || kind == PipeKind.ShortTeePlusUp || kind == PipeKind.ShortTeePlusDown; float num2 = ((kind == PipeKind.ShortStraight || flag2 || flag3) ? 0.5f : 1f); float num3 = (flag ? 0.25f : 0.5f); List<Vector3> list = new List<Vector3>(); if (kind == PipeKind.Riser) { list.Add(Vector3.down); list.Add(Vector3.up); } else if (pipeNode.Terminal) { list.Add(Vector3.forward * num3); } else { list.Add(Vector3.back * num2); Vector3 item; switch (kind) { default: item = Vector3.forward * num2; break; case PipeKind.DownBend: case PipeKind.TightDownBend: item = Vector3.down * num2; break; case PipeKind.UpBend: case PipeKind.TightUpBend: item = Vector3.up * num2; break; case PipeKind.Bend: case PipeKind.TightBend: item = Vector3.right * num2; break; } list.Add(item); if (kind == PipeKind.Tee || kind == PipeKind.ShortTee || kind == PipeKind.TeePlusUp || kind == PipeKind.TeePlusDown || kind == PipeKind.ShortTeePlusUp || kind == PipeKind.ShortTeePlusDown) { list.Add(Vector3.right * num2); } if (kind == PipeKind.TeeUp || kind == PipeKind.ShortTeeUp || kind == PipeKind.TeePlusUp || kind == PipeKind.ShortTeePlusUp) { list.Add(Vector3.up * num2); } if (kind == PipeKind.TeeDown || kind == PipeKind.ShortTeeDown || kind == PipeKind.TeePlusDown || kind == PipeKind.ShortTeePlusDown) { list.Add(Vector3.down * num2); } if (kind == PipeKind.Cross || kind == PipeKind.SixWay || kind == PipeKind.ShortCross || kind == PipeKind.ShortSixWay) { list.Add(Vector3.left * num2); list.Add(Vector3.right * num2); } if (kind == PipeKind.SixWay || kind == PipeKind.ShortSixWay) { list.Add(Vector3.up * num2); list.Add(Vector3.down * num2); } } pipeNode.Ends = list.ToArray(); pipeNode.Directions = list.Select((Vector3 e) => ((Vector3)(ref e)).normalized).ToArray(); GameObject val7 = new GameObject("pipe_mesh"); val7.layer = val.layer; val7.transform.SetParent(val.transform, false); PipeModels.Build(val7, pipeNode, kind, num3); Vector3[] ends = pipeNode.Ends; for (int num4 = 0; num4 < ends.Length; num4++) { Vector3 localPosition = ends[num4]; GameObject val8 = new GameObject("_snap"); val8.tag = "snappoint"; val8.transform.SetParent(val.transform, false); val8.transform.localPosition = localPosition; val8.transform.localRotation = Quaternion.FromToRotation(Vector3.forward, ((Vector3)(ref localPosition)).normalized); } if (pipeNode.Terminal) { GameObject val9 = new GameObject("_fp_dock"); val9.tag = "snappoint"; val9.transform.SetParent(val.transform, false); val9.transform.localPosition = Vector3.back * num3; val9.transform.localRotation = Quaternion.Euler(0f, 180f, 0f); } if (kind == PipeKind.Stretch) { val.AddComponent<StretchPipe>(); } Piece component = val.GetComponent<Piece>(); component.m_name = Label(kind); MetalPlacement.Apply(component, scene); component.m_category = (PieceCategory)1; component.m_usage = (UsageTagFlags)2050; component.m_description = (pipeNode.Terminal ? "Aim at a matching colored port to snap and align automatically. Connect pipes to the narrow end. Hold the game's alternative-placement control for free placement." : "Aim at a chest port, machine port, or pipe collar to snap automatically. Only physically connected pipes share items."); if (kind == PipeKind.Stretch) { component.m_description = "Click a port or free pipe end to start. Aim to stretch, then click to finish. Select another piece or unequip the Hammer to cancel. One saved piece, up to 16m."; } if (kind == PipeKind.Straight || kind == PipeKind.ShortStraight) { component.m_description = PipeLanguage.Token(component.m_description) + " " + PipeLanguage.Token("While snapping to a pipe: [ / ] turn, Page Up / Page Down tilt, backslash resets. Maximum bend: 15 degrees."); } Sprite val10 = PipeIcons.Render(val7, kind); if (Object.op_Implicit((Object)(object)val10)) { component.m_icon = val10; } component.m_enabled = true; component.m_noClipping = false; component.m_clipEverything = true; component.m_groundOnly = false; component.m_groundPiece = false; component.m_noInWater = false; component.m_craftingStation = scene.GetPrefab("piece_workbench").GetComponent<CraftingStation>(); Requirement[] array = (Requirement[])(object)new Requirement[2]; Requirement val11 = new Requirement(); val11.m_resItem = scene.GetPrefab("Wood").GetComponent<ItemDrop>(); val11.m_amount = 2; val11.m_recover = true; array[0] = val11; Requirement val12 = new Requirement(); val12.m_resItem = scene.GetPrefab("Copper").GetComponent<ItemDrop>(); val12.m_amount = 1; val12.m_recover = true; array[1] = val12; component.m_resources = array; WearNTear component2 = val.GetComponent<WearNTear>(); component2.m_new = val7; component2.m_worn = val7; component2.m_broken = val7; component2.m_wet = null; component2.m_noRoofWear = false; component2.m_noSupportWear = false; component2.m_supports = true; component2.m_health = 150f; component2.m_autoCreateFragments = false; component2.m_fragmentRoots = (GameObject[])(object)new GameObject[0]; val.SetActive(true); Plugin.Prefabs.Add(val); } } public static class PipeCollisionPath { public const float Tolerance = 0.01f; public static int[] Simplify(Point[] points) { if (points == null || points.Length < 2) { throw new ArgumentException("A pipe needs two endpoints."); } List<int> list = new List<int>(); list.Add(0); Split(points, 0, points.Length - 1, list); return list.ToArray(); } private static void Split(Point[] p, int first, int last, List<int> keep) { float num = 0.0001f; int num2 = -1; PipeRun one = new PipeRun(0, p[first], p[last]); for (int i = first + 1; i < last; i++) { float num3 = BodyConnections.DistanceSquared(one, new PipeRun(1, p[i], p[i])); if (num3 > num) { num = num3; num2 = i; } } if (num2 < 0) { keep.Add(last); return; } Split(p, first, num2, keep); Split(p, num2, last, keep); } } internal static class PipeDeflection { private static Transform ghost; private static int frame = -1; private static float yaw; private static float pitch; internal static void Update(Transform current) { if ((Object)(object)ghost != (Object)(object)current) { ghost = current; yaw = (pitch = 0f); } if (frame != Time.frameCount) { frame = Time.frameCount; if (ZInput.GetKeyDown((KeyCode)91, false)) { yaw = Mathf.Max(-15f, yaw - 5f); } if (ZInput.GetKeyDown((KeyCode)93, false)) { yaw = Mathf.Min(15f, yaw + 5f); } if (ZInput.GetKeyDown((KeyCode)280, false)) { pitch = Mathf.Min(15f, pitch + 5f); } if (ZInput.GetKeyDown((KeyCode)281, false)) { pitch = Mathf.Max(-15f, pitch - 5f); } if (ZInput.GetKeyDown((KeyCode)92, false)) { yaw = (pitch = 0f); } } } internal static Quaternion Apply(Quaternion aligned, Transform target) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) Quaternion val = Quaternion.AngleAxis(yaw, target.up) * Quaternion.AngleAxis(pitch, target.right); float num = Quaternion.Angle(Quaternion.identity, val); if (num > 15f) { val = Quaternion.Slerp(Quaternion.identity, val, 15f / num); } return val * aligned; } } internal static class PipeGuideScheduler { private static HashSet<MachinePort> visiblePorts = new HashSet<MachinePort>(); private static HashSet<MachinePort> nextPorts = new HashSet<MachinePort>(); private static HashSet<PipeNode> visiblePipes = new HashSet<PipeNode>(); private static HashSet<PipeNode> nextPipes = new HashSet<PipeNode>(); private static GameObject lastGhost; private static Player lastPlayer; private static float nextRefresh; private static bool showing; internal static void Tick() { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0127: 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) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: 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_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; PipeNode ghostNode = PipeSnapping.GhostNode; bool flag = Object.op_Implicit((Object)(object)PipeSnapping.GhostChest); bool flag2 = Object.op_Implicit((Object)(object)ghostNode) && ghostNode.Kind == PipeKind.Stretch; if (!