Decompiled source of BasicItemSync v0.1.0

BasicItemSync.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BasicItemSync.Data;
using BasicItemSync.Modules.Hooks;
using BasicItemSync.Modules.Network.Client;
using BasicItemSync.Modules.Network.Server;
using BepInEx;
using GenericVariableExtension;
using HarmonyLib;
using HutongGames.PlayMaker;
using HutongGames.PlayMaker.Actions;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using SSMP.Api.Client;
using SSMP.Api.Client.Networking;
using SSMP.Api.Command;
using SSMP.Api.Command.Server;
using SSMP.Api.Server;
using SSMP.Api.Server.Networking;
using SSMP.Logging;
using SSMP.Networking.Packet;
using SSMP.Networking.Packet.Data;
using Silksong.AssetHelper.ManagedAssets;
using TeamCherry.Localization;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BasicItemSync")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+40f31cdea2e2ed2295a61cb322755c47cd9a53b8")]
[assembly: AssemblyProduct("BasicItemSync")]
[assembly: AssemblyTitle("BasicItemSync")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/BobbyTheCatfish/BasicItemSync")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BasicItemSync
{
	internal class Common
	{
		internal const string AddonName = "BasicItemSync";

		internal const string AddonVersion = "0.1.0";

		internal const int AddonApiVersion = 1;

		public static bool FlagAllowed(SyncServerSettings settings, FlagType flag)
		{
			if (ServerAddon.Settings.KillSwitch)
			{
				return false;
			}
			return flag switch
			{
				FlagType.Ability => settings.SyncAbilities, 
				FlagType.Map => settings.SyncMaps, 
				FlagType.Pin => settings.SyncPins, 
				FlagType.Bellshrine => settings.SyncProgression, 
				FlagType.Boss => settings.SyncBattles, 
				FlagType.Arena => settings.SyncBattles, 
				FlagType.Progression => settings.SyncProgression, 
				FlagType.Flea => settings.SyncCollectables, 
				FlagType.Collectable => settings.SyncCollectables, 
				FlagType.Bellway => settings.SyncTransit, 
				FlagType.Ventrica => settings.SyncTransit, 
				FlagType.Currency => settings.SyncCurrency, 
				FlagType.Mask => settings.SyncUpgrades, 
				FlagType.Spool => settings.SyncUpgrades, 
				FlagType.Pouch => settings.SyncUpgrades, 
				FlagType.CraftingKit => settings.SyncUpgrades, 
				FlagType.Quest => settings.SyncQuests, 
				FlagType.Tool => settings.SyncTools, 
				FlagType.Crest => settings.SyncTools, 
				FlagType.SilkHeart => settings.SyncUpgrades, 
				FlagType.Needle => settings.SyncUpgrades, 
				FlagType.Bench => settings.SyncProgression, 
				FlagType.Shortcut => true, 
				FlagType.QuestItem => settings.SyncQuestItems, 
				FlagType.DoNotSync => false, 
				_ => false, 
			};
		}
	}
	internal enum FlagType
	{
		Ability,
		Map,
		Pin,
		Bellshrine,
		Boss,
		Arena,
		Progression,
		Collectable,
		Bellway,
		Ventrica,
		Mask,
		Spool,
		Pouch,
		CraftingKit,
		SilkHeart,
		Needle,
		Quest,
		QuestItem,
		Tool,
		Crest,
		Currency,
		Shortcut,
		Bench,
		Flea,
		DoNotSync
	}
	internal enum InternalCurrencyType
	{
		Rosary,
		ShellShard
	}
	internal enum Packets
	{
		BoolPlayerData,
		IntPlayerData,
		FloatPlayerData,
		Collectable,
		Currency,
		Quest,
		Tool,
		Upgrade,
		Settings,
		PersistentBool,
		PersistentInt
	}
	internal class FakeLogger : ILogger
	{
		public void Debug(string message)
		{
		}

		public void Error(string message)
		{
		}

		public void Info(string message)
		{
		}

		public void Message(string message)
		{
		}

		public void Warn(string message)
		{
		}
	}
	internal static class Log
	{
		private static ILogger logger = (ILogger)(object)new FakeLogger();

		public static void SetLogger(ILogger log)
		{
			logger = log;
		}

		public static void LogInfo(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Info(obj.ToString());
			}
		}

		public static void LogWarning(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Warn(obj.ToString());
			}
		}

		public static void LogError(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Error(obj.ToString());
			}
		}

		public static void LogFatal(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Error(obj.ToString());
			}
		}

		public static void LogDebug(params object[] data)
		{
		}

		public static void LogMessage(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Message(obj.ToString());
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("io.github.bobbythecatfish.basicitemsync", "BasicItemSync", "0.1.0")]
	public class SyncPlugin : BaseUnityPlugin
	{
		private static List<Action> CurrentFrameActions = new List<Action>();

		private static List<Action> NextFrameActions = new List<Action>();

		internal static SyncPlugin Instance;

		internal static Dictionary<string, ManagedAsset<FakeCollectable>> Collectables = new Dictionary<string, ManagedAsset<FakeCollectable>>();

		public const string Id = "io.github.bobbythecatfish.basicitemsync";

		public static string Name => "BasicItemSync";

		public static string Version => "0.1.0";

		private void Awake()
		{
			Instance = this;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin " + Name + " (io.github.bobbythecatfish.basicitemsync) has loaded!"));
			ClientAddon.RegisterAddon((ClientAddon)(object)new ClientAddon());
			ServerAddon.RegisterAddon((ServerAddon)(object)new ServerAddon());
			Collectables["Mask"] = ManagedAsset<FakeCollectable>.FromNonSceneAsset("Assets/Data Assets/Collectables/Fake Collectables/Heart Piece.asset", "dataassets_assets_assets/dataassets/collectables/fakecollectables");
			Collectables["Spool"] = ManagedAsset<FakeCollectable>.FromNonSceneAsset("Assets/Data Assets/Collectables/Fake Collectables/Silk Spool.asset", "dataassets_assets_assets/dataassets/collectables/fakecollectables");
			Collectables["Pouch"] = ManagedAsset<FakeCollectable>.FromNonSceneAsset("Assets/Data Assets/Collectables/Fake Collectables/Tool Pouch Pickup.asset", "dataassets_assets_assets/dataassets/collectables/fakecollectables");
			Collectables["CraftKit"] = ManagedAsset<FakeCollectable>.FromNonSceneAsset("Assets/Data Assets/Collectables/Fake Collectables/Tool Kit Pickup.asset", "dataassets_assets_assets/dataassets/collectables/fakecollectables");
			Collectables["SilkHeart"] = ManagedAsset<FakeCollectable>.FromNonSceneAsset("Assets/Data Assets/Collectables/Fake Collectables/Silk Heart.asset", "dataassets_assets_assets/dataassets/collectables/fakecollectables");
			Collectables["Needle"] = ManagedAsset<FakeCollectable>.FromNonSceneAsset("Assets/Data Assets/Collectables/Fake Collectables/Needle Upgrade.asset", "dataassets_assets_assets/dataassets/collectables/fakecollectables");
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		}

		internal static void AddNextFrameAction(Action action)
		{
			NextFrameActions.Add(action);
		}

		private void Update()
		{
			if (CurrentFrameActions.Count > 0)
			{
				Action[] array = CurrentFrameActions.ToArray();
				CurrentFrameActions.Clear();
				Action[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i]();
				}
			}
		}

		private void LateUpdate()
		{
			if (NextFrameActions.Count > 0)
			{
				CurrentFrameActions = NextFrameActions.ToList();
				NextFrameActions.Clear();
			}
		}
	}
}
namespace BasicItemSync.Modules
{
	internal class BattleManager
	{
		private static BattleScene? GetBattleScene(string keyName)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			DeactivateIfPlayerdataTrue val2 = default(DeactivateIfPlayerdataTrue);
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				BattleScene[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<BattleScene>();
				foreach (BattleScene val in componentsInChildren)
				{
					if (((Component)val).TryGetComponent<DeactivateIfPlayerdataTrue>(ref val2) && val2.boolName == keyName)
					{
						return val;
					}
				}
			}
			return null;
		}

		public static void DefeatBattleScene(string keyName)
		{
			if (keyName == "defeatedBellBeast")
			{
				OnBellBeast();
				return;
			}
			BattleScene battleScene = GetBattleScene(keyName);
			if (!Object.op_Implicit((Object)(object)battleScene))
			{
				return;
			}
			if (battleScene.started)
			{
				int currentWave = battleScene.currentWave;
				battleScene.DoEndBattle();
				HealthManager[] componentsInChildren = ((Component)battleScene.waves[currentWave]).gameObject.GetComponentsInChildren<HealthManager>();
				foreach (HealthManager val in componentsInChildren)
				{
					if (!val.isDead)
					{
						val.Die((float?)0f, (AttackTypes)0, true);
					}
				}
			}
			else
			{
				((Component)battleScene).gameObject.SetActive(false);
			}
		}

