Decompiled source of Self to Shelf v2.0.0

tony4twentys-Self To Shelf.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using HarmonyLib;
using Peak;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zorro.Core;
using Zorro.Core.Serizalization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyTitle("Self To Shelf")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Self To Shelf")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e8ea1f77-f217-4354-81c5-cbe5a7eb2cdd")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
public static class UniqueShelfShroomDataEntryKey
{
	public static readonly DataEntryKey IsUnique = (DataEntryKey)180;
}
[BepInPlugin("tony4twentys.Self_To_Shelf", "Self to Shelf", "2.0.0")]
public class SelfToShelf : BaseUnityPlugin
{
	private struct PendingFungusWarp
	{
		public Character thrower;

		public Vector3 destination;

		public Vector3 spawnSearchPos;

		public bool isUnique;

		public bool isCloud;

		public bool shouldWarp;
	}

	[HarmonyPatch(typeof(ShelfShroom), "Break")]
	private static class ShelfShroom_Break_Patch
	{
		private static void Prefix(ShelfShroom __instance, Collision coll, ref PendingFungusWarp __state)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			__state = default(PendingFungusWarp);
			try
			{
				if (!((Object)(object)__instance == (Object)null) && !__instance.alreadyBroke)
				{
					Item item = __instance.item;
					if (ItemHasTeleportPower(item) && coll != null && coll.contactCount > 0)
					{
						ContactPoint val = coll.contacts[0];
						__state.shouldWarp = true;
						__state.thrower = GetThrower(item);
						__state.spawnSearchPos = ((ContactPoint)(ref val)).point;
						__state.destination = ((ContactPoint)(ref val)).point + ((ContactPoint)(ref val)).normal * GetWarpOffWallDistance();
						__state.isUnique = ItemIsUnique(item);
						__state.isCloud = false;
					}
				}
			}
			catch (Exception ex)
			{
				LogOnce(ref _loggedShelfBreakError, "ShelfShroom.Break prefix failed", ex);
			}
		}

