Decompiled source of MJNetworkCore v0.1.18

plugins/MJNetworkCore.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MJNetworkCore
{
	internal static class ActiveObjectHooks
	{
		private static readonly Dictionary<int, ZDOID> ViewIds = new Dictionary<int, ZDOID>();

		internal static void ResetMappings()
		{
			ViewIds.Clear();
		}

		internal static void RegisterView(ZNetView view)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)view == (Object)null || Plugin.Registry == null)
			{
				return;
			}
			try
			{
				if (view.IsValid())
				{
					ZDO zDO = view.GetZDO();
					if (zDO != null)
					{
						ViewIds[((Object)view).GetInstanceID()] = zDO.m_uid;
						Plugin.Registry.Register(zDO, ((Component)view).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("Register view failed: " + ex.Message);
			}
		}

		internal static void UnregisterView(ZNetView view)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)view == (Object)null || Plugin.Registry == null)
			{
				return;
			}
			try
			{
				int instanceID = ((Object)view).GetInstanceID();
				if (ViewIds.TryGetValue(instanceID, out var value))
				{
					ViewIds.Remove(instanceID);
					Plugin.Registry.Unregister(value, ((Component)view).gameObject);
					return;
				}
				ZDO zDO = view.GetZDO();
				if (zDO != null)
				{
					Plugin.Registry.Unregister(zDO.m_uid, ((Component)view).gameObject);
				}
			}
			catch
			{
			}
		}

		internal static void SeedCurrentlyLoadedViews()
		{
			try
			{
				ZNetView[] array = Object.FindObjectsByType<ZNetView>((FindObjectsSortMode)0);
				for (int i = 0; i < array.Length; i++)
				{
					RegisterView(array[i]);
				}
				Plugin.LogDebug("Seeded loaded ZNetViews: " + array.Length);
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("Loaded-view seed failed: " + ex.Message);
			}
		}
	}
	internal static class CoreClientControls
	{
		private static FieldInfo _hovering;

		private static readonly int[] Steps = new int[7] { 0, 1, 5, 10, 25, 50, 100 };

		private static GUIStyle _networkStyle;

		internal static void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			bool flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305);
			bool flag2 = Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307);
			bool flag3 = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
			if (flag && flag3 && Input.GetKeyDown((KeyCode)118))
			{
				StorageRef storageRef = HoveredStorage(localPlayer);
				if (storageRef != null && storageRef.RequiresNetworkOptIn && storageRef.Zdo != null)
				{
					ZNetView val = (((Object)(object)storageRef.GameObject == (Object)null) ? null : storageRef.GameObject.GetComponent<ZNetView>());
					if ((Object)(object)val != (Object)null && val.IsValid() && !val.IsOwner())
					{
						val.ClaimOwnership();
					}
					bool flag4 = !storageRef.NetworkOptInEnabled;
					storageRef.Zdo.Set(CoreUtil.StorageNetworkEnabledHash, flag4);
					CoreUtil.ForceSend(storageRef.Zdo);
					if (Plugin.Registry != null)
					{
						Plugin.Registry.MarkDirty();
					}
					Show("Vernichter-Netzwerk: " + (flag4 ? "AN" : "AUS"));
				}
			}
			else if (flag && flag3 && Input.GetKeyDown((KeyCode)110))
			{
				NetworkInfo networkInfo = HoveredNetwork(localPlayer);
				if (networkInfo != null && !NetworkApi.RequestNetworkRename(networkInfo))
				{
					Show("MJ Network Map & Statistics wird zum Benennen benoetigt.");
				}
			}
			else
			{
				if (!flag || !flag2 || !Input.GetKeyDown((KeyCode)101))
				{
					return;
				}
				StorageRef storageRef2 = HoveredStorage(localPlayer);
				if (storageRef2 == null)
				{
					return;
				}
				int reserve = StorageApi.GetReserve(storageRef2);
				int value = Steps[0];
				for (int i = 0; i < Steps.Length; i++)
				{
					if (Steps[i] > reserve)
					{
						value = Steps[i];
						break;
					}
					if (i == Steps.Length - 1)
					{
						value = Steps[0];
					}
				}
				StorageApi.SetReserve(storageRef2, value);
				Show(storageRef2.PrefabName + ": Mindestbestand = " + value);
			}
		}

		internal static void OnGUI()
		{
		}

		internal static string AppendStationHover(CraftingStation station, string current)
		{
			if ((Object)(object)station == (Object)null)
			{
				return current;
			}
			NetworkInfo networkForStation = NetworkApi.GetNetworkForStation(station);
			if (networkForStation == null)
			{
				return current;
			}
			string text = (string.IsNullOrWhiteSpace(networkForStation.Name) ? "unbenannt" : networkForStation.Name);
			string text2 = "Netzwerk: " + text + "\n[Strg+Shift+N] Netzwerk benennen";
			if (!string.IsNullOrEmpty(current))
			{
				return current.TrimEnd(Array.Empty<char>()) + "\n" + text2;
			}
			return text2;
		}

		internal static string AppendStorageHover(GameObject go, string current)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)go == (Object)null)
			{
				return current;
			}
			ZNetView val = go.GetComponentInParent<ZNetView>() ?? go.GetComponent<ZNetView>();
			if ((Object)(object)val == (Object)null || !val.IsValid() || val.GetZDO() == null)
			{
				return current;
			}
			StorageRef storageRef = null;
			foreach (StorageRef storage in NetworkApi.Storages)
			{
				if (storage != null)
				{
					ZDOID id = storage.Id;
					if (((ZDOID)(ref id)).Equals(val.GetZDO().m_uid))
					{
						storageRef = storage;
						break;
					}
				}
			}
			if (storageRef == null || !storageRef.RequiresNetworkOptIn)
			{
				return current;
			}
			string text = "[Strg+Shift+V] Vernichter-Netzwerk: " + (storageRef.NetworkOptInEnabled ? "AN" : "AUS");
			if (!string.IsNullOrEmpty(current) && current.IndexOf("Vernichter-Netzwerk", StringComparison.Ordinal) >= 0)
			{
				return current;
			}
			if (!string.IsNullOrEmpty(current))
			{
				return current.TrimEnd(Array.Empty<char>()) + "\n" + text;
			}
			return text;
		}

		private static NetworkInfo HoveredNetwork(Player p)
		{
			GameObject val = HoveredObject(p);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			CraftingStation val2 = val.GetComponentInParent<CraftingStation>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = val.GetComponent<CraftingStation>();
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				return NetworkApi.GetNetworkForStation(val2);
			}
			return null;
		}

		private static StorageRef HoveredStorage(Player p)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = HoveredObject(p);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			ZNetView componentInParent = val.GetComponentInParent<ZNetView>();
			if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsValid())
			{
				return null;
			}
			foreach (StorageRef storage in NetworkApi.Storages)
			{
				ZDOID id = storage.Id;
				if (((ZDOID)(ref id)).Equals(componentInParent.GetZDO().m_uid))
				{
					return storage;
				}
			}
			return null;
		}

		private static GameObject HoveredObject(Player p)
		{
			_hovering = _hovering ?? AccessTools.Field(typeof(Player), "m_hovering");
			if (!(_hovering == null))
			{
				object? value = _hovering.GetValue(p);
				return (GameObject)((value is GameObject) ? value : null);
			}
			return null;
		}

		private static void Show(string s)
		{
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)2, s, 0, (Sprite)null, false, true);
			}
		}
	}
	internal sealed class CoreConfig
	{
		internal readonly ConfigEntry<float> RebuildDebounceSeconds;

		internal readonly ConfigEntry<float> StorageAttachExtraRange;

		internal readonly ConfigEntry<int> DefaultReserve;

		internal readonly ConfigEntry<float> SnapshotSeconds;

		internal readonly ConfigEntry<bool> PlayerBuiltOnly;

		internal readonly ConfigEntry<bool> NetworkWideBuildStations;

		internal readonly ConfigEntry<bool> VerboseLogging;

		internal CoreConfig(ConfigFile cfg)
		{
			RebuildDebounceSeconds = cfg.Bind<float>("Network", "RebuildDebounceSeconds", 0.2f, "Wait this long after loaded stations/containers change before rebuilding the active network graph.");
			StorageAttachExtraRange = cfg.Bind<float>("Network", "StorageAttachExtraRange", 0f, "Extra meters beyond the actual crafting-station build radius in which a storage belongs to that network.");
			DefaultReserve = cfg.Bind<int>("Storage", "DefaultReserve", 1, "Minimum amount each consuming module leaves in a container unless that container has its own override.");
			SnapshotSeconds = cfg.Bind<float>("Performance", "SnapshotSeconds", 0.25f, "How long a network resource snapshot may be reused for UI/count checks.");
			PlayerBuiltOnly = cfg.Bind<bool>("Network", "PlayerBuiltOnly", true, "Only player-built crafting stations and storage pieces participate in networks. Prevents dungeon/world stations from polluting the network list.");
			NetworkWideBuildStations = cfg.Bind<bool>("Building", "NetworkWideBuildStations", true, "If true, a required build station may be anywhere in the same connected MJ network. The build point/player still has to be inside that network.");
			VerboseLogging = cfg.Bind<bool>("Debug", "VerboseLogging", false, "Extra diagnostic logging.");
		}
	}
	internal static class CoreRpc
	{
		private const string RpcName = "MJNC_Settings_v1";

		private const int OpReserve = 1;

		private const int OpNetworkName = 2;

		private const int OpNetworkBool = 3;

		private static ZRoutedRpc _registeredOn;

		private static MethodInfo _getServerPeerId;

		internal static void EnsureRegistered()
		{
			if (ZRoutedRpc.instance == null || _registeredOn == ZRoutedRpc.instance)
			{
				return;
			}
			try
			{
				ZRoutedRpc.instance.Register<ZPackage>("MJNC_Settings_v1", (Action<long, ZPackage>)OnRpc);
				_registeredOn = ZRoutedRpc.instance;
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("Core RPC registration: " + ex.Message);
			}
		}

		internal static void SetReserve(StorageRef storage, int value)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			if (storage != null && storage.Zdo != null)
			{
				ZPackage val = new ZPackage();
				val.Write(1);
				val.Write(storage.Id);
				val.Write(Math.Max(0, value));
				Send(val);
			}
		}

		internal static void SetNetworkName(NetworkInfo network, string name)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			if (network != null && network.Stations.Count != 0)
			{
				ZPackage val = new ZPackage();
				val.Write(2);
				val.Write(network.Stations[0].Id);
				val.Write(name ?? string.Empty);
				Send(val);
			}
		}

		internal static void SetNetworkBool(NetworkInfo network, string key, bool value)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			if (network != null && network.Stations.Count != 0 && IsSafeKey(key))
			{
				ZPackage val = new ZPackage();
				val.Write(3);
				val.Write(network.Stations[0].Id);
				val.Write(key);
				val.Write(value ? 1 : 0);
				Send(val);
			}
		}

		private static void Send(ZPackage p)
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				p.SetPos(0);
				OnRpc(0L, p);
			}
			else if (ZRoutedRpc.instance != null)
			{
				long serverPeerId = GetServerPeerId();
				if (serverPeerId != 0L)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerId, "MJNC_Settings_v1", new object[1] { p });
				}
			}
		}

		private static void OnRpc(long sender, ZPackage p)
		{
			//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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			if (p == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				int num = p.ReadInt();
				ZDOID val = p.ReadZDOID();
				switch (num)
				{
				case 1:
				{
					ZDO val2 = ((ZDOMan.instance == null) ? null : ZDOMan.instance.GetZDO(val));
					if (val2 != null)
					{
						val2.Set(CoreUtil.ReserveHash, Math.Max(0, p.ReadInt()), false);
						CoreUtil.ForceSend(val2);
						NetworkApi.InvalidateSnapshots();
					}
					break;
				}
				case 2:
				{
					string text = p.ReadString();
					NetworkInfo networkInfo2 = FindNetworkByStation(val);
					if (networkInfo2 != null)
					{
						for (int j = 0; j < networkInfo2.Stations.Count; j++)
						{
							networkInfo2.Stations[j].Zdo.Set(CoreUtil.NetworkNameHash, text);
							CoreUtil.ForceSend(networkInfo2.Stations[j].Zdo);
						}
						if (Plugin.Registry != null)
						{
							Plugin.Registry.MarkDirty();
						}
					}
					break;
				}
				case 3:
				{
					string key = p.ReadString();
					bool flag = p.ReadInt() != 0;
					if (!IsSafeKey(key))
					{
						break;
					}
					NetworkInfo networkInfo = FindNetworkByStation(val);
					if (networkInfo != null)
					{
						int num2 = CoreUtil.NetworkSettingHash(key);
						for (int i = 0; i < networkInfo.Stations.Count; i++)
						{
							networkInfo.Stations[i].Zdo.Set(num2, flag ? 1 : 0, false);
							CoreUtil.ForceSend(networkInfo.Stations[i].Zdo);
						}
						NetworkApi.RaiseNetworksChanged();
					}
					break;
				}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("Core RPC failed: " + ex.Message);
			}
		}

		private static NetworkInfo FindNetworkByStation(ZDOID id)
		{
			//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_0028: Unknown result type (might be due to invalid IL or missing references)
			IReadOnlyList<NetworkInfo> networks = NetworkApi.Networks;
			for (int i = 0; i < networks.Count; i++)
			{
				for (int j = 0; j < networks[i].Stations.Count; j++)
				{
					ZDOID id2 = networks[i].Stations[j].Id;
					if (((ZDOID)(ref id2)).Equals(id))
					{
						return networks[i];
					}
				}
			}
			return null;
		}

		private static bool IsSafeKey(string key)
		{
			if (string.IsNullOrWhiteSpace(key) || key.Length > 64)
			{
				return false;
			}
			foreach (char c in key)
			{
				if (!char.IsLetterOrDigit(c) && c != '.' && c != '_' && c != '-')
				{
					return false;
				}
			}
			return true;
		}

		private static long GetServerPeerId()
		{
			try
			{
				_getServerPeerId = _getServerPeerId ?? AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", Type.EmptyTypes, (Type[])null);
				object obj = ((_getServerPeerId == null) ? null : _getServerPeerId.Invoke(ZRoutedRpc.instance, null));
				return (obj is long) ? ((long)obj) : 0;
			}
			catch
			{
				return 0L;
			}
		}
	}
	internal static class CoreUtil
	{
		internal static readonly int ItemsHash = Stable("items");

		internal static readonly int InUseHash = Stable("InUse");

		internal static readonly int LegacyInUseHash = Stable("inUse");

		internal static readonly int ReserveHash = Stable("mjnc_reserve");

		internal static readonly int NetworkNameHash = Stable("mjnc_network_name");

		internal static readonly int NetworkIdentityHash = Stable("mjnc_network_id_v2");

		internal static readonly int StorageNetworkIdentityHash = Stable("mjnc_storage_network_id_v2");

		internal static readonly int NetworkStationTypesHash = Stable("mjnc_network_station_types_v2");

		internal static readonly int StorageNetworkEnabledHash = StringExtensionMethods.GetStableHashCode("mjnc_storage_network_enabled");

		private static MethodInfo _forceSend;

		private static FieldInfo _zdoVarsInUse;

		private static FieldInfo _containerInUse;

		private static FieldInfo _inventoryGuiCurrentContainer;

		private static MethodInfo _mucInventoryBlockGet;

		private static MethodInfo _mucInventoryBlockAnyBlocked;

		private static bool _mucResolved;

		private static bool _mucUnavailable;

		internal static int Stable(string value)
		{
			return StringExtensionMethods.GetStableHashCode(value);
		}

		internal static int NetworkSettingHash(string key)
		{
			return Stable("mjnc_net_" + (key ?? string.Empty).Trim().ToLowerInvariant());
		}

		internal static GameObject GetPrefab(ZDO zdo)
		{
			if (zdo == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			try
			{
				return ZNetScene.instance.GetPrefab(zdo.GetPrefab());
			}
			catch
			{
				return null;
			}
		}

		internal static string PrefabName(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return string.Empty;
			}
			string text = ((Object)go).name ?? string.Empty;
			if (!text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				return text;
			}
			return text.Substring(0, text.Length - 7);
		}

		internal static bool IsInUse(ZDO zdo)
		{
			if (zdo == null)
			{
				return false;
			}
			try
			{
				_zdoVarsInUse = _zdoVarsInUse ?? AccessTools.Field(typeof(ZDOVars), "s_inUse");
				if (_zdoVarsInUse != null)
				{
					object value = _zdoVarsInUse.GetValue(null);
					if (value is int && zdo.GetInt((int)value, 0) != 0)
					{
						return true;
					}
				}
			}
			catch
			{
			}
			try
			{
				if (zdo.GetInt(InUseHash, 0) != 0)
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				if (zdo.GetBool(InUseHash, false))
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				if (zdo.GetInt(LegacyInUseHash, 0) != 0)
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				if (zdo.GetBool(LegacyInUseHash, false))
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		internal static bool IsInUse(StorageRef storage)
		{
			if (storage == null)
			{
				return false;
			}
			if (IsInUse(storage.Zdo))
			{
				return true;
			}
			Container val = storage.Container;
			try
			{
				if ((Object)(object)val == (Object)null && (Object)(object)storage.GameObject != (Object)null)
				{
					val = storage.GameObject.GetComponent<Container>() ?? storage.GameObject.GetComponentInChildren<Container>(true);
				}
			}
			catch
			{
			}
			if ((Object)(object)val != (Object)null)
			{
				try
				{
					_containerInUse = _containerInUse ?? AccessTools.Field(typeof(Container), "m_inUse");
					if (_containerInUse != null && (bool)_containerInUse.GetValue(val))
					{
						return true;
					}
				}
				catch
				{
				}
				try
				{
					if ((Object)(object)InventoryGui.instance != (Object)null)
					{
						_inventoryGuiCurrentContainer = _inventoryGuiCurrentContainer ?? AccessTools.Field(typeof(InventoryGui), "m_currentContainer");
						Container val2 = (Container)((_inventoryGuiCurrentContainer == null) ? null : /*isinst with value type is only supported in some contexts*/);
						if ((Object)(object)val2 != (Object)null && val2 == val)
						{
							return true;
						}
					}
				}
				catch
				{
				}
				try
				{
					Inventory inventory = val.GetInventory();
					if (inventory != null && IsMultiUserChestTransactionPending(inventory))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static bool IsMultiUserChestTransactionPending(Inventory inventory)
		{
			if (inventory == null || _mucUnavailable)
			{
				return false;
			}
			try
			{
				Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos;
				if (pluginInfos == null || !pluginInfos.TryGetValue("com.maxsch.valheim.MultiUserChest", out var value) || value == null || (Object)(object)value.Instance == (Object)null)
				{
					return false;
				}
				if (!_mucResolved)
				{
					Type type = ((object)value.Instance).GetType().Assembly.GetType("MultiUserChest.InventoryBlock", throwOnError: false);
					if (type == null)
					{
						_mucUnavailable = true;
						return false;
					}
					_mucInventoryBlockGet = type.GetMethod("Get", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Inventory) }, null);
					_mucInventoryBlockAnyBlocked = type.GetMethod("IsAnySlotBlocked", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					_mucResolved = true;
					if (_mucInventoryBlockGet == null || _mucInventoryBlockAnyBlocked == null)
					{
						_mucUnavailable = true;
						return false;
					}
				}
				object obj = _mucInventoryBlockGet.Invoke(null, new object[1] { inventory });
				if (obj == null)
				{
					return false;
				}
				object obj2 = _mucInventoryBlockAnyBlocked.Invoke(obj, null);
				return obj2 is bool && (bool)obj2;
			}
			catch
			{
				_mucUnavailable = true;
				return false;
			}
		}

		internal static void ForceSend(ZDO zdo)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null || ZDOMan.instance == null)
			{
				return;
			}
			try
			{
				_forceSend = _forceSend ?? AccessTools.Method(typeof(ZDOMan), "ForceSendZDO", new Type[1] { typeof(ZDOID) }, (Type[])null);
				if (_forceSend != null)
				{
					_forceSend.Invoke(ZDOMan.instance, new object[1] { zdo.m_uid });
				}
			}
			catch
			{
			}
		}

		internal static bool EnsureOwnership(StorageRef storage)
		{
			if (storage == null || storage.Zdo == null || IsInUse(storage))
			{
				return false;
			}
			try
			{
				ZNetView val = (((Object)(object)storage.GameObject == (Object)null) ? null : storage.GameObject.GetComponent<ZNetView>());
				if ((Object)(object)val != (Object)null && val.IsValid())
				{
					if (!val.IsOwner())
					{
						val.ClaimOwnership();
					}
					if (!val.IsOwner() && ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()))
					{
						return false;
					}
				}
				return true;
			}
			catch
			{
				return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer();
			}
		}
	}
	public enum StorageKind
	{
		VanillaContainer,
		MakailItemDrawer
	}
	public sealed class StationRef
	{
		public ZDO Zdo { get; internal set; }

		public ZDOID Id { get; internal set; }

		public GameObject GameObject { get; internal set; }

		public CraftingStation Station { get; internal set; }

		public Vector3 Position { get; internal set; }

		public float BuildRange { get; internal set; }

		public string StationName { get; internal set; }

		public string PrefabName { get; internal set; }

		public bool IsLive => (Object)(object)GameObject != (Object)null;

		public bool IsRelay { get; internal set; }
	}
	public sealed class StorageRef
	{
		public ZDO Zdo { get; internal set; }

		public ZDOID Id { get; internal set; }

		public GameObject GameObject { get; internal set; }

		public Container Container { get; internal set; }

		public StorageKind Kind { get; internal set; }

		public Vector3 Position { get; internal set; }

		public string PrefabName { get; internal set; }

		public int NetworkId { get; internal set; }

		public bool RequiresNetworkOptIn { get; internal set; }

		public bool NetworkOptInEnabled
		{
			get
			{
				if (RequiresNetworkOptIn)
				{
					if (Zdo != null)
					{
						return Zdo.GetBool(CoreUtil.StorageNetworkEnabledHash, false);
					}
					return false;
				}
				return true;
			}
		}
	}
	public sealed class TrackedWorldObject
	{
		public ZDO Zdo { get; internal set; }

		public ZDOID Id { get; internal set; }

		public GameObject GameObject { get; internal set; }

		public Vector3 Position { get; internal set; }

		public string PrefabName { get; internal set; }
	}
	public sealed class NetworkInfo
	{
		internal readonly List<StationRef> MutableStations = new List<StationRef>();

		internal readonly List<StorageRef> MutableStorages = new List<StorageRef>();

		internal readonly HashSet<string> KnownStationTypes = new HashSet<string>(StringComparer.Ordinal);

		public int Id { get; internal set; }

		public string Name { get; internal set; }

		public IReadOnlyList<StationRef> Stations => MutableStations;

		public IReadOnlyList<StorageRef> Storages => MutableStorages;

		public int StationCount
		{
			get
			{
				int num = 0;
				foreach (StationRef mutableStation in MutableStations)
				{
					if (mutableStation != null && !mutableStation.IsRelay)
					{
						num++;
					}
				}
				return num;
			}
		}

		public int StorageCount => MutableStorages.Count;

		public int LiveStationCount
		{
			get
			{
				int num = 0;
				for (int i = 0; i < MutableStations.Count; i++)
				{
					if (MutableStations[i] != null && !MutableStations[i].IsRelay && MutableStations[i].IsLive)
					{
						num++;
					}
				}
				return num;
			}
		}

		public int LiveStorageCount
		{
			get
			{
				int num = 0;
				for (int i = 0; i < MutableStorages.Count; i++)
				{
					if (MutableStorages[i] != null && (Object)(object)MutableStorages[i].GameObject != (Object)null)
					{
						num++;
					}
				}
				return num;
			}
		}

		public bool IsLoaded
		{
			get
			{
				if (LiveStationCount <= 0)
				{
					return LiveStorageCount > 0;
				}
				return true;
			}
		}

		public bool ContainsXZ(Vector3 point)
		{
			//IL_0011: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < MutableStations.Count; i++)
			{
				StationRef stationRef = MutableStations[i];
				float num = point.x - stationRef.Position.x;
				float num2 = point.z - stationRef.Position.z;
				float buildRange = stationRef.BuildRange;
				if (num * num + num2 * num2 <= buildRange * buildRange)
				{
					return true;
				}
			}
			return false;
		}
	}
	public sealed class ResourceSnapshot
	{
		private readonly Dictionary<string, int> _total;

		private readonly Dictionary<string, int> _available;

		public IReadOnlyDictionary<string, int> Total => _total;

		public IReadOnlyDictionary<string, int> Available => _available;

		internal ResourceSnapshot(Dictionary<string, int> total, Dictionary<string, int> available)
		{
			_total = total;
			_available = available;
		}

		public int GetTotal(string prefab)
		{
			return GetEquivalent(_total, prefab);
		}

		public int GetAvailable(string prefab)
		{
			return GetEquivalent(_available, prefab);
		}

		private static int GetEquivalent(Dictionary<string, int> map, string prefab)
		{
			if (map == null || string.IsNullOrEmpty(prefab))
			{
				return 0;
			}
			int num = 0;
			foreach (KeyValuePair<string, int> item in map)
			{
				if (StorageApi.AreEquivalentPrefabs(item.Key, prefab))
				{
					num += item.Value;
				}
			}
			return num;
		}
	}
	internal sealed class StorageData
	{
		internal StorageRef Node;

		internal Inventory Inventory;

		internal string DrawerPrefab;

		internal int DrawerQuantity;

		internal bool Dirty;
	}
	internal sealed class UnionFind
	{
		private readonly int[] _parent;

		private readonly byte[] _rank;

		internal UnionFind(int n)
		{
			_parent = new int[n];
			_rank = new byte[n];
			for (int i = 0; i < n; i++)
			{
				_parent[i] = i;
			}
		}

		internal int Find(int x)
		{
			int num = _parent[x];
			if (num != x)
			{
				_parent[x] = Find(num);
			}
			return _parent[x];
		}

		internal void Union(int a, int b)
		{
			int num = Find(a);
			int num2 = Find(b);
			if (num != num2)
			{
				if (_rank[num] < _rank[num2])
				{
					_parent[num] = num2;
					return;
				}
				if (_rank[num] > _rank[num2])
				{
					_parent[num2] = num;
					return;
				}
				_parent[num2] = num;
				_rank[num]++;
			}
		}
	}
	public static class NetworkApi
	{
		private sealed class SnapshotEntry
		{
			internal int Revision;

			internal float At;

			internal ResourceSnapshot Snapshot;
		}

		public delegate void ReadOnlyResourceProvider(NetworkInfo network, IDictionary<string, int> total);

		private sealed class PlannedTake
		{
			internal StorageRef Storage;

			internal string Prefab;

			internal int Amount;
		}

		private static NetworkRegistry _registry;

		private static CoreConfig _settings;

		private static readonly Dictionary<int, SnapshotEntry> Snapshots = new Dictionary<int, SnapshotEntry>();

		private static readonly List<ReadOnlyResourceProvider> ReadOnlyProviders = new List<ReadOnlyResourceProvider>();

		public const string AutoStorageEnabledSetting = "autostorage.enabled";

		private static readonly Dictionary<string, string> InventoryNamePrefabCache = new Dictionary<string, string>(StringComparer.Ordinal);

		public static int Revision
		{
			get
			{
				if (_registry != null)
				{
					return _registry.Revision;
				}
				return 0;
			}
		}

		public static IReadOnlyList<NetworkInfo> Networks
		{
			get
			{
				if (_registry != null)
				{
					return _registry.Networks;
				}
				return new NetworkInfo[0];
			}
		}

		public static IEnumerable<StorageRef> Storages
		{
			get
			{
				if (_registry != null)
				{
					return _registry.Storages;
				}
				return new StorageRef[0];
			}
		}

		public static IEnumerable<TrackedWorldObject> ActiveGroundDrops
		{
			get
			{
				if (_registry != null)
				{
					return _registry.GroundDrops;
				}
				return new TrackedWorldObject[0];
			}
		}

		public static IEnumerable<TrackedWorldObject> ActiveCreatures
		{
			get
			{
				if (_registry != null)
				{
					return _registry.Creatures;
				}
				return new TrackedWorldObject[0];
			}
		}

		public static IEnumerable<TrackedWorldObject> ActiveMachines
		{
			get
			{
				if (_registry != null)
				{
					return _registry.Machines;
				}
				return new TrackedWorldObject[0];
			}
		}

		public static event Action NetworksChanged;

		public static event Action<TrackedWorldObject> GroundDropRegistered;

		public static event Action<TrackedWorldObject> CreatureRegistered;

		public static event Action<TrackedWorldObject> MachineRegistered;

		public static event Action<NetworkInfo> NetworkRenameRequested;

		public static event Action<ZDOID> StationDestroyed;

		internal static void Initialize(NetworkRegistry registry, CoreConfig settings)
		{
			_registry = registry;
			_settings = settings;
			registry.DropRegistered += delegate(TrackedWorldObject o)
			{
				if (NetworkApi.GroundDropRegistered != null)
				{
					NetworkApi.GroundDropRegistered(o);
				}
			};
			registry.CreatureRegistered += delegate(TrackedWorldObject o)
			{
				if (NetworkApi.CreatureRegistered != null)
				{
					NetworkApi.CreatureRegistered(o);
				}
			};
			registry.MachineRegistered += delegate(TrackedWorldObject o)
			{
				if (NetworkApi.MachineRegistered != null)
				{
					NetworkApi.MachineRegistered(o);
				}
			};
		}

		internal static void Shutdown()
		{
			Snapshots.Clear();
		}

		internal static void RaiseStationDestroyed(ZDOID id)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkApi.StationDestroyed != null)
			{
				NetworkApi.StationDestroyed(id);
			}
		}

		public static NetworkInfo GetNetworkForStation(CraftingStation station)
		{
			if (_registry != null)
			{
				return _registry.FindForStation(station);
			}
			return null;
		}

		public static NetworkInfo GetNetworkAt(Vector3 position)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (_registry != null)
			{
				return _registry.FindForPosition(position);
			}
			return null;
		}

		public static NetworkInfo GetNetworkForBuildPiece(Piece piece, Vector3 position)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (_registry != null)
			{
				return _registry.FindForBuildPiece(piece, position);
			}
			return null;
		}

		public static NetworkInfo GetNetworkById(int id)
		{
			IReadOnlyList<NetworkInfo> networks = Networks;
			for (int i = 0; i < networks.Count; i++)
			{
				if (networks[i].Id == id)
				{
					return networks[i];
				}
			}
			return null;
		}

		public static void RegisterReadOnlyResourceProvider(ReadOnlyResourceProvider provider)
		{
			if (provider != null && !ReadOnlyProviders.Contains(provider))
			{
				ReadOnlyProviders.Add(provider);
				InvalidateSnapshots();
			}
		}

		public static void UnregisterReadOnlyResourceProvider(ReadOnlyResourceProvider provider)
		{
			if (provider != null && ReadOnlyProviders.Remove(provider))
			{
				InvalidateSnapshots();
			}
		}

		public static bool GetNetworkBool(NetworkInfo network, string key, bool defaultValue)
		{
			if (network == null || string.IsNullOrWhiteSpace(key))
			{
				return defaultValue;
			}
			int num = CoreUtil.NetworkSettingHash(key);
			bool flag = false;
			for (int i = 0; i < network.Stations.Count; i++)
			{
				ZDO zdo = network.Stations[i].Zdo;
				if (zdo != null)
				{
					switch (zdo.GetInt(num, int.MinValue))
					{
					case 0:
						return false;
					case int.MinValue:
						continue;
					}
					flag = true;
				}
			}
			if (!flag)
			{
				return defaultValue;
			}
			return true;
		}

		public static void SetNetworkBool(NetworkInfo network, string key, bool value)
		{
			if (network != null && !string.IsNullOrWhiteSpace(key))
			{
				CoreRpc.SetNetworkBool(network, key, value);
			}
		}

		public static List<StorageRef> GetStoragesNearest(NetworkInfo network, Vector3 origin)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			List<StorageRef> list = new List<StorageRef>();
			if (network == null)
			{
				return list;
			}
			for (int i = 0; i < network.MutableStorages.Count; i++)
			{
				list.Add(network.MutableStorages[i]);
			}
			list.Sort((StorageRef a, StorageRef b) => SqrXZ(a.Position, origin).CompareTo(SqrXZ(b.Position, origin)));
			return list;
		}

		public static List<StorageRef> GetStoragesNear(Vector3 origin, float range)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			float num = range * range;
			List<StorageRef> list = new List<StorageRef>();
			foreach (StorageRef storage in Storages)
			{
				if (SqrXZ(storage.Position, origin) <= num)
				{
					list.Add(storage);
				}
			}
			list.Sort((StorageRef a, StorageRef b) => SqrXZ(a.Position, origin).CompareTo(SqrXZ(b.Position, origin)));
			return list;
		}

		public static int GetAvailableForInventoryName(NetworkInfo network, string inventoryName)
		{
			if (network == null || string.IsNullOrEmpty(inventoryName))
			{
				return 0;
			}
			ResourceSnapshot snapshot = GetSnapshot(network);
			int available = snapshot.GetAvailable(inventoryName);
			if (available > 0)
			{
				return available;
			}
			string text = ResolvePrefabNameFromInventoryName(inventoryName);
			if (!string.IsNullOrEmpty(text))
			{
				return snapshot.GetAvailable(text);
			}
			return 0;
		}

		private static string ResolvePrefabNameFromInventoryName(string inventoryName)
		{
			if (InventoryNamePrefabCache.TryGetValue(inventoryName, out var value))
			{
				return value;
			}
			string text = string.Empty;
			try
			{
				ObjectDB instance = ObjectDB.instance;
				if ((Object)(object)instance != (Object)null)
				{
					FieldInfo field = typeof(ObjectDB).GetField("m_items", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					IEnumerable enumerable = ((field == null) ? null : (field.GetValue(instance) as IEnumerable));
					if (enumerable != null)
					{
						foreach (object item in enumerable)
						{
							GameObject val = (GameObject)((item is GameObject) ? item : null);
							if (!((Object)(object)val == (Object)null))
							{
								string text2 = CoreUtil.PrefabName(val);
								if (string.Equals(text2, inventoryName, StringComparison.Ordinal))
								{
									text = text2;
									break;
								}
								ItemDrop component = val.GetComponent<ItemDrop>();
								if (string.Equals(((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) ? string.Empty : component.m_itemData.m_shared.m_name, inventoryName, StringComparison.Ordinal))
								{
									text = text2;
									break;
								}
							}
						}
					}
				}
			}
			catch
			{
			}
			InventoryNamePrefabCache[inventoryName] = text;
			return text;
		}

		public static ResourceSnapshot GetSnapshot(NetworkInfo network)
		{
			if (network == null)
			{
				return EmptySnapshot();
			}
			float unscaledTime = Time.unscaledTime;
			float num = ((_settings == null) ? 0.25f : Mathf.Max(0.02f, _settings.SnapshotSeconds.Value));
			if (Snapshots.TryGetValue(network.Id, out var value) && value.Revision == Revision && unscaledTime - value.At <= num)
			{
				return value.Snapshot;
			}
			Dictionary<string, int> total = new Dictionary<string, int>(StringComparer.Ordinal);
			Dictionary<string, int> available = new Dictionary<string, int>(StringComparer.Ordinal);
			for (int i = 0; i < network.MutableStorages.Count; i++)
			{
				StorageApi.TryAccumulateSnapshot(network.MutableStorages[i], total, available);
			}
			for (int j = 0; j < ReadOnlyProviders.Count; j++)
			{
				ReadOnlyResourceProvider readOnlyResourceProvider = ReadOnlyProviders[j];
				if (readOnlyResourceProvider != null)
				{
					try
					{
						readOnlyResourceProvider(network, total);
					}
					catch (Exception ex)
					{
						Plugin.LogWarning("Read-only resource provider failed: " + ex.Message);
					}
				}
			}
			ResourceSnapshot resourceSnapshot = new ResourceSnapshot(total, available);
			Snapshots[network.Id] = new SnapshotEntry
			{
				Revision = Revision,
				At = unscaledTime,
				Snapshot = resourceSnapshot
			};
			return resourceSnapshot;
		}

		public static bool CanWithdraw(NetworkInfo network, IDictionary<string, int> wanted)
		{
			if (network == null || wanted == null)
			{
				return false;
			}
			ResourceSnapshot snapshot = GetSnapshot(network);
			foreach (KeyValuePair<string, int> item in wanted)
			{
				if (item.Value > 0 && snapshot.GetAvailable(item.Key) < item.Value)
				{
					return false;
				}
			}
			return true;
		}

		public static bool TryWithdraw(NetworkInfo network, IDictionary<string, int> wanted, Vector3 origin, out string reason)
		{
			//IL_0033: 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_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			reason = string.Empty;
			if (network == null)
			{
				reason = "no network";
				return false;
			}
			if (wanted == null || wanted.Count == 0)
			{
				return true;
			}
			if (!CanWithdraw(network, wanted))
			{
				reason = "not enough available stock after reserve";
				return false;
			}
			List<StorageRef> storagesNearest = GetStoragesNearest(network, origin);
			Dictionary<ZDOID, StorageData> dictionary = new Dictionary<ZDOID, StorageData>();
			List<PlannedTake> list = new List<PlannedTake>();
			HashSet<ZDOID> hashSet = new HashSet<ZDOID>();
			foreach (KeyValuePair<string, int> item in wanted)
			{
				int num = Math.Max(0, item.Value);
				if (num <= 0)
				{
					continue;
				}
				for (int i = 0; i < storagesNearest.Count && num > 0; i++)
				{
					StorageRef storageRef = storagesNearest[i];
					if (!dictionary.TryGetValue(storageRef.Id, out var value))
					{
						if (!StorageApi.TryLoad(storageRef, out value))
						{
							continue;
						}
						dictionary[storageRef.Id] = value;
					}
					int num2 = Math.Max(0, StorageApi.Count(value, item.Key) - StorageApi.GetReserve(storageRef));
					if (num2 > 0)
					{
						int num3 = Math.Min(num2, num);
						list.Add(new PlannedTake
						{
							Storage = storageRef,
							Prefab = item.Key,
							Amount = num3
						});
						hashSet.Add(storageRef.Id);
						num -= num3;
					}
				}
				if (num > 0)
				{
					reason = "stock changed during preflight";
					return false;
				}
			}
			foreach (ZDOID item2 in hashSet)
			{
				if (!dictionary.TryGetValue(item2, out var value2) || value2 == null || value2.Node == null)
				{
					reason = "planned container vanished";
					return false;
				}
				if (!CoreUtil.EnsureOwnership(value2.Node))
				{
					reason = "container busy or ownership unavailable";
					return false;
				}
			}
			Dictionary<ZDOID, StorageData> dictionary2 = new Dictionary<ZDOID, StorageData>();
			foreach (ZDOID item3 in hashSet)
			{
				if (!dictionary.TryGetValue(item3, out var value3) || value3 == null || value3.Node == null)
				{
					reason = "planned container vanished";
					return false;
				}
				if (!StorageApi.TryLoad(value3.Node, out var data))
				{
					reason = "container became busy or unreadable";
					return false;
				}
				dictionary2[item3] = data;
			}
			Dictionary<string, int> dictionary3 = new Dictionary<string, int>(StringComparer.Ordinal);
			Dictionary<string, int> dictionary4 = new Dictionary<string, int>(StringComparer.Ordinal);
			for (int j = 0; j < list.Count; j++)
			{
				PlannedTake plannedTake = list[j];
				string key = PlanKey(plannedTake.Storage.Id, plannedTake.Prefab);
				dictionary3.TryGetValue(key, out var value4);
				dictionary3[key] = value4 + plannedTake.Amount;
			}
			foreach (KeyValuePair<ZDOID, StorageData> item4 in dictionary2)
			{
				foreach (PlannedTake item5 in list)
				{
					ZDOID id = item5.Storage.Id;
					if (((ZDOID)(ref id)).Equals(item4.Key))
					{
						string key2 = PlanKey(item4.Key, item5.Prefab);
						if (!dictionary4.ContainsKey(key2))
						{
							dictionary4[key2] = Math.Max(0, StorageApi.Count(item4.Value, item5.Prefab) - StorageApi.GetReserve(item4.Value.Node));
						}
					}
				}
			}
			foreach (KeyValuePair<string, int> item6 in dictionary3)
			{
				dictionary4.TryGetValue(item6.Key, out var value5);
				if (value5 < item6.Value)
				{
					reason = "container changed while acquiring ownership";
					return false;
				}
			}
			for (int k = 0; k < list.Count; k++)
			{
				PlannedTake plannedTake2 = list[k];
				if (!dictionary2.TryGetValue(plannedTake2.Storage.Id, out var value6))
				{
					reason = "transaction storage missing";
					return false;
				}
				if (StorageApi.RemoveAvailable(value6, plannedTake2.Prefab, plannedTake2.Amount) != plannedTake2.Amount)
				{
					reason = "unexpected removal mismatch";
					return false;
				}
			}
			foreach (StorageData value7 in dictionary2.Values)
			{
				StorageApi.Save(value7);
			}
			InvalidateSnapshots();
			return true;
		}

		private unsafe static string PlanKey(ZDOID id, string prefab)
		{
			return ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).ToString() + "|" + (prefab ?? string.Empty);
		}

		private static ResourceSnapshot EmptySnapshot()
		{
			return new ResourceSnapshot(new Dictionary<string, int>(), new Dictionary<string, int>());
		}

		public static string GetNetworkName(NetworkInfo network)
		{
			if (network == null || string.IsNullOrWhiteSpace(network.Name))
			{
				return "Sonstige";
			}
			return network.Name;
		}

		public static void SetNetworkName(NetworkInfo network, string name)
		{
			if (network != null)
			{
				CoreRpc.SetNetworkName(network, name ?? string.Empty);
			}
		}

		public static void InvalidateSnapshots()
		{
			Snapshots.Clear();
		}

		internal static void RaiseNetworksChanged()
		{
			if (NetworkApi.NetworksChanged != null)
			{
				NetworkApi.NetworksChanged();
			}
		}

		public static bool RequestNetworkRename(NetworkInfo network)
		{
			if (network == null || NetworkApi.NetworkRenameRequested == null)
			{
				return false;
			}
			NetworkApi.NetworkRenameRequested(network);
			return true;
		}

		private static Dictionary<string, int> CountLocal(List<ItemData> items)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			for (int i = 0; i < items.Count; i++)
			{
				string prefabName = StorageApi.GetPrefabName(items[i]);
				if (!string.IsNullOrEmpty(prefabName))
				{
					Add(dictionary, prefabName, items[i].m_stack);
				}
			}
			return dictionary;
		}

		private static void Add(Dictionary<string, int> d, string key, int amount)
		{
			if (amount > 0 && !string.IsNullOrEmpty(key))
			{
				d.TryGetValue(key, out var value);
				d[key] = value + amount;
			}
		}

		private static float SqrXZ(Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			float num = a.x - b.x;
			float num2 = a.z - b.z;
			return num * num + num2 * num2;
		}
	}
	internal sealed class NetworkRegistry
	{
		private readonly Dictionary<ZDOID, StationRef> _stations = new Dictionary<ZDOID, StationRef>();

		private readonly Dictionary<ZDOID, StorageRef> _storages = new Dictionary<ZDOID, StorageRef>();

		private readonly Dictionary<ZDOID, TrackedWorldObject> _drops = new Dictionary<ZDOID, TrackedWorldObject>();

		private readonly Dictionary<ZDOID, TrackedWorldObject> _creatures = new Dictionary<ZDOID, TrackedWorldObject>();

		private readonly Dictionary<ZDOID, TrackedWorldObject> _machines = new Dictionary<ZDOID, TrackedWorldObject>();

		private readonly List<NetworkInfo> _networks = new List<NetworkInfo>();

		private readonly Dictionary<int, NetworkInfo> _byId = new Dictionary<int, NetworkInfo>();

		private readonly Dictionary<ZDOID, NetworkInfo> _byStation = new Dictionary<ZDOID, NetworkInfo>();

		private readonly HashSet<int> _splitPendingNetworkIds = new HashSet<int>();

		private bool _dirty = true;

		private float _lastDirtyAt;

		private int _revision;

		private static MethodInfo _getExtensionCount;

		private static FieldInfo _extraRangePerLevel;

		private static FieldInfo _rangeBuild;

		private static MethodInfo _getStationBuildRange;

		private static FieldInfo _creatorHashField;

		private static int? _creatorHash;

		internal int Revision => _revision;

		internal IReadOnlyList<NetworkInfo> Networks => _networks;

		internal IEnumerable<StorageRef> Storages => _storages.Values;

		internal IEnumerable<TrackedWorldObject> GroundDrops => _drops.Values;

		internal IEnumerable<TrackedWorldObject> Creatures => _creatures.Values;

		internal IEnumerable<TrackedWorldObject> Machines => _machines.Values;

		internal event Action<TrackedWorldObject> DropRegistered;

		internal event Action<TrackedWorldObject> CreatureRegistered;

		internal event Action<TrackedWorldObject> MachineRegistered;

		internal void Reset()
		{
			_stations.Clear();
			_storages.Clear();
			_drops.Clear();
			_creatures.Clear();
			_machines.Clear();
			_networks.Clear();
			_byId.Clear();
			_byStation.Clear();
			_splitPendingNetworkIds.Clear();
			_dirty = true;
			_lastDirtyAt = Time.unscaledTime;
			_revision++;
			NetworkApi.InvalidateSnapshots();
		}

		internal void Register(ZDO zdo, GameObject instance)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null || (Object)(object)instance == (Object)null)
			{
				return;
			}
			GameObject val = CoreUtil.GetPrefab(zdo) ?? instance;
			Vector3 position;
			try
			{
				position = zdo.GetPosition();
			}
			catch
			{
				position = instance.transform.position;
			}
			ZDOID uid = zdo.m_uid;
			bool flag = false;
			bool num = Plugin.Settings == null || !Plugin.Settings.PlayerBuiltOnly.Value || IsPlayerBuilt(zdo);
			string text = CoreUtil.PrefabName(val);
			CraftingStation val2 = FindStationComponent(instance);
			CraftingStation val3 = FindStationComponent(val);
			bool flag2 = string.Equals(text, "piece_mj_network_relay", StringComparison.OrdinalIgnoreCase);
			CraftingStation station;
			float num2;
			string text2;
			StationRef value;
			Vector3 val4;
			if (num && (flag2 || (Object)(object)val3 != (Object)null || (Object)(object)val2 != (Object)null))
			{
				station = (flag2 ? null : (val2 ?? val3));
				num2 = (flag2 ? 15f : GetBuildRange(station));
				text2 = (flag2 ? string.Empty : GetStationName(station));
				if (!_stations.TryGetValue(uid, out value))
				{
					value = new StationRef();
					_stations[uid] = value;
					flag = true;
				}
				else
				{
					if (value.GameObject == instance)
					{
						val4 = value.Position - position;
						if (!(((Vector3)(ref val4)).sqrMagnitude > 0.0001f) && !(Mathf.Abs(value.BuildRange - num2) > 0.001f) && string.Equals(value.StationName, text2, StringComparison.Ordinal))
						{
							goto IL_0155;
						}
					}
					flag = true;
				}
				goto IL_0155;
			}
			goto IL_01a2;
			IL_02ea:
			StorageRef value2;
			value2.Zdo = zdo;
			value2.Id = uid;
			value2.GameObject = instance;
			Container val5;
			value2.Container = val5;
			StorageKind storageKind;
			value2.Kind = storageKind;
			value2.Position = position;
			value2.PrefabName = text;
			bool flag3;
			value2.RequiresNetworkOptIn = flag3;
			goto IL_032e;
			IL_0155:
			value.Zdo = zdo;
			value.Id = uid;
			value.GameObject = instance;
			value.Station = station;
			value.Position = position;
			value.BuildRange = num2;
			value.IsRelay = flag2;
			value.StationName = text2;
			value.PrefabName = text;
			goto IL_01a2;
			IL_01a2:
			flag3 = IsIncinerator(text, instance, val);
			val5 = instance.GetComponent<Container>();
			Container val6 = val.GetComponent<Container>();
			if (flag3)
			{
				if ((Object)(object)val5 == (Object)null)
				{
					val5 = instance.GetComponentInChildren<Container>(true);
				}
				if ((Object)(object)val6 == (Object)null)
				{
					val6 = val.GetComponentInChildren<Container>(true);
				}
			}
			bool flag4 = IsMakailDrawer(text);
			bool flag5 = (Object)(object)val.GetComponent<TombStone>() != (Object)null || (Object)(object)instance.GetComponent<TombStone>() != (Object)null;
			Piece val7 = val.GetComponent<Piece>() ?? instance.GetComponent<Piece>();
			if (num && !flag5 && ((Object)(object)val5 != (Object)null || (Object)(object)val6 != (Object)null) && ((Object)(object)val7 != (Object)null || flag4))
			{
				storageKind = (flag4 ? StorageKind.MakailItemDrawer : StorageKind.VanillaContainer);
				if (!_storages.TryGetValue(uid, out value2))
				{
					value2 = new StorageRef();
					value2.NetworkId = zdo.GetInt(CoreUtil.StorageNetworkIdentityHash, -1);
					_storages[uid] = value2;
					flag = true;
				}
				else
				{
					if (value2.GameObject == instance)
					{
						val4 = value2.Position - position;
						if (!(((Vector3)(ref val4)).sqrMagnitude > 0.0001f) && value2.Kind == storageKind && string.Equals(value2.PrefabName, text, StringComparison.Ordinal) && value2.RequiresNetworkOptIn == flag3)
						{
							goto IL_02ea;
						}
					}
					flag = true;
				}
				goto IL_02ea;
			}
			goto IL_032e;
			IL_032e:
			bool num3 = (Object)(object)val.GetComponent<ItemDrop>() != (Object)null || (Object)(object)instance.GetComponent<ItemDrop>() != (Object)null;
			bool flag6 = (Object)(object)(instance.GetComponent<Fish>() ?? val.GetComponent<Fish>()) != (Object)null;
			if (num3 && !flag6)
			{
				TrackedWorldObject trackedWorldObject = MakeTracked(zdo, instance, val, position);
				bool num4 = !_drops.ContainsKey(uid);
				_drops[uid] = trackedWorldObject;
				if (num4 && this.DropRegistered != null)
				{
					this.DropRegistered(trackedWorldObject);
				}
			}
			else if (flag6)
			{
				_drops.Remove(uid);
			}
			Tameable obj2 = instance.GetComponent<Tameable>() ?? val.GetComponent<Tameable>();
			MonsterAI val8 = instance.GetComponent<MonsterAI>() ?? val.GetComponent<MonsterAI>();
			if ((Object)(object)obj2 != (Object)null && (Object)(object)val8 != (Object)null)
			{
				TrackedWorldObject trackedWorldObject2 = MakeTracked(zdo, instance, val, position);
				bool num5 = !_creatures.ContainsKey(uid);
				_creatures[uid] = trackedWorldObject2;
				if (num5 && this.CreatureRegistered != null)
				{
					this.CreatureRegistered(trackedWorldObject2);
				}
			}
			if ((Object)(object)(instance.GetComponent<Smelter>() ?? val.GetComponent<Smelter>()) != (Object)null || (Object)(object)(instance.GetComponent<Fireplace>() ?? val.GetComponent<Fireplace>()) != (Object)null || (Object)(object)(instance.GetComponent<CookingStation>() ?? val.GetComponent<CookingStation>()) != (Object)null || (Object)(object)(instance.GetComponent<Fermenter>() ?? val.GetComponent<Fermenter>()) != (Object)null || (Object)(object)(instance.GetComponent<ShieldGenerator>() ?? val.GetComponent<ShieldGenerator>()) != (Object)null)
			{
				TrackedWorldObject trackedWorldObject3 = MakeTracked(zdo, instance, val, position);
				bool num6 = !_machines.ContainsKey(uid);
				_machines[uid] = trackedWorldObject3;
				if (num6 && this.MachineRegistered != null)
				{
					this.MachineRegistered(trackedWorldObject3);
				}
			}
			if (flag)
			{
				MarkDirty();
			}
		}

		internal void Unregister(ZDOID id, GameObject instance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (_stations.TryGetValue(id, out var value) && ((Object)(object)instance == (Object)null || value.GameObject == instance))
			{
				value.GameObject = null;
				value.Station = null;
			}
			if (_storages.TryGetValue(id, out var value2) && ((Object)(object)instance == (Object)null || value2.GameObject == instance))
			{
				value2.GameObject = null;
				value2.Container = null;
			}
			if (_drops.TryGetValue(id, out var value3) && ((Object)(object)instance == (Object)null || value3.GameObject == instance))
			{
				_drops.Remove(id);
			}
			if (_creatures.TryGetValue(id, out value3) && ((Object)(object)instance == (Object)null || value3.GameObject == instance))
			{
				_creatures.Remove(id);
			}
			if (_machines.TryGetValue(id, out value3) && ((Object)(object)instance == (Object)null || value3.GameObject == instance))
			{
				_machines.Remove(id);
			}
		}

		internal void ForgetDestroyed(ZDOID id)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			bool flag2 = false;
			int num = 0;
			if (_stations.TryGetValue(id, out var value))
			{
				flag2 = true;
				try
				{
					if (value.Zdo != null)
					{
						num = value.Zdo.GetInt(CoreUtil.NetworkIdentityHash, 0);
					}
				}
				catch
				{
				}
				flag |= _stations.Remove(id);
			}
			if (_storages.TryGetValue(id, out var _))
			{
				flag |= _storages.Remove(id);
			}
			_drops.Remove(id);
			_creatures.Remove(id);
			_machines.Remove(id);
			if (num > 0)
			{
				_splitPendingNetworkIds.Add(num);
			}
			if (flag2)
			{
				NetworkApi.RaiseStationDestroyed(id);
			}
			if (flag)
			{
				MarkDirty();
			}
		}

		internal void ForgetDrop(ZDOID id)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			_drops.Remove(id);
		}

		internal void MarkDirty()
		{
			_dirty = true;
			_lastDirtyAt = Time.unscaledTime;
			NetworkApi.InvalidateSnapshots();
		}

		internal void RebuildIfDirty(float now)
		{
			if (_dirty)
			{
				float num = ((Plugin.Settings == null) ? 0.2f : Mathf.Max(0f, Plugin.Settings.RebuildDebounceSeconds.Value));
				if (!(now - _lastDirtyAt < num))
				{
					Rebuild();
				}
			}
		}

		internal NetworkInfo FindForStation(CraftingStation station)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)station == (Object)null)
			{
				return null;
			}
			try
			{
				ZNetView val = ((Component)station).GetComponent<ZNetView>() ?? ((Component)station).GetComponentInParent<ZNetView>();
				ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null);
				if (val2 != null && _byStation.TryGetValue(val2.m_uid, out var value))
				{
					return value;
				}
			}
			catch
			{
			}
			return FindForPosition(((Component)station).transform.position);
		}

		internal NetworkInfo FindForPosition(Vector3 point)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			NetworkInfo result = null;
			float num = float.MaxValue;
			for (int i = 0; i < _networks.Count; i++)
			{
				NetworkInfo networkInfo = _networks[i];
				if (!networkInfo.ContainsXZ(point))
				{
					continue;
				}
				for (int j = 0; j < networkInfo.MutableStations.Count; j++)
				{
					Vector3 position = networkInfo.MutableStations[j].Position;
					float num2 = position.x - point.x;
					float num3 = position.z - point.z;
					float num4 = num2 * num2 + num3 * num3;
					if (num4 < num)
					{
						num = num4;
						result = networkInfo;
					}
				}
			}
			return result;
		}

		internal NetworkInfo FindForBuildPiece(Piece piece, Vector3 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			NetworkInfo networkInfo = FindForPosition(point);
			if ((Object)(object)piece == (Object)null)
			{
				return networkInfo;
			}
			CraftingStation craftingStation = piece.m_craftingStation;
			if ((Object)(object)craftingStation == (Object)null)
			{
				return networkInfo;
			}
			if (networkInfo == null)
			{
				return null;
			}
			if (!SupportsStation(networkInfo, GetStationName(craftingStation)))
			{
				return null;
			}
			return networkInfo;
		}

		internal bool SupportsStation(NetworkInfo network, string wanted)
		{
			if (network == null || string.IsNullOrEmpty(wanted))
			{
				return false;
			}
			string text = NormalizeStationKey(wanted);
			if (text.Length == 0)
			{
				return false;
			}
			if (network.KnownStationTypes.Contains(text))
			{
				return true;
			}
			for (int i = 0; i < network.MutableStations.Count; i++)
			{
				if (StationMatchesName(network.MutableStations[i], wanted))
				{
					return true;
				}
			}
			return false;
		}

		internal CraftingStation FindRepresentativeStation(NetworkInfo network, string wanted)
		{
			if (network == null || !SupportsStation(network, wanted))
			{
				return null;
			}
			for (int i = 0; i < network.MutableStations.Count; i++)
			{
				StationRef stationRef = network.MutableStations[i];
				if (!StationMatchesName(stationRef, wanted))
				{
					continue;
				}
				if ((Object)(object)stationRef.Station != (Object)null)
				{
					return stationRef.Station;
				}
				try
				{
					CraftingStation val = FindStationComponent((stationRef.Zdo == null) ? null : CoreUtil.GetPrefab(stationRef.Zdo));
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
				catch
				{
				}
			}
			try
			{
				string text = NormalizeStationKey(wanted);
				CraftingStation[] array = Resources.FindObjectsOfTypeAll<CraftingStation>();
				foreach (CraftingStation val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null) && (NormalizeStationKey(GetStationName(val2)) == text || NormalizeStationKey(CoreUtil.PrefabName(((Component)val2).gameObject)) == text))
					{
						return val2;
					}
				}
			}
			catch
			{
			}
			for (int k = 0; k < network.MutableStations.Count; k++)
			{
				if (network.MutableStations[k] != null && (Object)(object)network.MutableStations[k].Station != (Object)null)
				{
					return network.MutableStations[k].Station;
				}
			}
			return null;
		}

		private void Rebuild()
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_058f: Unknown result type (might be due to invalid IL or missing references)
			//IL_059b: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			_dirty = false;
			_networks.Clear();
			_byId.Clear();
			_byStation.Clear();
			List<StationRef> list = new List<StationRef>(_stations.Values);
			for (int i = 0; i < list.Count; i++)
			{
				StationRef stationRef = list[i];
				if (stationRef == null)
				{
					continue;
				}
				if ((Object)(object)stationRef.Station != (Object)null)
				{
					stationRef.BuildRange = GetBuildRange(stationRef.Station);
					stationRef.StationName = GetStationName(stationRef.Station);
					if ((Object)(object)stationRef.GameObject != (Object)null)
					{
						stationRef.PrefabName = CoreUtil.PrefabName(stationRef.GameObject);
					}
				}
				if (stationRef.BuildRange <= 0f)
				{
					stationRef.BuildRange = 20f;
				}
			}
			UnionFind unionFind = new UnionFind(list.Count);
			for (int j = 0; j < list.Count; j++)
			{
				for (int k = j + 1; k < list.Count; k++)
				{
					StationRef stationRef2 = list[j];
					StationRef stationRef3 = list[k];
					float num = stationRef2.Position.x - stationRef3.Position.x;
					float num2 = stationRef2.Position.z - stationRef3.Position.z;
					float num3 = stationRef2.BuildRange + stationRef3.BuildRange;
					if (num * num + num2 * num2 <= num3 * num3)
					{
						unionFind.Union(j, k);
					}
				}
			}
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			for (int l = 0; l < list.Count; l++)
			{
				int num4 = ReadInt((list[l] == null) ? null : list[l].Zdo, CoreUtil.NetworkIdentityHash, 0);
				if (num4 > 0 && !_splitPendingNetworkIds.Contains(num4))
				{
					if (dictionary.TryGetValue(num4, out var value))
					{
						unionFind.Union(value, l);
					}
					else
					{
						dictionary[num4] = l;
					}
				}
			}
			Dictionary<int, List<StationRef>> dictionary2 = new Dictionary<int, List<StationRef>>();
			for (int m = 0; m < list.Count; m++)
			{
				int key = unionFind.Find(m);
				if (!dictionary2.TryGetValue(key, out var value2))
				{
					value2 = (dictionary2[key] = new List<StationRef>());
				}
				value2.Add(list[m]);
			}
			List<List<StationRef>> list3 = new List<List<StationRef>>(dictionary2.Values);
			list3.Sort((List<StationRef> a, List<StationRef> b) => string.CompareOrdinal(SmallestStationKey(a), SmallestStationKey(b)));
			HashSet<int> hashSet = new HashSet<int>();
			for (int num5 = 0; num5 < list3.Count; num5++)
			{
				List<StationRef> list4 = list3[num5];
				bool flag = false;
				for (int num6 = 0; num6 < list4.Count; num6++)
				{
					if (list4[num6] != null && !list4[num6].IsRelay)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					continue;
				}
				int num7 = ChoosePersistentNetworkId(list4);
				if (num7 <= 0 || hashSet.Contains(num7))
				{
					num7 = DeriveUniqueNetworkId(list4, hashSet);
				}
				hashSet.Add(num7);
				NetworkInfo networkInfo = new NetworkInfo
				{
					Id = num7,
					Name = string.Empty
				};
				_networks.Add(networkInfo);
				_byId[num7] = networkInfo;
				for (int num8 = 0; num8 < list4.Count; num8++)
				{
					StationRef stationRef4 = list4[num8];
					if (stationRef4 != null)
					{
						networkInfo.MutableStations.Add(stationRef4);
						_byStation[stationRef4.Id] = networkInfo;
						if (!stationRef4.IsRelay)
						{
							AddStationType(networkInfo.KnownStationTypes, stationRef4.StationName);
							AddStationType(networkInfo.KnownStationTypes, stationRef4.PrefabName);
							AddPersistedStationTypes(networkInfo.KnownStationTypes, stationRef4.Zdo);
						}
					}
				}
				string text = SerializeStationTypes(networkInfo.KnownStationTypes);
				if (!CanPersistMetadata())
				{
					continue;
				}
				for (int num9 = 0; num9 < list4.Count; num9++)
				{
					StationRef stationRef5 = list4[num9];
					if (stationRef5 == null || stationRef5.Zdo == null)
					{
						continue;
					}
					try
					{
						bool flag2 = false;
						if (stationRef5.Zdo.GetInt(CoreUtil.NetworkIdentityHash, 0) != num7)
						{
							stationRef5.Zdo.Set(CoreUtil.NetworkIdentityHash, num7, false);
							flag2 = true;
						}
						if (!string.Equals(stationRef5.Zdo.GetString(CoreUtil.NetworkStationTypesHash, string.Empty), text, StringComparison.Ordinal))
						{
							stationRef5.Zdo.Set(CoreUtil.NetworkStationTypesHash, text);
							flag2 = true;
						}
						if (flag2)
						{
							CoreUtil.ForceSend(stationRef5.Zdo);
						}
					}
					catch
					{
					}
				}
			}
			for (int num10 = 0; num10 < _networks.Count; num10++)
			{
				_networks[num10].Name = ResolveName(_networks[num10]);
			}
			float num11 = ((Plugin.Settings == null) ? 0f : Mathf.Max(0f, Plugin.Settings.StorageAttachExtraRange.Value));
			foreach (StorageRef value4 in _storages.Values)
			{
				if (value4 == null)
				{
					continue;
				}
				value4.NetworkId = -1;
				if (value4.RequiresNetworkOptIn && !value4.NetworkOptInEnabled)
				{
					continue;
				}
				NetworkInfo value3 = null;
				float num12 = float.MaxValue;
				for (int num13 = 0; num13 < _networks.Count; num13++)
				{
					NetworkInfo networkInfo2 = _networks[num13];
					for (int num14 = 0; num14 < networkInfo2.MutableStations.Count; num14++)
					{
						StationRef stationRef6 = networkInfo2.MutableStations[num14];
						float num15 = value4.Position.x - stationRef6.Position.x;
						float num16 = value4.Position.z - stationRef6.Position.z;
						float num17 = num15 * num15 + num16 * num16;
						float num18 = stationRef6.BuildRange + num11;
						if (num17 <= num18 * num18 && num17 < num12)
						{
							num12 = num17;
							value3 = networkInfo2;
						}
					}
				}
				if (value3 == null)
				{
					int num19 = ReadInt(value4.Zdo, CoreUtil.StorageNetworkIdentityHash, -1);
					if (num19 > 0)
					{
						_byId.TryGetValue(num19, out value3);
					}
				}
				if (value3 == null)
				{
					continue;
				}
				value4.NetworkId = value3.Id;
				value3.MutableStorages.Add(value4);
				if (!CanPersistMetadata() || value4.Zdo == null)
				{
					continue;
				}
				try
				{
					if (value4.Zdo.GetInt(CoreUtil.StorageNetworkIdentityHash, -1) != value3.Id)
					{
						value4.Zdo.Set(CoreUtil.StorageNetworkIdentityHash, value3.Id, false);
						CoreUtil.ForceSend(value4.Zdo);
					}
				}
				catch
				{
				}
			}
			_splitPendingNetworkIds.Clear();
			_revision++;
			NetworkApi.InvalidateSnapshots();
			NetworkApi.RaiseNetworksChanged();
			Plugin.LogDebug("Network rebuild: stations=" + list.Count + ", storages=" + _storages.Count + ", networks=" + _networks.Count + ", rev=" + _revision);
		}

		private static string SmallestStationKey(List<StationRef> members)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			string text = null;
			if (members != null)
			{
				for (int i = 0; i < members.Count; i++)
				{
					StationRef stationRef = members[i];
					if (stationRef != null)
					{
						string text2 = ((object)stationRef.Id/*cast due to .constrained prefix*/).ToString();
						if (text == null || string.CompareOrdinal(text2, text) < 0)
						{
							text = text2;
						}
					}
				}
			}
			return text ?? string.Empty;
		}

		private static int DeriveUniqueNetworkId(List<StationRef> members, HashSet<int> assigned)
		{
			string text = SmallestStationKey(members);
			int num = 0;
			int num2;
			while (true)
			{
				num2 = StringExtensionMethods.GetStableHashCode("mjnc-network|" + text + ((num == 0) ? string.Empty : ("|" + num))) & 0x7FFFFFFF;
				if (num2 == 0)
				{
					num2 = 1;
				}
				if (assigned == null || !assigned.Contains(num2))
				{
					break;
				}
				num++;
			}
			return num2;
		}

		private static int ChoosePersistentNetworkId(List<StationRef> members)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			string text = null;
			for (int i = 0; i < members.Count; i++)
			{
				StationRef stationRef = members[i];
				if (stationRef != null)
				{
					int num2 = ReadInt(stationRef.Zdo, CoreUtil.NetworkIdentityHash, 0);
					if (num2 > 0 && (num == 0 || num2 < num))
					{
						num = num2;
					}
					string text2 = ((object)stationRef.Id/*cast due to .constrained prefix*/).ToString();
					if (text == null || string.CompareOrdinal(text2, text) < 0)
					{
						text = text2;
					}
				}
			}
			if (num > 0)
			{
				return num;
			}
			int num3 = StringExtensionMethods.GetStableHashCode("mjnc-network|" + (text ?? Guid.NewGuid().ToString("N"))) & 0x7FFFFFFF;
			if (num3 != 0)
			{
				return num3;
			}
			return 1;
		}

		private static int ReadInt(ZDO zdo, int hash, int fallback)
		{
			if (zdo == null)
			{
				return fallback;
			}
			try
			{
				return zdo.GetInt(hash, fallback);
			}
			catch
			{
				return fallback;
			}
		}

		private static bool CanPersistMetadata()
		{
			try
			{
				return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer();
			}
			catch
			{
				return false;
			}
		}

		private static void AddStationType(HashSet<string> set, string value)
		{
			if (set != null)
			{
				string text = NormalizeStationKey(value);
				if (text.Length > 0)
				{
					set.Add(text);
				}
			}
		}

		private static void AddPersistedStationTypes(HashSet<string> set, ZDO zdo)
		{
			if (set == null || zdo == null)
			{
				return;
			}
			try
			{
				string text = zdo.GetString(CoreUtil.NetworkStationTypesHash, string.Empty);
				if (!string.IsNullOrEmpty(text))
				{
					string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
					for (int i = 0; i < array.Length; i++)
					{
						AddStationType(set, array[i]);
					}
				}
			}
			catch
			{
			}
		}

		private static string SerializeStationTypes(HashSet<string> set)
		{
			if (set == null || set.Count == 0)
			{
				return string.Empty;
			}
			List<string> list = new List<string>(set);
			list.Sort(StringComparer.Ordinal);
			return string.Join(";", list.ToArray());
		}

		private string ResolveName(NetworkInfo n)
		{
			for (int i = 0; i < n.MutableStations.Count; i++)
			{
				string text = n.MutableStations[i].Zdo.GetString(CoreUtil.NetworkNameHash, string.Empty);
				if (!string.IsNullOrWhiteSpace(text))
				{
					return text.Trim();
				}
			}
			return string.Empty;
		}

		private static TrackedWorldObject MakeTracked(ZDO zdo, GameObject instance, GameObject prefab, Vector3 pos)
		{
			//IL_000e: 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 new TrackedWorldObject
			{
				Zdo = zdo,
				Id = zdo.m_uid,
				GameObject = instance,
				Position = pos,
				PrefabName = CoreUtil.PrefabName(prefab)
			};
		}

		private static bool IsIncinerator(string prefabName, GameObject instance, GameObject prefab)
		{
			string text = (prefabName ?? string.Empty).ToLowerInvariant();
			if (text.Contains("incinerator") || text.Contains("obliterator") || text.Contains("vernichter"))
			{
				return true;
			}
			try
			{
				Type type = typeof(Player).Assembly.GetType("Incinerator");
				if (type != null && (((Object)(object)instance != (Object)null && (Object)(object)instance.GetComponent(type) != (Object)null) || ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent(type) != (Object)null)))
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool IsPlayerBuilt(ZDO zdo)
		{
			if (zdo == null)
			{
				return false;
			}
			try
			{
				if (!_creatorHash.HasValue)
				{
					int value = StringExtensionMethods.GetStableHashCode("creator");
					Type type = typeof(ZDO).Assembly.GetType("ZDOVars");
					if (type != null)
					{
						_creatorHashField = _creatorHashField ?? type.GetField("s_creator", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
						if (_creatorHashField != null && _creatorHashField.FieldType == typeof(int))
						{
							value = (int)_creatorHashField.GetValue(null);
						}
					}
					_creatorHash = value;
				}
				return zdo.GetLong(_creatorHash.Value, 0L) != 0;
			}
			catch
			{
				return true;
			}
		}

		private static bool IsMakailDrawer(string prefabName)
		{
			return string.Equals(prefabName, "piece_drawer", StringComparison.OrdinalIgnoreCase);
		}

		internal static float GetBuildRange(CraftingStation station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return 20f;
			}
			try
			{
				_getStationBuildRange = _getStationBuildRange ?? AccessTools.Method(typeof(CraftingStation), "GetStationBuildRange", Type.EmptyTypes, (Type[])null);
				if (_getStationBuildRange != null)
				{
					object obj = _getStationBuildRange.Invoke(station, null);
					if (obj != null)
					{
						return Mathf.Max(1f, Convert.ToSingle(obj));
					}
				}
				_rangeBuild = _rangeBuild ?? AccessTools.Field(typeof(CraftingStation), "m_rangeBuild");
				float num = ((_rangeBuild != null) ? Convert.ToSingle(_rangeBuild.GetValue(station)) : 20f);
				_getExtensionCount = _getExtensionCount ?? AccessTools.Method(typeof(CraftingStation), "GetExtentionCount", new Type[1] { typeof(bool) }, (Type[])null);
				_extraRangePerLevel = _extraRangePerLevel ?? AccessTools.Field(typeof(CraftingStation), "m_extraRangePerLevel");
				if (_getExtensionCount != null && _extraRangePerLevel != null)
				{
					object obj2 = _getExtensionCount.Invoke(station, new object[1] { false });
					int num2 = ((obj2 is int) ? ((int)obj2) : 0);
					num += (float)num2 * Convert.ToSingle(_extraRangePerLevel.GetValue(station));
				}
				return Mathf.Max(1f, num);
			}
			catch
			{
				return 20f;
			}
		}

		private static CraftingStation FindStationComponent(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return null;
			}
			CraftingStation component = go.GetComponent<CraftingStation>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			try
			{
				return go.GetComponentInChildren<CraftingStation>(true);
			}
			catch
			{
				return null;
			}
		}

		internal static bool StationMatchesName(StationRef station, string wanted)
		{
			if (station == null || string.IsNullOrEmpty(wanted))
			{
				return false;
			}
			if (string.Equals(station.StationName, wanted, StringComparison.Ordinal))
			{
				return true;
			}
			string text = NormalizeStationKey(wanted);
			if (text.Length == 0)
			{
				return false;
			}
			if (string.Equals(NormalizeStationKey(station.StationName), text, StringComparison.Ordinal))
			{
				return true;
			}
			if (string.Equals(NormalizeStationKey(station.PrefabName), text, StringComparison.Ordinal))
			{
				return true;
			}
			try
			{
				CraftingStation station2 = station.Station;
				if ((Object)(object)station2 != (Object)null)
				{
					string stationName = GetStationName(station2);
					if (string.Equals(stationName, wanted, StringComparison.Ordinal) || string.Equals(NormalizeStationKey(stationName), text, StringComparison.Ordinal))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			try
			{
				GameObject gameObject = station.GameObject;
				if ((Object)(object)gameObject != (Object)null)
				{
					string text2 = CoreUtil.PrefabName(gameObject);
					if (string.Equals(text2, wanted, StringComparison.Ordinal) || string.Equals(NormalizeStationKey(text2), text, StringComparison.Ordinal))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		internal static string NormalizeStationKey(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			string text = value.Trim();
			if (text.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(0, text.Length - 7);
			}
			text = text.Trim().ToLowerInvariant();
			if (text.StartsWith("$piece_", StringComparison.Ordinal))
			{
				text = text.Substring(7);
			}
			else if (text.StartsWith("piece_", StringComparison.Ordinal))
			{
				text = text.Substring(6);
			}
			else if (text.StartsWith("$", StringComparison.Ordinal))
			{
				text = text.Substring(1);
			}
			char[] array = text.ToCharArray();
			StringBuilder stringBuilder = new StringBuilder(array.Length);
			foreach (char c in array)
			{
				if (char.IsLetterOrDigit(c))
				{
					stringBuilder.Append(c);
				}
			}
			string text2 = stringBuilder.ToString();
			switch (text2)
			{
			case "steinmetz":
			case "stonecutter":
			case "stonemason":
				return "stonecutter";
			case "werkbank":
			case "workbench":
				return "workbench";
			case "schmiede":
			case "forge":
				return "forge";
			case "schwarzschmiede":
			case "blackforge":
				return "blackforge";
			default:
				return text2;
			}
		}

		internal static string GetStationName(CraftingStation station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return string.Empty;
			}
			try
			{
				return station.m_name ?? string.Empty;
			}
			catch
			{
				return ((Object)(object)((Component)station).gameObject != (Object)null) ? ((Object)((Component)station).gameObject).name : string.Empty;
			}
		}
	}
	internal static class PatchBootstrap
	{
		internal static void Install(Harmony harmony)
		{
			Patch(harmony, AccessTools.Method(typeof(ZNetView), "Awake", (Type[])null, (Type[])null), null, AccessTools.Method(typeof(ZNetViewAwakePatch), "Postfix", (Type[])null, (Type[])null), "ZNetView.Awake");
			Patch(harmony, AccessTools.Method(typeof(ZNetView), "OnDestroy", (Type[])null, (Type[])null), AccessTools.Method(typeof(ZNetViewDestroyPatch), "Prefix", (Type[])null, (Type[])null), null, "ZNetView.OnDestroy");
			Patch(harmony, AccessTools.Method(typeof(Container), "OnContainerChanged", (Type[])null, (Type[])null), null, AccessTools.Method(typeof(ContainerChangedPatch), "Postfix", (Type[])null, (Type[])null), "Container.OnContainerChanged", optional: true);
			MethodInfo postfix = AccessTools.Method(typeof(PieceSetCreatorPatch), "Postfix", (Type[])null, (Type[])null);
			MethodInfo[] methods = typeof(Piece).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == "SetCreator" && methodInfo.ReturnType == typeof(void))
				{
					Patch(harmony, methodInfo, null, postfix, "Piece.SetCreator", optional: true);
				}
			}
			MethodInfo postfix2 = AccessTools.Method(typeof(CraftingStationHoverPatch), "Postfix", (Type[])null, (Type[])null);
			MethodInfo[] methods2 = typeof(CraftingStation).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods2)
			{
				if (methodInfo2.Name == "GetHoverText" && methodInfo2.ReturnType == typeof(string) && methodInfo2.GetParameters().Length == 0)
				{
					Patch(harmony, methodInfo2, null, postfix2, "CraftingStation.GetHoverText", optional: true);
				}
			}
			MethodInfo postfix3 = AccessTools.Method(typeof(NetworkWideBuildStationPatch), "Postfix", (Type[])null, (Type[])null);
			MethodInfo[] methods3 = typeof(CraftingStation).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo3 in methods3)
			{
				if (methodInfo3.Name == "HaveBuildStationInRange" && methodInfo3.ReturnType == typeof(CraftingStation))
				{
					Patch(harmony, methodInfo3, null, postfix3, "CraftingStation.HaveBuildStationInRange(network-wide)", optional: true);
				}
			}
			MethodInfo prefix = AccessTools.Method(typeof(ZdoDestroyedPatch), "Prefix", (Type[])null, (Type[])null);
			MethodInfo[] methods4 = typeof(ZDOMan).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo4 in methods4)
			{
				if (methodInfo4.Name != "DestroyZDO")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo4.GetParameters();
				bool flag = false;
				for (int m = 0; m < parameters.Length; m++)
				{
					if (parameters[m].ParameterType == typeof(ZDOID) || parameters[m].ParameterType == typeof(ZDO))
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					Patch(harmony, methodInfo4, prefix, null, "ZDOMan.DestroyZDO(persistent-network cleanup)", optional: true);
				}
			}
			MethodInfo prefix2 = AccessTools.Method(typeof(WearNTearRemovePatch), "Prefix", (Type[])null, (Type[])null);
			MethodInfo[] methods5 = typeof(WearNTear).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo5 in methods5)
			{
				if (methodInfo5.Name == "Remove")
				{
					Patch(harmony, methodInfo5, prefix2, null, "WearNTear.Remove(real station removal)", optional: true);
				}
			}
			MethodInfo postfix4 = AccessTools.Method(typeof(ContainerNetworkHoverPatch), "Postfix", (Type[])null, (Type[])null);
			MethodInfo[] methods6 = typeof(Container).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo6 in methods6)
			{
				if (methodInfo6.Name == "GetHoverText" && methodInfo6.ReturnType == typeof(string) && methodInfo6.GetParameters().Length == 0)
				{
					Patch(harmony, methodInfo6, null, postfix4, "Container.GetHoverText(network opt-in)", optional: true);
				}
			}
		}

		private static void Patch(Harmony harmony, MethodBase original, MethodInfo prefix, MethodInfo postfix, string label, bool optional = false)
		{
			//IL_003c: 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)
			if (original == null)
			{
				if (!optional)
				{
					Plugin.LogWarning("Core patch target missing: " + label);
				}
				else
				{
					Plugin.LogDebug("Optional core patch target missing: " + label);
				}
				return;
			}
			try
			{
				HarmonyMethod val = ((prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix));
				HarmonyMethod val2 = ((postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix));
				harmony.Patch(original, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.LogDebug("Patched core target: " + label);
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("Core patch failed " + label + ": " + ex.Message);
			}
		}
	}
	internal static class ZNetViewAwakePatch
	{
		private static void Postfix(ZNetView __instance)
		{
			ActiveObjectHooks.RegisterView(__instance);
		}
	}
	internal static class ZNetViewDestroyPatch
	{
		private static void Prefix(ZNetView __instance)
		{
			ActiveObjectHooks.UnregisterView(__instance);
		}
	}
	internal static class ContainerChangedPatch
	{
		private static void Postfix(Container __instance)
		{
			NetworkApi.InvalidateSnapshots();
		}
	}
	internal static class PieceSetCreatorPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Piece __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null || Plugin.Registry == null)
				{
					return;
				}
				ZNetView val = ((Component)__instance).GetComponent<ZNetView>() ?? ((Component)__instance).GetComponentInParent<ZNetView>();
				if ((Object)(object)val == (Object)null || !val.IsValid())
				{
					return;
				}
				bool flag = (Object)(object)((Component)__instance).GetComponent<CraftingStation>() != (Object)null || (Object)(object)((Component)__instance).GetComponentInChildren<CraftingStation>(true) != (Object)null;
				bool flag2 = (Object)(object)((Component)__instance).GetComponent<Container>() != (Object)null;
				bool flag3 = ((Object)((Component)__instance).gameObject).name.StartsWith("piece_mj_network_relay", StringComparison.OrdinalIgnoreCase);
				if (flag || flag2 || flag3)
				{
					ActiveObjectHooks.RegisterView(val);
					if (flag || flag3)
					{
						Plugin.Registry.RebuildIfDirty(float.MaxValue);
					}
				}
			}
			catch
			{
			}
		}
	}
	internal static class CraftingStationHoverPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(CraftingStation __instance, ref string __result)
		{
			try
			{
				__result = CoreClientControls.AppendStationHover(__instance, __result);
			}
			catch
			{
			}
		}
	}
	internal static class ContainerNetworkHoverPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Container __instance, ref string __result)
		{
			try
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__result = CoreClientControls.AppendStorageHover(((Component)__instance).gameObject, __result);
				}
			}
			catch
			{
			}
		}
	}
	internal static class NetworkWideBuildStationPatch
	{
		private static readonly Dictionary<string, CraftingStation> VirtualStations = new Dictionary<string, CraftingStation>(StringComparer.Ordinal);

		[HarmonyPriority(0)]
		private unsafe static void Postfix(object[] __args, ref CraftingStation __result)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: 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_0126: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__result != (Object)null || Plugin.Settings == null || !Plugin.Settings.NetworkWideBuildStations.Value || Plugin.Registry == null)
				{
					return;
				}
				string text = null;
				Vector3 val = Vector3.zero;
				bool flag = false;
				if (__args != null)
				{
					for (int i = 0; i < __args.Length; i++)
					{
						if (text == null && __args[i] is string)
						{
							text = (string)__args[i];
						}
						if (!flag && __args[i] is Vector3)
						{
							val = (Vector3)__args[i];
							flag = true;
						}
					}
				}
				if (string.IsNullOrEmpty(text) || !flag)
				{
					return;
				}
				Plugin.Registry.RebuildIfDirty(float.MaxValue);
				NetworkInfo networkAt = NetworkApi.GetNetworkAt(val);
				if (networkAt == null || !Plugin.Registry.SupportsStation(networkAt, text))
				{
					CraftingStation[] array = Object.FindObjectsOfType<CraftingStation>();
					foreach (CraftingStation val2 in array)
					{
						if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null) && !(NetworkRegistry.NormalizeStationKey(NetworkRegistry.GetStationName(val2)) != NetworkRegistry.NormalizeStationKey(text)))
						{
							float num = val.x - ((Component)val2).transform.position.x;
							float num2 = val.z - ((Component)val2).transform.position.z;
							if (!(num * num + num2 * num2 > 100f))
							{
								__result = val2;
								break;
							}
						}
					}
				}
				else
				{
					__result = GetVirtualStation(text);
					string[] obj = new string[6] { "Network-wide station satisfied: ", text, " at ", null, null, null };
					Vector3 val3 = val;
					obj[3] = ((object)(*(Vector3*)(&val3))/*cast due to .constrained prefix*/).ToString();
					obj[4] = " via network ";
					obj[5] = networkAt.Id.ToString();
					Plugin.LogDebug(string.Concat(obj));
				}
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("Network-wide station patch failed: " + ex.Message);
			}
		}

		private static CraftingStation GetVirtualStation(string name)
		{
			//IL_0042: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			string text = NetworkRegistry.NormalizeStationKey(name);
			if (VirtualStations.TryGetValue(text, out var value) && (Object)(object)value != (Object)null)
			{
				value.m_name = name;
				return value;
			}
			GameObject val = new GameObject("MJNC_VirtualBuildStation_" + (string.IsNullOrEmpty(text) ? "station" : text))
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			val.SetActive(false);
			value = val.AddComponent<CraftingStation>();
			value.m_name = name;
			VirtualStations[text] = value;
			return value;
		}
	}
	internal static class WearNTearRemovePatch
	{
		[HarmonyPriority(800)]
		private static void Prefix(WearNTear __instance)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance == (Object)null || Plugin.Registry == null)
				{
					return;
				}
				GameObject gameObject = ((Component)__instance).gameObject;
				CraftingStation val = gameObject.GetComponent<CraftingStation>();
				if ((Object)(object)val == (Object)null)
				{
					val = gameObject.GetComponentInChildren<CraftingStation>(true);
				}
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				ZNetView val2 = gameObject.GetComponent<ZNetView>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = gameObject.GetComponentInParent<ZNetView>();
				}
				if (!((Object)(object)val2 == (Object)null) && val2.IsValid())
				{
					ZDO zDO = val2.GetZDO();
					if (zDO != null)
					{
						Plugin.Registry.ForgetDestroyed(zDO.m_uid);
					}
				}
			}
			catch
			{
			}
		}
	}
	internal static class ZdoDestroyedPatch
	{
		[HarmonyPriority(800)]
		private static void Prefix(object[] __args)
		{
			//IL_0022: 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)
			if (Plugin.Registry == null || __args == null)
			{
				return;
			}
			try
			{
				foreach (object obj in __args)
				{
					if (obj is ZDOID)
					{
						Plugin.Registry.ForgetDestroyed((ZDOID)obj);
						break;
					}
					ZDO val = (ZDO)((obj is ZDO) ? obj : null);
					if (val != null)
					{
						Plugin.Registry.ForgetDestroyed(val.m_uid);
						break;
					}
				}
			}
			catch
			{
			}
		}
	}
	public static class PlayerInventoryApi
	{
		private static MethodInfo _changed;

		public static int Count(Player player, string prefabName)
		{
			if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(prefabName))
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			int num = 0;
			List<ItemData> allItems = inventory.GetAllItems();
			for (int i = 0; i < allItems.Count; i++)
			{
				if (StorageApi.MatchesResource(allItems[i], prefabName))
				{
					num += allItems[i].m_stack;
				}
			}
			return num;
		}

		public static bool Remove(Player player, string prefabName, int amount)
		{
			if (amount <= 0)
			{
				return true;
			}
			if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(prefabName))
			{
				return false;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null || Count(player, prefabName) < amount)
			{
				return false;
			}
			int num = amount;
			List<ItemData> allItems = inventory.GetAllItems();
			int num2 = allItems.Count - 1;
			while (num2 >= 0 && num > 0)
			{
				ItemData val = allItems[num2];
				if (StorageApi.MatchesResource(val, prefabName))
				{
					int num3 = Math.Min(val.m_stack, num);
					val.m_stack -= num3;
					num -= num3;
					if (val.m_stack <= 0)
					{
						allItems.RemoveAt(num2);
					}
				}
				num2--;
			}
			if (num != 0)
			{
				return false;
			}
			try
			{
				_changed = _changed ?? typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (_changed != null)
				{
					_changed.Invoke(inventory, null);
				}
			}
			catch
			{
			}
			return true;
		}
	}
	[BepInPlugin("marcojudith.networkcore", "MJ Network Core", "0.1.18")]
	[BepInDependency("com.maxsch.valheim.MultiUserChest", "0.6.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private sealed class PendingTopologyRefresh
		{
			internal ZNetView View;

			internal float At;

			internal int Passes;
		}

		public const string PluginGuid = "marcojudith.networkcore";

		public const string PluginName = "MJ Network Core";

		public const string PluginVersion = "0.1.18";

		private ZDOMan _lastZdoMan;

		private readonly List<PendingTopologyRefresh> _pendingTopology = new List<PendingTopologyRefresh>();

		internal static Plugin Instance { get; private set; }

		internal static Harmony Harmony { get; private set; }

		internal static CoreConfig Settings { get; private set; }

		internal static NetworkRegistry Registry { get; private set; }

		private void Awake()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			Instance = this;
			Settings = new CoreConfig(((BaseUnityPlugin)this).Config);
			Registry = new NetworkRegistry();
			NetworkApi.Initialize(Registry, Settings);
			Harmony = new Harmony("marcojudith.networkcore");
			PatchBootstrap.Install(Harmony);
			CoreRpc.EnsureRegistere