		private static void OnBellBeast()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0023: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_008c: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name == "Bone_05")
			{
				Scene sceneByName = SceneManager.GetSceneByName("Bone_05_boss");
				if (((Scene)(ref sceneByName)).IsValid())
				{
					GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
					for (int i = 0; i < rootGameObjects.Length; i++)
					{
						rootGameObjects[i].SetActive(false);
					}
				}
			}
			else if (((Scene)(ref activeScene)).name == "Memory_Silk_Heart_BellBeast")
			{
				SceneLoadInfo val = new SceneLoadInfo
				{
					SceneName = "Bone_05",
					EntryGateName = "bot1",
					PreventCameraFadeOut = true,
					WaitForSceneTransitionCameraFade = false,
					Visualization = (SceneLoadVisualizations)0,
					AlwaysUnloadUnusedAssets = true,
					IsFirstLevelForPlayer = false
				};
				HeroController.instance.SetSilkRegenBlocked(false);
				PlayerData.instance.disableInventory = false;
				ToolItemManager.SetIsInCutscene(false);
				GameManager.instance.BeginSceneTransition(val);
			}
		}
	}
	internal class ClientState
	{
		public static string LastItem = "";

		public static string LastPlayerData = "";

		public static string LastPersistent = "";

		public static int LastCurrency = 0;

		public static FlagType LastUpgrade = FlagType.Currency;

		public static bool WasItemReceived(string item)
		{
			return LastItem == item;
		}

		public static bool WasCurrencyReceived(int amount)
		{
			return LastCurrency == amount;
		}

		public static bool WasUpgradeReceived(FlagType flagType)
		{
			return LastUpgrade == flagType;
		}

		public static bool WasPersistentReceived(string key)
		{
			return LastPersistent == key;
		}
	}
	internal class ObjectHelper
	{
		public static PersistentItem<T>? FindPersistent<T>(string sceneName, string id) where T : IEquatable<T>
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				PersistentItem<T>[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<PersistentItem<T>>();
				foreach (PersistentItem<T> val in componentsInChildren)
				{
					if (val.ItemData.ID == id && val.ItemData.SceneName == sceneName)
					{
						return val;
					}
				}
			}
			return null;
		}
	}
	internal class PersistentHandler
	{
		public static void SetPersistentIntData(string sceneName, string keyName, int status, FlagType flagType)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			PersistentItemData<int> value = new PersistentItemData<int>
			{
				SceneName = sceneName,
				ID = keyName,
				IsSemiPersistent = false,
				Value = status
			};
			PersistentItemData<int> val = default(PersistentItemData<int>);
			if (SceneData.instance.PersistentInts.TryGetValue(sceneName, keyName, ref val))
			{
				val.Value = status;
			}
			else
			{
				SceneData.instance.PersistentInts.SetValue(value);
			}
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			if (flagType == FlagType.Currency && name != sceneName)
			{
				return;
			}
			PersistentItem<int> val2 = ObjectHelper.FindPersistent<int>(sceneName, keyName);
			if (!((Object)(object)val2 == (Object)null))
			{
				PersistentIntItem val3 = (PersistentIntItem)(object)((val2 is PersistentIntItem) ? val2 : null);
				if (val3 != null)
				{
					((PersistentItem<int>)(object)val3).ItemData.Value = status;
					((PersistentItem<int>)(object)val3).Start();
				}
			}
		}

		public static void SetPersistentBoolData(string sceneName, string keyName, bool status, bool forceDisable = false)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			PersistentItemData<bool> value = new PersistentItemData<bool>
			{
				SceneName = sceneName,
				ID = keyName,
				IsSemiPersistent = false,
				Value = status
			};
			PersistentItemData<bool> val = default(PersistentItemData<bool>);
			if (SceneData.instance.PersistentBools.TryGetValue(sceneName, keyName, ref val))
			{
				val.Value = status;
			}
			else
			{
				SceneData.instance.PersistentBools.SetValue(value);
			}
			PersistentItem<bool> val2 = ObjectHelper.FindPersistent<bool>(sceneName, keyName);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			PersistentBoolItem val3 = (PersistentBoolItem)(object)((val2 is PersistentBoolItem) ? val2 : null);
			if (val3 == null)
			{
				return;
			}
			Lever val4 = default(Lever);
			Lever_tk2d val5 = default(Lever_tk2d);
			PersistentBoolItemResponder val6 = default(PersistentBoolItemResponder);
			if (((Component)val3).TryGetComponent<Lever>(ref val4))
			{
				TrackTriggerObjects canHitTrigger = val4.canHitTrigger;
				val4.canHitTrigger = null;
				val4.Hit(new HitInstance
				{
					IsFirstHit = true,
					IsNailTag = true,
					Direction = 0f
				});
				val4.canHitTrigger = canHitTrigger;
			}
			else if (((Component)val3).TryGetComponent<Lever_tk2d>(ref val5))
			{
				TrackTriggerObjects canHitTrigger2 = val5.canHitTrigger;
				val5.canHitTrigger = null;
				val5.Hit(new HitInstance
				{
					IsFirstHit = true,
					IsNailTag = true,
					Direction = 0f
				});
				val5.canHitTrigger = canHitTrigger2;
			}
			else if (Object.op_Implicit((Object)(object)((PersistentItem<bool>)(object)val3).fsm))
			{
				((PersistentItem<bool>)(object)val3).SetValueOnFSM(((PersistentItem<bool>)(object)val3).fsm, status);
				((PersistentItem<bool>)(object)val3).fsm.SendEvent("QUICK BREAK");
				((PersistentItem<bool>)(object)val3).fsm.SendEvent("ACTIVATE");
				((PersistentItem<bool>)(object)val3).fsm.SendEvent("DESTROY");
			}
			else if (((Component)val3).TryGetComponent<PersistentBoolItemResponder>(ref val6))
			{
				val6.InvokeEvents(status);
			}
			if (val3.disableIfActivated || forceDisable)
			{
				if (Object.op_Implicit((Object)(object)val3.disablePrefabIfActivated))
				{
					val3.disablePrefabIfActivated.SetActive(false);
				}
				((Component)val3).gameObject.SetActive(false);
			}
		}
	}
	internal class QuestHandler
	{
		public static void EndQuest(string name)
		{
			FullQuestBase quest = QuestManager.GetQuest(name);
			if (Object.op_Implicit((Object)(object)quest))
			{
				quest.SilentlyComplete();
				quest.ConsumeTarget();
				UI.ShowPopup((ICollectableUIMsgItem)(object)new QuestPopupItem(quest));
			}
		}

		public static void EndQuestSilent(string name)
		{
			FullQuestBase quest = QuestManager.GetQuest(name);
			if (Object.op_Implicit((Object)(object)quest))
			{
				quest.SilentlyComplete();
			}
		}
	}
	internal class UI
	{
		public static void ShowPopup(ICollectableUIMsgItem item)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			CollectableUIMsg.Spawn(item, Color.white, (CollectableUIMsg)null, false);
		}
	}
	internal class QuestPopupItem : ICollectableUIMsgItem, IUIMsgPopupItem
	{
		public FullQuestBase Quest;

		public QuestPopupItem(FullQuestBase quest)
		{
			Quest = quest;
		}

		public Object GetRepresentingObject()
		{
			return (Object)(object)Quest;
		}

		public float GetUIMsgIconScale()
		{
			return 1f;
		}

		public string GetUIMsgName()
		{
			//IL_0006: 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)
			return Language.Get(((BasicQuestBase)Quest).DisplayName.Key, ((BasicQuestBase)Quest).DisplayName.Sheet);
		}

		public Sprite GetUIMsgSprite()
		{
			return ((BasicQuestBase)Quest).QuestType.Icon;
		}

		public bool HasUpgradeIcon()
		{
			return false;
		}
	}
	internal class Upgrader
	{
		private static FakeCollectable? MaskCollectable;

		private static FakeCollectable? SpoolCollectable;

		private static FakeCollectable? PouchCollectable;

		private static FakeCollectable? CraftingKitCollectable;

		private static FakeCollectable? SilkHeartCollectable;

		private static FakeCollectable? NeedleUpgrade;

		public static bool UpgradeMask(string sceneName)
		{
			string text = "Heart Piece";
			if (sceneName == "Bone_East_LavaChallenge")
			{
				text += " (1)";
			}
			PersistentHandler.SetPersistentBoolData(sceneName, text, status: true, forceDisable: true);
			PlayerData instance = PlayerData.instance;
			instance.heartPieces++;
			if (PlayerData.instance.heartPieces >= 4)
			{
				PlayerData.instance.heartPieces = 0;
				HeroController.instance.AddToMaxHealth(1);
				HeroController.instance.MaxHealth();
				EventRegister.SendEvent("MAX HP UP", (GameObject)null);
			}
			LoadAndDisplay(ref MaskCollectable, "Mask", "UI", "SHOP_SHELLFRAG_NAME");
			return Save();
		}

		public static bool UpgradeSpool(string sceneName)
		{
			PersistentHandler.SetPersistentBoolData(sceneName, "Silk Spool", status: true, forceDisable: true);
			PlayerData instance = PlayerData.instance;
			instance.silkSpoolParts++;
			if (PlayerData.instance.silkSpoolParts >= 2)
			{
				PlayerData.instance.silkSpoolParts = 0;
				HeroController.instance.AddToMaxSilk(1);
				EventRegister.SendEvent("SPOOL MAX UP", (GameObject)null);
			}
			LoadAndDisplay(ref SpoolCollectable, "Spool", "UI", "SHOP_SPOOL_SEGMENT_NAME");
			return Save();
		}

		public static bool GiveCollectable(string persistentScene, string persistentKey, string itemKey)
		{
			if (!string.IsNullOrEmpty(persistentScene) && !string.IsNullOrEmpty(persistentKey))
			{
				PersistentHandler.SetPersistentBoolData(persistentScene, persistentKey, status: true, forceDisable: true);
			}
			CollectableItem itemByName = CollectableItemManager.GetItemByName(itemKey);
			itemByName.AddAmount(1);
			UI.ShowPopup((ICollectableUIMsgItem)(object)itemByName);
			return Save();
		}

		public static bool UpgradePouch()
		{
			PlayerData instance = PlayerData.instance;
			instance.ToolPouchUpgrades++;
			LoadAndDisplay(ref PouchCollectable, "Pouch", "UI", "INV_NAME_TOOLPOUCH");
			return Save();
		}

		public static bool UpgradeCraftingKit()
		{
			PlayerData instance = PlayerData.instance;
			instance.ToolKitUpgrades++;
			LoadAndDisplay(ref CraftingKitCollectable, "CraftKit", "UI", "INV_MSG_TOOLKIT");
			return Save();
		}

		public static bool UpgradeSilkHeart(string scene)
		{
			if (HeroControllerHook.LastCollectedScene == scene)
			{
				return false;
			}
			HeroControllerHook.LastCollectedScene = scene;
			PlayerData instance = PlayerData.instance;
			instance.silkRegenMax++;
			LoadAndDisplay(ref SilkHeartCollectable, "SilkHeart", "UI", "INV_MSG_THREAD_HEART");
			return Save();
		}

		public static bool UpgradeNeedle()
		{
			PlayerData instance = PlayerData.instance;
			instance.nailUpgrades++;
			LoadAndDisplay(ref NeedleUpgrade, "Needle", "UI", "INV_MSG_NEEDLE_UPGRADE");
			return Save();
		}

		private static void LoadAndDisplay(ref FakeCollectable? assetRef, string dictKey, string langSheet, string langKey)
		{
			//IL_004b: 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)
			if ((Object)(object)assetRef == (Object)null)
			{
				if (!SyncPlugin.Collectables.TryGetValue(dictKey, out ManagedAsset<FakeCollectable> value))
				{
					return;
				}
				if (!((ManagedAssetBase<FakeCollectable>)(object)value).IsLoaded)
				{
					((MonoBehaviour)SyncPlugin.Instance).StartCoroutine(Coroutine(value));
					return;
				}
				assetRef = ((ManagedAssetBase<FakeCollectable>)(object)value).Handle.Result;
			}
			UI.ShowPopup((ICollectableUIMsgItem)(object)assetRef);
			IEnumerator Coroutine(ManagedAsset<FakeCollectable> asset)
			{
				if (asset != null)
				{
					((ManagedAssetBase<FakeCollectable>)(object)asset).Load();
					yield return ((ManagedAssetBase<FakeCollectable>)(object)asset).Handle;
					if (((ManagedAssetBase<FakeCollectable>)(object)asset).Handle.OperationException != null)
					{
						Debug.LogError((object)$"Error loading asset: {((ManagedAssetBase<FakeCollectable>)(object)asset).Handle.OperationException}");
					}
					else
					{
						FakeCollectable result = ((ManagedAssetBase<FakeCollectable>)(object)asset).Handle.Result;
						result.uiMsgName = new LocalisedString
						{
							Sheet = langSheet,
							Key = langKey
						};
						UI.ShowPopup((ICollectableUIMsgItem)(object)result);
					}
				}
			}
		}

		public static bool Save()
		{
			if (!Object.op_Implicit((Object)(object)HeroController.SilentInstance))
			{
				Log.LogError("[CLI: SAVE] Not in save file. Cannot save data.");
				return false;
			}
			GameManager.instance.SaveGame((Action<bool>)delegate
			{
			});
			return true;
		}

		public static bool NoOp()
		{
			return false;
		}
	}
}
namespace BasicItemSync.Modules.Network
{
	internal class ClientPacket : IPacketData
	{
		public virtual bool IsReliable => true;

		public virtual bool DropReliableDataIfNewerExists => false;

		public virtual void ReadData(IPacket packet)
		{
		}

		public virtual void WriteData(IPacket packet)
		{
		}
	}
	internal class SendFlagPacket : ClientPacket
	{
		public string Key = "";

		public string Name = "";

		public FlagType FlagType;

		public override void WriteData(IPacket packet)
		{
			packet.Write(Key);
			packet.Write(Name);
			packet.Write((int)FlagType);
		}

		public override void ReadData(IPacket packet)
		{
			Key = packet.ReadString();
			Name = packet.ReadString();
			FlagType = (FlagType)packet.ReadInt();
		}
	}
	internal class SendBoolItemPacket : SendFlagPacket
	{
		public bool State = true;

		public override void WriteData(IPacket packet)
		{
			base.WriteData(packet);
			packet.Write(State);
		}

		public override void ReadData(IPacket packet)
		{
			base.ReadData(packet);
			State = packet.ReadBool();
		}
	}
	internal class SendUpgradeItemPacket : SendFlagPacket
	{
		private FlagType UpgradeType;

		public override void WriteData(IPacket packet)
		{
			base.WriteData(packet);
			packet.Write((int)UpgradeType);
		}

		public override void ReadData(IPacket packet)
		{
			base.ReadData(packet);
			UpgradeType = (FlagType)packet.ReadInt();
		}
	}
	internal class SendPersistentPacket : SendFlagPacket
	{
		public string PersistentScene = "";

		public string PersistentObject = "";

		public override void WriteData(IPacket packet)
		{
			base.WriteData(packet);
			packet.Write(PersistentScene);
			packet.Write(PersistentObject);
		}

		public override void ReadData(IPacket packet)
		{
			base.ReadData(packet);
			PersistentScene = packet.ReadString();
			PersistentObject = packet.ReadString();
		}
	}
	internal class SendPersistentBoolPacket : SendPersistentPacket
	{
		public bool State = true;

		public override void WriteData(IPacket packet)
		{
			base.WriteData(packet);
			packet.Write(State);
		}

		public override void ReadData(IPacket packet)
		{
			base.ReadData(packet);
			State = packet.ReadBool();
		}
	}
	internal class SendPersistentIntPacket : SendPersistentPacket
	{
		public int State;

		public override void WriteData(IPacket packet)
		{
			base.WriteData(packet);
			packet.Write(State);
		}

		public override void ReadData(IPacket packet)
		{
			base.ReadData(packet);
			State = packet.ReadInt();
		}
	}
	internal class SendIntItemPacket : SendFlagPacket
	{
		public int Number;

		public override void WriteData(IPacket packet)
		{
			base.WriteData(packet);
			packet.Write(Number);
		}

		public override void ReadData(IPacket packet)
		{
			base.ReadData(packet);
			Number = packet.ReadInt();
		}
	}
	internal class SendFloatItemPacket : SendFlagPacket
	{
		public float Number;

		public override void WriteData(IPacket packet)
		{
			base.WriteData(packet);
			packet.Write(Number);
		}

		public override void ReadData(IPacket packet)
		{
			base.ReadData(packet);
			Number = packet.ReadFloat();
		}
	}
	internal class SendCurrencyPacket : ClientPacket
	{
		public InternalCurrencyType CurrencyType;

		public int Amount;

		public override bool IsReliable => false;

		public override void WriteData(IPacket packet)
		{
			packet.Write((byte)CurrencyType);
			packet.Write(Amount);
		}

		public override void ReadData(IPacket packet)
		{
			CurrencyType = (InternalCurrencyType)packet.ReadByte();
			Amount = packet.ReadInt();
		}
	}
	internal class SettingsUpdatePacket : IPacketData
	{
		public SyncServerSettings Settings;

		public bool IsReliable => true;

		public bool DropReliableDataIfNewerExists => true;

		public void WriteData(IPacket packet)
		{
			List<bool> list = Settings.ToValues();
			packet.Write(list.Count);
			foreach (bool item in list)
			{
				packet.Write(item);
			}
		}

