Decompiled source of DafoertNite Patches v1.2.0

plugins/DafoertNitePatches.dll

Decompiled 2 weeks 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 BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace InventoryHarmonizer
{
	internal static class AutomaticFuelNewContainers
	{
		internal const string AutomaticFuelGuid = "TastyChickenLegs.AutomaticFuel";

		private static MethodInfo _addContainer;

		private static FieldInfo _containerList;

		internal static void Apply(ConfigFile config, Harmony harmony)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			if (HarmonizerPlugin.Loaded("TastyChickenLegs.AutomaticFuel") && config.Bind<bool>("AutomaticFuel + new containers", "Enabled", true, "Let freshly built modded containers supply fuel right away instead of after the area reloads.").Value)
			{
				_addContainer = AccessTools.Method("AutomaticFuel.TastyUtils:AddContainer", new Type[2]
				{
					typeof(Container),
					typeof(ZNetView)
				}, (Type[])null);
				Type type = AccessTools.TypeByName("AutomaticFuel.AutomaticFuelPlugin");
				_containerList = ((type != null) ? AccessTools.Field(type, "ContainerList") : null);
				MethodInfo methodInfo = AccessTools.Method(typeof(Piece), "SetCreator", (Type[])null, (Type[])null);
				if (_addContainer == null || _containerList == null || methodInfo == null)
				{
					HarmonizerPlugin.Log.LogWarning((object)"AutomaticFuel + new containers: a mod changed internally; this fix is inactive.");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(AutomaticFuelNewContainers), "SetCreatorPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				HarmonizerPlugin.Log.LogInfo((object)"AutomaticFuel + new containers: newly built containers supply fuel right away.");
			}
		}

		private static void SetCreatorPostfix(Piece __instance)
		{
			Container component = ((Component)__instance).GetComponent<Container>();
			if (!((Object)(object)component == (Object)null) && _containerList.GetValue(null) is List<Container> list && !list.Contains(component))
			{
				_addContainer.Invoke(null, new object[2]
				{
					component,
					((Component)component).GetComponent<ZNetView>()
				});
			}
		}
	}
	internal static class GoblinSoundpack
	{
		private sealed class Sound
		{
			public ConfigEntry<string> ClipList;

			public AudioClip[] Clips;

			public float MinPitch;

			public float MaxPitch;

			public float MinVol;

			public float MaxVol;
		}

		internal const string OldModGuid = "dafoertnite.goblins";

		private const string Section = "Goblin soundpack";

		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<bool> _pitchVariation;

		private static ConfigEntry<string> _excluded;

		private static ConfigEntry<string> _idleClips;

		private static ConfigEntry<string> _alertClips;

		private static ConfigEntry<string> _hitClips;

		private static ConfigEntry<string> _deathClips;

		private static ConfigEntry<float> _chance;

		private static ConfigEntry<float> _cooldown;

		private static ConfigEntry<float> _idleFrequency;

		private static ConfigEntry<float> _originalChance;

		private static readonly Dictionary<string, AudioClip> Clips = new Dictionary<string, AudioClip>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, Sound> Sounds = new Dictionary<string, Sound>();

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

		private static float _nextAllowed;

		internal static void Apply(BaseUnityPlugin plugin, ConfigFile config, Harmony harmony)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Expected O, but got Unknown
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Expected O, but got Unknown
			_enabled = config.Bind<bool>("Goblin soundpack", "Enabled", true, "Goblins have something to say.");
			_idleClips = config.Bind<string>("Goblin soundpack", "IdleClips", "fortnite.wav*5, laugh.wav*2, goblin-idle.wav*3", "Clips for idle grunts. Comma-separated clip file names from the sounds folder; one is picked at random. Add *N to weight a clip, e.g. fortnite.wav*3 is three times as likely. Empty keeps the normal goblin sound. Changes apply live.");
			_alertClips = config.Bind<string>("Goblin soundpack", "AlertClips", "fortnite.wav*12, something-of-a-scientist.wav*5, goblin-spotted.wav*3", "Clips when a goblin spots you. Comma-separated clip file names from the sounds folder; one is picked at random. Add *N to weight a clip, e.g. fortnite.wav*3 is three times as likely. Empty keeps the normal goblin sound. Changes apply live.");
			_hitClips = config.Bind<string>("Goblin soundpack", "HitClips", "fortnite.wav*7, goblin-idle.wav*3", "Clips when a goblin gets hit. Comma-separated clip file names from the sounds folder; one is picked at random. Add *N to weight a clip, e.g. fortnite.wav*3 is three times as likely. Empty keeps the normal goblin sound. Changes apply live.");
			_deathClips = config.Bind<string>("Goblin soundpack", "DeathClips", "dying.wav*2, goblin-death.wav, skeleton-death.wav", "Clips when a goblin dies. Comma-separated clip file names from the sounds folder; one is picked at random. Add *N to weight a clip, e.g. fortnite.wav*3 is three times as likely. Empty keeps the normal goblin sound. Changes apply live.");
			_chance = config.Bind<float>("Goblin soundpack", "Chance", 1f, new ConfigDescription("Chance that a goblin sound plays a clip.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_cooldown = config.Bind<float>("Goblin soundpack", "CooldownSeconds", 0f, new ConfigDescription("Minimum seconds between clips across all goblins.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
			_originalChance = config.Bind<float>("Goblin soundpack", "OriginalSoundChance", 0f, new ConfigDescription("When a clip can't play (cooldown or Chance), how often the normal goblin sound plays instead; otherwise it stays silent.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_pitchVariation = config.Bind<bool>("Goblin soundpack", "PitchVariation", true, "Keep the game's random pitch variation on the clips.");
			_idleFrequency = config.Bind<float>("Goblin soundpack", "IdleSoundFrequency", 2f, new ConfigDescription("How often goblins make idle sounds, relative to normal (2 = twice as often). Applies after a world load.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			_excluded = config.Bind<string>("Goblin soundpack", "ExcludedGoblins", "GoblinKing", "Comma-separated creature prefab names starting with \"Goblin\" that are left alone (GoblinKing is Yagluth).");
			if (!_enabled.Value)
			{
				return;
			}
			if (HarmonizerPlugin.Loaded("dafoertnite.goblins"))
			{
				HarmonizerPlugin.Log.LogWarning((object)"Goblin soundpack: the old DafoertGoblins mod is installed; remove it. Skipping the soundpack so goblins don't speak twice.");
				return;
			}
			string path = Path.Combine(Path.GetDirectoryName(plugin.Info.Location), "sounds");
			if (!Directory.Exists(path))
			{
				HarmonizerPlugin.Log.LogInfo((object)"Goblin soundpack: no sounds folder; goblins sound normal.");
				return;
			}
			string[] files = Directory.GetFiles(path);
			foreach (string text in files)
			{
				if (text.EndsWith(".wav", StringComparison.OrdinalIgnoreCase) || text.EndsWith(".ogg", StringComparison.OrdinalIgnoreCase))
				{
					((MonoBehaviour)plugin).StartCoroutine(LoadClip(text));
				}
			}
			harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNetScene), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(GoblinSoundpack), "ScanPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(ZSFX), "Play", (Type[])null, (Type[])null), new HarmonyMethod(typeof(GoblinSoundpack), "PlayPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			HarmonizerPlugin.Log.LogInfo((object)"Goblin soundpack: active.");
		}

		private static IEnumerator LoadClip(string path)
		{
			AudioType val = (AudioType)(path.EndsWith(".ogg", StringComparison.OrdinalIgnoreCase) ? 14 : 20);
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(path).AbsoluteUri, val);
			try
			{
				yield return request.SendWebRequest();
				AudioClip val2 = (((int)request.result == 1) ? DownloadHandlerAudioClip.GetContent(request) : null);
				if ((Object)(object)val2 == (Object)null || val2.length <= 0f)
				{
					HarmonizerPlugin.Log.LogError((object)("Goblin soundpack: could not load " + path + " (" + request.error + "). Use WAV or Ogg Vorbis."));
					yield break;
				}
				string key = (((Object)val2).name = Path.GetFileName(path));
				Clips[key] = val2;
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static string PrefabName(GameObject go)
		{
			return ((Object)go).name.Replace("(Clone)", "").Trim();
		}

		private static bool IsGoblin(GameObject go)
		{
			string name = PrefabName(go);
			if (!name.StartsWith("Goblin", StringComparison.Ordinal) || (Object)(object)go.GetComponent<BaseAI>() == (Object)null)
			{
				return false;
			}
			return _excluded.Value.Split(',').All((string excluded) => excluded.Trim() != name);
		}

		private static void ScanPostfix(ZNetScene __instance)
		{
			Sounds.Clear();
			int num = 0;
			foreach (GameObject prefab in __instance.m_prefabs)
			{
				if (!((Object)(object)prefab == (Object)null) && IsGoblin(prefab))
				{
					num++;
					BaseAI component = prefab.GetComponent<BaseAI>();
					if (!IdleIntervals.TryGetValue(((Object)prefab).name, out var value))
					{
						value = (IdleIntervals[((Object)prefab).name] = component.m_idleSoundInterval);
					}
					component.m_idleSoundInterval = value / Mathf.Max(_idleFrequency.Value, 0.1f);
					Register(component.m_alertedEffects, _alertClips);
					Register(component.m_idleSound, _idleClips);
					Character component2 = prefab.GetComponent<Character>();
					if (!((Object)(object)component2 == (Object)null))
					{
						Register(component2.m_hitEffects, _hitClips);
						Register(component2.m_deathEffects, _deathClips);
					}
				}
			}
			HarmonizerPlugin.Log.LogInfo((object)("Goblin soundpack: " + num + " goblin types, " + Sounds.Count + " sounds replaced, " + Clips.Count + " clips loaded."));
		}

		private static void Register(EffectList effects, ConfigEntry<string> clipList)
		{
			if (effects == null || effects.m_effectPrefabs == null)
			{
				return;
			}
			EffectData[] effectPrefabs = effects.m_effectPrefabs;
			foreach (EffectData val in effectPrefabs)
			{
				if ((Object)(object)val.m_prefab == (Object)null)
				{
					continue;
				}
				ZSFX[] componentsInChildren = val.m_prefab.GetComponentsInChildren<ZSFX>(true);
				foreach (ZSFX val2 in componentsInChildren)
				{
					if (!Sounds.ContainsKey(((Object)((Component)val2).gameObject).name))
					{
						Sounds[((Object)((Component)val2).gameObject).name] = new Sound
						{
							ClipList = clipList,
							Clips = val2.m_audioClips,
							MinPitch = val2.m_minPitch,
							MaxPitch = val2.m_maxPitch,
							MinVol = val2.m_minVol,
							MaxVol = val2.m_maxVol
						};
					}
				}
			}
		}

		private static void PlayPrefix(ZSFX __instance)
		{
			if (!_enabled.Value || !Sounds.TryGetValue(PrefabName(((Component)__instance).gameObject), out var value))
			{
				return;
			}
			__instance.m_audioClips = value.Clips;
			__instance.m_minPitch = value.MinPitch;
			__instance.m_maxPitch = value.MaxPitch;
			__instance.m_minVol = value.MinVol;
			__instance.m_maxVol = value.MaxVol;
			AudioClip val = PickClip(value.ClipList.Value);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (Time.time >= _nextAllowed && Random.value < _chance.Value)
			{
				_nextAllowed = Time.time + _cooldown.Value;
				__instance.m_audioClips = (AudioClip[])(object)new AudioClip[1] { val };
				if (!_pitchVariation.Value)
				{
					__instance.m_minPitch = 1f;
					__instance.m_maxPitch = 1f;
				}
			}
			else if (Random.value >= _originalChance.Value)
			{
				__instance.m_minVol = 0f;
				__instance.m_maxVol = 0f;
			}
		}

		private static AudioClip PickClip(string list)
		{
			if (string.IsNullOrEmpty(list))
			{
				return null;
			}
			List<AudioClip> list2 = new List<AudioClip>();
			string[] array = list.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split('*');
				if (array2.Length < 2 || !int.TryParse(array2[1].Trim(), out var result))
				{
					result = 1;
				}
				if (Clips.TryGetValue(array2[0].Trim(), out var value))
				{
					for (int j = 0; j < Mathf.Clamp(result, 0, 100); j++)
					{
						list2.Add(value);
					}
				}
			}
			if (list2.Count <= 0)
			{
				return null;
			}
			return list2[Random.Range(0, list2.Count)];
		}
	}
	[BepInPlugin("dafoertnite.patches", "DafoertNite Patches", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class HarmonizerPlugin : BaseUnityPlugin
	{
		public const string Guid = "dafoertnite.patches";

		public const string Name = "DafoertNite Patches";

		public const string Version = "1.2.0";

		private const string OldGuid = "inventoryharmonizer";

		internal static ManualLogSource Log;

		private FileSystemWatcher _watcher;

		private volatile bool _reloadConfig;

		private DateTime _configWritten;

		private void Awake()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			if (Loaded("inventoryharmonizer"))
			{
				Log.LogWarning((object)"Inventory Harmonizer (the old name of this mod) is also installed; remove it. DafoertNite Patches stays inactive until then.");
				return;
			}
			Harmony harmony = new Harmony("dafoertnite.patches");
			VssModdedContainers.Apply(((BaseUnityPlugin)this).Config, harmony);
			MultiCraftChestNetwork.Apply(((BaseUnityPlugin)this).Config, harmony);
			MultiCraftAdventureBackpacks.Apply(((BaseUnityPlugin)this).Config, harmony);
			AutomaticFuelNewContainers.Apply(((BaseUnityPlugin)this).Config, harmony);
			GoblinSoundpack.Apply((BaseUnityPlugin)(object)this, ((BaseUnityPlugin)this).Config, harmony);
			_watcher = new FileSystemWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath));
			_watcher.Changed += delegate
			{
				_reloadConfig = true;
			};
			_watcher.EnableRaisingEvents = true;
			_configWritten = File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath);
		}

		private void Update()
		{
			if (_reloadConfig)
			{
				_reloadConfig = false;
				if (!(File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath) == _configWritten))
				{
					((BaseUnityPlugin)this).Config.Reload();
					_configWritten = File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath);
					Log.LogInfo((object)"Config reloaded.");
				}
			}
		}

		private void OnDestroy()
		{
			if (_watcher != null)
			{
				_watcher.Dispose();
			}
		}

		internal static bool Loaded(string guid)
		{
			return Chainloader.PluginInfos.ContainsKey(guid);
		}
	}
	internal static class MultiCraftAdventureBackpacks
	{
		internal const string AdventureBackpacksGuid = "vapok.mods.adventurebackpacks";

		private static MethodInfo _enter;

		private static MethodInfo _exit;

		internal static void Apply(ConfigFile config, Harmony harmony)
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_0112: Expected O, but got Unknown
			if (HarmonizerPlugin.Loaded("vapok.mods.adventurebackpacks") && HarmonizerPlugin.Loaded("maximods.valheim.multicraft") && config.Bind<bool>("MultiCraft + AdventureBackpacks", "Enabled", true, "Let MultiCraft count materials in your equipped backpack when working out how many items you can craft.").Value)
			{
				MethodInfo methodInfo = AccessTools.Method("MultiCraft.Helper:GetAvailableItems", new Type[1] { typeof(string) }, (Type[])null);
				Type type = AccessTools.TypeByName("AdventureBackpacks.Features.CraftingContext");
				_enter = ((type != null) ? type.GetMethod("Enter", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) : null);
				_exit = ((type != null) ? type.GetMethod("Exit", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) : null);
				if (methodInfo == null || _enter == null || _exit == null)
				{
					HarmonizerPlugin.Log.LogWarning((object)"MultiCraft + AdventureBackpacks: a mod changed internally; this fix is inactive.");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(MultiCraftAdventureBackpacks), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(MultiCraftAdventureBackpacks), "Finalizer", (Type[])null), (HarmonyMethod)null);
				HarmonizerPlugin.Log.LogInfo((object)"MultiCraft + AdventureBackpacks: MultiCraft now counts backpack contents.");
			}
		}

		private static void Prefix(out bool __state)
		{
			__state = false;
			try
			{
				_enter.Invoke(null, null);
				__state = true;
			}
			catch (Exception ex)
			{
				HarmonizerPlugin.Log.LogWarning((object)("MultiCraft + AdventureBackpacks: " + ex.Message));
			}
		}

		private static Exception Finalizer(bool __state, Exception __exception)
		{
			if (__state)
			{
				_exit.Invoke(null, null);
			}
			return __exception;
		}
	}
	internal static class MultiCraftChestNetwork
	{
		internal const string ChestNetworkGuid = "jordan.chestnetwork";

		internal const string MultiCraftGuid = "maximods.valheim.multicraft";

		internal static void Apply(ConfigFile config, Harmony harmony)
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_00e0: Expected O, but got Unknown
			if (HarmonizerPlugin.Loaded("jordan.chestnetwork") && HarmonizerPlugin.Loaded("maximods.valheim.multicraft") && config.Bind<bool>("MultiCraft + ChestNetwork", "Enabled", true, "Let MultiCraft count materials in ChestNetwork chests when working out how many items you can craft.").Value)
			{
				MethodInfo methodInfo = AccessTools.Method("MultiCraft.Helper:GetAvailableItems", new Type[1] { typeof(string) }, (Type[])null);
				Type type = AccessTools.Inner(AccessTools.TypeByName("ChestNetwork.Plugin.Patches.RequirementPatches"), "CheckScope");
				MethodInfo methodInfo2 = ((type != null) ? AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null) : null);
				MethodInfo methodInfo3 = ((type != null) ? AccessTools.Method(type, "Finalizer", (Type[])null, (Type[])null) : null);
				if (methodInfo == null || methodInfo2 == null || methodInfo3 == null)
				{
					HarmonizerPlugin.Log.LogWarning((object)"MultiCraft + ChestNetwork: a mod changed internally; this fix is inactive.");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null);
				HarmonizerPlugin.Log.LogInfo((object)"MultiCraft + ChestNetwork: MultiCraft now counts ChestNetwork chests.");
			}
		}
	}
	internal static class VssModdedContainers
	{
		internal const string VssGuid = "georo.vss";

		private const string OldBridgeGuid = "vssbridge.containers";

		private static ConfigEntry<bool> _logContainers;

		private static MethodInfo _vssRegister;

		private static readonly HashSet<string> Extra = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> Excluded = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, bool> Cache = new Dictionary<string, bool>();

		internal static void Apply(ConfigFile config, Harmony harmony)
		{
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Expected O, but got Unknown
			if (!HarmonizerPlugin.Loaded("georo.vss"))
			{
				return;
			}
			ConfigEntry<bool> obj = config.Bind<bool>("VSS + modded containers", "Enabled", true, "Let VSS link standalone containers from other mods that players build with the hammer. Carts, ships, graves, the Obliterator and world loot stay excluded.");
			ConfigEntry<string> val = config.Bind<string>("VSS + modded containers", "ExtraPrefabs", "", "Comma-separated prefab names to always link.");
			ConfigEntry<string> val2 = config.Bind<string>("VSS + modded containers", "ExcludedPrefabs", "", "Comma-separated prefab names to never link through this fix.");
			_logContainers = config.Bind<bool>("VSS + modded containers", "LogContainerPrefabs", false, "Log each container prefab this fix evaluates (once per prefab), to find names for the lists above.");
			if (!obj.Value)
			{
				return;
			}
			if (HarmonizerPlugin.Loaded("vssbridge.containers"))
			{
				HarmonizerPlugin.Log.LogWarning((object)"VSS: the old VSS Container Bridge is installed; remove it. Skipping this fix to avoid patching twice.");
				return;
			}
			Type type = AccessTools.TypeByName("VSS.VssStorageScanner");
			if (type != null && type.GetMethod("Supported", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(Container),
				typeof(bool)
			}, null) != null)
			{
				HarmonizerPlugin.Log.LogInfo((object)"VSS: this VSS version supports modded containers itself; fix not needed.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method("VSS.VssStorageScanner:Supported", new Type[1] { typeof(Container) }, (Type[])null);
			if (methodInfo == null)
			{
				HarmonizerPlugin.Log.LogWarning((object)"VSS: VssStorageScanner.Supported(Container) not found; this fix is inactive.");
				return;
			}
			Parse(val.Value, Extra);
			Parse(val2.Value, Excluded);
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(VssModdedContainers), "SupportedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_vssRegister = AccessTools.Method("VSS.VssContainerAwakePatch:Postfix", new Type[1] { typeof(Container) }, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(Piece), "SetCreator", (Type[])null, (Type[])null);
			if (_vssRegister != null && methodInfo2 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(VssModdedContainers), "SetCreatorPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				HarmonizerPlugin.Log.LogWarning((object)"VSS: could not hook piece placement; new modded containers link after the area reloads.");
			}
			HarmonizerPlugin.Log.LogInfo((object)"VSS: modded containers can be linked.");
		}

		private static void SupportedPostfix(Container container, ref bool __result)
		{
			if (__result || (Object)(object)container == (Object)null || (Object)(object)container.m_wagon != (Object)null || container.m_autoDestroyEmpty)
			{
				return;
			}
			ZNetView component = ((Component)container).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return;
			}
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(component.GetZDO().GetPrefab()) : null);
			string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : ((Object)((Component)container).gameObject).name.Replace("(Clone)", "").Trim());
			if (!Cache.TryGetValue(text, out var value))
			{
				value = Evaluate(container, component, text);
				Cache[text] = value;
				if (_logContainers.Value)
				{
					HarmonizerPlugin.Log.LogInfo((object)("VSS: container prefab '" + text + "' -> " + (value ? "linked" : "ignored")));
				}
			}
			__result = value && component.GetZDO().GetLong(ZDOVars.s_creator, 0L) != 0;
		}

		private static bool Evaluate(Container container, ZNetView view, string name)
		{
			if (Excluded.Contains(name))
			{
				return false;
			}
			if (Extra.Contains(name))
			{
				return true;
			}
			if ((Object)(object)container.m_rootObjectOverride != (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)view).GetComponent<Piece>() == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)view).GetComponent<Ship>() == (Object)null && (Object)(object)((Component)view).GetComponent<TombStone>() == (Object)null)
			{
				return (Object)(object)((Component)view).GetComponent<Incinerator>() == (Object)null;
			}
			return false;
		}

		private static void SetCreatorPostfix(Piece __instance)
		{
			Container component = ((Component)__instance).GetComponent<Container>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			try
			{
				_vssRegister.Invoke(null, new object[1] { component });
			}
			catch (Exception ex)
			{
				HarmonizerPlugin.Log.LogWarning((object)("VSS: registration failed: " + ex.Message));
			}
		}

		private static void Parse(string value, HashSet<string> into)
		{
			if (string.IsNullOrEmpty(value))
			{
				return;
			}
			string[] array = value.Split(',');
			foreach (string text in array)
			{
				if (text.Trim().Length > 0)
				{
					into.Add(text.Trim());
				}
			}
		}
	}
}