Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BasicItemSync v0.1.4
BasicItemSync.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BasicItemSync.Data; using BasicItemSync.Modules; using BasicItemSync.Modules.Hooks; using BasicItemSync.Modules.Mocks; using BasicItemSync.Modules.Network.Client; using BasicItemSync.Modules.Network.Server; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; 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.Client; 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.ResourceManagement.ResourceProviders; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BasicItemSync")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.1.4.0")] [assembly: AssemblyInformationalVersion("0.1.4+10c83be3909b0405b5ddfcf3e06e82b6dd61e136")] [assembly: AssemblyProduct("BasicItemSync")] [assembly: AssemblyTitle("BasicItemSync")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/BobbyTheCatfish/BasicItemSync")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.4.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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class ExtensionMarkerAttribute : Attribute { private readonly string <Name>k__BackingField; public string Name => <Name>k__BackingField; public ExtensionMarkerAttribute(string name) { <Name>k__BackingField = name; } } } 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.4"; internal const int AddonApiVersion = 1; } internal enum FlagType { Ability, Map, Pin, Bellshrine, Boss, Arena, Progression, Collectable, Bellway, Ventrica, Mask, Spool, Pouch, CraftingKit, SilkHeart, Needle, Quest, QuestStart, 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(); private static IModSettings settings = new MockModSettings(); public static void SetLogger(ILogger log) { logger = log; try { ModSettings modSettings = new ModSettings(); bool instanceDebugLogs = modSettings.InstanceDebugLogs; settings = modSettings; } catch { logger.Warn("Unable to load ModSettings. Likely using standalone server."); } } private static bool ShouldLog(LogEventArgs log) { if (log.Source.SourceName == "SSMP" && log.Data is string text && text.StartsWith("[BasicItemSync")) { return true; } return false; } 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) { if (settings.InstanceDebugLogs) { foreach (object obj in data) { logger.Debug(obj.ToString()); } } } 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.4")] 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.4"; private void Awake() { Instance = this; ModSettings.Init(((BaseUnityPlugin)this).Config); ((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; foreach (Action action in array2) { action(); } } } 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_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects(); GameObject[] array = rootGameObjects; DeactivateIfPlayerdataTrue val3 = default(DeactivateIfPlayerdataTrue); foreach (GameObject val in array) { BattleScene[] componentsInChildren = val.GetComponentsInChildren<BattleScene>(); BattleScene[] array2 = componentsInChildren; foreach (BattleScene val2 in array2) { if (((Component)val2).TryGetComponent<DeactivateIfPlayerdataTrue>(ref val3) && val3.boolName == keyName) { return val2; } } } return null; } public static void DefeatBattleScene(string keyName) { if (keyName == "defeatedBellBeast") { OnBellBeast(); return; } BattleScene battleScene = GetBattleScene(keyName); if (Object.op_Implicit((Object)(object)battleScene)) { DefeatBattleScene(battleScene); } } public static void DefeatBattleScene(BattleScene battle) { if (battle.started) { int currentWave = battle.currentWave; battle.DoEndBattle(); HealthManager[] componentsInChildren = ((Component)battle.waves[currentWave]).gameObject.GetComponentsInChildren<HealthManager>(); foreach (HealthManager val in componentsInChildren) { if (!val.isDead) { val.Die((float?)0f, (AttackTypes)0, true); } } return; } battle.BattleCompleted(); battle.completed = true; if (!string.IsNullOrEmpty(battle.setPDBoolOnEnd)) { VariableExtensionsGeneric.SetVariable<bool>((object)PlayerData.instance, battle.setPDBoolOnEnd, true); } if (!string.IsNullOrEmpty(battle.setExtraPDBoolOnEnd)) { VariableExtensionsGeneric.SetVariable<bool>((object)PlayerData.instance, battle.setExtraPDBoolOnEnd, true); } if (Object.op_Implicit((Object)(object)battle.camLocks) && !battle.dontDisableCamlocksOnEnd) { battle.camLocks.SetActive(false); } if (battle.openGatesOnEnd) { battle.SendEventToChildren("BG OPEN"); } if (Object.op_Implicit((Object)(object)battle.endScene)) { battle.SendEventToChildren("BATTLE END"); } if (Object.op_Implicit((Object)(object)battle.activeDuringBattle)) { battle.activeDuringBattle.SetActive(false); } if (battle.disableActiveBeforeBattleAtEnd) { battle.activeBeforeBattle.SetActive(false); } if (!string.IsNullOrEmpty(battle.battleEndEventRegister)) { EventRegister.SendEvent(battle.battleEndEventRegister, (GameObject)null); } } private static void OnBellBeast() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) SceneData.instance.PersistentBools.SetValue(new PersistentItemData<bool> { ID = "Silk Heart", SceneName = "Bone_05", IsSemiPersistent = false, Value = false, Mutator = (PersistentMutatorTypes)0 }); Scene activeScene = SceneManager.GetActiveScene(); bool flag = ClientAddon.Settings.FlagAllowed(FlagType.SilkHeart); if (!(((Scene)(ref activeScene)).name == "Bone_05")) { return; } Scene sceneByName = SceneManager.GetSceneByName("Bone_05_boss"); if (((Scene)(ref sceneByName)).IsValid()) { GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects(); foreach (GameObject val in rootGameObjects) { val.SetActive(false); } } if (flag) { return; } GameObject val2 = ((Scene)(ref sceneByName)).GetRootGameObjects()[0]; for (int j = 0; j < val2.transform.childCount; j++) { Transform child = val2.transform.GetChild(j); if (((Object)child).name == "Silk Heart") { ((Component)child).gameObject.SetActive(true); break; } } } } 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 ModSettings : IModSettings { private static ConfigEntry<bool> _debugPlayerData; private static ConfigEntry<bool> _debugLogs; public bool InstanceDebugPlayerData => DebugPlayerData; public static bool DebugPlayerData => _debugPlayerData?.Value ?? false; public bool InstanceDebugLogs => DebugLogs; public static bool DebugLogs => _debugLogs?.Value ?? false; public static void Init(ConfigFile config) { _debugLogs = config.Bind<bool>("Debug", "Enable debug logs", true, (ConfigDescription)null); _debugPlayerData = config.Bind<bool>("Debug", "Enable PlayerData logs", false, (ConfigDescription)null); } } internal static class ObjectHelper { [SpecialName] public sealed class <G>$DA70E330990F800FE2D4138C4621F754 { [SpecialName] public static class <M>$8E4C3D964507E1AE94619A23CAEF85BC { } [ExtensionMarker("<M>$8E4C3D964507E1AE94619A23CAEF85BC")] public static string GetLocal(LocalisedString str) { throw new NotSupportedException(); } } public static PersistentItem<T>? FindPersistent<T>(string sceneName, string id) where T : IEquatable<T> { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) Scene scene = SceneManager.GetActiveScene(); return ((IEnumerable<PersistentItem<T>>)Resources.FindObjectsOfTypeAll<PersistentItem<T>>()).FirstOrDefault((Func<PersistentItem<T>, bool>)((PersistentItem<T> p) => p.ItemData.ID == id && p.ItemData.SceneName == sceneName && ((Component)p).gameObject.scene == scene)); } public static string GetLocal(LocalisedString str) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Language.Get(str.Key, str.Sheet); } } internal class PersistentHandler { private static readonly List<string> FsmEvents = new List<string>(5) { "QUICK BREAK", "ACTIVATE", "ACTIVATED", "DESTROY", "UNLOCK" }; public static void SetPersistentIntData(string sceneName, string id, int status, FlagType flagType) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) PersistentItemData<int> val = default(PersistentItemData<int>); if (SceneData.instance.PersistentInts.TryGetValue(sceneName, id, ref val)) { val.Value = status; } else { PersistentItemData<int> value = new PersistentItemData<int> { SceneName = sceneName, ID = id, IsSemiPersistent = false, Value = status }; SceneData.instance.PersistentInts.SetValue(value); } if (flagType == FlagType.Currency) { Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != sceneName) { return; } } PersistentItem<int> val2 = ObjectHelper.FindPersistent<int>(sceneName, id); 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 id, bool status, bool forceDisable = false) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) PersistentItemData<bool> val = default(PersistentItemData<bool>); if (SceneData.instance.PersistentBools.TryGetValue(sceneName, id, ref val)) { val.Value = status; } else { PersistentItemData<bool> value = new PersistentItemData<bool> { SceneName = sceneName, ID = id, IsSemiPersistent = false, Value = status }; SceneData.instance.PersistentBools.SetValue(value); } PersistentItem<bool> val2 = ObjectHelper.FindPersistent<bool>(sceneName, id); if (!((Object)(object)val2 == (Object)null)) { PersistentBoolItem val3 = (PersistentBoolItem)(object)((val2 is PersistentBoolItem) ? val2 : null); if (val3 != null) { ((PersistentItem<bool>)(object)val3).ItemData.Value = status; Lever val4 = default(Lever); Lever_tk2d val5 = default(Lever_tk2d); PersistentBoolItemResponder val6 = default(PersistentBoolItemResponder); CollectableItemPickup val7 = default(CollectableItemPickup); BattleScene battle = default(BattleScene); 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); string activeStateName = ((PersistentItem<bool>)(object)val3).fsm.ActiveStateName; foreach (string fsmEvent in FsmEvents) { if (((PersistentItem<bool>)(object)val3).fsm.ActiveStateName == activeStateName) { ((PersistentItem<bool>)(object)val3).fsm.SendEvent(fsmEvent); } } } else if (((Component)val3).TryGetComponent<PersistentBoolItemResponder>(ref val6)) { val6.InvokeEvents(status); } else if (((Component)val3).TryGetComponent<CollectableItemPickup>(ref val7)) { forceDisable = true; } else if (((Component)val3).TryGetComponent<BattleScene>(ref battle)) { BattleManager.DefeatBattleScene(battle); } if (Object.op_Implicit((Object)(object)val3.disablePrefabIfActivated)) { val3.disablePrefabIfActivated.SetActive(false); } if (val3.disableIfActivated || forceDisable) { ((Component)val3).gameObject.SetActive(false); } return; } } Scene activeScene = SceneManager.GetActiveScene(); if (sceneName == ((Scene)(ref activeScene)).name) { Log.LogWarning("Unable to find persistent " + sceneName + " " + id); } } } 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 PopupItem(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_0002: Unknown result type (might be due to invalid IL or missing references) CollectableUIMsg.Spawn(item, Color.white, (CollectableUIMsg)null, false); } public static void ShowPopup(FlagType flagType, string key, string name) { if (!string.IsNullOrEmpty(name)) { if (1 == 0) { } PopupItem popupItem = flagType switch { FlagType.Ability => GetAbilityIcon(key), FlagType.Map => GetMap(name), FlagType.Pin => GetPin(key, name), _ => null, }; if (1 == 0) { } PopupItem popupItem2 = popupItem; if (popupItem2 != null) { ShowPopup((ICollectableUIMsgItem)(object)popupItem2); } } } private static PopupItem? GetAbilityIcon(string key) { Transform inv = GetInventory(); Transform layout = inv.GetChild(1).GetChild(0).GetChild(1) .GetChild(2) .GetChild(2); if (1 == 0) { } PopupItem result = key switch { "hasDash" => GetIcon(0, "Swift Step"), "hasHarpoonDash" => GetIcon(1, "Clawline"), "HasBoundCrestUpgrader" => GetIcon(2, "Sylphsong"), "hasSuperJump" => GetIcon(3, "Sillk Soar"), "hasWalljump" => GetIcon(4, "Cling Grip"), "hasNeedolin" => GetIcon(5, "Needolin"), "UnlockedFastTravelTeleport" => GetIcon(5, "Beastling Call"), "hasBrolly" => GetCloakIcon(1), "hasDoubleJump" => GetCloakIcon(2), "hasChargeSlash" => GetNeedleStrike(), _ => null, }; if (1 == 0) { } return result; static PopupItem? GetCloakIcon(int state) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) CollectableItem byName = ((NamedScriptableObjectList<CollectableItem>)(object)ManagerSingleton<CollectableItemManager>.Instance.masterList).GetByName("Dresses"); CollectableItemStates val = (CollectableItemStates)(object)((byName is CollectableItemStates) ? byName : null); if (val == null) { return null; } ItemState val2 = val.states[state]; return new PopupItem(ObjectHelper.GetLocal(val2.DisplayName), val2.Icon); } PopupItem GetIcon(int index, string text) { SpriteRenderer component = ((Component)layout.GetChild(index)).GetComponent<SpriteRenderer>(); return new PopupItem(text, component.sprite); } PopupItem GetNeedleStrike() { SpriteRenderer component = ((Component)inv.GetChild(1).GetChild(0).GetChild(0) .GetChild(1)).GetComponent<SpriteRenderer>(); return new PopupItem("Needle Strike", component.sprite); } } private static PopupItem GetMap(string name) { Transform inventory = GetInventory(); InventoryPane component = ((Component)inventory.GetChild(2)).GetComponent<InventoryPane>(); return new PopupItem(name + " Map", component.ListIcon); } private static PopupItem? GetPin(string key, string name) { Transform inventory = GetInventory(); Transform map = inventory.GetChild(2); if (1 == 0) { } PopupItem result = key switch { "hasPinBench" => GetSpecialPin(0), "hasPinCocoon" => GetSpecialPin(1), "hasPinShop" => GetSpecialPin(4), "hasPinSpa" => GetSpecialPin(1), "hasPinStag" => GetSpecialPin(1), "hasPinTube" => GetSpecialPin(5), "hasPinFleaMarrowlands" => GetSpecialPin(3), "hasPinFleaMidlands" => GetSpecialPin(3), "hasPinFleaBlastedlands" => GetSpecialPin(3), "hasPinFleaCitadel" => GetSpecialPin(3), "hasPinFleaPeaklands" => GetSpecialPin(3), "hasPinFleaMucklands" => GetSpecialPin(3), "hasMarker_a" => GetMarkerPin(0), "hasMarker_b" => GetMarkerPin(1), "hasMarker_c" => GetMarkerPin(2), "hasMarker_d" => GetMarkerPin(3), "hasMarker_e" => GetMarkerPin(4), _ => null, }; if (1 == 0) { } return result; PopupItem GetMarkerPin(int index) { Transform child = map.GetChild(1).GetChild(5); int num = child.childCount - 1; Transform child2 = child.GetChild(num).GetChild(index); SpriteRenderer componentInChildren = ((Component)child2).GetComponentInChildren<SpriteRenderer>(true); return new PopupItem(name, componentInChildren.sprite); } PopupItem GetSpecialPin(int index) { Transform child = map.GetChild(3).GetChild(0).GetChild(index); SpriteRenderer componentInChildren = ((Component)child).GetComponentInChildren<SpriteRenderer>(true); return new PopupItem(name, componentInChildren.sprite); } } private static Transform GetInventory() { GameObject gameObject = ((Component)GameCameras.instance.hudCamera).gameObject; return gameObject.transform.GetChild(0).GetChild(4); } } internal class PopupItem : ICollectableUIMsgItem, IUIMsgPopupItem { public string Name; public Sprite Sprite; public Object Object; public PopupItem(FullQuestBase quest) { //IL_0011: 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) Object = (Object)(object)quest; Name = Language.Get(((BasicQuestBase)quest).DisplayName.Key, ((BasicQuestBase)quest).DisplayName.Sheet); Sprite = ((BasicQuestBase)quest).QuestType.Icon; } public PopupItem(string name, Sprite sprite) { Name = name; Sprite = sprite; Object = (Object)(object)sprite; } public Object GetRepresentingObject() { return Object; } public float GetUIMsgIconScale() { return 1f; } public string GetUIMsgName() { return Name; } public Sprite GetUIMsgSprite() { return Sprite; } 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 itemKey, int amount) { CollectableItem itemByName = CollectableItemManager.GetItemByName(itemKey); if (!Object.op_Implicit((Object)(object)itemByName)) { CollectableRelic relic = CollectableRelicManager.GetRelic(itemKey); if (!Object.op_Implicit((Object)(object)relic)) { Log.LogError("Unknown collectable " + itemKey); return false; } ((SavedItem)relic).Get(false); return Save(); } itemByName.AddAmount(amount); 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) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) PersistentItemData<bool> val = default(PersistentItemData<bool>); if (SceneData.instance.PersistentBools.TryGetValue(scene, "Silk Heart", ref val) && val.Value) { Log.LogDebug("[CLI: Upgrade Silk Heart] Already collected silk heart for " + scene); return false; } PlayerData instance = PlayerData.instance; instance.silkRegenMax++; Log.LogDebug("[CLI: Upgrade Silk Heart] Collecting silk heart for " + scene); SceneData.instance.PersistentBools.SetValue(new PersistentItemData<bool> { ID = "Silk Heart", SceneName = scene, IsSemiPersistent = false, Value = true, Mutator = (PersistentMutatorTypes)0 }); LoadAndDisplay(ref SilkHeartCollectable, "SilkHeart", "UI", "INV_DESC_SPOOL_SILKHEARTS"); 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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.Patches { [HarmonyPatch(typeof(SceneLoad))] internal class ScenePatches { [HarmonyPatch("Begin")] [HarmonyPrefix] private static void Begin(SceneLoad __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown __instance.Finish += (FinishDelegate)delegate { OnFinish(__instance); }; } private static void OnFinish(SceneLoad __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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 references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) SceneInstance result = __instance.OperationHandle.Result; Scene scene = ((SceneInstance)(ref result)).Scene; if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).name == "Bone_05") { OnBellBeast(scene); } } private static void OnBellBeast(Scene scene) { bool flag = ClientAddon.Settings.FlagAllowed(FlagType.SilkHeart); bool flag2 = ClientAddon.Settings.FlagAllowed(FlagType.Boss); PersistentItemData<bool> val = default(PersistentItemData<bool>); if (!flag && flag2 && SceneData.instance.PersistentBools.TryGetValue(((Scene)(ref scene)).name, "Silk Heart", ref val) && !val.Value) { GameObject val2 = ((IEnumerable<GameObject>)((Scene)(ref scene)).GetRootGameObjects()).FirstOrDefault((Func<GameObject, bool>)((GameObject obj) => ((Object)obj).name == "Silk Heart")); if (Object.op_Implicit((Object)(object)val2)) { val2.SetActive(true); } } } } } namespace BasicItemSync.Modules.Network { internal class Packet : 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 : Packet { 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 SendPersistentBoolsPacket : Packet { public Dictionary<(string, string), (bool, FlagType)> Values = new Dictionary<(string, string), (bool, FlagType)>(); public override void WriteData(IPacket packet) { packet.Write(Values.Count); foreach (KeyValuePair<(string, string), (bool, FlagType)> value in Values) { string item = value.Key.Item1; string item2 = value.Key.Item2; bool item3 = value.Value.Item1; FlagType item4 = value.Value.Item2; packet.Write(item); packet.Write(item2); packet.Write(item3); packet.Write((byte)item4); } } public override void ReadData(IPacket packet) { int num = packet.ReadInt(); for (int i = 0; i < num; i++) { string item = packet.ReadString(); string item2 = packet.ReadString(); bool item3 = packet.ReadBool(); FlagType item4 = (FlagType)packet.ReadByte(); Values.Add((item, item2), (item3, item4)); } } } internal class SendPersistentIntsPacket : Packet { public Dictionary<(string, string), (int, FlagType)> Values = new Dictionary<(string, string), (int, FlagType)>(); public override void WriteData(IPacket packet) { packet.Write(Values.Count); foreach (KeyValuePair<(string, string), (int, FlagType)> value in Values) { string item = value.Key.Item1; string item2 = value.Key.Item2; int item3 = value.Value.Item1; FlagType item4 = value.Value.Item2; packet.Write(item); packet.Write(item2); packet.Write(item3); packet.Write((byte)item4); } } public override void ReadData(IPacket packet) { int num = packet.ReadInt(); for (int i = 0; i < num; i++) { string item = packet.ReadString(); string item2 = packet.ReadString(); int item3 = packet.ReadInt(); FlagType item4 = (FlagType)packet.ReadByte(); Values.Add((item, item2), (item3, item4)); } } } internal class SendIntItemPacket : SendFlagPacket { public int Number = 0; 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 = 0f; 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 : Packet { public short Rosaries; public short Shards; public override bool IsReliable => false; public override void WriteData(IPacket packet) { packet.Write(Rosaries); packet.Write(Shards); } public override void ReadData(IPacket packet) { Rosaries = packet.ReadShort(); Shards = packet.ReadShort(); } } internal class SettingsUpdatePacket : Packet { public SyncServerSettings Settings = new SyncServerSettings(); public override bool IsReliable => true; public override bool DropReliableDataIfNewerExists => true; public override void WriteData(IPacket packet) { List<bool> list = Settings.ToValues(); packet.Write(list.Count); foreach (bool item in list) { packet.Write(item); } } public override void ReadData(IPacket packet) { List<bool> list = new List<bool>(); int num = packet.ReadInt(); 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}"); if (1 == 0) { } IPacketData result = (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<SendIntItemPacket>(), Packets.PersistentBool => new PacketDataCollection<SendPersistentBoolsPacket>(), Packets.PersistentInt => new PacketDataCollection<SendPersistentIntsPacket>(), Packets.Settings => new SettingsUpdatePacket(), _ => new ErrorThrowingPacket(packetID, server: true), }); if (1 == 0) { } return result; } } internal class ErrorThrowingPacket : Packet { 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<SendIntItemPacket>(Packets.Collectable, (GenericServerPacketHandler<SendIntItemPacket>)OnCollectable); Receiver.RegisterPacketHandler<SendPersistentBoolsPacket>(Packets.PersistentBool, (GenericServerPacketHandler<SendPersistentBoolsPacket>)OnPersistentBool); Receiver.RegisterPacketHandler<SendPersistentIntsPacket>(Packets.PersistentInt, (GenericServerPacketHandler<SendPersistentIntsPacket>)OnPersistentInt); Receiver.RegisterPacketHandler<SettingsUpdatePacket>(Packets.Settings, (GenericServerPacketHandler<SettingsUpdatePacket>)OnSettings); } private static void Broadcast(ushort senderId, Packets type, Packet packet) { if (Sender == null) { return; } foreach (IServerPlayer player in ServerAddon.api.ServerManager.Players) { if (player.Id != senderId) { Sender.SendCollectionData<Packet>(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, SendIntItemPacket packet) { OnFlag(id, packet, Packets.Collectable, isPD: false); } private static void OnPersistentBool(ushort id, SendPersistentBoolsPacket packet) { SendPersistentBoolsPacket sendPersistentBoolsPacket = new SendPersistentBoolsPacket(); foreach (KeyValuePair<(string, string), (bool, FlagType)> value in packet.Values) { if (ServerAddon.Settings.FlagAllowed(value.Value.Item2)) { sendPersistentBoolsPacket.Values.Add(value.Key, value.Value); } } if (sendPersistentBoolsPacket.Values.Count != 0) { Broadcast(id, Packets.PersistentBool, sendPersistentBoolsPacket); } } private static void OnPersistentInt(ushort id, SendPersistentIntsPacket packet) { SendPersistentIntsPacket sendPersistentIntsPacket = new SendPersistentIntsPacket(); foreach (KeyValuePair<(string, string), (int, FlagType)> value in packet.Values) { if (ServerAddon.Settings.FlagAllowed(value.Value.Item2)) { sendPersistentIntsPacket.Values.Add(value.Key, value.Value); } } if (sendPersistentIntsPacket.Values.Count != 0) { Broadcast(id, Packets.PersistentInt, sendPersistentIntsPacket); } } private static void Announce(ushort id, SendFlagPacket packet, bool isPossiblySilent) { FlagType flagType = packet.FlagType; Log.LogDebug($"[SERVER: Network Forwarder Announce] Received {flagType}"); if (!isPossiblySilent || !string.IsNullOrEmpty(packet.Name)) { if (1 == 0) { } 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 (1 == 0) { } string text2 = text; if (!string.IsNullOrEmpty(text2)) { IServerPlayer player = ServerAddon.api.ServerManager.GetPlayer(id); string newValue = (string.IsNullOrEmpty(packet.Name) ? packet.Key : packet.Name); string text3 = (((player != null) ? player.Username : null) ?? "Unknown Player") + " " + text2.Replace("$", newValue); ServerAddon.api.ServerManager.BroadcastMessage(text3); } } } 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); } } private static void OnSettings(ushort id, SettingsUpdatePacket packet) { IServerPlayer val = default(IServerPlayer); if (ServerAddon.api.ServerManager.TryGetPlayer(id, ref val)) { if (!val.IsAuthorized) { ServerAddon.api.ServerManager.SendMessage(val, "You aren't authorized to change settings."); return; } ServerAddon.Settings.CopyFrom(packet.Settings); ServerAddon.Settings.SaveToFile(); SendSettingsUpdate(); } } } 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.4"; public override void Initialize(IServerApi serverApi) { Log.SetLogger(((ServerAddon)this).Logger); Log.LogInfo("Item Sync Server Addon enabled"); Instance = this; api = serverApi; Settings = SyncServerSettings.ReadFromFile(); NetworkForwarder.Initialize(); ((ICommandManager<IServerCommand>)(object)((ServerAddon)this).ServerApi.CommandManager).RegisterCommand((IServerCommand)(object)new SettingCommand(Settings)); 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[] fields = typeof(SyncServerSettings).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo fieldInfo = fields.FirstOrDefault((FieldInfo s) => s.Name.Equals(settingName, StringComparison.CurrentCultureIgnoreCase)); if (fieldInfo == null) { commandSender.SendMessage("Unknown setting '" + arguments[1] + "'"); return; } if (arguments.Length == 2) { bool flag = (bool)fieldInfo.GetValue(Settings); commandSender.SendMessage($"Setting '{fieldInfo.Name}' is currently {flag}"); return; } bool flag2; if (arguments[2] == "true") { flag2 = true; } else { if (!(arguments[2] == "false")) { SendUsage(); return; } flag2 = false; } fieldInfo.SetValue(Settings, flag2); Settings.SaveToFile(); NetworkForwarder.SendSettingsUpdate(); void SendUsage() { commandSender.SendMessage("Invalid usage: " + Trigger + " <setting> <true/false>"); } } } internal class SyncServerSettings { public bool KillSwitch = false; public bool SyncAbilities = true; public bool SyncMaps = true; public bool SyncPins = true; public bool SyncCurrency = true; public bool SyncSpendingCurrency = false; public bool SyncQuests = true; public bool SyncQuestItems = false; public bool SyncBosses = true; public bool SyncArenas = true; public bool SyncProgression = true; public bool SyncFleas = true; public bool SyncCollectables = true; public bool SyncUpgrades = true; public bool SyncTools = true; public bool SyncCrests = true; public bool SyncTransit = true; public bool SyncShortcuts = true; public bool FlagAllowed(FlagType flag) { if (ServerAddon.Settings.KillSwitch) { return false; } if (1 == 0) { } bool result = flag switch { FlagType.Ability => SyncAbilities, FlagType.Map => SyncMaps, FlagType.Pin => SyncPins, FlagType.Bellshrine => SyncProgression, FlagType.Boss => SyncBosses, FlagType.Arena => SyncArenas, FlagType.Progression => SyncProgression, FlagType.Flea => SyncFleas, 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.QuestStart => SyncQuestItems, FlagType.QuestItem => SyncQuestItems, FlagType.Tool => SyncTools, FlagType.Crest => SyncCrests, FlagType.SilkHeart => SyncUpgrades, FlagType.Needle => SyncUpgrades, FlagType.Bench => SyncProgression, FlagType.Shortcut => SyncShortcuts, FlagType.DoNotSync => false, _ => false, }; if (1 == 0) { } return result; } public List<bool> ToValues() { List<FieldInfo> properties = GetProperties(); List<bool> list = new List<bool>(); foreach (FieldInfo item in properties) { list.Add((bool)item.GetValue(this)); } return list; } public static List<FieldInfo> GetProperties() { List<FieldInfo> list = typeof(SyncServerSettings).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList(); list.Sort((FieldInfo a, FieldInfo b) => a.Name.CompareTo(b.Name)); return list; } public void CopyFrom(SyncServerSettings settings) { List<FieldInfo> properties = GetProperties(); foreach (FieldInfo item in properties) { item.SetValue(this, item.GetValue(settings)); } } public static SyncServerSettings PopulateFromValues(List<bool> values) { SyncServerSettings syncServerSettings = new SyncServerSettings(); List<FieldInfo> properties = GetProperties(); if (properties.Count != values.Count) { Log.LogWarning("Mismatched server setting property count"); } for (int i = 0; i < properties.Count; i++) { FieldInfo fieldInfo = properties[i]; bool flag = values[i]; fieldInfo.SetValue(syncServerSettings, flag); } return syncServerSettings; } public static SyncServerSettings ReadFromFile() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = Path.Combine(directoryName, "ServerSettings.json"); if (!File.Exists(text)) { Log.LogWarning("[SERVER: SETTINGS] " + text + " doesn't exist"); SyncServerSettings syncServerSettings = new SyncServerSettings(); syncServerSettings.SaveToFile(); return syncServerSettings; } try { string text2 = File.ReadAllText(text); SyncServerSettings syncServerSettings2 = JsonConvert.DeserializeObject<SyncServerSettings>(text2); return syncServerSettings2 ?? 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 directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = Path.Combine(directoryName, "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.4"; 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(); ((ICommandManager<IClientCommand>)(object)api.CommandManager).RegisterCommand((IClientCommand)(object)new SettingUICommand(Settings)); api.ClientManager.ConnectEvent += OnConnect; api.ClientManager.DisconnectEvent += OnDisconnect; } private void OnConnect() { EventHooks.Initialize(); Settings.CopyFrom(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<SendIntItemPacket>(Packets.Collectable, (GenericClientPacketHandler<SendIntItemPacket>)OnCollectable); Receiver.RegisterPacketHandler<SendPersistentBoolsPacket>(Packets.PersistentBool, (GenericClientPacketHandler<SendPersistentBoolsPacket>)OnPersistentBools); Receiver.RegisterPacketHandler<SendPersistentIntsPacket>(Packets.PersistentInt, (GenericClientPacketHandler<SendPersistentIntsPacket>)OnPersistentInt); } private static bool HandleSpecialData(SendFlagPacket packet) { UI.ShowPopup(packet.FlagType, packet.Key, packet.Name); return false; } private static void OnIntFlag(SendIntItemPacket packet) { SyncPlugin.AddNextFrameAction(delegate { ClientState.LastItem = packet.Key; if (!HandleSpecialData(packet)) { PlayerData.instance.SetInt(packet.Key, packet.Number); } ClientState.LastItem = ""; }); } private static void OnFloatFlag(SendFloatItemPacket packet) { SyncPlugin.AddNextFrameAction(delegate { ClientState.LastItem = packet.Key; if (!HandleSpecialData(packet)) { PlayerData.instance.SetFloat(packet.Key, packet.Number); } ClientState.LastItem = ""; }); } private static void OnBoolFlag(SendBoolItemPacket packet) { SyncPlugin.AddNextFrameAction(delegate { ClientState.LastItem = packet.Key; if (!HandleSpecialData(packet)) { 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.Rosaries; if (packet.Rosaries != 0) { CurrencyManager.AddGeo((int)packet.Rosaries); } ClientState.LastCurrency = packet.Shards; if (packet.Shards != 0) { CurrencyManager.AddShards((int)packet.Shards); } ClientState.LastCurrency = 0; }); } private static void OnQuestItem(SendBoolItemPacket packet) { SyncPlugin.AddNextFrameAction(delegate { ClientState.LastItem = packet.Key; if (!HandleSpecialData(packet)) { QuestHandler.EndQuest(packet.Key); } ClientState.LastItem = ""; }); } private static void OnTool(SendBoolItemPacket packet) { SyncPlugin.AddNextFrameAction(delegate { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Invalid comparison between Unknown and I4 ClientState.LastItem = packet.Key; if (!HandleSpecialData(packet)) { 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); if ((int)toolByName.Type == 3 && !ToolItemManager.GetCurrentEquippedTools().Any((ToolItem t) => (int)t.Type == 3)) { ToolItemManager.AutoEquip(toolByName); } } else { toolByName.Lock(); } } } } ClientState.LastItem = ""; }); } private static void OnUpgrade(SendFlagPacket packet) { if (!string.IsNullOrEmpty(packet.Name)) { SyncPlugin.AddNextFrameAction(delegate { ClientState.LastItem = packet.Name; if (!HandleSpecialData(packet)) { QuestHandler.EndQuestSilent(packet.Name); } ClientState.LastItem = ""; }); } SyncPlugin.AddNextFrameAction(delegate { ClientState.LastUpgrade = packet.FlagType; if (!HandleSpecialData(packet)) { FlagType flagType = packet.FlagType; if (1 == 0) { } switch (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; } if (true) { } } ClientState.LastUpgrade = FlagType.DoNotSync; }); } private static void OnCollectable(SendIntItemPacket packet) { SyncPlugin.AddNextFrameAction(delegate { ClientState.LastItem = packet.Key; if (!HandleSpecialData(packet)) { Upgrader.GiveCollectable(packet.Key, packet.Number); } ClientState.LastItem = ""; }); } private static void OnPersistentBools(SendPersistentBoolsPacket packet) { foreach (KeyValuePair<(string, string), (bool, FlagType)> value in packet.Values) { string item = value.Key.Item1; string item2 = value.Key.Item2; bool item3 = value.Value.Item1; PersistentHandler.SetPersistentBoolData(item, item2, item3); } } private static void OnPersistentInt(SendPersistentIntsPacket packet) { foreach (KeyValuePair<(string, string), (int, FlagType)> value in packet.Values) { string item = value.Key.Item1; string item2 = value.Key.Item2; int item3 = value.Value.Item1; FlagType item4 = value.Value.Item2; PersistentHandler.SetPersistentIntData(item, item2, item3, item4); } } 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 SendPersistentBoolsPacket PersistentBoolsToSend = new SendPersistentBoolsPacket(); private static SendPersistentIntsPacket PersistentIntsToSend = new SendPersistentIntsPacket(); public static void Initialize() { Sender = ClientAddon.api.NetClient.GetNetworkSender<Packets>((ClientAddon)(object)ClientAddon.Instance); } private static void SendCollectionData(Packets type, Packet packet) { if (!ClientAddon.api.NetClient.IsConnected || Sender == null) { Log.LogDebug("[CLI: Network Sender Collection] Not connected"); } else if (!(packet is SendFlagPacket sendFlagPacket) || CanSync(sendFlagPacket.FlagType)) { Log.LogDebug($"[CLI: Network Sender Collection] Sending {type}"); Sender.SendCollectionData<Packet>(type, packet); } } private static void SendSingleData(Packets type, Packet packet) { if (!ClientAddon.api.NetClient.IsConnected || Sender == null) { Log.LogDebug("[CLI: Network Sender Single] Not connected"); } else if (!(packet is SendFlagPacket sendFlagPacket) || CanSync(sendFlagPacket.FlagType)) { Log.LogDebug($"[CLI: Network Sender Single] Sending {type}"); Sender.SendSingleData(type, (IPacketData)(object)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 || ShardsToSend != 0) { SendCollectionData(Packets.Currency, new SendCurrencyPacket { Rosaries = (short)RosariesToSend, Shards = (short)ShardsToSend }); RosariesToSend = 0; ShardsToSend = 0; } } public static void SendPendingPersistents() { if (PersistentBoolsToSend.Values.Count > 0) { SendCollectionData(Packets.PersistentBool, PersistentBoolsToSend); } if (PersistentIntsToSend.Values.Count > 0) { SendCollectionData(Packets.PersistentInt, PersistentIntsToSend); } PersistentBoolsToSend = new SendPersistentBoolsPacket(); PersistentIntsToSend = new SendPersistentIntsPacket(); } public static void SendFlag(string playerDataKey, FlagType flagType, string name, bool state = true) { SendCollectionData(Packets.BoolPlayerData, new SendBoolItemPacket { Key = playerDataKey, Name = name, FlagType = flagType, State = state }); } public static void SendInt(string playerDataKey, FlagType flagType, string name, int state) { SendCollectionData(Packets.IntPlayerData, new SendIntItemPacket { Key = playerDataKey, Name = name, FlagType = flagType, Number = state }); } public static void SendQuestComplete(string internalName, string displayName) { SendCollectionData(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) { SendCollectionData(Packets.Tool, new SendBoolItemPacket { Key = toolName, Name = displayName, FlagType = (isCrest ? FlagType.Crest : FlagType.Tool), State = state }); } public static void SendUpgrade(string sceneName, FlagType upgradeType) { SendCollectionData(Packets.Upgrade, new SendFlagPacket { Key = sceneName, Name = "", FlagType = upgradeType }); } public static void SendCollectable(string key, string itemName, int amount, FlagType flagType = FlagType.Collectable) { SendCollectionData(Packets.Collectable, new SendIntItemPacket { Key = key, Name = itemName, Number = amount, FlagType = flagType }); } public static void AddPersistentIntData(string id, string scene, int value, FlagType flagType) { if (!PersistentIntsToSend.Values.ContainsKey((scene, id)) && CanSync(flagType)) { PersistentIntsToSend.Values[(scene, id)] = (value, flagType); if (PersistentIntsToSend.Values.Count == 1 && PersistentBoolsToSend.Values.Count == 0) { SyncPlugin.AddNextFrameAction(SendPendingPersistents); } } } public static void AddPersistentBoolData(string id, string scene, bool value, FlagType flagType) { if (!PersistentBoolsToSend.Values.ContainsKey((scene, id)) && CanSync(flagType)) { PersistentBoolsToSend.Values[(scene, id)] = (value, flagType); if (PersistentBoolsToSend.Values.Count == 1 && PersistentIntsToSend.Values.Count == 0) { SyncPlugin.AddNextFrameAction(SendPendingPersistents); } } } public static void SendSettings(Dictionary<string, bool> settings) { SettingsUpdatePacket packet = new SettingsUpdatePacket { Settings = SyncServerSettings.PopulateFromValues(settings.Values.ToList()) }; SendSingleData(Packets.Settings, packet); } } internal class SettingsUI : MonoBehaviour { public bool ShowSettings = false; private const int width = 500; private const int x = 710; private Rect WindowRect = new Rect(710f, 20f, 500f, 360f); private Vector2 ScrollPosition = Vector2.zero; public SyncServerSettings Settings; public Dictionary<string, bool> SettingValues = new Dictionary<string, bool>(); public void SetProps() { foreach (FieldInfo property in SyncServerSettings.GetProperties()) { SettingValues[property.Name] = VariableExtensionsGeneric.GetVariable<bool>((object)Settings, property.Name); } } private void OnGUI() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (ShowSettings) { Color backgroundColor = GUI.backgroundColor; GUI.backgroundColor = Color.black; WindowRect = GUI.Window(987, WindowRect, new WindowFunction(DrawUI), "BasicItemSync Settings"); GUI.backgroundColor = backgroundColor; } } private void DrawUI(int id) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) ScrollPosition = GUILayout.BeginScrollView(ScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(500f), GUILayout.Height(300f) }); foreach (KeyValuePair<string, bool> item in SettingValues.ToList()) { SettingValues[item.Key] = GUILayout.Toggle(item.Value, item.Key, Array.Empty<GUILayoutOption>()); } GUILayout.EndScrollView(); GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(1f), GUILayout.ExpandWidth(true) }); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Save", Array.Empty<GUILayoutOption>())) { ShowSettings = false; NetworkSender.SendSettings(SettingValues); Object.Destroy((Object)(object)this); } else if (GUILayout.Button("Cancel", Array.Empty<GUILayoutOption>())) { ShowSettings = false; Object.Destroy((Object)(object)this); } else { GUILayout.EndHorizontal(); GUI.DragWindow(new Rect(0f, 0f, 1920f, 1080f)); } } } internal class SettingUICommand : IClientCommand, ICommand { private readonly SyncServerSettings Settings; private static SettingsUI? UI; public string Trigger => "/sync-ui"; public string[] Aliases => Array.Empty<string>(); public SettingUICommand(SyncServerSettings settings) { Settings = settings; } public void Execute(string[] arguments) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)UI != (Object)null)) { GameObject val = new GameObject("Sync Settings UI"); UI = val.AddComponent<SettingsUI>(); UI.Settings = Settings; UI.SetProps(); UI.ShowSettings = true; } } } } namespace BasicItemSync.Modules.Mocks { internal interface IModSettings { bool InstanceDebugPlayerData { get; } bool InstanceDebugLogs { get; } } internal class MockModSettings : IModSettings { public bool InstanceDebugPlayerData => false; public bool InstanceDebugLogs => true; } } namespace BasicItemSync.Modules.Hooks { [HarmonyPatch(typeof(CollectableItemPickup))] internal class CollectableItemPickupHook { public static readonly Dictionary<string, FlagType> CollectableTypes = new Dictionary<string, FlagType> { { "Ant Trapper Item", FlagType.QuestItem }, { "Architect Key", FlagType.Progression }, { "Beastfly Remains", 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 Gourmand", 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.Collectable }, { "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 }, { "Ancient Egg Abyss Middle", FlagType.Collectable }, { "Bone Record Bone_East_14", FlagType.Collectable }, { "Bone Record Greymoor_flooded_corridor", FlagType.Collectable }, { "Bone Record Understore_Map_Room", FlagType.Collectable }, { "Bone Record Wisp Top", FlagType.Collectable }, { "Librarian Melody Cylinder", FlagType.Collectable }, { "Psalm Cylinder Grindle", FlagType.Collectable }, { "Psalm Cylinder Hang", FlagType.Collectable }, { "Psalm Cylinder Librarian", FlagType.Collectable }, { "Psalm Cylinder Library Roof", FlagType.Collectable }, { "Psalm Cylinder Ward", FlagType.Collectable }, { "Seal Chit Aspid_01", FlagType.Collectable }, { "Seal Chit City Merchant", FlagType.Collectable }, { "Seal Chit Silk Siphon", FlagType.Collectable }, { "Seal Chit Ward Corpse", FlagType.Collectable }, { "Weaver Record Conductor", FlagType.Collectable }, { "Weaver Record Sprint_Challenge", FlagType.Collectable }, { "Weaver Record Weave_08", FlagType.Collectable }, { "Weaver Totem Bonetown_upper_room", FlagType.Collectable }, { "Weaver Totem Slab_Bottom", FlagType.Collectable }, { "Weaver Totem Witch", FlagType.Collectable } }; [HarmonyPatch("DoPickupAction")] [HarmonyPostfix] public static void DoPickupAction(CollectableItemPickup __instance, ref bool __result) { string name = ((Object)__instance.Item).name; if (ClientState.WasItemReceived(name) || !__result || !Object.op_Implicit((Object)(object)__instance.Item)) { return; } if (!CollectableTypes.TryGetValue(name, out var value)) { if (!(__instance.Item is CollectableRelic)) { Log.LogWarning("Unknown item " + name); return; } value = FlagType.Collectable; } if (value != FlagType.DoNotSync) { string playerDataBool = __instance.playerDataBool; PlayerDataHook.BoolUpdated(playerDataBool, value: true, (Operation)0); string popupName = __instance.Item.GetPopupName(); NetworkSender.SendCollectable(name, popupName, 1, value); if (Object.op_Implicit((Object)(object)__instance.persistent)) { PersistentBoolItemHook.UpdateValue(__instance.persistent); } } } } [HarmonyPatch(typeof(CurrencyManager))] internal class CurrencyManagerHook { [HarmonyPatch("ChangeCurrency")] [HarmonyPostfix] public static void ChangeCurrency(int amount, CurrencyType type) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) Log.LogDebug($"[CLI: CURRENCY] {amount} {type}s added"); if ((amount >= 1 || (ClientAddon.Settings.SyncSpendingCurrency && PlayerData.instance.health != 0 && !PlayerData.instance.atBench)) && !ClientState.WasCurrencyReceived(amount)) { InternalCurrencyType currencyType = (((int)type != 0) ? InternalCurrencyType.ShellShard : InternalCurrencyType.Rosary); NetworkSender.AddCurrency(currencyType, amount); } } } internal class EventHooks { private static GameObject? HookObj; private static readonly 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); AddHook("BEAST DEFEATED", OnBellBeastDefeated); } 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_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) 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 OnBellBeastDefeated() { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) PlayerData.instance.SetBool("defeatedBellBeast", true); bool flag = ClientAddon.Settings.FlagAllowed(FlagType.SilkHeart); bool flag2 = ClientAddon.Settings.FlagAllowed(FlagType.Boss); if (!flag || flag2) { return; } PersistentItemData<bool> val = default(PersistentItemData<bool>); if (!SceneData.instance.PersistentBools.TryGetValue("Bone_05", "Silk Heart", ref val)) { Log.LogDebug("[CLI: EventHook.OBBD] No silk heart persistent for Bone_05"); return; } if (!val.Value) { Log.LogDebug("[CLI: EventHook.OBBD] Haven't accepted silk heart for Bone_05"); return; } Scene sceneByName = SceneManager.GetSceneByName("Bone_05_boss"); if (((Scene)(ref sceneByName)).IsValid()) { Log.LogDebug("[CLI: EventHook.OBBD] Deactivating bell beast"); GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects(); foreach (GameObject val2 in rootGameObjects) { val2.SetActive(false); } PlayerData.instance.UnlockedFastTravel = true; } } } [HarmonyPatch(typeof(HeroController))] internal class HeroControllerHook { [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 void AddToMaxSilkRegen() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (!ClientState.WasUpgradeReceived(FlagType.SilkHeart)) { Scene activeScene = SceneManager.GetActiveScene(); string text = ((Scene)(ref activeScene)).name; if (text == "Memory_Silk_Heart_BellBeast") { text = "Bone_05"; } SceneData.instance.PersistentBools.SetValue(new PersistentItemData<bool> { ID = "Silk Heart", SceneName = text, IsSemiPersistent = false, Value = true, Mutator = (PersistentMutatorTypes)0 }); NetworkSender.SendUpgrade(text, FlagType.SilkHeart); } } } [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 }, {