		public void ReadData(IPacket packet)
		{
			int num = packet.ReadInt();
			List<bool> list = new List<bool>();
			for (int i = 0; i < num; i++)
			{
				list.Add(packet.ReadBool());
			}
			Settings = SyncServerSettings.PopulateFromValues(list);
		}
	}
	internal class SendQuestItemPacket : SendBoolItemPacket
	{
	}
	internal static class PacketInstantiate
	{
		internal static IPacketData Instantiate(Packets packetID)
		{
			Log.LogDebug($"[PACKETS] Received {packetID}");
			return (IPacketData)(packetID switch
			{
				Packets.BoolPlayerData => new PacketDataCollection<SendBoolItemPacket>(), 
				Packets.IntPlayerData => new PacketDataCollection<SendIntItemPacket>(), 
				Packets.FloatPlayerData => new PacketDataCollection<SendFloatItemPacket>(), 
				Packets.Currency => new PacketDataCollection<SendCurrencyPacket>(), 
				Packets.Quest => new PacketDataCollection<SendBoolItemPacket>(), 
				Packets.Tool => new PacketDataCollection<SendBoolItemPacket>(), 
				Packets.Upgrade => new PacketDataCollection<SendFlagPacket>(), 
				Packets.Collectable => new PacketDataCollection<SendPersistentBoolPacket>(), 
				Packets.PersistentBool => new PacketDataCollection<SendPersistentBoolPacket>(), 
				Packets.PersistentInt => new PacketDataCollection<SendPersistentIntPacket>(), 
				Packets.Settings => new SettingsUpdatePacket(), 
				_ => new ErrorThrowingPacket(packetID, server: true), 
			});
		}
	}
	internal class ErrorThrowingPacket : ClientPacket
	{
		public ErrorThrowingPacket(Packets id, bool server)
		{
			Log.LogError(id.ToString(), server);
			throw new NotImplementedException(id.ToString());
		}
	}
}
namespace BasicItemSync.Modules.Network.Server
{
	internal class NetworkForwarder
	{
		private static IServerAddonNetworkReceiver<Packets> Receiver;

		private static IServerAddonNetworkSender<Packets> Sender;

		public static void Initialize()
		{
			Sender = ServerAddon.api.NetServer.GetNetworkSender<Packets>((ServerAddon)(object)ServerAddon.Instance);
			Receiver = ServerAddon.api.NetServer.GetNetworkReceiver<Packets>((ServerAddon)(object)ServerAddon.Instance, (Func<Packets, IPacketData>)PacketInstantiate.Instantiate);
			Receiver.RegisterPacketHandler<SendBoolItemPacket>(Packets.BoolPlayerData, (GenericServerPacketHandler<SendBoolItemPacket>)OnBool);
			Receiver.RegisterPacketHandler<SendIntItemPacket>(Packets.IntPlayerData, (GenericServerPacketHandler<SendIntItemPacket>)OnInt);
			Receiver.RegisterPacketHandler<SendFloatItemPacket>(Packets.FloatPlayerData, (GenericServerPacketHandler<SendFloatItemPacket>)OnFloat);
			Receiver.RegisterPacketHandler<SendCurrencyPacket>(Packets.Currency, (GenericServerPacketHandler<SendCurrencyPacket>)OnCurrency);
			Receiver.RegisterPacketHandler<SendBoolItemPacket>(Packets.Quest, (GenericServerPacketHandler<SendBoolItemPacket>)OnQuest);
			Receiver.RegisterPacketHandler<SendBoolItemPacket>(Packets.Tool, (GenericServerPacketHandler<SendBoolItemPacket>)OnTool);
			Receiver.RegisterPacketHandler<SendFlagPacket>(Packets.Upgrade, (GenericServerPacketHandler<SendFlagPacket>)OnUpgrade);
			Receiver.RegisterPacketHandler<SendPersistentBoolPacket>(Packets.Collectable, (GenericServerPacketHandler<SendPersistentBoolPacket>)OnCollectable);
			Receiver.RegisterPacketHandler<SendPersistentBoolPacket>(Packets.PersistentBool, (GenericServerPacketHandler<SendPersistentBoolPacket>)OnPersistentBool);
			Receiver.RegisterPacketHandler<SendPersistentIntPacket>(Packets.PersistentInt, (GenericServerPacketHandler<SendPersistentIntPacket>)OnPersistentInt);
		}

		private static void Broadcast(ushort senderId, Packets type, ClientPacket packet)
		{
			if (Sender == null)
			{
				return;
			}
			foreach (IServerPlayer player in ServerAddon.api.ServerManager.Players)
			{
				if (player.Id != senderId)
				{
					Sender.SendCollectionData<ClientPacket>(type, packet, player.Id);
				}
			}
		}

		public static void SendSettingsUpdate()
		{
			SettingsUpdatePacket settingsUpdatePacket = new SettingsUpdatePacket
			{
				Settings = ServerAddon.Settings
			};
			ServerAddon.api.ServerManager.BroadcastMessage("Sync settings have been updated");
			Sender.BroadcastSingleData(Packets.Settings, (IPacketData)(object)settingsUpdatePacket);
		}

		public static void SendSettingsUpdate(ushort id)
		{
			SettingsUpdatePacket settingsUpdatePacket = new SettingsUpdatePacket
			{
				Settings = ServerAddon.Settings
			};
			Sender.SendSingleData(Packets.Settings, (IPacketData)(object)settingsUpdatePacket, id);
		}

		private static void OnCurrency(ushort id, SendCurrencyPacket packet)
		{
			if (ServerAddon.Settings.FlagAllowed(FlagType.Currency))
			{
				Broadcast(id, Packets.Currency, packet);
			}
		}

		private static void OnBool(ushort id, SendBoolItemPacket packet)
		{
			OnFlag(id, packet, Packets.BoolPlayerData, isPD: true);
		}

		private static void OnInt(ushort id, SendIntItemPacket packet)
		{
			OnFlag(id, packet, Packets.IntPlayerData, isPD: true);
		}

		private static void OnFloat(ushort id, SendFloatItemPacket packet)
		{
			OnFlag(id, packet, Packets.FloatPlayerData, isPD: true);
		}

		private static void OnQuest(ushort id, SendBoolItemPacket packet)
		{
			OnFlag(id, packet, Packets.Quest, isPD: false);
		}

		private static void OnTool(ushort id, SendBoolItemPacket packet)
		{
			OnFlag(id, packet, Packets.Tool, isPD: false);
		}

		private static void OnUpgrade(ushort id, SendFlagPacket packet)
		{
			OnFlag(id, packet, Packets.Upgrade, isPD: false);
		}

		private static void OnCollectable(ushort id, SendPersistentBoolPacket packet)
		{
			OnFlag(id, packet, Packets.Collectable, isPD: false);
		}

		private static void OnPersistentBool(ushort id, SendPersistentBoolPacket packet)
		{
			OnFlag(id, packet, Packets.PersistentBool, isPD: true);
		}

		private static void OnPersistentInt(ushort id, SendPersistentIntPacket packet)
		{
			OnFlag(id, packet, Packets.PersistentInt, isPD: true);
		}

		private static void Announce(ushort id, SendFlagPacket packet, bool isPossiblySilent)
		{
			FlagType flagType = packet.FlagType;
			Log.LogDebug($"[SERVER] Received {flagType}");
			if (!isPossiblySilent || !string.IsNullOrEmpty(packet.Name))
			{
				string text = flagType switch
				{
					FlagType.Ability => "obtained $", 
					FlagType.Map => "obtained $ Map", 
					FlagType.Pin => "obtained $", 
					FlagType.Bellshrine => "activated the $ Bellshrine", 
					FlagType.Boss => "defeated $", 
					FlagType.Arena => "defeated $", 
					FlagType.Progression => "obtained the $", 
					FlagType.Collectable => "collected a $", 
					FlagType.Bellway => "unlocked the $ Bellway Station", 
					FlagType.Ventrica => "unlocked the $ Ventrica", 
					FlagType.Mask => "obtained the Mask Shard in $", 
					FlagType.Spool => "obtained the Spool Fragment in $", 
					FlagType.Pouch => "obtained a Tool Pouch from $", 
					FlagType.CraftingKit => "obtained a Crafting Kit from $", 
					FlagType.SilkHeart => "obtained a Silk Heart", 
					FlagType.Needle => "upgraded their needle", 
					FlagType.Quest => "finished the $ quest", 
					FlagType.QuestItem => "", 
					FlagType.Tool => "obtained $", 
					FlagType.Crest => "obtained $ Crest", 
					FlagType.Currency => "", 
					FlagType.Bench => "unlocked a bench", 
					FlagType.Flea => "saved a flea from $", 
					_ => "", 
				};
				if (!string.IsNullOrEmpty(text))
				{
					IServerPlayer player = ServerAddon.api.ServerManager.GetPlayer(id);
					string text2 = string.Concat(str2: text.Replace("$", string.IsNullOrEmpty(packet.Name) ? packet.Key : packet.Name), str0: ((player != null) ? player.Username : null) ?? "Unknown Player", str1: " ");
					ServerAddon.api.ServerManager.BroadcastMessage(text2);
				}
			}
		}

		private static void OnFlag(ushort id, SendFlagPacket packet, Packets type, bool isPD)
		{
			if (ServerAddon.Settings.FlagAllowed(packet.FlagType))
			{
				Announce(id, packet, isPD);
				Broadcast(id, type, packet);
			}
		}
	}
	internal class ServerAddon : ServerAddon
	{
		public static IServerApi api;

		public static ServerAddon Instance;

		public static SyncServerSettings Settings;

		public override bool NeedsNetwork => true;

		public override uint ApiVersion => 1u;

		protected override string Name => "BasicItemSync";

		protected override string Version => "0.1.0";

		public override void Initialize(IServerApi serverApi)
		{
			Log.SetLogger(((ServerAddon)this).Logger);
			Log.LogInfo("Item Sync Server Addon enabled");
			Settings = SyncServerSettings.ReadFromFile();
			Instance = this;
			api = serverApi;
			NetworkForwarder.Initialize();
			api.ServerManager.PlayerConnectEvent += OnPlayerConnect;
		}

		private void OnPlayerConnect(IServerPlayer player)
		{
			NetworkForwarder.SendSettingsUpdate(player.Id);
		}
	}
	internal class SettingCommand : IServerCommand, ICommand
	{
		private readonly SyncServerSettings Settings;

		public bool AuthorizedOnly => true;

		public string Trigger => "/sync";

		public string[] Aliases => Array.Empty<string>();

		public SettingCommand(SyncServerSettings settings)
		{
			Settings = settings;
		}

		public void Execute(ICommandSender commandSender, string[] arguments)
		{
			if (arguments.Length < 2)
			{
				SendUsage();
				return;
			}
			string settingName = "Sync" + arguments[1];
			FieldInfo fieldInfo = Extensions.GetAllFields(typeof(SyncServerSettings), BindingFlags.Public).FirstOrDefault((FieldInfo s) => s.Name.Equals(settingName, StringComparison.CurrentCultureIgnoreCase));
			if (fieldInfo == null)
			{
				commandSender.SendMessage("Unknown setting '" + settingName);
				return;
			}
			if (arguments.Length == 2)
			{
				bool variable = VariableExtensionsGeneric.GetVariable<bool>((object)Settings, fieldInfo.Name);
				commandSender.SendMessage($"Setting '{fieldInfo.Name}' is currently {variable}");
				return;
			}
			bool flag;
			if (arguments[2] == "true")
			{
				flag = true;
			}
			else
			{
				if (!(arguments[2] == "false"))
				{
					SendUsage();
					return;
				}
				flag = false;
			}
			VariableExtensionsGeneric.SetVariable<bool>((object)Settings, fieldInfo.Name, flag);
			NetworkForwarder.SendSettingsUpdate();
			void SendUsage()
			{
				commandSender.SendMessage("Invalid usage: " + Trigger + " <setting> <true/false>");
			}
		}
	}
	internal class SyncServerSettings
	{
		public bool KillSwitch;

		public bool SyncCurrency = true;

		public bool SyncQuests = true;

		public bool SyncQuestItems;

		public bool SyncTools = true;

		public bool SyncAbilities = true;

		public bool SyncMaps = true;

		public bool SyncPins = true;

		public bool SyncBattles = true;

		public bool SyncProgression = true;

		public bool SyncCollectables = true;

		public bool SyncUpgrades = true;

		public bool SyncTransit = true;

		public bool SyncShortcuts = true;

		public bool FlagAllowed(FlagType flag)
		{
			if (ServerAddon.Settings.KillSwitch)
			{
				return false;
			}
			return flag switch
			{
				FlagType.Ability => SyncAbilities, 
				FlagType.Map => SyncMaps, 
				FlagType.Pin => SyncPins, 
				FlagType.Bellshrine => SyncProgression, 
				FlagType.Boss => SyncBattles, 
				FlagType.Arena => SyncBattles, 
				FlagType.Progression => SyncProgression, 
				FlagType.Flea => SyncCollectables, 
				FlagType.Collectable => SyncCollectables, 
				FlagType.Bellway => SyncTransit, 
				FlagType.Ventrica => SyncTransit, 
				FlagType.Currency => SyncCurrency, 
				FlagType.Mask => SyncUpgrades, 
				FlagType.Spool => SyncUpgrades, 
				FlagType.Pouch => SyncUpgrades, 
				FlagType.CraftingKit => SyncUpgrades, 
				FlagType.Quest => SyncQuests, 
				FlagType.QuestItem => SyncQuestItems, 
				FlagType.Tool => SyncTools, 
				FlagType.Crest => SyncTools, 
				FlagType.SilkHeart => SyncUpgrades, 
				FlagType.Needle => SyncUpgrades, 
				FlagType.Bench => SyncProgression, 
				FlagType.Shortcut => SyncShortcuts, 
				FlagType.DoNotSync => false, 
				_ => false, 
			};
		}