		private static void Postfix(PendingFungusWarp __state)
		{
			//IL_0018: 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)
			try
			{
				if (__state.shouldWarp)
				{
					TeleportThrowerAndNearby(__state.thrower, __state.destination);
					if (__state.isUnique)
					{
						FungusNetworkSync.SchedulePaintSpawn(__state.spawnSearchPos, isCloud: false);
					}
				}
			}
			catch (Exception ex)
			{
				LogOnce(ref _loggedShelfBreakError, "ShelfShroom.Break postfix failed", ex);
			}
		}
	}

	[HarmonyPatch(typeof(CloudFungus), "Break")]
	private static class CloudFungus_Break_Patch
	{
		private static void Prefix(CloudFungus __instance, ref PendingFungusWarp __state)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			__state = default(PendingFungusWarp);
			try
			{
				if (!((Object)(object)__instance == (Object)null) && !__instance.alreadyBroke)
				{
					Item item = __instance.item;
					if (ItemHasTeleportPower(item))
					{
						Vector3 position = ((Component)__instance).transform.position;
						__state.shouldWarp = true;
						__state.thrower = GetThrower(item);
						__state.spawnSearchPos = position;
						__state.destination = position + Vector3.up * GetWarpOffWallDistance();
						__state.isUnique = ItemIsUnique(item);
						__state.isCloud = true;
					}
				}
			}
			catch (Exception ex)
			{
				LogOnce(ref _loggedCloudBreakError, "CloudFungus.Break prefix failed", ex);
			}
		}

		private static void Postfix(PendingFungusWarp __state)
		{
			//IL_0018: 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)
			try
			{
				if (__state.shouldWarp)
				{
					TeleportThrowerAndNearby(__state.thrower, __state.destination);
					if (__state.isUnique)
					{
						FungusNetworkSync.SchedulePaintSpawn(__state.spawnSearchPos, isCloud: true);
					}
				}
			}
			catch (Exception ex)
			{
				LogOnce(ref _loggedCloudBreakError, "CloudFungus.Break postfix failed", ex);
			}
		}
	}

	[HarmonyPatch(typeof(Item), "Start")]
	private static class Item_Start_Patch
	{
		private static void Postfix(Item __instance)
		{
			try
			{
				FungusSpawnHelper.Initialize(__instance);
			}
			catch (Exception ex)
			{
				LogOnce(ref _loggedItemStartError, "Item.Start postfix failed", ex);
			}
		}
	}

	[HarmonyPatch(typeof(Item), "OnInstanceDataRecieved")]
	private static class Item_OnInstanceDataRecieved_Patch
	{
		private static void Postfix(Item __instance)
		{
			try
			{
				if (IsShelfFungus(__instance) && ShelfToShelfRuntime.ShouldApplyModEffects())
				{
					FungusNetworkSync.TryApplyRemembered(__instance);
					FungusVisuals.ApplyFromItemData(__instance);
				}
			}
			catch (Exception ex)
			{
				LogOnce(ref _loggedInstanceDataError, "Item.OnInstanceDataRecieved postfix failed", ex);
			}
		}
	}

	[HarmonyPatch(typeof(Item), "GetName")]
	private static class Item_GetName_Patch
	{
		private static bool Prefix(Item __instance, ref string __result)
		{
			try
			{
				if (!IsShelfFungus(__instance))
				{
					return true;
				}
				if (!ShelfToShelfRuntime.ShouldApplyModEffects())
				{
					return true;
				}
				if (!FungusNetworkSync.GetIsUnique(__instance))
				{
					return true;
				}
				__result = FungusVisuals.UniqueName(__instance);
				return false;
			}
			catch (Exception ex)
			{
				LogOnce(ref _loggedGetItemNameError, "Item.GetName prefix failed", ex);
				return true;
			}
		}
	}

	[HarmonyPatch(typeof(Item), "GetItemName")]
	[HarmonyPriority(0)]
	private static class Item_GetItemName_Patch
	{
		private static void Postfix(Item __instance, ItemInstanceData data, ref string __result)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (IsShelfFungus(__instance) && ShelfToShelfRuntime.ShouldApplyModEffects())
				{
					bool flag = FungusNetworkSync.GetIsUnique(__instance);
					IntItemData val = default(IntItemData);
					if (!flag && data != null && data.TryGetDataEntry<IntItemData>(UniqueShelfShroomDataEntryKey.IsUnique, ref val) && val != null && val.Value == 1)
					{
						flag = true;
					}
					if (flag)
					{
						__result = FungusVisuals.UniqueName(__instance);
					}
				}
			}
			catch (Exception ex)
			{
				LogOnce(ref _loggedGetItemNameError, "Item.GetItemName postfix failed", ex);
			}
		}
	}

	[HarmonyPatch(typeof(RunManager), "StartRun")]
	private static class Patch_RunManager_StartRun
	{
		private static void Postfix()
		{
			if (ShelfToShelfRuntime.ShouldApplyModEffects() && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
			{
				ShelfToShelfNetProxy.BroadcastNow();
				FungusNetworkSync.BroadcastAll();
				FungusSpawnHelper.RetagUntaggedFungus();
			}
		}
	}

	internal const byte EventCode = 163;

	internal const int ProtocolVersion = 203;

	internal const string EventMagic = "tony4twentys.Self_To_Shelf";

	private static Harmony _harmony;

	internal static SelfToShelf Instance;

	private ConfigEntry<bool> pullOtherPlayers;

	private ConfigEntry<float> huddlePullMultiplier;

	private ConfigEntry<float> uniqueShelfShroomChance;

	private ConfigEntry<float> uniqueCloudFungusChance;

	internal static bool syncedPullOtherPlayers;

	internal static float syncedHuddlePullMultiplier;

	internal static float syncedUniqueShelfShroomChance;

	internal static float syncedUniqueCloudFungusChance;

	internal static bool IsSyncingFromNet;

	private static float _warpOffWallDistance;

	private static bool _loggedItemStartError;

	private static bool _loggedGetItemNameError;

	private static bool _loggedShelfBreakError;

	private static bool _loggedCloudBreakError;

	private static bool _loggedWarpError;

	private static bool _loggedInstanceDataError;

	internal static void LogInfo(string msg)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
		}
		else
		{
			Debug.Log((object)msg);
		}
	}

	private static void LogOnce(ref bool flag, string message, Exception ex)
	{
		if (!flag)
		{
			flag = true;
			LogInfo("[Self To Shelf] " + message + ": " + ex);
		}
	}

	internal static float NormalizeChance(float raw)
	{
		if (raw > 1f)
		{
			raw *= 0.01f;
		}
		if (raw < 0f)
		{
			return 0f;
		}
		if (raw > 1f)
		{
			return 1f;
		}
		return raw;
	}

	internal static bool RollChance(float chance)
	{
		chance = NormalizeChance(chance);
		if (chance <= 0f)
		{
			return false;
		}
		if (chance >= 1f)
		{
			return true;
		}
		return Random.value < chance;
	}

	internal static float ClampMultiplier(float raw)
	{
		if (raw < 0f)
		{
			return 0f;
		}
		if (raw > 20f)
		{
			return 20f;
		}
		return raw;
	}

	internal static bool IsHostAuthority()
	{
		return !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient;
	}

	internal void RefreshSyncedFromLocal()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient)
		{
			syncedPullOtherPlayers = pullOtherPlayers.Value;
			syncedHuddlePullMultiplier = ClampMultiplier(huddlePullMultiplier.Value);
			syncedUniqueShelfShroomChance = NormalizeChance(uniqueShelfShroomChance.Value);
			syncedUniqueCloudFungusChance = NormalizeChance(uniqueCloudFungusChance.Value);
		}
	}

	internal static void ApplyNetworkSnapshot(bool pullOthers, float huddleMultiplier, float shelfChance, float cloudChance)
	{
		syncedPullOtherPlayers = pullOthers;
		syncedHuddlePullMultiplier = ClampMultiplier(huddleMultiplier);
		syncedUniqueShelfShroomChance = NormalizeChance(shelfChance);
		syncedUniqueCloudFungusChance = NormalizeChance(cloudChance);
	}

	internal static object[] PackEvent(byte sub, params object[] rest)
	{
		int num = ((rest != null) ? rest.Length : 0);
		object[] array = new object[3 + num];
		array[0] = "tony4twentys.Self_To_Shelf";
		array[1] = 203;
		array[2] = sub;
		if (rest != null)
		{
			for (int i = 0; i < rest.Length; i++)
			{
				array[3 + i] = rest[i];
			}
		}
		return array;
	}

	internal static bool TryReadEvent(object[] arr, out byte sub)
	{
		sub = 0;
		if (arr == null || arr.Length < 3)
		{
			return false;
		}
		string text = arr[0] as string;
		if (text != "tony4twentys.Self_To_Shelf")
		{
			return false;
		}
		if (Convert.ToInt32(arr[1]) != 203)
		{
			return false;
		}
		sub = Convert.ToByte(arr[2]);
		return true;
	}

	private void OnLocalConfigChanged(object sender, EventArgs args)
	{
		if (!IsSyncingFromNet && IsHostAuthority())
		{
			RefreshSyncedFromLocal();
			ShelfToShelfNetProxy.ScheduleBroadcast();
			LogInfo("[Self To Shelf] Config updated. Huddle pull x" + syncedHuddlePullMultiplier + ", shelf unique " + syncedUniqueShelfShroomChance + ", cloud unique " + syncedUniqueCloudFungusChance);
		}
	}

	internal static float GetUniqueChance(Item item)
	{
		if (FungusVisuals.IsCloud(item))
		{
			return (IsHostAuthority() && (Object)(object)Instance != (Object)null) ? NormalizeChance(Instance.uniqueCloudFungusChance.Value) : syncedUniqueCloudFungusChance;
		}
		return (IsHostAuthority() && (Object)(object)Instance != (Object)null) ? NormalizeChance(Instance.uniqueShelfShroomChance.Value) : syncedUniqueShelfShroomChance;
	}

	private void Awake()
	{
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Expected O, but got Unknown
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Expected O, but got Unknown
		Instance = this;
		pullOtherPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Teleport", "Pull Other Players", true, "Teleport nearby players with you when a Warp Shelf or Warp Cloud fungus places.");
		huddlePullMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Teleport", "Huddle Pull Multiplier", 2f, "How many times the in-game huddle warming radius to pull nearby scouts. 2 = twice the player-heat huddle. Increase to pull a wider group.");
		uniqueShelfShroomChance = ((BaseUnityPlugin)this).Config.Bind<float>("Unique", "Unique ShelfShroom Chance", 0.2f, "Chance a shelf fungus is Warp Shelf Fungus (teleports). 0 = never, 1 or 100 = always, or 0-100 percent.");
		uniqueCloudFungusChance = ((BaseUnityPlugin)this).Config.Bind<float>("Unique", "Unique Cloud Fungus Chance", 0.2f, "Chance a cloud fungus is Warp Cloud Fungus (teleports). 0 = never, 1 or 100 = always, or 0-100 percent.");
		RefreshSyncedFromLocal();
		pullOtherPlayers.SettingChanged += OnLocalConfigChanged;
		huddlePullMultiplier.SettingChanged += OnLocalConfigChanged;
		uniqueShelfShroomChance.SettingChanged += OnLocalConfigChanged;
		uniqueCloudFungusChance.SettingChanged += OnLocalConfigChanged;
		_harmony = new Harmony("tony4twentys.Self_To_Shelf");
		_harmony.PatchAll();
		GameObject val = new GameObject("SelfToShelf_NetProxy");
		Object.DontDestroyOnLoad((Object)(object)val);
		val.AddComponent<ShelfToShelfNetProxy>();
		SceneManager.sceneLoaded += OnSceneLoaded;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[Self To Shelf] 2.0.0 loaded. Photon " + (byte)163 + "."));
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		if (ShelfToShelfRuntime.ShouldApplyModEffects())
		{
			if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
			{
				ShelfToShelfNetProxy.BroadcastNow();
				FungusNetworkSync.BroadcastAll();
				FungusSpawnHelper.RetagUntaggedFungus();
			}
			else if (!PhotonNetwork.InRoom)
			{
				RefreshSyncedFromLocal();
				FungusSpawnHelper.RetagUntaggedFungus();
			}
		}
	}

	private void OnDestroy()
	{
		if (pullOtherPlayers != null)
		{
			pullOtherPlayers.SettingChanged -= OnLocalConfigChanged;
		}
		if (huddlePullMultiplier != null)
		{
			huddlePullMultiplier.SettingChanged -= OnLocalConfigChanged;
		}
		if (uniqueShelfShroomChance != null)
		{
			uniqueShelfShroomChance.SettingChanged -= OnLocalConfigChanged;
		}
		if (uniqueCloudFungusChance != null)
		{
			uniqueCloudFungusChance.SettingChanged -= OnLocalConfigChanged;
		}
		try
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}
		catch
		{
		}
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}

	internal static bool IsShelfFungus(Item item)
	{
		if (!Object.op_Implicit((Object)(object)item))
		{
			return false;
		}
		if ((Object)(object)((Component)item).GetComponent<CloudFungus>() != (Object)null)
		{
			return NameContains(item, "CloudFungus");
		}
		if ((Object)(object)((Component)item).GetComponent<ShelfShroom>() == (Object)null)
		{
			return false;
		}
		if (NameContains(item, "HealingPuff"))
		{
			return false;
		}
		return NameContains(item, "ShelfShroom");
	}

	internal static bool IsLiveWorldItem(Item item)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: 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_004e: Invalid comparison between Unknown and I4
		if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null)
		{
			return false;
		}
		Scene scene = ((Component)item).gameObject.scene;
		if (!((Scene)(ref scene)).IsValid())
		{
			return false;
		}
		if ((((Object)((Component)item).gameObject).hideFlags & 0x3D) > 0)
		{
			return false;
		}
		return true;
	}

	private static bool NameContains(Item item, string token)
	{
		if (((Object)item).name != null && ((Object)item).name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return true;
		}
		if (item.UIData != null && item.UIData.itemName != null && item.UIData.itemName.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return true;
		}
		return false;
	}

	internal static bool IsTeleportSpawn(Transform spawn)
	{
		if ((Object)(object)spawn == (Object)null)
		{
			return false;
		}
		return ((Object)spawn).name.Contains("ShelfShroomSpawn") || ((Object)spawn).name.Contains("CloudFungusPlaced");
	}

	internal static bool IsCharacterDead(Character character)
	{
		return (Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null || character.data.dead;
	}

	internal static bool ItemHasTeleportPower(Item item)
	{
		if (!ShelfToShelfRuntime.ShouldApplyModEffects())
		{
			return false;
		}
		if (!IsShelfFungus(item))
		{
			return false;
		}
		return FungusNetworkSync.GetIsUnique(item);
	}

	internal static bool ItemIsUnique(Item item)
	{
		return FungusNetworkSync.GetIsUnique(item);
	}

	internal static Vector3 GetHuddleOrigin(Character character)
	{
		//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_0080: 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_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)character == (Object)null)
		{
			return Vector3.zero;
		}
		if (character.refs != null)
		{
			if ((Object)(object)character.refs.heatEmission != (Object)null)
			{
				return ((Component)character.refs.heatEmission).transform.position;
			}
			if ((Object)(object)character.refs.hip != (Object)null)
			{
				return character.refs.hip.transform.position;
			}
		}
		return character.Center;
	}

	internal static float GetHuddleWarmRadius(Character character)
	{
		if ((Object)(object)character != (Object)null && character.refs != null && (Object)(object)character.refs.heatEmission != (Object)null && character.refs.heatEmission.radius > 0f)
		{
			return character.refs.heatEmission.radius;
		}
		return 1f;
	}

	internal static float GetPullRadius(Character character)
	{
		return GetHuddleWarmRadius(character) * syncedHuddlePullMultiplier;
	}

	internal static bool IsInHuddlePullRange(Character thrower, Character other)
	{
		//IL_001d: 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)
		if ((Object)(object)thrower == (Object)null || (Object)(object)other == (Object)null)
		{
			return false;
		}
		return Vector3.Distance(GetHuddleOrigin(thrower), other.Center) < GetPullRadius(thrower);
	}

	internal static Character GetThrower(Item item)
	{
		if (!Object.op_Implicit((Object)(object)item))
		{
			return null;
		}
		if (Object.op_Implicit((Object)(object)item.lastThrownCharacter))
		{
			return item.lastThrownCharacter;
		}
		if (Object.op_Implicit((Object)(object)item.holderCharacter))
		{
			return item.holderCharacter;
		}
		return Character.localCharacter;
	}

	internal static float GetWarpOffWallDistance()
	{
		if (_warpOffWallDistance > 0f)
		{
			return _warpOffWallDistance;
		}
		GameObject val = Resources.Load<GameObject>("0_Items/WarpFungus");
		if ((Object)(object)val != (Object)null)
		{
			WarpOnThrow val2 = val.GetComponent<WarpOnThrow>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = val.GetComponentInChildren<WarpOnThrow>(true);
			}
			if ((Object)(object)val2 != (Object)null && val2.moveAwayFromWallDistance > 0.01f)
			{
				_warpOffWallDistance = val2.moveAwayFromWallDistance;
			}
		}
		if (_warpOffWallDistance <= 0f)
		{
			_warpOffWallDistance = 1.5f;
		}
		return _warpOffWallDistance;
	}

	internal static void WarpLikeFungus(Character character, Vector3 position)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		if (!IsCharacterDead(character) && !((Object)(object)((MonoBehaviourPun)character).photonView == (Object)null))
		{
			((MonoBehaviourPun)character).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { position, true });
		}
	}

	internal static void TeleportThrowerAndNearby(Character thrower, Vector3 destination)
	{
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (IsCharacterDead(thrower))
			{
				return;
			}
			List<Character> list = new List<Character>();
			list.Add(thrower);
			if (syncedPullOtherPlayers && Character.AllCharacters != null)
			{
				foreach (Character allCharacter in Character.AllCharacters)
				{
					if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter == (Object)(object)thrower) && !IsCharacterDead(allCharacter) && IsInHuddlePullRange(thrower, allCharacter))
					{
						list.Add(allCharacter);
					}
				}
			}
			foreach (Character item in list)
			{
				WarpLikeFungus(item, destination);
			}
		}
		catch (Exception ex)
		{
			LogOnce(ref _loggedWarpError, "Teleport failed", ex);
		}
	}
}
internal static class FungusIcons
{
	private static Texture2D _shelfIcon;