		public List<bool> ToValues()
		{
			List<PropertyInfo> properties = GetProperties();
			List<bool> list = new List<bool>();
			foreach (PropertyInfo item in properties)
			{
				list.Add(VariableExtensionsGeneric.GetVariable<bool>((object)this, item.Name));
			}
			return list;
		}

		private static List<PropertyInfo> GetProperties()
		{
			List<PropertyInfo> list = typeof(SyncServerSettings).GetProperties().ToList();
			list.Sort((PropertyInfo a, PropertyInfo b) => a.Name.CompareTo(b.Name));
			return list;
		}

		public void CopyFrom(SyncServerSettings settings)
		{
			foreach (PropertyInfo property in GetProperties())
			{
				VariableExtensionsGeneric.SetVariable<bool>((object)this, property.Name, VariableExtensionsGeneric.GetVariable<bool>((object)settings, property.Name));
			}
		}

		public static SyncServerSettings PopulateFromValues(List<bool> values)
		{
			SyncServerSettings syncServerSettings = new SyncServerSettings();
			List<PropertyInfo> properties = GetProperties();
			int num = Math.Min(properties.Count, values.Count);
			if (num != properties.Count)
			{
				Log.LogWarning("Mismatched server setting property count");
			}
			for (int i = 0; i < num; i++)
			{
				PropertyInfo propertyInfo = properties[i];
				bool flag = values[i];
				propertyInfo.SetValue(syncServerSettings, flag);
			}
			return syncServerSettings;
		}

		public static SyncServerSettings ReadFromFile()
		{
			string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ServerSettings.json");
			if (!File.Exists(text))
			{
				Log.LogWarning("[SERVER: SETTINGS] " + text + " doesn't exist");
				SyncServerSettings syncServerSettings = new SyncServerSettings();
				syncServerSettings.SaveToFile();
				return syncServerSettings;
			}
			try
			{
				return JsonConvert.DeserializeObject<SyncServerSettings>(File.ReadAllText(text)) ?? new SyncServerSettings();
			}
			catch (Exception arg)
			{
				Log.LogError($"[SERVER: SETTINGS] Could not load server settings from file:\n{arg}");
				return new SyncServerSettings();
			}
		}

		public void SaveToFile()
		{
			string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ServerSettings.json");
			if (!Directory.Exists(Path.GetDirectoryName(text)))
			{
				Log.LogWarning("[SERVER: SETTINGS] " + text + " directory doesn't exist");
				return;
			}
			string text2 = JsonConvert.SerializeObject((object)this, (Formatting)1);
			if (text2 == null)
			{
				return;
			}
			try
			{
				File.WriteAllText(text, text2);
			}
			catch (Exception arg)
			{
				Log.LogError($"[SERVER: SETTINGS] Could not write server settings to file:\n{arg}");
			}
		}
	}
}
namespace BasicItemSync.Modules.Network.Client
{
	internal class ClientAddon : ClientAddon
	{
		public static IClientApi api;

		public static ClientAddon Instance;

		public static SyncServerSettings Settings = new SyncServerSettings();

		private static readonly WaitForSeconds CurrencyTimer = new WaitForSeconds(4f);

		private static Coroutine? CurrencyRoutine;

		public override bool NeedsNetwork => true;

		public override uint ApiVersion => 1u;

		protected override string Name => "BasicItemSync";

		protected override string Version => "0.1.0";

		public override void Initialize(IClientApi clientApi)
		{
			Log.SetLogger(((ClientAddon)this).Logger);
			Log.LogInfo("Sync Client Addon enabled");
			Settings = new SyncServerSettings();
			Instance = this;
			api = clientApi;
			NetworkSender.Initialize();
			NetworkReceiver.Initialize();
			api.ClientManager.ConnectEvent += OnConnect;
			api.ClientManager.DisconnectEvent += OnDisconnect;
		}

		private void OnConnect()
		{
			EventHooks.Initialize();
			Settings = new SyncServerSettings();
			api.UiManager.ChatBox.AddMessage("BasicItemSync is in beta. Please report any bugs to the link on the mod page.");
			CurrencyRoutine = ((MonoBehaviour)SyncPlugin.Instance).StartCoroutine(CurrencySender());
		}

		private void OnDisconnect()
		{
			EventHooks.Uninitialize();
			if (CurrencyRoutine != null)
			{
				NetworkSender.SendPendingCurrency();
				((MonoBehaviour)SyncPlugin.Instance).StopCoroutine(CurrencyRoutine);
			}
		}

		public static void LocalChat(string message)
		{
			api.UiManager.ChatBox.AddMessage(message);
		}

		private static IEnumerator CurrencySender()
		{
			while (true)
			{
				NetworkSender.SendPendingCurrency();
				yield return CurrencyTimer;
			}
		}
	}
	internal class NetworkReceiver
	{
		private static IClientAddonNetworkReceiver<Packets> Receiver;

		public static void Initialize()
		{
			Receiver = ClientAddon.api.NetClient.GetNetworkReceiver<Packets>((ClientAddon)(object)ClientAddon.Instance, (Func<Packets, IPacketData>)PacketInstantiate.Instantiate);
			Receiver.RegisterPacketHandler<SettingsUpdatePacket>(Packets.Settings, (GenericClientPacketHandler<SettingsUpdatePacket>)OnSettingsUpdate);
			Receiver.RegisterPacketHandler<SendBoolItemPacket>(Packets.BoolPlayerData, (GenericClientPacketHandler<SendBoolItemPacket>)OnBoolFlag);
			Receiver.RegisterPacketHandler<SendIntItemPacket>(Packets.IntPlayerData, (GenericClientPacketHandler<SendIntItemPacket>)OnIntFlag);
			Receiver.RegisterPacketHandler<SendFloatItemPacket>(Packets.FloatPlayerData, (GenericClientPacketHandler<SendFloatItemPacket>)OnFloatFlag);
			Receiver.RegisterPacketHandler<SendCurrencyPacket>(Packets.Currency, (GenericClientPacketHandler<SendCurrencyPacket>)OnCurrency);
			Receiver.RegisterPacketHandler<SendBoolItemPacket>(Packets.Quest, (GenericClientPacketHandler<SendBoolItemPacket>)OnQuestItem);
			Receiver.RegisterPacketHandler<SendBoolItemPacket>(Packets.Tool, (GenericClientPacketHandler<SendBoolItemPacket>)OnTool);
			Receiver.RegisterPacketHandler<SendFlagPacket>(Packets.Upgrade, (GenericClientPacketHandler<SendFlagPacket>)OnUpgrade);
			Receiver.RegisterPacketHandler<SendPersistentBoolPacket>(Packets.Collectable, (GenericClientPacketHandler<SendPersistentBoolPacket>)OnCollectable);
			Receiver.RegisterPacketHandler<SendPersistentBoolPacket>(Packets.PersistentBool, (GenericClientPacketHandler<SendPersistentBoolPacket>)OnPersistentBool);
			Receiver.RegisterPacketHandler<SendPersistentIntPacket>(Packets.PersistentInt, (GenericClientPacketHandler<SendPersistentIntPacket>)OnPersistentInt);
		}

		private static void OnIntFlag(SendIntItemPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastItem = packet.Key;
				PlayerData.instance.SetInt(packet.Key, packet.Number);
				ClientState.LastItem = "";
			});
		}

		private static void OnFloatFlag(SendFloatItemPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastItem = packet.Key;
				PlayerData.instance.SetFloat(packet.Key, packet.Number);
				ClientState.LastItem = "";
			});
		}

		private static void OnBoolFlag(SendBoolItemPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastItem = packet.Key;
				PlayerData.instance.SetBool(packet.Key, packet.State);
				ClientState.LastItem = "";
				if (packet.FlagType == FlagType.Boss || packet.FlagType == FlagType.Arena)
				{
					BattleManager.DefeatBattleScene(packet.Key);
				}
			});
		}

		private static void OnCurrency(SendCurrencyPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastCurrency = packet.Amount;
				if (packet.CurrencyType == InternalCurrencyType.Rosary)
				{
					CurrencyManager.AddGeo(packet.Amount);
				}
				else
				{
					CurrencyManager.AddShards(packet.Amount);
				}
				ClientState.LastCurrency = 0;
			});
		}

		private static void OnQuestItem(SendBoolItemPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastItem = packet.Key;
				QuestHandler.EndQuest(packet.Key);
				ClientState.LastItem = "";
			});
		}

		private static void OnTool(SendBoolItemPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastItem = packet.Key;
				if (packet.FlagType == FlagType.Crest)
				{
					ToolCrest crestByName = ToolItemManager.GetCrestByName(packet.Key);
					if (Object.op_Implicit((Object)(object)crestByName))
					{
						crestByName.Unlock();
					}
				}
				else
				{
					ToolItem toolByName = ToolItemManager.GetToolByName(packet.Key);
					if (Object.op_Implicit((Object)(object)toolByName))
					{
						PlayerData.instance.SeenToolGetPrompt = true;
						PlayerData.instance.SeenToolWeaponGetPrompt = true;
						if (packet.State)
						{
							toolByName.Unlock((Action)null, (PopupFlags)3);
						}
						else
						{
							toolByName.Lock();
						}
					}
				}
				ClientState.LastItem = "";
			});
		}

		private static void OnUpgrade(SendFlagPacket packet)
		{
			if (!string.IsNullOrEmpty(packet.Name))
			{
				SyncPlugin.AddNextFrameAction(delegate
				{
					ClientState.LastItem = packet.Name;
					QuestHandler.EndQuestSilent(packet.Name);
					ClientState.LastItem = "";
				});
			}
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastUpgrade = packet.FlagType;
				switch (packet.FlagType)
				{
				case FlagType.Mask:
					Upgrader.UpgradeMask(packet.Key);
					break;
				case FlagType.Spool:
					Upgrader.UpgradeSpool(packet.Key);
					break;
				case FlagType.Pouch:
					Upgrader.UpgradePouch();
					break;
				case FlagType.CraftingKit:
					Upgrader.UpgradeCraftingKit();
					break;
				case FlagType.SilkHeart:
					Upgrader.UpgradeSilkHeart(packet.Key);
					break;
				case FlagType.Needle:
					Upgrader.UpgradeNeedle();
					break;
				default:
					Upgrader.NoOp();
					break;
				}
				ClientState.LastUpgrade = FlagType.DoNotSync;
			});
		}

		private static void OnCollectable(SendPersistentBoolPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastItem = packet.Key;
				Upgrader.GiveCollectable(packet.PersistentScene, packet.PersistentObject, packet.Key);
				ClientState.LastItem = "";
			});
		}

		private static void OnPersistentBool(SendPersistentBoolPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastItem = packet.Key;
				PersistentHandler.SetPersistentBoolData(packet.PersistentScene, packet.PersistentObject, packet.State);
				ClientState.LastItem = "";
			});
		}

		private static void OnPersistentInt(SendPersistentIntPacket packet)
		{
			SyncPlugin.AddNextFrameAction(delegate
			{
				ClientState.LastItem = packet.Key;
				PersistentHandler.SetPersistentIntData(packet.PersistentScene, packet.PersistentObject, packet.State, packet.FlagType);
				ClientState.LastItem = "";
			});
		}

		private static void OnSettingsUpdate(SettingsUpdatePacket packet)
		{
			ClientAddon.Settings.CopyFrom(packet.Settings);
			Log.LogInfo("[CLI] Received new settings");
		}
	}
	internal class NetworkSender
	{
		private static IClientAddonNetworkSender<Packets>? Sender;

		private static int RosariesToSend = 0;

		private static int ShardsToSend = 0;

		private static Dictionary<(string, string), SendPersistentPacket> PersistentsToSend = new Dictionary<(string, string), SendPersistentPacket>();

		public static void Initialize()
		{
			Sender = ClientAddon.api.NetClient.GetNetworkSender<Packets>((ClientAddon)(object)ClientAddon.Instance);
		}

		private static void SendData(Packets type, ClientPacket packet)
		{
			if (!ClientAddon.api.NetClient.IsConnected || Sender == null)
			{
				Log.LogDebug("Not connected");
			}
			else if (!(packet is SendFlagPacket sendFlagPacket) || CanSync(sendFlagPacket.FlagType))
			{
				Log.LogDebug($"[CLI] Sending {type}");
				Sender.SendCollectionData<ClientPacket>(type, packet);
			}
		}

		private static bool CanSync(FlagType flagType)
		{
			if (!ClientAddon.Settings.FlagAllowed(flagType))
			{
				Log.LogDebug($"[CLI] Syncing {flagType} is disabled.");
				return false;
			}
			return true;
		}

		public static void AddCurrency(InternalCurrencyType currencyType, int amount)
		{
			if (CanSync(FlagType.Currency))
			{
				if (currencyType == InternalCurrencyType.Rosary)
				{
					RosariesToSend += amount;
				}
				else
				{
					ShardsToSend += amount;
				}
			}
		}

		public static void SendPendingCurrency()
		{
			if (RosariesToSend > 0)
			{
				SendData(Packets.Currency, new SendCurrencyPacket
				{
					CurrencyType = InternalCurrencyType.Rosary,
					Amount = RosariesToSend
				});
			}
			if (ShardsToSend > 0)
			{
				SendData(Packets.Currency, new SendCurrencyPacket
				{
					CurrencyType = InternalCurrencyType.ShellShard,
					Amount = ShardsToSend
				});
			}
			RosariesToSend = 0;
			ShardsToSend = 0;
		}

		public static void SendPendingPersistents()
		{
			if (PersistentsToSend.Count > 0)
			{
				foreach (SendPersistentPacket value in PersistentsToSend.Values)
				{
					SendData(Packets.PersistentBool, value);
				}
			}
			PersistentsToSend.Clear();
		}

		public static void SendFlag(string playerDataKey, FlagType flagType, string name, bool state = true)
		{
			SendData(Packets.BoolPlayerData, new SendBoolItemPacket
			{
				Key = playerDataKey,
				Name = name,
				FlagType = flagType,
				State = state
			});
		}

		public static void SendInt(string playerDataKey, FlagType flagType, string name, int state)
		{
			SendData(Packets.IntPlayerData, new SendIntItemPacket
			{
				Key = playerDataKey,
				Name = name,
				FlagType = flagType,
				Number = state
			});
		}

		public static void SendQuestComplete(string internalName, string displayName)
		{
			SendData(Packets.Quest, new SendBoolItemPacket
			{
				Key = internalName,
				Name = displayName,
				FlagType = FlagType.Quest,
				State = true
			});
		}

		public static void SendTool(string toolName, string displayName, bool state, bool isCrest)
		{
			SendData(Packets.Tool, new SendBoolItemPacket
			{
				Key = toolName,
				Name = displayName,
				FlagType = (isCrest ? FlagType.Crest : FlagType.Tool),
				State = state
			});
		}

		public static void SendUpgrade(string sceneName, FlagType upgradeType)
		{
			SendData(Packets.Upgrade, new SendFlagPacket
			{
				Key = sceneName,
				Name = "",
				FlagType = upgradeType
			});
		}

		public static void SendCollectable(string key, string itemName, string persistentKey, string persistentScene, FlagType flagType = FlagType.Collectable)
		{
			SendData(Packets.Collectable, new SendPersistentBoolPacket
			{
				Key = key,
				Name = itemName,
				FlagType = flagType,
				PersistentObject = persistentKey,
				PersistentScene = persistentScene
			});
		}

		public static void AddPersistentIntData(string id, string scene, int value, FlagType flagType)
		{
			if (!PersistentsToSend.ContainsKey((scene, id)))
			{
				PersistentsToSend[(scene, id)] = new SendPersistentIntPacket
				{
					Key = "",
					Name = "",
					FlagType = flagType,
					PersistentObject = id,
					PersistentScene = scene,
					State = value
				};
				if (PersistentsToSend.Count == 1)
				{
					SyncPlugin.AddNextFrameAction(SendPendingPersistents);
				}
			}
		}

		public static void AddPersistentBoolData(string id, string scene, bool value, FlagType flagType)
		{
			if (!PersistentsToSend.ContainsKey((scene, id)))
			{
				PersistentsToSend[(scene, id)] = new SendPersistentBoolPacket
				{
					Key = "",
					Name = "",
					FlagType = flagType,
					PersistentObject = id,
					PersistentScene = scene,
					State = value
				};
				if (PersistentsToSend.Count == 1)
				{
					SyncPlugin.AddNextFrameAction(SendPendingPersistents);
				}
			}
		}
	}
}
namespace BasicItemSync.Modules.Hooks
{
	[HarmonyPatch(typeof(CollectableItemPickup))]
	internal class CollectableItemPickupHook
	{
		private static Dictionary<string, FlagType> CollectableTypes = new Dictionary<string, FlagType>
		{
			{
				"Ant Trapper Item",
				FlagType.QuestItem
			},
			{
				"Architect Key",
				FlagType.Progression
			},
			{
				"Beastfly Remainss",
				FlagType.QuestItem
			},
			{
				"Belltown House Key",
				FlagType.Progression
			},
			{
				"Blue Goop Jar",
				FlagType.QuestItem
			},
			{
				"Broken SilkShot",
				FlagType.Tool
			},
			{
				"Broodmother Remains",
				FlagType.QuestItem
			},
			{
				"Clover Heart",
				FlagType.Progression
			},
			{
				"Cog Heart Pieces",
				FlagType.Progression
			},
			{
				"Common Spine",
				FlagType.QuestItem
			},
			{
				"Conchfly Remains",
				FlagType.QuestItem
			},
			{
				"Coral Chunk",
				FlagType.QuestItem
			},
			{
				"Coral Heart",
				FlagType.Progression
			},
			{
				"Coral Ingredient",
				FlagType.QuestItem
			},
			{
				"Courier Supplies",
				FlagType.DoNotSync
			},
			{
				"Courier Supplies Mask Maker",
				FlagType.DoNotSync
			},
			{
				"Courier Supplies Slave",
				FlagType.DoNotSync
			},
			{
				"Craw Summons",
				FlagType.Progression
			},
			{
				"Crawbell",
				FlagType.Collectable
			},
			{
				"Crest Socket Unlocker",
				FlagType.Collectable
			},
			{
				"Crow Feather",
				FlagType.QuestItem
			},
			{
				"Crowman Memento",
				FlagType.Collectable
			},
			{
				"Dock Demo Key",
				FlagType.DoNotSync
			},
			{
				"Dock Key",
				FlagType.Progression
			},
			{
				"Dresses",
				FlagType.DoNotSync
			},
			{
				"Enemy Morsel Seared",
				FlagType.QuestItem
			},
			{
				"Enemy Morsel Shredded",
				FlagType.QuestItem
			},
			{
				"Enemy Morsel Speared",
				FlagType.QuestItem
			},
			{
				"Extractor Machine Pins",
				FlagType.QuestItem
			},
			{
				"Farsight",
				FlagType.Collectable
			},
			{
				"Fine Pins",
				FlagType.QuestItem
			},
			{
				"Fixer Idol",
				FlagType.Quest
			},
			{
				"Flower Heart",
				FlagType.Progression
			},
			{
				"Great Shard",
				FlagType.Collectable
			},
			{
				"Grey Memento",
				FlagType.Collectable
			},
			{
				"Growstone",
				FlagType.Quest
			},
			{
				"Hunter Heart",
				FlagType.Collectable
			},
			{
				"Hunter Memento",
				FlagType.Collectable
			},
			{
				"Materium",
				FlagType.Collectable
			},
			{
				"Memento Garmond",
				FlagType.Collectable
			},
			{
				"Memento Seth",
				FlagType.Collectable
			},
			{
				"Memento Surface",
				FlagType.Collectable
			},
			{
				"Mossberry",
				FlagType.QuestItem
			},
			{
				"Mossberry Stew",
				FlagType.QuestItem
			},
			{
				"Pale Oil",
				FlagType.QuestItem
			},
			{
				"Pickled Roach Egg",
				FlagType.QuestItem
			},
			{
				"Pilgrim Rag",
				FlagType.QuestItem
			},
			{
				"Plasmium",
				FlagType.QuestItem
			},
			{
				"Plasmium Blood",
				FlagType.QuestItem
			},
			{
				"Plasmium Gland",
				FlagType.Quest
			},
			{
				"Pristine Core",
				FlagType.Progression
			},
			{
				"Quill",
				FlagType.Collectable
			},
			{
				"R Ancient Egg",
				FlagType.Collectable
			},
			{
				"R Bone Record",
				FlagType.Collectable
			},
			{
				"R Librarian Melody Cylinder",
				FlagType.Progression
			},
			{
				"R Psalm Cylinder",
				FlagType.Collectable
			},
			{
				"R Seal Chit",
				FlagType.Collectable
			},
			{
				"R Weaver Record",
				FlagType.Collectable
			},
			{
				"R Weaver Totem",
				FlagType.Collectable
			},
			{
				"Roach Corpse Item",
				FlagType.QuestItem
			},
			{
				"Rock Roller Item",
				FlagType.QuestItem
			},
			{
				"Rosary_Set_Frayed",
				FlagType.Collectable
			},
			{
				"Rosary_Set_Huge_White",
				FlagType.Collectable
			},
			{
				"Rosary_Set_Large",
				FlagType.Collectable
			},
			{
				"Rosary_Set_Medium",
				FlagType.Collectable
			},
			{
				"Rosary_Set_Small",
				FlagType.Collectable
			},
			{
				"Shard Pouch",
				FlagType.Collectable
			},
			{
				"Shell Flower",
				FlagType.QuestItem
			},
			{
				"Shining Cog",
				FlagType.QuestItem
			},
			{
				"Silk Grub",
				FlagType.Collectable
			},
			{
				"Silver Bellclapper",
				FlagType.QuestItem
			},
			{
				"Simple Key",
				FlagType.Collectable
			},
			{
				"Skull King Fragment",
				FlagType.QuestItem
			},
			{
				"Slab Key",
				FlagType.Progression
			},
			{
				"Snare Soul Bell Hermit",
				FlagType.Progression
			},
			{
				"Snare Soul Churchkeeper",
				FlagType.Progression
			},
			{
				"Snare Soul Swamp Bug",
				FlagType.Progression
			},
			{
				"Song Pilgrim Cloak",
				FlagType.QuestItem
			},
			{
				"Sprintmaster Memento",
				FlagType.Collectable
			},
			{
				"Tool Metal",
				FlagType.Collectable
			},
			{
				"Vintage Nectar",
				FlagType.QuestItem
			},
			{
				"Ward Boss Key",
				FlagType.Progression
			},
			{
				"Ward Key",
				FlagType.Progression
			},
			{
				"White Flower",
				FlagType.Progression
			},
			{
				"Wood Witch Item",
				FlagType.Progression
			}
		};