	private static Texture2D _cloudIcon;

	private static bool _refreshQueued;

	private static bool _loggedShelfMissing;

	private static bool _loggedCloudMissing;

	private static bool _loggedError;

	internal static void QueueLiveRefresh()
	{
		if ((Object)(object)SelfToShelf.Instance == (Object)null)
		{
			ApplyLiveNow();
		}
		else if (!_refreshQueued)
		{
			_refreshQueued = true;
			((MonoBehaviour)SelfToShelf.Instance).StartCoroutine(LiveRefreshDeferred());
		}
	}

	private static IEnumerator LiveRefreshDeferred()
	{
		yield return null;
		_refreshQueued = false;
		ApplyLiveNow();
	}

	private static void ApplyLiveNow()
	{
		try
		{
			RefreshVisibleSlots();
		}
		catch (Exception ex)
		{
			LogOnce(ref _loggedError, "[Self To Shelf] inventory icon refresh failed", ex);
		}
	}

	private static void RefreshVisibleSlots()
	{
		GUIManager instance = GUIManager.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		Character val = (((Object)(object)Character.observedCharacter != (Object)null) ? Character.observedCharacter : Character.localCharacter);
		if ((Object)(object)val == (Object)null || (Object)(object)val.player == (Object)null)
		{
			return;
		}
		InventoryItemUI[] items = instance.items;
		ItemSlot[] itemSlots = val.player.itemSlots;
		if (items != null && itemSlots != null)
		{
			int num = Mathf.Min(items.Length, itemSlots.Length);
			for (int i = 0; i < num; i++)
			{
				RefreshSlot(items[i], itemSlots[i]);
			}
		}
		if ((Object)(object)instance.temporaryItem != (Object)null)
		{
			RefreshSlot(instance.temporaryItem, val.player.tempFullSlot);
		}
		RefreshBackpackWheel(instance.backpackWheel);
	}

	internal static void RefreshSlot(InventoryItemUI slot, ItemSlot itemSlot)
	{
		if (!((Object)(object)slot == (Object)null) && itemSlot != null && !itemSlot.IsEmpty())
		{
			ApplyToUi(slot, itemSlot.prefab, itemSlot.data);
		}
	}

	private static void ApplyToUi(InventoryItemUI slot, Item prefab, ItemInstanceData data)
	{
		if (!((Object)(object)slot == (Object)null) && !((Object)(object)slot.icon == (Object)null) && !((Object)(object)prefab == (Object)null) && SelfToShelf.IsShelfFungus(prefab) && ShelfToShelfRuntime.ShouldApplyModEffects() && IsUnique(prefab, data))
		{
			Texture2D icon = GetIcon(FungusVisuals.IsCloud(prefab));
			if (!((Object)(object)icon == (Object)null))
			{
				slot.icon.texture = (Texture)(object)icon;
				((Behaviour)slot.icon).enabled = true;
				ApplyVanillaScale(slot, prefab);
			}
		}
	}