		[HarmonyPatch("DoPickupAction")]
		[HarmonyPostfix]
		public static void DoPickupAction(CollectableItemPickup __instance, ref bool __result)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			string name = ((Object)__instance.Item).name;
			if (ClientState.WasItemReceived(name) || !__result || !Object.op_Implicit((Object)(object)__instance.Item))
			{
				return;
			}
			if (!CollectableTypes.TryGetValue(((Object)__instance.Item).name, out var value))
			{
				if (!(__instance.Item is CollectableRelic))
				{
					return;
				}
				value = FlagType.Collectable;
			}
			if (value != FlagType.DoNotSync)
			{
				PlayerDataHook.BoolUpdated(__instance.playerDataBool, value: true, (Operation)0);
				string popupName = __instance.Item.GetPopupName();
				string persistentKey;
				string persistentScene;
				if (Object.op_Implicit((Object)(object)__instance.persistent))
				{
					persistentKey = ((PersistentItem<bool>)(object)__instance.persistent).ItemData.ID;
					persistentScene = ((PersistentItem<bool>)(object)__instance.persistent).ItemData.SceneName;
				}
				else
				{
					persistentKey = ((Object)((Component)__instance).gameObject).name;
					Scene activeScene = SceneManager.GetActiveScene();
					persistentScene = ((Scene)(ref activeScene)).name;
				}
				NetworkSender.SendCollectable(name, popupName, persistentKey, persistentScene, value);
			}
		}
	}
	[HarmonyPatch(typeof(CurrencyManager))]
	internal class CurrencyManagerHook
	{
		[HarmonyPatch("ChangeCurrency")]
		[HarmonyPostfix]
		public static void ChangeCurrency(int amount, CurrencyType type)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (amount >= 1 && !ClientState.WasCurrencyReceived(amount))
			{
				NetworkSender.AddCurrency(((int)type != 0) ? InternalCurrencyType.ShellShard : InternalCurrencyType.Rosary, amount);
			}
		}
	}
	internal class EventHooks
	{
		private static GameObject? HookObj;

		private static List<EventRegister> Hooks = new List<EventRegister>();

		private static bool CollectedRecently = false;

		public static void Initialize()
		{
			AddHook("HEART PIECE COLLECTED", OnMask);
			AddHook("SILK SPOOL SAVE", OnSilkSpool);
		}

		public static void Uninitialize()
		{
			foreach (EventRegister hook in Hooks)
			{
				EventRegister.UnsubscribeEvent(hook);
			}
			if (Object.op_Implicit((Object)(object)HookObj))
			{
				Object.Destroy((Object)(object)HookObj);
			}
		}

		private static void AddHook(string eventName, Action action)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)HookObj))
			{
				HookObj = new GameObject("BasicItemSync Event Hooks");
				Object.DontDestroyOnLoad((Object)(object)HookObj);
			}
			EventRegister val = HookObj.AddComponent<EventRegister>();
			val.SubscribedEvent = eventName;
			((EventBase)val).ReceivedEvent += action;
			EventRegister.SubscribeEvent(val);
			Hooks.Add(val);
		}

		private static void SendUpgrade(FlagType upgradeType)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (!CollectedRecently && !ClientState.WasUpgradeReceived(upgradeType))
			{
				CollectedRecently = true;
				Scene activeScene = SceneManager.GetActiveScene();
				NetworkSender.SendUpgrade(((Scene)(ref activeScene)).name, upgradeType);
				SyncPlugin.AddNextFrameAction(delegate
				{
					CollectedRecently = false;
				});
			}
		}

		private static void OnMask()
		{
			SendUpgrade(FlagType.Mask);
		}

		private static void OnSilkSpool()
		{
			SendUpgrade(FlagType.Spool);
		}

		private static void OnPouch()
		{
			SendUpgrade(FlagType.Pouch);
		}

		private static void OnCraftingKit()
		{
			SendUpgrade(FlagType.CraftingKit);
		}
	}
	[HarmonyPatch(typeof(HeroController))]
	internal class HeroControllerHook
	{
		public static string LastCollectedScene = "";

		[HarmonyPatch("CocoonBroken", new Type[]
		{
			typeof(bool),
			typeof(bool)
		})]
		[HarmonyPrefix]
		public static void CocoonBrokenPrefix(out int __state)
		{
			__state = ClientState.LastCurrency;
			int heroCorpseMoneyPool = PlayerData.instance.HeroCorpseMoneyPool;
			if (heroCorpseMoneyPool != 0)
			{
				ClientState.LastCurrency = heroCorpseMoneyPool;
			}
		}

		[HarmonyPatch("CocoonBroken", new Type[]
		{
			typeof(bool),
			typeof(bool)
		})]
		[HarmonyPostfix]
		public static void CocoonBrokenPostfix(int __state)
		{
			ClientState.LastCurrency = __state;
		}

		[HarmonyPatch("AddToMaxSilkRegen")]
		[HarmonyPrefix]
		public static bool AddToMaxSilkRegen()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (ClientState.WasUpgradeReceived(FlagType.SilkHeart))
			{
				return true;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name == LastCollectedScene)
			{
				return false;
			}
			activeScene = SceneManager.GetActiveScene();
			NetworkSender.SendUpgrade(LastCollectedScene = ((Scene)(ref activeScene)).name, FlagType.SilkHeart);
			return true;
		}
	}
	public abstract class PersistentItemMock : MonoBehaviour
	{
		public delegate void SetValueEvent(bool value);

		public delegate void GetValueEvent(out bool value);

		[SerializeField]
		private PlayerDataTest saveCondition;

		private bool dontSave;

		private bool hasSetup;

		private bool isValueOverridden;

		private GameManager gm;

		private PlayMakerFSM fsm;

		private PersistentItemData<bool> itemData;

		private bool started;

		private bool disableIfActivated;

		private GameObject disablePrefabIfActivated;

		public PersistentItemData<bool> ItemData
		{
			get
			{
				EnsureSetup();
				return itemData;
			}
		}

		protected bool DefaultValue => false;

		protected PersistentItemData<bool> SerializedItemData => itemData;

		public bool HasLoadedValue { get; private set; }

		public bool LoadedValue { get; private set; }

		public event SetValueEvent? OnSetSaveState;

		public event GetValueEvent? OnGetSaveState;

		public event Action? SemiPersistentReset;

		protected virtual void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (itemData == null)
			{
				itemData = new PersistentItemData<bool>();
			}
			if (saveCondition == null)
			{
				saveCondition = new PlayerDataTest();
			}
			gm = GameManager.instance;
			gm.SavePersistentObjects += SaveState;
			if (Object.op_Implicit((Object)(object)disablePrefabIfActivated))
			{
				OnSetSaveState += delegate(bool value)
				{
					if (value)
					{
						disablePrefabIfActivated.SetActive(false);
					}
				};
			}
			if (!disableIfActivated)
			{
				return;
			}
			OnSetSaveState += delegate(bool value)
			{
				if (value)
				{
					((Component)this).gameObject.SetActive(false);
				}
			};
		}

		private void OnEnable()
		{
			if (SerializedItemData.IsSemiPersistent)
			{
				gm.ResetSemiPersistentObjects += ResetState;
			}
			if (this.OnGetSaveState == null)
			{
				fsm = LookForMyFSM();
			}
		}

		private void OnDisable()
		{
			if ((Object)(object)gm != (Object)null)
			{
				gm.ResetSemiPersistentObjects -= ResetState;
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)gm != (Object)null)
			{
				gm.SavePersistentObjects -= SaveState;
			}
		}

		private void Start()
		{
			started = true;
			EnsureSetup();
			CheckIsValid();
			bool flag = false;
			PersistentItemData<bool> val = default(PersistentItemData<bool>);
			if (SceneData.instance.PersistentBools.TryGetValue(itemData.SceneName, itemData.ID, ref val))
			{
				itemData.Value = val.Value;
				flag = true;
			}
			if (flag)
			{
				this.OnSetSaveState?.Invoke(itemData.Value);
				if ((Object)(object)fsm == (Object)null)
				{
					fsm = LookForMyFSM();
				}
				if ((Object)(object)fsm != (Object)null)
				{
					fsm.FsmVariables.FindFsmBool("Activated").Value = itemData.Value;
				}
				HasLoadedValue = true;
				LoadedValue = itemData.Value;
			}
			else
			{
				UpdateValue();
			}
		}

		private void UpdateValue()
		{
			if (!isValueOverridden)
			{
				if (this.OnGetSaveState != null)
				{
					this.OnGetSaveState(out ItemData.Value);
				}
				else
				{
					UpdateActivatedFromFSM();
				}
			}
		}

		private void CheckIsValid()
		{
			Type type = ((object)this).GetType();
			if (((Component)this).GetComponents(type).Length > 1)
			{
				Debug.LogError((object)$"There is more than one component of type: <b>{type}</b> on <b>{((Object)((Component)this).gameObject).name}</b>, please remove one!", (Object)(object)this);
			}
		}

		public void SaveState()
		{
			if (!saveCondition.IsDefined || saveCondition.IsFulfilled)
			{
				SaveStateNoCondition();
			}
		}

		public void SaveStateNoCondition()
		{
			EnsureSetup();
			if (!isValueOverridden)
			{
				if (this.OnGetSaveState != null)
				{
					this.OnGetSaveState(out itemData.Value);
				}
				else
				{
					UpdateActivatedFromFSM();
				}
			}
			HasLoadedValue = true;
			LoadedValue = itemData.Value;
			if (!dontSave)
			{
				SceneData.instance.PersistentBools.SetValue(itemData);
			}
		}

		private void ResetState()
		{
			if (!itemData.IsSemiPersistent)
			{
				return;
			}
			SaveState();
			if (!itemData.Value.Equals(DefaultValue))
			{
				itemData.Value = DefaultValue;
				this.SemiPersistentReset?.Invoke();
				if ((Object)(object)fsm != (Object)null)
				{
					fsm.SendEvent("RESET");
				}
			}
		}

		private void EnsureSetup()
		{
			//IL_005d: 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)
			if (!hasSetup)
			{
				hasSetup = true;
				itemData = SerializedItemData;
				if (string.IsNullOrEmpty(itemData.ID))
				{
					itemData.ID = ((Object)this).name;
				}
				if (string.IsNullOrEmpty(itemData.SceneName))
				{
					PersistentItemData<bool> obj = itemData;
					Scene scene = ((Component)this).gameObject.scene;
					obj.SceneName = GameManager.GetBaseSceneName(((Scene)(ref scene)).name);
				}
			}
		}

		private void UpdateActivatedFromFSM()
		{
			if ((Object)(object)fsm != (Object)null)
			{
				itemData.Value = fsm.FsmVariables.FindFsmBool("Activated").Value;
			}
			else
			{
				fsm = LookForMyFSM();
			}
		}

		protected virtual PlayMakerFSM LookForMyFSM()
		{
			PlayMakerFSM[] components = ((Component)this).GetComponents<PlayMakerFSM>();
			if (components == null)
			{
				return null;
			}
			return FSMUtility.FindFSMWithPersistentBool(components);
		}
	}
	[HarmonyPatch(typeof(PersistentItem<bool>))]
	internal class PersistentBoolItemHook
	{
		private static readonly Dictionary<string, FlagType> PersistentTypes = new Dictionary<string, FlagType>
		{
			{
				"moss vine cluster",
				FlagType.Shortcut
			},
			{
				"abyss_collapse_wall_bot",
				FlagType.Shortcut
			},
			{
				"shaman_collapse_wall",
				FlagType.Shortcut
			},
			{
				"explode_wall",
				FlagType.Shortcut
			},
			{
				"explode_wall 4",
				FlagType.Shortcut
			},
			{
				"explode_wall fake",
				FlagType.Shortcut
			},
			{
				"abyss_collapse_wall",
				FlagType.Shortcut
			},
			{
				"weaver_lift_power_chamber",
				FlagType.Shortcut
			},
			{
				"ant_lever_persistent",
				FlagType.Shortcut
			},
			{
				"one way wall",
				FlagType.Shortcut
			},
			{
				"collapser small",
				FlagType.Shortcut
			},
			{
				"collapser small_bell_type",
				FlagType.Shortcut
			},
			{
				"breakable wall aqueduct start",
				FlagType.Shortcut
			},
			{
				"breakable wall",
				FlagType.Shortcut
			},
			{
				"breakable wall bot mid",
				FlagType.Shortcut
			},
			{
				"breakable wall_silhouette",
				FlagType.Shortcut
			},
			{
				"drop_planks",
				FlagType.Shortcut
			},
			{
				"inverse remasker",
				FlagType.Shortcut
			},
			{
				"grouped remasker",
				FlagType.Shortcut
			},
			{
				"grouped remasker_large",
				FlagType.Shortcut
			},
			{
				"secret mask",
				FlagType.Shortcut
			},
			{
				"secret mask new",
				FlagType.Shortcut
			},
			{
				"secret mask new sharp ultra",
				FlagType.Shortcut
			},
			{
				"secret mask new gate",
				FlagType.Shortcut
			},
			{
				"slab_vent_mask",
				FlagType.Shortcut
			},
			{
				"breakable window",
				FlagType.Shortcut
			},
			{
				"breakable window arborium",
				FlagType.Shortcut
			},
			{
				"coral crust wall sphere",
				FlagType.Shortcut
			},
			{
				"crust wall",
				FlagType.Shortcut
			},
			{
				"coral crust wall tall",
				FlagType.Shortcut
			},
			{
				"coral crust wall mid",
				FlagType.Shortcut
			},
			{
				"coral crust wall small",
				FlagType.Shortcut
			},
			{
				"song_lever_side old",
				FlagType.Shortcut
			},
			{
				"song_lever_side",
				FlagType.Shortcut
			},
			{
				"song_lever_side right",
				FlagType.Shortcut
			},
			{
				"bell wall tall",
				FlagType.Shortcut
			},
			{
				"mines lift",
				FlagType.Shortcut
			},
			{
				"act3_bellway_01_breakable_wall",
				FlagType.Shortcut
			},
			{
				"wind rock",
				FlagType.Shortcut
			},
			{
				"plank_wall_cluster",
				FlagType.Shortcut
			},
			{
				"understore lever",
				FlagType.Shortcut
			},
			{
				"gg_breakable_junk_pile_red",
				FlagType.Shortcut
			},
			{
				"charm_break_wall",
				FlagType.Shortcut
			},
			{
				"bone lever",
				FlagType.Shortcut
			},
			{
				"chain drop platform",
				FlagType.Shortcut
			},
			{
				"bone gate",
				FlagType.Shortcut
			},
			{
				"fall_platform_barrels",
				FlagType.Shortcut
			},
			{
				"lever",
				FlagType.Shortcut
			},
			{
				"song_gate_small",
				FlagType.Shortcut
			},
			{
				"trapdoor lever",
				FlagType.Shortcut
			},
			{
				"plate",
				FlagType.Shortcut
			},
			{
				"bone carriage",
				FlagType.Shortcut
			},
			{
				"barrel plat lift",
				FlagType.Shortcut
			},
			{
				"dockdashexploderock",
				FlagType.Shortcut
			},
			{
				"explode_wall (7) - boneEast07_openedMidRoof",
				FlagType.Shortcut
			},
			{
				"bone_east_10_church",
				FlagType.Shortcut
			},
			{
				"toll door",
				FlagType.Shortcut
			},
			{
				"toll door breakable cog",
				FlagType.Shortcut
			},
			{
				"dropbomb rock",
				FlagType.Shortcut
			},
			{
				"bone east 11 cross over group",
				FlagType.Shortcut
			},
			{
				"coal bucket plat",
				FlagType.Shortcut
			},
			{
				"explode_wall_norck",
				FlagType.Shortcut
			},
			{
				"hornet_pressure_plate_small_persistent",
				FlagType.Shortcut
			},
			{
				"clover gate",
				FlagType.Shortcut
			},
			{
				"cog_lever",
				FlagType.Shortcut
			},
			{
				"active",
				FlagType.Shortcut
			},
			{
				"cog_junk_pile_break",
				FlagType.Shortcut
			},
			{
				"pipe_vent_hatch broken",
				FlagType.Shortcut
			},
			{
				"plank_wall_cluster_metal",
				FlagType.Shortcut
			},
			{
				"slide_gate_ring",
				FlagType.Shortcut
			},
			{
				"coral10rightsidegate",
				FlagType.Shortcut
			},
			{
				"coral crust mask",
				FlagType.Shortcut
			},
			{
				"coral_gate_large",
				FlagType.Shortcut
			},
			{
				"stalactite group bottom",
				FlagType.Shortcut
			},
			{
				"stalactite group top",
				FlagType.Shortcut
			},
			{
				"breakable blocker struts",
				FlagType.Shortcut
			},
			{
				"cradle_plat",
				FlagType.Shortcut
			},
			{
				"cradle_spike_plat",
				FlagType.Shortcut
			},
			{
				"aspid_sealed_gate_stone",
				FlagType.Shortcut
			},
			{
				"harpoon ring pull switch",
				FlagType.Shortcut
			},
			{
				"dock_pressure_plate_lock",
				FlagType.Shortcut
			},
			{
				"greymoor_lever_simple_edited",
				FlagType.Shortcut
			},
			{
				"Dust_02Gate",
				FlagType.Shortcut
			},
			{
				"greymoor_lever_simple",
				FlagType.Shortcut
			},
			{
				"break wall dustpen cage",
				FlagType.Shortcut
			},
			{
				"plat collider",
				FlagType.Shortcut
			},
			{
				"bell chain plat",
				FlagType.Shortcut
			},
			{
				"greymoor stand lever - bridge",
				FlagType.Shortcut
			},
			{
				"greymoor stand lever - crane",
				FlagType.Shortcut
			},
			{
				"hornet_cage_rect_lift_greymoor",
				FlagType.Shortcut
			},
			{
				"propeller",
				FlagType.Shortcut
			},
			{
				"greymoor_breakable_plat",
				FlagType.Shortcut
			},
			{
				"belltown_lever_drop_plat",
				FlagType.Shortcut
			},
			{
				"greymoor_drop_propeller",
				FlagType.Shortcut
			},
			{
				"grey_wood_chain_plat_mid_breakable",
				FlagType.Shortcut
			},
			{
				"greymoor stand lever",
				FlagType.Shortcut
			},
			{
				"greystore_floor_shortcut",
				FlagType.Shortcut
			},
			{
				"bank_door",
				FlagType.Shortcut
			},
			{
				"bot blocker",
				FlagType.Shortcut
			},
			{
				"innerworks_lever",
				FlagType.Shortcut
			},
			{
				"top shortcut",
				FlagType.Shortcut
			},
			{
				"attic_ladder",
				FlagType.Shortcut
			},
			{
				"understore propeller",
				FlagType.Shortcut
			},
			{
				"gg_breakable_junk_pile_gold",
				FlagType.Shortcut
			},
			{
				"understore big plate gate",
				FlagType.Shortcut
			},
			{
				"barrel plat lift thin",
				FlagType.Shortcut
			},
			{
				"plug_gate",
				FlagType.Shortcut
			},
			{
				"stalactite group",
				FlagType.Shortcut
			},
			{
				"vine platform",
				FlagType.Shortcut
			},
			{
				"bone lever 2",
				FlagType.Shortcut
			},
			{
				"thick silk vines",
				FlagType.Shortcut
			},
			{
				"shellwood twig wall",
				FlagType.Shortcut
			},
			{
				"hornet_cage_rect_lift_organ",
				FlagType.Shortcut
			},
			{
				"organ_lift_broken_drop",
				FlagType.Shortcut
			},
			{
				"one way wall crystal",
				FlagType.Shortcut
			},
			{
				"junk_pile_break_peak",
				FlagType.Shortcut
			},
			{
				"crystal break chunk",
				FlagType.Shortcut
			},
			{
				"drop pillar_chunk",
				FlagType.Shortcut
			},
			{
				"sack_multi_breakable",
				FlagType.Shortcut
			},
			{
				"diving_bell_door_breakable",
				FlagType.Shortcut
			},
			{
				"dock_sealed_gate",
				FlagType.Shortcut
			},
			{
				"cage_mid_small_long_sway drop",
				FlagType.Shortcut
			},
			{
				"breakablewallswampbenchshortcut",
				FlagType.Shortcut
			},
			{
				"plank_wall_cluster_swamp",
				FlagType.Shortcut
			},
			{
				"witch cluster vine",
				FlagType.Shortcut
			},
			{
				"drop_planks_horizontal",
				FlagType.Shortcut
			},
			{
				"gloom_lift_destroy",
				FlagType.Shortcut
			},
			{
				"hornet_pressure_plate",
				FlagType.Shortcut
			},
			{
				"shellwood hive",
				FlagType.Shortcut
			},
			{
				"hornet_cage_rect_lift",
				FlagType.Shortcut
			},
			{
				"plank solid 2",
				FlagType.Shortcut
			},
			{
				"shellwood twig wall start",
				FlagType.Shortcut
			},
			{
				"shellwood twig wall top",
				FlagType.Shortcut
			},
			{
				"slab_jail_lever",
				FlagType.Shortcut
			},
			{
				"door_slabcaged",
				FlagType.Shortcut
			},
			{
				"slab lock",
				FlagType.Shortcut
			},
			{
				"slab_cage_plat_thin_fall",
				FlagType.Shortcut
			},
			{
				"slab lock l",
				FlagType.Shortcut
			},
			{
				"slab lock r",
				FlagType.Shortcut
			},
			{
				"breakable wall waterways",
				FlagType.Shortcut
			},
			{
				"jail gate door - persistent",
				FlagType.Shortcut
			},
			{
				"breakable floor_basic song_01",
				FlagType.Shortcut
			},
			{
				"breakable wall entrance secret",
				FlagType.Shortcut
			},
			{
				"breakable wall ruin lift",
				FlagType.Shortcut
			},
			{
				"chain platform breaker",
				FlagType.Shortcut
			},
			{
				"breakable wall  second",
				FlagType.Shortcut
			},
			{
				"propeller understore propeller",
				FlagType.Shortcut
			},
			{
				"hatch",
				FlagType.Shortcut
			},
			{
				"song_lever_side - merchant quest accepted",
				FlagType.Shortcut
			},
			{
				"breakable floor_basic",
				FlagType.Shortcut
			},
			{
				"cradle_pipe_trapdoor",
				FlagType.Shortcut
			},
			{
				"one way vinewall",
				FlagType.Shortcut
			},
			{
				"snail_collapse_wall",
				FlagType.Shortcut
			},
			{
				"pipe_cog_lever",
				FlagType.Shortcut
			},
			{
				"barrel plat lift dropper bottom",
				FlagType.Shortcut
			},
			{
				"barrel plat lift dropper",
				FlagType.Shortcut
			},
			{
				"collapser small understore grate",
				FlagType.Shortcut
			},
			{
				"fall_platform_barrel wide",
				FlagType.Shortcut
			},
			{
				"cog_05_shortcut",
				FlagType.Shortcut
			},
			{
				"innerworks trap bridge large",
				FlagType.Shortcut
			},
			{
				"architect shrine door",
				FlagType.Shortcut
			},
			{
				"fall platform support pole",
				FlagType.Shortcut
			},
			{
				"fall_platform_barrel",
				FlagType.Shortcut
			},
			{
				"understore lever l main",
				FlagType.Shortcut
			},
			{
				"under_lift_large",
				FlagType.Shortcut
			},
			{
				"lock_machine",
				FlagType.Shortcut
			},
			{
				"pipe_vent_hatch",
				FlagType.Shortcut
			},
			{
				"ward_junk_pile_break",
				FlagType.Shortcut
			},
			{
				"ward_junk_pile_break 1",
				FlagType.Shortcut
			},
			{
				"ward_junk_pile_break 2",
				FlagType.Shortcut
			},
			{
				"ward_junk_pile_break 3",
				FlagType.Shortcut
			},
			{
				"ward_junk_pile_break 4",
				FlagType.Shortcut
			},
			{
				"junk hatch",
				FlagType.Shortcut
			},
			{
				"crest_shrine_break_tube",
				FlagType.Shortcut
			},
			{
				"loom_room_jar2",
				FlagType.Shortcut
			},
			{
				"ant_item_string",
				FlagType.Collectable
			},
			{
				"tool_metal_deposit",
				FlagType.Collectable
			},
			{
				"ladybug craft pickup",
				FlagType.CraftingKit
			},
			{
				"silk grub large cocoon",
				FlagType.Collectable
			},
			{
				"silk grub small cocoon 1",
				FlagType.Collectable
			},
			{
				"silk grub small cocoon 2",
				FlagType.Collectable
			},
			{
				"breakable hang sack memory locket",
				FlagType.Collectable
			},
			{
				"collectable item pickup",
				FlagType.Collectable
			},
			{
				"slab_item_chain",
				FlagType.Collectable
			},
			{
				"breakable hang sack 3",
				FlagType.Collectable
			},
			{
				"heart piece",
				FlagType.Mask
			},
			{
				"library_glass_heart_piece",
				FlagType.Mask
			},
			{
				"silk spool",
				FlagType.Spool
			},
			{
				"lamp_hang_top",
				FlagType.Spool
			},
			{
				"moss_berry_fruit",
				FlagType.QuestItem
			},
			{
				"nectar pickup",
				FlagType.QuestItem
			},
			{
				"bone chest",
				FlagType.Currency
			},
			{
				"geo small persistent",
				FlagType.Currency
			},
			{
				"geo mid persistent",
				FlagType.Currency
			},
			{
				"ant chest",
				FlagType.Currency
			},
			{
				"shell shard 01 persistent",
				FlagType.Currency
			},
			{
				"shell shard 02 persistent",
				FlagType.Currency
			},
			{
				"shell shard 03 persistent",
				FlagType.Currency
			},
			{
				"city shard chest",
				FlagType.Currency
			},
			{
				"pilgrim chest",
				FlagType.Currency
			},
			{
				"craw_home_front",
				FlagType.Currency
			},
			{
				"craw_home_right",
				FlagType.Currency
			},
			{
				"craw_home_hang",
				FlagType.Currency
			},
			{
				"chest",
				FlagType.Currency
			},
			{
				"shell shard fossil shellwood",
				FlagType.Currency
			},
			{
				"churchkeeper_rosary",
				FlagType.Currency
			},
			{
				"cog_choir_cylinder",
				FlagType.Progression
			},
			{
				"thread_memory_orb_source",
				FlagType.Progression
			},
			{
				"shrine pressure plate l",
				FlagType.Progression
			},
			{
				"shrine pressure plate TR",
				FlagType.Progression
			},
			{
				"shrine pressure plate BR",
				FlagType.Progression
			},
			{
				"plaque pressure plate",
				FlagType.Progression
			},
			{
				"memory orb group",
				FlagType.Progression
			},
			{
				"song knight tube",
				FlagType.Progression
			},
			{
				"diving bell door",
				FlagType.Progression
			},
			{
				"prince cell door",
				FlagType.Progression
			},
			{
				"slab_break_weaver_gate_ring",
				FlagType.Progression
			},
			{
				"organ webbed bench",
				FlagType.Bench
			},
			{
				"fake bench collapser",
				FlagType.Bench
			}
		};

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void Start(PersistentItem<bool> __instance)
		{
			if (!Object.op_Implicit((Object)(object)__instance.fsm) || __instance.ItemData.Value)
			{
				return;
			}
			FsmState[] fsmStates = __instance.fsm.FsmStates;
			foreach (FsmState val in fsmStates)
			{
				int num = -1;
				int num2 = 0;
				while (num2 < val.Actions.Length)
				{
					FsmStateAction obj = val.Actions[num2];
					SetFsmBool val2 = (SetFsmBool)(object)((obj is SetFsmBool) ? obj : null);
					if (val2 == null || !(val2.variableName.Value == "Activated"))
					{
						FsmStateAction obj2 = val.Actions[num2];
						SetBoolValue val3 = (SetBoolValue)(object)((obj2 is SetBoolValue) ? obj2 : null);
						if (val3 == null || !(((NamedVariable)val3.boolVariable).Name == "Activated"))
						{
							num2++;
							continue;
						}
					}
					num = num2;
					break;
				}
				if (num != -1)
				{
					PersistentHook persistentHook = new PersistentHook();
					((FsmStateAction)persistentHook).Init(val);
					List<FsmStateAction> list = val.Actions.ToList();
					list.Insert(num + 1, (FsmStateAction)(object)persistentHook);
					val.Actions = list.ToArray();
					val.SaveActions();
					break;
				}
			}
		}

		[HarmonyPatch("SaveStateNoCondition")]
		[HarmonyPrefix]
		private static void SaveStateNoConditionPrefix(PersistentItem<bool> __instance, out bool __state)
		{
			__state = __instance.ItemData.Value;
		}

		[HarmonyPatch("SaveStateNoCondition")]
		[HarmonyPostfix]
		public static void SaveStateNoConditionPostfix(PersistentItem<bool> __instance, bool __state)
		{
			if (__state == __instance.ItemData.Value)
			{
				Log.LogDebug($"persistent '{__instance.ItemData.ID}' value was the same ({__instance.ItemData.Value}), skipping");
				return;
			}
			if (__instance.itemData.IsSemiPersistent || __instance.dontSave)
			{
				Log.LogDebug("persistent '" + __instance.ItemData.ID + "' value was semipersistent");
				return;
			}
			string iD = __instance.itemData.ID;
			string sceneName = __instance.itemData.SceneName;
			bool value = __instance.itemData.Value;
			string text = Regex.Replace(iD.ToLower(), " ?\\((\\d+|Clone)\\)$", "");
			Gate val = default(Gate);
			FlagType flagType;
			FlagType value2;
			if (((Component)__instance).TryGetComponent<Gate>(ref val))
			{
				flagType = FlagType.Shortcut;
			}
			else if (PersistentTypes.TryGetValue(text, out value2))
			{
				flagType = value2;
			}
			else if (text.StartsWith("remask"))
			{
				flagType = FlagType.Shortcut;
			}
			else if (text.StartsWith("black_thread_core"))
			{
				flagType = FlagType.Boss;
			}
			else if (text.StartsWith("bell_toll"))
			{
				flagType = FlagType.Bench;
			}
			else
			{
				if (!text.StartsWith("battle scene") && !text.StartsWith("black thread battle scene") && !text.StartsWith("boss scene"))
				{
					Log.LogDebug("persistent '" + __instance.ItemData.ID + "' value was not sent");
					return;
				}
				flagType = FlagType.Arena;
			}
			Log.LogDebug($"[CLI: PERSISTENT] {text}, {flagType}");
			NetworkSender.AddPersistentBoolData(iD, sceneName, value, flagType);
		}
	}
	[HarmonyPatch(typeof(Lever))]
	internal static class LeverHook
	{
		[HarmonyPatch("Hit")]
		[HarmonyPostfix]
		public static void Hit(Lever __instance, ref HitResponse __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__result.response != 0 && !__instance.doesNotActivate)
			{
				string playerDataBool = __instance.playerDataBool;
				bool value = true;
				PlayerDataHook.BoolUpdated(playerDataBool, value, (Operation)0);
				if (Object.op_Implicit((Object)(object)__instance.persistent) && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponentInParent<DialDoorBridge>()))
				{
					((PersistentItem<bool>)(object)__instance.persistent).ItemData.Value = true;
					PersistentBoolItemHook.SaveStateNoConditionPostfix((PersistentItem<bool>)(object)__instance.persistent, __state: false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Lever_tk2d))]
	internal static class Lever_tk2dHook
	{
		[HarmonyPatch("Hit")]
		[HarmonyPrefix]
		public static void Hit(Lever_tk2d __instance, HitInstance damageInstance)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			HitInstance val = damageInstance;
			PersistentBoolItem val2 = default(PersistentBoolItem);
			if (((HitInstance)(ref val)).IsNailDamage && (!Object.op_Implicit((Object)(object)__instance.canHitTrigger) || __instance.canHitTrigger.IsInside) && !__instance.activated && ((Component)__instance).TryGetComponent<PersistentBoolItem>(ref val2))
			{
				((PersistentItem<bool>)(object)val2).ItemData.Value = true;
				PersistentBoolItemHook.SaveStateNoConditionPostfix((PersistentItem<bool>)(object)val2, __state: false);
			}
		}
	}
	internal class PersistentHook : FsmStateAction
	{
		public override void OnEnter()
		{
			GameObject gameObject = ((Component)((FsmStateAction)this).Fsm.Owner).gameObject;
			if (Object.op_Implicit((Object)(object)gameObject))
			{
				PersistentBoolItem component = gameObject.GetComponent<PersistentBoolItem>();
				if (Object.op_Implicit((Object)(object)component))
				{
					((PersistentItem<bool>)(object)component).SaveState();
					((FsmStateAction)this).Finish();
				}
			}
		}
	}
	[HarmonyPatch(typeof(PersistentItem<int>))]
	internal class PersistentIntItemHook
	{
		private static readonly string[] CurrencyItems = new string[4] { "rosary", "shell", "song", "ant_" };

		[HarmonyPatch("SaveStateNoCondition")]
		[HarmonyPrefix]
		private static void SaveStateNoCondition_Prefix(PersistentItem<int> __instance, out int __state)
		{
			__state = __instance.ItemData.Value;
		}

		[HarmonyPatch("SaveStateNoCondition")]
		[HarmonyPostfix]
		public static void SaveStateNoConditionPostfix(PersistentItem<int> __instance, int __state)
		{
			if (__state == __instance.ItemData.Value)
			{
				Log.LogDebug($"persistent '{__instance.ItemData.ID}' value was the same ({__instance.ItemData.Value}), skipping");
				return;
			}
			if (__instance.itemData.IsSemiPersistent || __instance.dontSave)
			{
				Log.LogDebug("persistent '" + __instance.ItemData.ID + "' value was semipersistent");
				return;
			}
			string iD = __instance.itemData.ID;
			string sceneName = __instance.itemData.SceneName;
			int value = __instance.itemData.Value;
			FlagType flagType = FlagType.DoNotSync;
			string text = iD.ToLower();
			string[] currencyItems = CurrencyItems;
			foreach (string value2 in currencyItems)
			{
				if (text.StartsWith(value2))
				{
					flagType = FlagType.Currency;
					break;
				}
			}
			if (flagType == FlagType.DoNotSync)
			{
				if (iD.StartsWith("bellshrine"))
				{
					flagType = FlagType.Bellshrine;
				}
				else if (iD.StartsWith("library sliding"))
				{
					flagType = FlagType.Shortcut;
				}
			}
			if (flagType == FlagType.DoNotSync)
			{
				Log.LogDebug("persistent '" + __instance.ItemData.ID + "' value was not sent");
			}
			else
			{
				Log.LogDebug($"[CLI: PERSISTENT INT] {text}, {flagType}");
				NetworkSender.AddPersistentIntData(iD, sceneName, value, flagType);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerData))]
	internal static class PlayerDataHook
	{
		[HarmonyPatch("SetBool")]
		[HarmonyPrefix]
		private static void SetBool(string boolName, bool value)
		{
			BoolUpdated(boolName, value, (Operation)0);
		}

		[HarmonyPatch("SetInt")]
		[HarmonyPrefix]
		private static void SetInt(string intName, int value)
		{
			IntUpdated(intName, value, (Operation)3);
		}

		public static void BoolUpdated(string boolName, bool value, Operation operation = (Operation)0)
		{
			//IL_0048: 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)
			//IL_0052: Invalid comparison between Unknown and I4
			if (string.IsNullOrEmpty(boolName))
			{
				return;
			}
			Log.LogDebug("[CLI: PD BOOL] " + boolName);
			if (!ItemNames.BoolKeys.TryGetValue(boolName, out var value2) || ClientState.WasItemReceived(boolName))
			{
				return;
			}
			bool state = value;
			bool flag = PlayerData.instance.GetBool(boolName);
			if ((int)operation != 0 || value != flag)
			{
				if ((int)operation == 1)
				{
					state = !flag;
				}
				NetworkSender.SendFlag(boolName, value2.Type, value2.Name, state);
			}
		}

		public static void IntUpdated(string intName, int value, Operation operation = (Operation)3)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Invalid comparison between Unknown and I4
			if (string.IsNullOrEmpty(intName))
			{
				return;
			}
			Log.LogDebug("[CLI: PD INT] " + intName);
			if (!ItemNames.IntKeys.TryGetValue(intName, out var value2))
			{
				return;
			}
			int num = PlayerData.instance.GetInt(intName);
			int num2 = num;
			if ((int)operation == 3 && value == num)
			{
				return;
			}
			if ((int)operation == 0)
			{
				num2 += value;
			}
			else if ((int)operation == 1)
			{
				num2 -= value;
			}
			else
			{
				if ((int)operation != 2)
				{
					return;
				}
				num2 *= value;
			}
			NetworkSender.SendInt(intName, value2.Type, value2.Name, num2);
		}
	}
	[HarmonyPatch(typeof(SetPlayerDataBool))]
	internal static class SetPlayerDataBoolHook
	{
		[HarmonyPatch("SetBool")]
		[HarmonyPrefix]
		public static void SetBool(SetPlayerDataBool __instance)
		{
			string boolName = __instance.boolName;
			bool value = __instance.value;
			PlayerDataHook.BoolUpdated(boolName, value, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(SetPlayerDataVariable))]
	internal static class SetPlayerDataVariableHook
	{
		[HarmonyPatch("OnEnter")]
		[HarmonyPrefix]
		public static void OnEnter(SetPlayerDataVariable __instance)
		{
			string value = __instance.VariableName.Value;
			object value2 = __instance.SetValue.GetValue();
			if (value2 is bool value3)
			{
				PlayerDataHook.BoolUpdated(value, value3, (Operation)0);
			}
			else if (value2 is int value4)
			{
				PlayerDataHook.IntUpdated(value, value4, (Operation)3);
			}
		}
	}
	[HarmonyPatch(typeof(StateChangeSequence))]
	internal static class StateChangeSequenceHook
	{
		[HarmonyPatch("SetIsCompleteBool")]
		[HarmonyPrefix]
		public static void OnEnter(StateChangeSequence __instance)
		{
			string isCompleteBool = __instance.isCompleteBool;
			bool value = true;
			PlayerDataHook.BoolUpdated(isCompleteBool, value, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(PlayerDataCollectable))]
	internal static class PlayerDataCollectableHook
	{
		[HarmonyPatch("Get")]
		[HarmonyPrefix]
		public static void Get(PlayerDataCollectable __instance)
		{
			PlayerDataHook.BoolUpdated(__instance.linkedPDBool, value: true, (Operation)0);
			PlayerDataHook.IntUpdated(__instance.linkedPDInt, 1, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(PlayerDataBoolCollectable))]
	internal static class PlayerDataBoolCollectableHook
	{
		[HarmonyPatch("Get")]
		[HarmonyPostfix]
		public static void UnlockSequence(PlayerDataBoolCollectable __instance)
		{
			string boolName = __instance.boolName;
			bool value = true;
			PlayerDataHook.BoolUpdated(boolName, value, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(CollectableItemBasic))]
	internal static class CollectableItemBasicHook
	{
		[HarmonyPatch("SetUniqueBool")]
		[HarmonyPrefix]
		private static void SetUniqueBool(CollectableItemBasic __instance)
		{
			PlayerDataHook.BoolUpdated(__instance.uniqueCollectBool, value: true, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(CaravanTroupeHunter))]
	internal static class CaravanTroupeHunterHook
	{
		[HarmonyPatch("OnPurchasedItem")]
		[HarmonyPrefix]
		public static void OnPurchasedItem(CaravanTroupeHunter __instance, int itemIndex)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			string boolName = CaravanTroupeHunter.PdBools[__instance.currentListGroups[itemIndex]];
			bool value = true;
			PlayerDataHook.BoolUpdated(boolName, value, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(ConfigBase))]
	internal static class ControlReminderHook
	{
		[HarmonyPatch("DoAppear")]
		[HarmonyPrefix]
		public static void DoAppear(ConfigBase __instance)
		{
			string playerDataBool = __instance.PlayerDataBool;
			bool value = true;
			PlayerDataHook.BoolUpdated(playerDataBool, value, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(CurrencyObjectBase))]
	internal static class CurrencyObjectBaseHook
	{
		[HarmonyPatch("CollectPopup")]
		[HarmonyPrefix]
		private static void CollectPopup(CurrencyObjectBase __instance)
		{
			PlayerDataHook.BoolUpdated(__instance.firstGetPDBool, value: true, (Operation)0);
			PlayerDataHook.BoolUpdated(__instance.popupPDBool, value: true, (Operation)0);
		}
	}
	[HarmonyPatch]
	internal static class GameManagerHook
	{
		private static MethodInfo TargetMethod()
		{
			return typeof(GameManager).GetMethod("SetPlayerDataVariable", BindingFlags.Instance | BindingFlags.Public).MakeGenericMethod(typeof(bool));
		}

		private static void Prefix(string fieldName, bool value)
		{
			PlayerDataHook.BoolUpdated(fieldName, value, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(ItemReceptacle))]
	internal static class ItemReceptacleHook
	{
		[HarmonyPatch("UnlockSequence")]
		[HarmonyPrefix]
		public static void UnlockSequence(ItemReceptacle __instance)
		{
			string playerDataBool = __instance.playerDataBool;
			bool value = true;
			PlayerDataHook.BoolUpdated(playerDataBool, value, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(PersistentPressurePlate))]
	internal static class PersistentPressurePlateHook
	{
		[HarmonyPatch("Activate")]
		[HarmonyPrefix]
		public static void Activate(PersistentPressurePlate __instance)
		{
			string playerDataBool = __instance.playerDataBool;
			bool value = true;
			PlayerDataHook.BoolUpdated(playerDataBool, value, (Operation)0);
		}
	}
	[HarmonyPatch(typeof(PlayerDataBoolOperation))]
	internal static class PlayerDataBoolOperationHook
	{
		[HarmonyPatch("Execute")]
		[HarmonyPrefix]
		public static void Execute(PlayerDataBoolOperation __instance)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing refer