	private static void ApplyVanillaScale(InventoryItemUI slot, Item prefab)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		float num = 1f;
		if ((Object)(object)prefab != (Object)null && prefab.UIData != null && prefab.UIData.iconScaleOffset > 0.01f)
		{
			num = prefab.UIData.iconScaleOffset;
		}
		((Component)slot.icon).transform.localScale = Vector3.one * num;
	}

	private static void RefreshBackpackWheel(BackpackWheel wheel)
	{
		if ((Object)(object)wheel == (Object)null || (Object)(object)wheel.currentlyHeldItem == (Object)null)
		{
			return;
		}
		Character localCharacter = Character.localCharacter;
		Item val = (((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null) ? localCharacter.data.currentItem : null);
		if (!((Object)(object)val == (Object)null) && SelfToShelf.IsShelfFungus(val) && FungusNetworkSync.GetIsUnique(val))
		{
			Texture2D icon = GetIcon(FungusVisuals.IsCloud(val));
			if ((Object)(object)icon != (Object)null)
			{
				wheel.currentlyHeldItem.texture = (Texture)(object)icon;
			}
		}
	}

	internal static bool IsUnique(Item prefab, ItemInstanceData data)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		IntItemData val = default(IntItemData);
		if (data != null && data.TryGetDataEntry<IntItemData>(UniqueShelfShroomDataEntryKey.IsUnique, ref val) && val != null)
		{
			return val.Value == 1;
		}
		return false;
	}

	internal static Texture2D GetIcon(bool isCloud)
	{
		if (isCloud)
		{
			return GetOrLoadIcon(ref _cloudIcon, "WarpCloudFungus.png", "Warp Cloud Fungus", ref _loggedCloudMissing);
		}
		return GetOrLoadIcon(ref _shelfIcon, "WarpShelfFungus.png", "Warp Shelf Fungus", ref _loggedShelfMissing);
	}

	private static Texture2D GetOrLoadIcon(ref Texture2D cached, string fileName, string label, ref bool loggedMissing)
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Expected O, but got Unknown
		if ((Object)(object)cached != (Object)null)
		{
			return cached;
		}
		try
		{
			byte[] array = ReadEmbeddedPng(fileName);
			if (array == null || array.Length == 0)
			{
				LogMissing(ref loggedMissing, fileName);
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			if (!LoadImage(val, array))
			{
				Object.Destroy((Object)(object)val);
				LogMissing(ref loggedMissing, fileName);
				return null;
			}
			cached = CopyToRgba(val);
			if ((Object)(object)cached != (Object)(object)val)
			{
				Object.Destroy((Object)(object)val);
			}
			PunchBlackToAlpha(cached);
			((Object)cached).hideFlags = (HideFlags)61;
		}
		catch (Exception ex)
		{
			LogOnce(ref _loggedError, "[Self To Shelf] " + label + " icon load failed", ex);
		}
		return cached;
	}

	private static bool LoadImage(Texture2D tex, byte[] bytes)
	{
		Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
		if (type == null)
		{
			return false;
		}
		MethodInfo method = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
		{
			typeof(Texture2D),
			typeof(byte[])
		}, null);
		if (method == null)
		{
			return false;
		}
		object obj = method.Invoke(null, new object[2] { tex, bytes });
		return obj is bool && (bool)obj;
	}

	private static byte[] ReadEmbeddedPng(string fileName)
	{
		Assembly assembly = typeof(FungusIcons).Assembly;
		string[] manifestResourceNames = assembly.GetManifestResourceNames();
		string text = null;
		for (int i = 0; i < manifestResourceNames.Length; i++)
		{
			if (manifestResourceNames[i] != null && manifestResourceNames[i].EndsWith(fileName, StringComparison.OrdinalIgnoreCase))
			{
				text = manifestResourceNames[i];
				break;
			}
		}
		if (text == null)
		{
			return null;
		}
		using Stream stream = assembly.GetManifestResourceStream(text);
		if (stream == null)
		{
			return null;
		}
		byte[] array = new byte[stream.Length];
		int num;
		for (int j = 0; j < array.Length; j += num)
		{
			num = stream.Read(array, j, array.Length - j);
			if (num <= 0)
			{
				break;
			}
		}
		return array;
	}

	private static Texture2D CopyToRgba(Texture2D src)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		Texture2D val = new Texture2D(((Texture)src).width, ((Texture)src).height, (TextureFormat)4, false);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)1;
		val.SetPixels32(src.GetPixels32());
		val.Apply(false, false);
		return val;
	}

	private static void PunchBlackToAlpha(Texture2D tex)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		Color32[] pixels = tex.GetPixels32();
		for (int i = 0; i < pixels.Length; i++)
		{
			Color32 val = pixels[i];
			if (val.r < 18 && val.g < 18 && val.b < 18)
			{
				val.a = 0;
				pixels[i] = val;
			}
		}
		tex.SetPixels32(pixels);
		tex.Apply(false, false);
	}

	private static void LogMissing(ref bool flagged, string fileName)
	{
		if (!flagged)
		{
			flagged = true;
			SelfToShelf.LogInfo("[Self To Shelf] Embedded " + fileName + " was missing.");
		}
	}

	private static void LogOnce(ref bool flagged, string message, Exception ex)
	{
		if (!flagged)
		{
			flagged = true;
			SelfToShelf.LogInfo(message + ": " + ex);
		}
	}
}
[HarmonyPatch(typeof(InventoryItemUI), "SetItem")]
internal static class InventoryItemUI_SetItem_FungusIconPatch
{
	private static void Postfix(InventoryItemUI __instance, ItemSlot slot)
	{
		try
		{
			FungusIcons.RefreshSlot(__instance, slot);
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(BackpackWheelSlice), "SetItemIcon")]
internal static class BackpackWheelSlice_SetItemIcon_FungusIconPatch
{
	private static void Postfix()
	{
		try
		{
			FungusIcons.QueueLiveRefresh();
		}
		catch
		{
		}
	}
}
internal static class ShelfToShelfRuntime
{
	internal static bool HostModConfirmed;

	internal static bool VanillaHostMode;

	internal static bool IsAwaitingHostSync => PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && !HostModConfirmed && !VanillaHostMode;

	internal static bool ShouldApplyModEffects()
	{
		if (VanillaHostMode)
		{
			return false;
		}
		if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && !HostModConfirmed)
		{
			return false;
		}
		return true;
	}

	internal static void OnJoinedRoom(bool isMaster)
	{
		VanillaHostMode = false;
		HostModConfirmed = isMaster;
		if (isMaster)
		{
			if ((Object)(object)SelfToShelf.Instance != (Object)null)
			{
				SelfToShelf.Instance.RefreshSyncedFromLocal();
			}
			FungusSpawnHelper.RetagUntaggedFungus();
			SelfToShelf.LogInfo("[Self To Shelf] Host joined — unique fungi and teleports enabled.");
		}
	}

	internal static void OnHostSyncReceived()
	{
		HostModConfirmed = true;
		VanillaHostMode = false;
		FungusSpawnHelper.RetagUntaggedFungus();
		SelfToShelf.LogInfo("[Self To Shelf] Host config snapshot applied.");
	}

	internal static void OnLeftRoom()
	{
		HostModConfirmed = false;
		VanillaHostMode = false;
		FungusNetworkSync.ClearRoomState();
		FungusSpawnHelper.ClearPending();
		if ((Object)(object)SelfToShelf.Instance != (Object)null)
		{
			SelfToShelf.Instance.RefreshSyncedFromLocal();
		}
	}

	internal static void OnHostModMissing()
	{
		HostModConfirmed = false;
		VanillaHostMode = true;
		FungusSpawnHelper.ClearPending();
		SelfToShelf.LogInfo("[Self To Shelf] Host does not appear to have Self To Shelf — unique fungi and teleports disabled.");
	}
}
internal class ShelfToShelfNetProxy : MonoBehaviourPunCallbacks, IOnEventCallback
{
	internal const byte SubConfig = 0;

	internal const byte SubConfigRequest = 1;

	internal const byte SubUniqueSync = 2;

	internal const byte SubUniqueRequest = 3;

	internal const byte SubSpawnSync = 4;

	private const float HostSyncTimeoutSeconds = 12f;

	private const float HostSyncRetrySeconds = 2f;

	internal static ShelfToShelfNetProxy Instance;

	private Coroutine _debounce;

	private Coroutine _hostSyncWatch;

	private void Awake()
	{
		Instance = this;
	}

	private void Start()
	{
		if (PhotonNetwork.InRoom)
		{
			((MonoBehaviourPunCallbacks)this).OnJoinedRoom();
		}
	}

	public override void OnEnable()
	{
		((MonoBehaviourPunCallbacks)this).OnEnable();
		PhotonNetwork.AddCallbackTarget((object)this);
	}

	public override void OnDisable()
	{
		PhotonNetwork.RemoveCallbackTarget((object)this);
		((MonoBehaviourPunCallbacks)this).OnDisable();
	}

	public override void OnJoinedRoom()
	{
		if (PhotonNetwork.IsMasterClient)
		{
			ShelfToShelfRuntime.OnJoinedRoom(isMaster: true);
			BroadcastNow();
			((MonoBehaviour)this).StartCoroutine(BroadcastAfterDelay(0.5f));
		}
		else
		{
			ShelfToShelfRuntime.OnJoinedRoom(isMaster: false);
			RequestHostSync();
			RestartHostSyncWatch();
		}
	}

	public override void OnLeftRoom()
	{
		StopHostSyncWatch();
		ShelfToShelfRuntime.OnLeftRoom();
	}

	public override void OnMasterClientSwitched(Player newMasterClient)
	{
		if (PhotonNetwork.IsMasterClient)
		{
			ShelfToShelfRuntime.OnJoinedRoom(isMaster: true);
			BroadcastNow();
			StopHostSyncWatch();
			((MonoBehaviour)this).StartCoroutine(BroadcastAfterDelay(0.5f));
		}
		else
		{
			ShelfToShelfRuntime.OnJoinedRoom(isMaster: false);
			RequestHostSync();
			RestartHostSyncWatch();
		}
	}

	public override void OnPlayerEnteredRoom(Player newPlayer)
	{
		if (PhotonNetwork.IsMasterClient)
		{
			((MonoBehaviour)this).StartCoroutine(BroadcastAfterDelay(0.5f));
		}
	}

	public void OnEvent(EventData e)
	{
		if (e == null || e.Code != 163)
		{
			return;
		}
		object[] array = e.CustomData as object[];
		if (SelfToShelf.TryReadEvent(array, out var sub))
		{
			if (sub == 1 && PhotonNetwork.IsMasterClient)
			{
				BroadcastNow();
				FungusNetworkSync.BroadcastAll();
			}
			else if (sub == 0)
			{
				ApplyConfigSnapshot(array);
			}
			else
			{
				FungusNetworkSync.HandleGameplayEvent(sub, array);
			}
		}
	}

	internal static void ScheduleBroadcast()
	{
		if (!((Object)(object)Instance == (Object)null) && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
		{
			if (Instance._debounce != null)
			{
				((MonoBehaviour)Instance).StopCoroutine(Instance._debounce);
			}
			Instance._debounce = ((MonoBehaviour)Instance).StartCoroutine(Instance.DebounceBroadcast());
		}
	}

	internal static void RequestHostSync()
	{
		//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_002d: 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: Expected O, but got Unknown
		if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
		{
			PhotonNetwork.RaiseEvent((byte)163, (object)SelfToShelf.PackEvent(1), new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)2
			}, SendOptions.SendReliable);
		}
	}

	internal void StartRoutine(IEnumerator routine)
	{
		if (routine != null)
		{
			((MonoBehaviour)this).StartCoroutine(routine);
		}
	}

	private void RestartHostSyncWatch()
	{
		StopHostSyncWatch();
		if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
		{
			_hostSyncWatch = ((MonoBehaviour)this).StartCoroutine(WatchForHostSync());
		}
	}

	private void StopHostSyncWatch()
	{
		if (_hostSyncWatch != null)
		{
			((MonoBehaviour)this).StopCoroutine(_hostSyncWatch);
			_hostSyncWatch = null;
		}
	}

	private IEnumerator WatchForHostSync()
	{
		float elapsed = 0f;
		float nextRetry = 2f;
		while (elapsed < 12f)
		{
			if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient || ShelfToShelfRuntime.HostModConfirmed)
			{
				yield break;
			}
			elapsed += Time.unscaledDeltaTime;
			if (elapsed >= nextRetry)
			{
				RequestHostSync();
				nextRetry += 2f;
			}
			yield return null;
		}
		if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && !ShelfToShelfRuntime.HostModConfirmed)
		{
			ShelfToShelfRuntime.OnHostModMissing();
		}
		_hostSyncWatch = null;
	}

	private IEnumerator DebounceBroadcast()
	{
		yield return (object)new WaitForSeconds(0.25f);
		BroadcastNow();
		_debounce = null;
	}

	private IEnumerator BroadcastAfterDelay(float seconds)
	{
		yield return (object)new WaitForSeconds(seconds);
		BroadcastNow();
		FungusNetworkSync.BroadcastAll();
		FungusSpawnHelper.RetagUntaggedFungus();
	}

	private static void ApplyConfigSnapshot(object[] arr)
	{
		if (arr == null || arr.Length < 7 || PhotonNetwork.IsMasterClient)
		{
			return;
		}
		try
		{
			SelfToShelf.IsSyncingFromNet = true;
			if ((Object)(object)Instance != (Object)null)
			{
				Instance.StopHostSyncWatch();
			}
			SelfToShelf.ApplyNetworkSnapshot(Convert.ToBoolean(arr[3]), Convert.ToSingle(arr[4]), Convert.ToSingle(arr[5]), Convert.ToSingle(arr[6]));
			ShelfToShelfRuntime.OnHostSyncReceived();
		}
		catch (Exception ex)
		{
			SelfToShelf.LogInfo("[Self To Shelf] Config snapshot error: " + ex.Message);
		}
		finally
		{
			SelfToShelf.IsSyncingFromNet = false;
		}
	}

	internal static void BroadcastNow()
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Expected O, but got Unknown
		if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
		{
			if ((Object)(object)SelfToShelf.Instance != (Object)null)
			{
				SelfToShelf.Instance.RefreshSyncedFromLocal();
			}
			PhotonNetwork.RaiseEvent((byte)163, (object)SelfToShelf.PackEvent(0, SelfToShelf.syncedPullOtherPlayers, SelfToShelf.syncedHuddlePullMultiplier, SelfToShelf.syncedUniqueShelfShroomChance, SelfToShelf.syncedUniqueCloudFungusChance), new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)0
			}, SendOptions.SendReliable);
		}
	}
}
internal static class FungusMaterials
{
	private const string WarpName = "M_Mushroom_Warp";

	private const string WeirdName = "M_Mushroom_Weird";

	private static Material _warp;

	private static Material _weird;

	private static bool _loggedWarpFail;

	private static bool _loggedWeirdFail;

	public static Material Warp
	{
		get
		{
			if ((Object)(object)_warp == (Object)null)
			{
				_warp = FindMaterial("M_Mushroom_Warp", new string[1] { "WarpFungus" });
			}
			if ((Object)(object)_warp == (Object)null && !_loggedWarpFail)
			{
				_loggedWarpFail = true;
				SelfToShelf.LogInfo("[Self To Shelf] Could not load M_Mushroom_Warp");
			}
			return _warp;
		}
	}

	public static Material Weird
	{
		get
		{
			if ((Object)(object)_weird == (Object)null)
			{
				_weird = FindMaterial("M_Mushroom_Weird", new string[2] { "CloudFungus", "WarpFungus" });
			}
			if ((Object)(object)_weird == (Object)null && !_loggedWeirdFail)
			{
				_loggedWeirdFail = true;
				SelfToShelf.LogInfo("[Self To Shelf] Could not load M_Mushroom_Weird");
			}
			return _weird;
		}
	}

	public static Material ForShelf()
	{
		return Warp;
	}

	public static Material ForCloud()
	{
		return Weird;
	}

	private static Material FindMaterial(string materialName, string[] prefabGuesses)
	{
		Material val = FindLoaded(materialName);
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		if (prefabGuesses != null)
		{
			for (int i = 0; i < prefabGuesses.Length; i++)
			{
				GameObject go = Resources.Load<GameObject>("0_Items/" + prefabGuesses[i]);
				val = FindOnObject(go, materialName);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
		}
		GameObject[] array = Resources.LoadAll<GameObject>("0_Items/");
		if (array != null)
		{
			for (int j = 0; j < array.Length; j++)
			{
				val = FindOnObject(array[j], materialName);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
		}
		return FindLoaded(materialName);
	}

	private static Material FindLoaded(string materialName)
	{
		Material[] array = Resources.FindObjectsOfTypeAll<Material>();
		if (array == null)
		{
			return null;
		}
		for (int i = 0; i < array.Length; i++)
		{
			if (NameMatches(array[i], materialName))
			{
				return array[i];
			}
		}
		return null;
	}

	private static Material FindOnObject(GameObject go, string materialName)
	{
		if ((Object)(object)go == (Object)null)
		{
			return null;
		}
		MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val in componentsInChildren)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			if (NameMatches(((Renderer)val).sharedMaterial, materialName))
			{
				return ((Renderer)val).sharedMaterial;
			}
			Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
			if (sharedMaterials == null)
			{
				continue;
			}
			for (int j = 0; j < sharedMaterials.Length; j++)
			{
				if (NameMatches(sharedMaterials[j], materialName))
				{
					return sharedMaterials[j];
				}
			}
		}
		return null;
	}

	private static bool NameMatches(Material mat, string materialName)
	{
		if ((Object)(object)mat == (Object)null || string.IsNullOrEmpty(((Object)mat).name))
		{
			return false;
		}
		return ((Object)mat).name == materialName || ((Object)mat).name.StartsWith(materialName + " ", StringComparison.Ordinal);
	}
}
internal static class FungusItemDataHelper
{
	public static void SetIntEntry(ItemInstanceData data, DataEntryKey key, int value)
	{
		//IL_000c: 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_0031: Expected O, but got Unknown
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		if (data != null)
		{
			IntItemData val = default(IntItemData);
			if (data.TryGetDataEntry<IntItemData>(key, ref val) && val != null)
			{
				val.Value = value;
				return;
			}
			IntItemData val2 = new IntItemData();
			((DataEntryValue)val2).Init();
			val2.Value = value;
			data.RegisterEntry<IntItemData>(key, val2);
		}
	}
}
internal static class FungusVisuals
{
	public static bool IsCloud(Item item)
	{
		return (Object)(object)item != (Object)null && (Object)(object)((Component)item).GetComponent<CloudFungus>() != (Object)null;
	}

	public static bool IsCloudSpawn(Transform spawn)
	{
		return (Object)(object)spawn != (Object)null && ((Object)spawn).name.Contains("CloudFungusPlaced");
	}

	public static string UniqueName(Item item)
	{
		return UniqueName(IsCloud(item));
	}

	public static string UniqueName(bool isCloud)
	{
		return isCloud ? "WARP CLOUD FUNGUS" : "WARP SHELF FUNGUS";
	}

	public static void ApplyToItem(Item item, bool isUnique)
	{
		if (Object.op_Implicit((Object)(object)item))
		{
			ApplyMaterial(((Component)item).gameObject, isUnique, IsCloud(item));
			if (isUnique)
			{
				FungusIcons.QueueLiveRefresh();
			}
		}
	}

	public static void ApplyToSpawn(Transform spawn, bool isCloud)
	{
		if (!((Object)(object)spawn == (Object)null))
		{
			ApplyMaterial(((Component)spawn).gameObject, isUnique: true, isCloud);
		}
	}

	public static void ApplyFromItemData(Item item)
	{
		if (ShelfToShelfRuntime.ShouldApplyModEffects() && SelfToShelf.IsShelfFungus(item))
		{
			ApplyToItem(item, FungusNetworkSync.GetIsUnique(item));
		}
	}

	private static void ApplyMaterial(GameObject go, bool isUnique, bool isCloud)
	{
		if ((Object)(object)go == (Object)null || !isUnique)
		{
			return;
		}
		Material val = (isCloud ? FungusMaterials.ForCloud() : FungusMaterials.ForShelf());
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			if ((Object)(object)componentsInChildren[i] != (Object)null)
			{
				((Renderer)componentsInChildren[i]).sharedMaterial = val;
			}
		}
	}
}
internal static class FungusInventoryHelper
{
	public static ItemSlot FindSlotForItem(Item item)
	{
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		Character val = (((Object)(object)item != (Object)null) ? item.holderCharacter : null);
		if ((Object)(object)val == (Object)null || (Object)(object)val.player == (Object)null)
		{
			return null;
		}
		if (item.data != null && item.data.guid != Guid.Empty)
		{
			ItemSlot val2 = FindSlotByGuid(val, item.data.guid);
			if (val2 != null)
			{
				return val2;
			}
		}
		if ((Object)(object)val.data != (Object)null && (Object)(object)val.data.currentItem == (Object)(object)item && val.refs != null && (Object)(object)val.refs.items != (Object)null)
		{
			Optionable<byte> currentSelectedSlot = val.refs.items.currentSelectedSlot;
			if (currentSelectedSlot.IsSome)
			{
				ItemSlot itemSlot = val.player.GetItemSlot(currentSelectedSlot.Value);
				if (itemSlot != null && !itemSlot.IsEmpty() && (Object)(object)itemSlot.prefab != (Object)null && itemSlot.prefab.itemID == item.itemID)
				{
					return itemSlot;
				}
			}
		}
		return null;
	}

	private static ItemSlot FindSlotByGuid(Character holder, Guid guid)
	{
		ItemSlot val = FindSlotByGuid(holder.player.itemSlots, guid);
		if (val != null)
		{
			return val;
		}
		if (SlotHasGuid(holder.player.tempFullSlot, guid))
		{
			return holder.player.tempFullSlot;
		}
		if (SlotHasGuid((ItemSlot)(object)holder.player.backpackSlot, guid))
		{
			return (ItemSlot)(object)holder.player.backpackSlot;
		}
		return null;
	}

	private static ItemSlot FindSlotByGuid(ItemSlot[] slots, Guid guid)
	{
		if (slots == null)
		{
			return null;
		}
		for (int i = 0; i < slots.Length; i++)
		{
			if (SlotHasGuid(slots[i], guid))
			{
				return slots[i];
			}
		}
		return null;
	}

	private static bool SlotHasGuid(ItemSlot slot, Guid guid)
	{
		return slot != null && !slot.IsEmpty() && slot.data != null && slot.data.guid == guid;
	}
}
internal static class FungusNetworkSync
{
	private static readonly Dictionary<int, int> UniqueByViewId = new Dictionary<int, int>();

	private static readonly Dictionary<int, bool> UniqueSpawnIsCloud = new Dictionary<int, bool>();

	private static readonly HashSet<int> DeferredTagInFlight = new HashSet<int>();

	public static bool CanTagItems()
	{
		if (!ShelfToShelfRuntime.ShouldApplyModEffects())
		{
			return false;
		}
		return !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient;
	}

	public static PhotonView GetItemView(Item item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return null;
		}
		try
		{
			if ((Object)(object)((MonoBehaviourPun)item).photonView != (Object)null)
			{
				return ((MonoBehaviourPun)item).photonView;
			}
		}
		catch
		{
		}
		return ((Component)item).GetComponent<PhotonView>();
	}

	public static PhotonView GetView(Component component)
	{
		if ((Object)(object)component == (Object)null)
		{
			return null;
		}
		PhotonView component2 = component.GetComponent<PhotonView>();
		if ((Object)(object)component2 != (Object)null)
		{
			return component2;
		}
		return component.GetComponentInParent<PhotonView>();
	}

	public static void ClearRoomState()
	{
		UniqueByViewId.Clear();
		UniqueSpawnIsCloud.Clear();
		DeferredTagInFlight.Clear();
	}

	public static void RememberUnique(int viewId, int unique)
	{
		if (viewId > 0)
		{
			UniqueByViewId[viewId] = unique;
		}
	}

	public static bool TryGetRememberedUnique(int viewId, out int unique)
	{
		return UniqueByViewId.TryGetValue(viewId, out unique);
	}

	public static bool TryGetRememberedUnique(Item item, out int unique)
	{
		unique = 0;
		PhotonView itemView = GetItemView(item);
		return (Object)(object)itemView != (Object)null && TryGetRememberedUnique(itemView.ViewID, out unique);
	}

	public static bool HasExplicitUnique(Item item)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		return (Object)(object)item != (Object)null && item.HasData(UniqueShelfShroomDataEntryKey.IsUnique);
	}

	public static bool GetIsUnique(Item item)
	{
		//IL_000b: 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_0061: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)item != (Object)null && item.HasData(UniqueShelfShroomDataEntryKey.IsUnique))
		{
			return item.GetData<IntItemData>(UniqueShelfShroomDataEntryKey.IsUnique).Value == 1;
		}
		if (TryGetRememberedUnique(item, out var unique))
		{
			return unique == 1;
		}
		ItemSlot val = FungusInventoryHelper.FindSlotForItem(item);
		IntItemData val2 = default(IntItemData);
		if (val != null && val.data != null && val.data.TryGetDataEntry<IntItemData>(UniqueShelfShroomDataEntryKey.IsUnique, ref val2) && val2 != null)
		{
			return val2.Value == 1;
		}
		return false;
	}

	public static void SetUnique(Item item, bool isUnique)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)item == (Object)null))
		{
			IntItemData data = item.GetData<IntItemData>(UniqueShelfShroomDataEntryKey.IsUnique);
			data.Value = (isUnique ? 1 : 0);
			PhotonView itemView = GetItemView(item);
			if ((Object)(object)itemView != (Object)null)
			{
				RememberUnique(itemView.ViewID, data.Value);
			}
			ItemSlot slot = FungusInventoryHelper.FindSlotForItem(item);
			CopyUniqueToSlot(item, slot);
		}
	}

	public static void CopyUniqueToSlot(Item item, ItemSlot slot)
	{
		//IL_005d: 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_0056: Expected O, but got Unknown
		if (!((Object)(object)item == (Object)null) && slot != null)
		{
			int value = (GetIsUnique(item) ? 1 : 0);
			if (slot.data == null)
			{
				slot.data = new ItemInstanceData((item.data != null) ? item.data.guid : Guid.NewGuid());
			}
			FungusItemDataHelper.SetIntEntry(slot.data, UniqueShelfShroomDataEntryKey.IsUnique, value);
		}
	}

	public static bool TryApplyRemembered(Item item)
	{
		if (!TryGetRememberedUnique(item, out var unique))
		{
			return false;
		}
		PhotonView itemView = GetItemView(item);
		if ((Object)(object)itemView != (Object)null)
		{
			UniqueByViewId.Remove(itemView.ViewID);
		}
		SetUnique(item, unique == 1);
		return true;
	}

	public static void ForgetUnique(int viewId)
	{
		if (viewId > 0)
		{
			UniqueByViewId.Remove(viewId);
		}
	}

	public static void ForgetUnique(Item item)
	{
		PhotonView itemView = GetItemView(item);
		if ((Object)(object)itemView != (Object)null)
		{
			ForgetUnique(itemView.ViewID);
		}
	}

	public static void PushUniqueState(Item item)
	{
		if ((Object)(object)item != (Object)null)
		{
			CopyUniqueToSlot(item, FungusInventoryHelper.FindSlotForItem(item));
		}
		PushItemInstanceData(item);
		BroadcastUnique(item);
		SyncHolderInventory(((Object)(object)item != (Object)null) ? item.holderCharacter : null);
	}

	public static void PushItemInstanceData(Item item)
	{
		if ((Object)(object)item == (Object)null || item.data == null || !PhotonNetwork.InRoom)
		{
			return;
		}
		PhotonView itemView = GetItemView(item);
		if (!((Object)(object)itemView == (Object)null) && (itemView.IsMine || PhotonNetwork.IsMasterClient) && HasExplicitUnique(item))
		{
			RememberUnique(itemView.ViewID, GetIsUnique(item) ? 1 : 0);
			try
			{
				itemView.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { item.data });
			}
			catch (Exception ex)
			{
				SelfToShelf.LogInfo("[Self To Shelf] SetItemInstanceDataRPC failed: " + ex.Message);
			}
			BroadcastUnique(item);
		}
	}

	public static void BroadcastUnique(Item item)
	{
		if (!((Object)(object)item == (Object)null) && PhotonNetwork.InRoom)
		{
			PhotonView itemView = GetItemView(item);
			if (!((Object)(object)itemView == (Object)null) && (itemView.IsMine || PhotonNetwork.IsMasterClient) && HasExplicitUnique(item))
			{
				int num = (GetIsUnique(item) ? 1 : 0);
				RememberUnique(itemView.ViewID, num);
				Raise(2, itemView.ViewID, num, (ReceiverGroup)0);
			}
		}
	}

	public static void BroadcastSpawn(int spawnViewId, bool isCloud)
	{
		if (spawnViewId <= 0)
		{
			return;
		}
		UniqueSpawnIsCloud[spawnViewId] = isCloud;
		if (!PhotonNetwork.InRoom)
		{
			return;
		}
		if (!PhotonNetwork.IsMasterClient)
		{
			PhotonView val = PhotonView.Find(spawnViewId);
			if ((Object)(object)val == (Object)null || !val.IsMine)
			{
				return;
			}
		}
		Raise(4, spawnViewId, isCloud ? 1 : 0, (ReceiverGroup)0);
	}

	public static void ApplyRemoteUnique(int itemViewId, int unique)
	{
		RememberUnique(itemViewId, unique);
		if (!ShelfToShelfRuntime.ShouldApplyModEffects())
		{
			return;
		}
		PhotonView val = PhotonView.Find(itemViewId);
		if (!((Object)(object)val == (Object)null))
		{
			Item component = ((Component)val).GetComponent<Item>();
			if (SelfToShelf.IsShelfFungus(component))
			{
				SetUnique(component, unique == 1);
				FungusVisuals.ApplyToItem(component, unique == 1);
			}
		}
	}

	public static void ApplyRemoteSpawn(int spawnViewId, bool isCloud)
	{
		UniqueSpawnIsCloud[spawnViewId] = isCloud;
		if (ShelfToShelfRuntime.ShouldApplyModEffects())
		{
			PhotonView val = PhotonView.Find(spawnViewId);
			if ((Object)(object)val == (Object)null)
			{
				StartRoutine(SpawnCatchupRoutine(spawnViewId, isCloud));
			}
			else
			{
				FungusVisuals.ApplyToSpawn(((Component)val).transform, isCloud);
			}
		}
	}

	public static void RequestUniqueFromHost(Item item)
	{
		if (!((Object)(object)item == (Object)null) && PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
		{
			PhotonView itemView = GetItemView(item);
			if (!((Object)(object)itemView == (Object)null))
			{
				Raise(3, itemView.ViewID, 0, (ReceiverGroup)2);
			}
		}
	}

	public static void RespondToUniqueRequest(int itemViewId)
	{
		if (!PhotonNetwork.IsMasterClient)
		{
			return;
		}
		PhotonView val = PhotonView.Find(itemViewId);
		Item item = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Item>() : null);
		if (SelfToShelf.IsShelfFungus(item))
		{
			if (!HasExplicitUnique(item))
			{
				FungusSpawnHelper.ScheduleDeferredTag(item);
				return;
			}
			BroadcastUnique(item);
			PushItemInstanceData(item);
		}
	}

	public static void BroadcastAll()
	{
		//IL_004a: 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 (!PhotonNetwork.IsMasterClient)
		{
			return;
		}
		Item[] array = Resources.FindObjectsOfTypeAll<Item>();
		if (array != null)
		{
			foreach (Item val in array)
			{
				if (SelfToShelf.IsShelfFungus(val) && !((Object)(object)((Component)val).gameObject == (Object)null))
				{
					Scene scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && HasExplicitUnique(val))
					{
						BroadcastUnique(val);
						PushItemInstanceData(val);
					}
				}
			}
		}
		foreach (KeyValuePair<int, bool> item in UniqueSpawnIsCloud)
		{
			Raise(4, item.Key, item.Value ? 1 : 0, (ReceiverGroup)0);
		}
	}

	public static void SyncHolderInventory(Character character)
	{
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)character == (Object)null || (Object)(object)character.player == (Object)null || !PhotonNetwork.InRoom || !character.IsLocal)
		{
			return;
		}
		PhotonView component = ((Component)character.player).GetComponent<PhotonView>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		try
		{
			InventorySyncData val = default(InventorySyncData);
			((InventorySyncData)(ref val))..ctor(character.player.itemSlots, character.player.backpackSlot, character.player.tempFullSlot);
			component.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2]
			{
				IBinarySerializable.ToManagedArray<InventorySyncData>(val),
				false
			});
		}
		catch (Exception ex)
		{
			SelfToShelf.LogInfo("[Self To Shelf] SyncInventoryRPC failed: " + ex.Message);
		}
	}

	public static void PreserveOnStash(Item item)
	{
		if (SelfToShelf.IsShelfFungus(item) && !((Object)(object)item.holderCharacter == (Object)null) && !((Object)(object)item.holderCharacter.player == (Object)null))
		{
			ItemSlot val = FungusInventoryHelper.FindSlotForItem(item);
			if (val != null && !val.IsEmpty())
			{
				CopyUniqueToSlot(item, val);
				SyncHolderInventory(item.holderCharacter);
			}
		}
	}

	public static void PreserveBeforeDrop(Item item)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		if (!SelfToShelf.IsShelfFungus(item) || (Object)(object)item.holderCharacter == (Object)null || (Object)(object)item.holderCharacter.player == (Object)null || !item.HasData(UniqueShelfShroomDataEntryKey.IsUnique))
		{
			return;
		}
		ItemSlot val = FungusInventoryHelper.FindSlotForItem(item);
		if (val == null || val.IsEmpty())
		{
			return;
		}
		try
		{
			CopyUniqueToSlot(item, val);
		}
		catch (Exception ex)
		{
			SelfToShelf.LogInfo("[Self To Shelf] preserve unique before drop failed: " + ex.Message);
		}
	}

	public static void ScheduleSpawnResync(Item item)
	{
		StartRoutine(SpawnResyncRoutine(item));
	}

	public static void ScheduleClientCatchup(Item item)
	{
		StartRoutine(ClientCatchupRoutine(item));
	}

	public static void SchedulePaintSpawn(Vector3 searchPos, bool isCloud)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		StartRoutine(PaintSpawnRoutine(searchPos, isCloud));
	}

	public static bool TryBeginDeferredTag(int viewId)
	{
		return DeferredTagInFlight.Add(viewId);
	}

	public static void EndDeferredTag(int viewId)
	{
		DeferredTagInFlight.Remove(viewId);
	}

	public static void StartRoutine(IEnumerator routine)
	{
		if (routine != null)
		{
			if ((Object)(object)ShelfToShelfNetProxy.Instance != (Object)null)
			{
				ShelfToShelfNetProxy.Instance.StartRoutine(routine);
			}
			else if ((Object)(object)SelfToShelf.Instance != (Object)null)
			{
				((MonoBehaviour)SelfToShelf.Instance).StartCoroutine(routine);
			}
		}
	}

	private static IEnumerator SpawnResyncRoutine(Item item)
	{
		yield return null;
		if ((Object)(object)item != (Object)null)
		{
			PushItemInstanceData(item);
		}
		yield return (object)new WaitForSeconds(0.35f);
		if ((Object)(object)item != (Object)null)
		{
			PushItemInstanceData(item);
		}
	}

	private static IEnumerator ClientCatchupRoutine(Item item)
	{
		float[] waits = new float[3] { 0.05f, 0.2f, 0.5f };
		for (int i = 0; i < waits.Length; i++)
		{
			yield return (object)new WaitForSeconds(waits[i]);
			if ((Object)(object)item == (Object)null)
			{
				break;
			}
			if (TryApplyRemembered(item) || HasExplicitUnique(item))
			{
				FungusVisuals.ApplyFromItemData(item);
				break;
			}
			RequestUniqueFromHost(item);
		}
	}

	private static IEnumerator SpawnCatchupRoutine(int viewId, bool isCloud)
	{
		float[] waits = new float[4] { 0.05f, 0.2f, 0.5f, 1f };
		for (int i = 0; i < waits.Length; i++)
		{
			yield return (object)new WaitForSeconds(waits[i]);
			PhotonView view = PhotonView.Find(viewId);
			if (!((Object)(object)view == (Object)null))
			{
				FungusVisuals.ApplyToSpawn(((Component)view).transform, isCloud);
				break;
			}
		}
	}

	private static IEnumerator PaintSpawnRoutine(Vector3 searchPos, bool isCloud)
	{
		//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)
		yield return null;
		yield return null;
		Transform spawn = FindSpawnNear(searchPos);
		if ((Object)(object)spawn == (Object)null)
		{
			yield return (object)new WaitForSeconds(0.25f);
			spawn = FindSpawnNear(searchPos);
		}
		if (!((Object)(object)spawn == (Object)null))
		{
			FungusVisuals.ApplyToSpawn(spawn, isCloud);
			PhotonView view = GetView((Component)(object)spawn);
			if ((Object)(object)view != (Object)null)
			{
				BroadcastSpawn(view.ViewID, isCloud);
			}
		}
	}

	private static Transform FindSpawnNear(Vector3 searchPos)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		Transform[] array = Object.FindObjectsByType<Transform>((FindObjectsSortMode)0);
		Transform result = null;
		float num = 0.9f;
		foreach (Transform val in array)
		{
			if (SelfToShelf.IsTeleportSpawn(val))
			{
				float num2 = Vector3.Distance(val.position, searchPos);
				if (num2 < num)
				{
					num = num2;
					result = val;
				}
			}
		}
		return result;
	}

	private static void Raise(byte sub, int viewId, int value, ReceiverGroup receivers)
	{
		//IL_0025: 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_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Expected O, but got Unknown
		try
		{
			PhotonNetwork.RaiseEvent((byte)163, (object)SelfToShelf.PackEvent(sub, viewId, value), new RaiseEventOptions
			{
				Receivers = receivers
			}, SendOptions.SendReliable);
		}
		catch (Exception ex)
		{
			SelfToShelf.LogInfo("[Self To Shelf] RaiseEvent failed: " + ex.Message);
		}
	}

	internal static void HandleGameplayEvent(byte sub, object[] payload)
	{
		if (payload == null || payload.Length < 4)
		{
			return;
		}
		int num = Convert.ToInt32(payload[3]);
		if (sub == 3)
		{
			RespondToUniqueRequest(num);
		}
		else if (payload.Length >= 5)
		{
			int num2 = Convert.ToInt32(payload[4]);
			switch (sub)
			{
			case 2:
				ApplyRemoteUnique(num, num2);
				break;
			case 4:
				ApplyRemoteSpawn(num, num2 == 1);
				break;
			}
		}
	}
}
internal static class FungusSpawnHelper
{
	private static bool _loggedInitError;

	private static readonly List<Item> _pendingHandshake = new List<Item>();

	public static void Initialize(Item item)
	{
		try
		{
			InitializeInner(item);
		}
		catch (Exception ex)
		{
			if (!_loggedInitError)
			{
				_loggedInitError = true;
				SelfToShelf.LogInfo("[Self To Shelf] fungus spawn init failed: " + ex);
			}
		}
	}

	private static void InitializeInner(Item item)
	{
		if (!SelfToShelf.IsShelfFungus(item) || !SelfToShelf.IsLiveWorldItem(item))
		{
			return;
		}
		if (!ShelfToShelfRuntime.ShouldApplyModEffects())
		{
			if (ShelfToShelfRuntime.IsAwaitingHostSync)
			{
				QueueUntilHandshake(item);
			}
		}
		else if (FungusNetworkSync.HasExplicitUnique(item))
		{
			FungusVisuals.ApplyFromItemData(item);
			if (FungusNetworkSync.CanTagItems())
			{
				FungusNetworkSync.PushItemInstanceData(item);
			}
		}
		else if (!FungusNetworkSync.CanTagItems())
		{
			FungusNetworkSync.TryApplyRemembered(item);
			if (FungusNetworkSync.HasExplicitUnique(item))
			{
				FungusVisuals.ApplyFromItemData(item);
				return;
			}
			FungusNetworkSync.RequestUniqueFromHost(item);
			FungusNetworkSync.ScheduleClientCatchup(item);
		}
		else
		{
			FungusNetworkSync.ForgetUnique(item);
			ScheduleDeferredTag(item);
		}
	}

	public static void QueueUntilHandshake(Item item)
	{
		if (!((Object)(object)item == (Object)null) && !_pendingHandshake.Contains(item))
		{
			_pendingHandshake.Add(item);
		}
	}

	public static void ClearPending()
	{
		_pendingHandshake.Clear();
	}

	public static void RetagUntaggedFungus()
	{
		if (!ShelfToShelfRuntime.ShouldApplyModEffects())
		{
			return;
		}
		for (int num = _pendingHandshake.Count - 1; num >= 0; num--)
		{
			Item val = _pendingHandshake[num];
			_pendingHandshake.RemoveAt(num);
			if ((Object)(object)val != (Object)null)
			{
				Initialize(val);
			}
		}
		Item[] array = Resources.FindObjectsOfTypeAll<Item>();
		if (array == null)
		{
			return;
		}
		foreach (Item item in array)
		{
			if (SelfToShelf.IsShelfFungus(item) && SelfToShelf.IsLiveWorldItem(item))
			{
				if (FungusNetworkSync.HasExplicitUnique(item))
				{
					FungusVisuals.ApplyFromItemData(item);
				}
				else
				{
					Initialize(item);
				}
			}
		}
	}

	public static void ScheduleDeferredTag(Item item)
	{
		if (!((Object)(object)item == (Object)null) && FungusNetworkSync.CanTagItems())
		{
			PhotonView itemView = FungusNetworkSync.GetItemView(item);
			int viewId = (((Object)(object)itemView != (Object)null) ? itemView.ViewID : ((Object)item).GetInstanceID());
			if (FungusNetworkSync.TryBeginDeferredTag(viewId))
			{
				FungusNetworkSync.StartRoutine(DeferredTagRoutine(item, viewId));
			}
		}
	}

	private static IEnumerator DeferredTagRoutine(Item item, int viewId)
	{
		yield return null;
		yield return null;
		try
		{
			if (!((Object)(object)item == (Object)null))
			{
				if (FungusNetworkSync.HasExplicitUnique(item))
				{
					FungusVisuals.ApplyFromItemData(item);
					FungusNetworkSync.PushItemInstanceData(item);
					yield break;
				}
				bool unique = SelfToShelf.RollChance(SelfToShelf.GetUniqueChance(item));
				FungusNetworkSync.SetUnique(item, unique);
				FungusVisuals.ApplyToItem(item, unique);
				FungusNetworkSync.PushUniqueState(item);
				FungusNetworkSync.ScheduleSpawnResync(item);
			}
		}
		finally
		{
			FungusNetworkSync.EndDeferredTag(viewId);
		}
	}
}
[HarmonyPatch(typeof(Item), "SetItemInstanceDataRPC")]
internal static class Item_SetItemInstanceDataRPC_Fungus_Patch
{
	private static bool _loggedError;

	private static void Postfix(Item __instance)
	{
		try
		{
			if (!SelfToShelf.IsShelfFungus(__instance))
			{
				return;
			}
			if (!ShelfToShelfRuntime.ShouldApplyModEffects())
			{
				if (ShelfToShelfRuntime.IsAwaitingHostSync)
				{
					FungusSpawnHelper.QueueUntilHandshake(__instance);
				}
				return;
			}
			if (FungusNetworkSync.CanTagItems())
			{
				if (FungusNetworkSync.HasExplicitUnique(__instance))
				{
					FungusVisuals.ApplyFromItemData(__instance);
				}
				else
				{
					FungusSpawnHelper.ScheduleDeferredTag(__instance);
				}
				return;
			}
			FungusNetworkSync.TryApplyRemembered(__instance);
			FungusVisuals.ApplyFromItemData(__instance);
			if (!FungusNetworkSync.HasExplicitUnique(__instance))
			{
				FungusNetworkSync.RequestUniqueFromHost(__instance);
				FungusNetworkSync.ScheduleClientCatchup(__instance);
			}
		}
		catch (Exception ex)
		{
			if (!_loggedError)
			{
				_loggedError = true;
				SelfToShelf.LogInfo("[Self To Shelf] SetItemInstanceDataRPC postfix failed: " + ex);
			}
		}
	}
}
[HarmonyPatch(typeof(Item), "OnDestroy")]
internal static class Item_OnDestroy_Fungus_Patch
{
	private static void Prefix(Item __instance)
	{
		if (SelfToShelf.IsShelfFungus(__instance))
		{
			FungusNetworkSync.ForgetUnique(__instance);
		}
	}
}
[HarmonyPatch(typeof(Item), "OnStash")]
internal static class Item_OnStash_Fungus_Patch
{
	private static void Prefix(Item __instance)
	{
		FungusNetworkSync.PreserveOnStash(__instance);
	}
}
[HarmonyPatch(typeof(CharacterItems), "DoDropping")]
internal static class CharacterItems_DoDropping_Fungus_Patch
{
	private static void Prefix()
	{
		try
		{
			Item item = (((Object)(object)Character.localCharacter != (Object)null && (Object)(object)Character.localCharacter.data != (Object)null) ? Character.localCharacter.data.currentItem : null);
			FungusNetworkSync.PreserveBeforeDrop(item);
		}
		catch
		{
		}
	}
}
namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
	public IgnoresAccessChecksToAttribute(string assemblyName)
	{
	}
}