Decompiled source of ItemSpawnFix v1.2.0

ItemSpawnFix.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using AIGraph;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Hook;
using GTFO.API;
using GTFO.API.Utilities;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using ItemSpawnFix.CustomSettings;
using ItemSpawnFix.Dependencies;
using ItemSpawnFix.JSON;
using ItemSpawnFix.JSON.Converters;
using ItemSpawnFix.Patches;
using ItemSpawnFix.Redistribute;
using ItemSpawnFix.Utils;
using LevelGeneration;
using MTFO.API;
using Microsoft.CodeAnalysis;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ItemSpawnFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+939a38ea5571eb3e4e6c7cfbabbb6052d61225a4")]
[assembly: AssemblyProduct("ItemSpawnFix")]
[assembly: AssemblyTitle("ItemSpawnFix")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
namespace ItemSpawnFix
{
	internal static class Configuration
	{
		private static readonly ConfigEntry<bool> _showDebugMessages;

		private static readonly ConfigFile configFile;

		public static bool ShowDebugMessages => _showDebugMessages.Value;

		static Configuration()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "ItemSpawnFix.cfg"), true);
			string text = "Debug Settings";
			_showDebugMessages = configFile.Bind<bool>(text, "Enable Logs", false, "Prints information to the logs when redistributing resources.");
		}

		public static void Init()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			LiveEdit.CreateListener(Paths.ConfigPath, "ItemSpawnFix.cfg", false).FileChanged += new LiveEditEventHandler(OnFileChanged);
		}

		private static void OnFileChanged(LiveEditEventArgs _)
		{
			configFile.Reload();
		}
	}
	internal static class DinoLogger
	{
		private static ManualLogSource logger = Logger.CreateLogSource("ItemSpawnFix");

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)8, (object)str);
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)32, (object)str);
			}
		}
	}
	[BepInPlugin("Dinorush.ItemSpawnFix", "ItemSpawnFix", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal sealed class EntryPoint : BasePlugin
	{
		public const string MODNAME = "ItemSpawnFix";

		public override void Load()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			SettingsManager.Init();
			Configuration.Init();
			RedistributeUtils.Init();
			LG_DistributionPatches.Init();
			LG_PopulatePatches.Init();
			new Harmony("ItemSpawnFix").PatchAll();
			((BasePlugin)this).Log.LogMessage((object)"Loaded ItemSpawnFix");
		}
	}
}
namespace ItemSpawnFix.Utils
{
	internal class DictListEnumerator<T> : IEnumerator<T>, IEnumerator, IDisposable
	{
		private readonly IEnumerator<List<T>> _valueEnumerator;

		private List<T>? _curList;

		private int _index;

		private T? _current;

		public T Current => _current;

		object IEnumerator.Current => Current;

		internal DictListEnumerator(Dictionary<string, List<T>> data)
		{
			_valueEnumerator = data.Values.GetEnumerator();
			if (_valueEnumerator.MoveNext())
			{
				_curList = _valueEnumerator.Current;
			}
			_index = -1;
		}

		public void Dispose()
		{
		}

		public bool MoveNext()
		{
			if (_curList == null || ++_index >= _curList.Count)
			{
				if (!_valueEnumerator.MoveNext())
				{
					return false;
				}
				_curList = _valueEnumerator.Current;
				_index = 0;
			}
			_current = _curList[_index];
			return true;
		}

		public void Reset()
		{
			_valueEnumerator.Reset();
			if (_valueEnumerator.MoveNext())
			{
				_curList = _valueEnumerator.Current;
			}
			_index = -1;
		}
	}
	internal static class StringExtensions
	{
		public static T ToEnum<T>(this string? value, T defaultValue) where T : struct
		{
			if (string.IsNullOrEmpty(value))
			{
				return defaultValue;
			}
			if (!Enum.TryParse<T>(value.Replace(" ", null), ignoreCase: true, out var result))
			{
				return defaultValue;
			}
			return result;
		}
	}
}
namespace ItemSpawnFix.Redistribute
{
	[HarmonyPatch(typeof(LG_ResourceContainer_Storage))]
	public static class RedistributeUtils
	{
		private static readonly List<(LG_ResourceContainer_Storage storage, StorageTracker slots)> _storages = new List<(LG_ResourceContainer_Storage, StorageTracker)>();

		private static readonly List<(LG_ResourceContainer_Storage storage, StorageTracker slots)> _storagesEmpty = new List<(LG_ResourceContainer_Storage, StorageTracker)>();

		private static readonly Dictionary<IntPtr, List<(LG_ResourceContainer_Storage storage, StorageTracker slots)>> _nodeStorages = new Dictionary<IntPtr, List<(LG_ResourceContainer_Storage, StorageTracker)>>();

		private static readonly Dictionary<IntPtr, List<(LG_ResourceContainer_Storage storage, StorageTracker slots)>> _nodeStoragesEmpty = new Dictionary<IntPtr, List<(LG_ResourceContainer_Storage, StorageTracker)>>();

		private static StorageTracker? _currentTracker;

		public static Random Random { get; private set; } = new Random();


		public static ExpeditionFunction DistributeFunction { get; set; } = (ExpeditionFunction)0;


		public static void Init()
		{
			LevelAPI.OnBuildStart += OnBuildStart;
		}

		private static void OnBuildStart()
		{
			SetSeed(Builder.BuildSeedRandom.Seed);
			_storages.Clear();
			_storagesEmpty.Clear();
			_nodeStorages.Clear();
			_nodeStoragesEmpty.Clear();
		}

		internal static void OnZoneFinished()
		{
			foreach (var item in _storagesEmpty)
			{
				SNet.DestroySelfManagedReplicatedObject(((Component)((Component)item.storage).transform.parent).gameObject);
			}
			_storages.Clear();
			_storagesEmpty.Clear();
			_nodeStorages.Clear();
			_nodeStoragesEmpty.Clear();
		}

		internal static void OnContainerStorageSpawned(LG_ResourceContainer_Storage storage)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)DistributeFunction != 10)
			{
				return;
			}
			(LG_ResourceContainer_Storage, StorageTracker) item = (storage, _currentTracker = new StorageTracker(storage));
			_storages.Add(item);
			_storagesEmpty.Add(item);
			AIG_CourseNode spawnNode = storage.m_core.SpawnNode;
			if (spawnNode != null)
			{
				List<(LG_ResourceContainer_Storage, StorageTracker)> list;
				if (!_nodeStorages.TryGetValue(((Il2CppObjectBase)spawnNode).Pointer, out List<(LG_ResourceContainer_Storage, StorageTracker)> value))
				{
					_nodeStorages.Add(((Il2CppObjectBase)spawnNode).Pointer, value = new List<(LG_ResourceContainer_Storage, StorageTracker)>());
					_nodeStoragesEmpty.Add(((Il2CppObjectBase)spawnNode).Pointer, list = new List<(LG_ResourceContainer_Storage, StorageTracker)>());
				}
				else
				{
					list = _nodeStoragesEmpty[((Il2CppObjectBase)spawnNode).Pointer];
				}
				value.Add(item);
				list.Add(item);
			}
		}

		internal static void OnContainerItemSpawned(LG_ResourceContainer_Storage storage, Transform align)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)DistributeFunction != 10 || _currentTracker == null)
			{
				return;
			}
			if (_currentTracker.Unused)
			{
				_storagesEmpty.RemoveAt(_storagesEmpty.Count - 1);
				AIG_CourseNode spawnNode = storage.m_core.SpawnNode;
				if (spawnNode != null && _nodeStoragesEmpty.TryGetValue(((Il2CppObjectBase)spawnNode).Pointer, out List<(LG_ResourceContainer_Storage, StorageTracker)> value))
				{
					value.RemoveAt(value.Count - 1);
				}
			}
			if (!_currentTracker.RemoveAndCheckSpace(align))
			{
				_storages.RemoveAt(_storages.Count - 1);
				AIG_CourseNode spawnNode2 = storage.m_core.SpawnNode;
				if (spawnNode2 != null && _nodeStorages.TryGetValue(((Il2CppObjectBase)spawnNode2).Pointer, out List<(LG_ResourceContainer_Storage, StorageTracker)> value2))
				{
					value2.RemoveAt(value2.Count - 1);
				}
			}
		}

		public static void SetSeed(int seed)
		{
			Random = new Random(seed);
		}

		public static bool TryRedistributeItems(AIG_CourseNode node, List<ResourceContainerSpawnData> items, out List<ResourceContainerSpawnData> remainingItems, bool empty)
		{
			remainingItems = new List<ResourceContainerSpawnData>();
			if (items.Count == 0)
			{
				return true;
			}
			remainingItems.EnsureCapacity(items.Count);
			Enumerator<ResourceContainerSpawnData> enumerator = items.GetEnumerator();
			while (enumerator.MoveNext())
			{
				ResourceContainerSpawnData current = enumerator.Current;
				remainingItems.Add(current);
			}
			if (_storages.Count == 0)
			{
				return false;
			}
			if (empty)
			{
				if (_nodeStoragesEmpty.TryGetValue(((Il2CppObjectBase)node).Pointer, out List<(LG_ResourceContainer_Storage, StorageTracker)> value))
				{
					TryRedistributeToList(remainingItems, value, _nodeStorages[((Il2CppObjectBase)node).Pointer]);
				}
				TryRedistributeToList(remainingItems, _storagesEmpty, _storages);
			}
			else
			{
				if (_nodeStorages.TryGetValue(((Il2CppObjectBase)node).Pointer, out List<(LG_ResourceContainer_Storage, StorageTracker)> value2))
				{
					TryRedistributeToList(remainingItems, value2);
				}
				TryRedistributeToList(remainingItems, _storages);
			}
			return remainingItems.Count == 0;
		}

		private static bool TryRedistributeToList(List<ResourceContainerSpawnData> items, List<(LG_ResourceContainer_Storage, StorageTracker)> storages, List<(LG_ResourceContainer_Storage, StorageTracker)>? parent = null)
		{
			if (storages.Count == 0)
			{
				return false;
			}
			StorageTracker currentTracker = _currentTracker;
			_currentTracker = null;
			int[] array = Enumerable.Range(0, storages.Count).ToArray();
			Shuffle(array);
			List<int> list = new List<int>();
			for (int i = 0; i < array.Length; i++)
			{
				if (items.Count <= 0)
				{
					break;
				}
				var (storage, storageTracker) = storages[array[i]];
				while (storageTracker.Count > 0 && items.Count > 0)
				{
					if (!storageTracker.RemoveRandomAndCheckSpace(out StorageSlot slot))
					{
						if (parent != null)
						{
							int index = parent.FindIndex(((LG_ResourceContainer_Storage, StorageTracker) pair) => ((Il2CppObjectBase)pair.Item1).Pointer == ((Il2CppObjectBase)storage).Pointer);
							parent.RemoveAt(index);
						}
						list.Add(array[i]);
					}
					else if (parent != null)
					{
						list.Add(array[i]);
					}
					SpawnItem(storage, slot, items[items.Count - 1]);
					items.RemoveAt(items.Count - 1);
				}
			}
			list.Sort((int a, int b) => b.CompareTo(a));
			foreach (int item in list)
			{
				storages.RemoveAt(item);
			}
			_currentTracker = currentTracker;
			return items.Count > 0;
		}

		private static void Shuffle<T>(T[] array)
		{
			int num = array.Length;
			while (num > 1)
			{
				int num2 = Random.Next(0, num--);
				int num3 = num2;
				int num4 = num;
				T val = array[num];
				T val2 = array[num2];
				array[num3] = val;
				array[num4] = val2;
			}
		}

		private static void SpawnItem(LG_ResourceContainer_Storage storage, StorageSlot storageSlot, ResourceContainerSpawnData data)
		{
			//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_0044: Expected I4, but got Unknown
			int num = Random.Next();
			eResourceContainerSpawnType type = data.m_type;
			switch ((int)type)
			{
			case 0:
			case 1:
			case 2:
			case 9:
				if ((Object)(object)storageSlot.ResourcePack != (Object)null)
				{
					storage.SpawnResourcePack(data, storageSlot.ResourcePack, num);
				}
				break;
			case 3:
				if ((Object)(object)storageSlot.CommoditySmall != (Object)null)
				{
					storage.SpawnCommodity(data, storageSlot.CommoditySmall, num);
				}
				break;
			case 4:
				if ((Object)(object)storageSlot.CommodityMedium != (Object)null)
				{
					storage.SpawnCommodity(data, storageSlot.CommodityMedium, num);
				}
				break;
			case 5:
				if ((Object)(object)storageSlot.CommodityLarge != (Object)null)
				{
					storage.SpawnCommodity(data, storageSlot.CommodityLarge, num);
				}
				break;
			case 6:
				if ((Object)(object)storageSlot.Consumable != (Object)null)
				{
					storage.SpawnConsumable(data, storageSlot.Consumable, num);
				}
				break;
			case 7:
				if ((Object)(object)storageSlot.Keycard != (Object)null)
				{
					storage.PlaceKeyCard(data, storageSlot.Keycard, num);
				}
				break;
			case 8:
				if ((Object)(object)storageSlot.Keycard != (Object)null)
				{
					storage.PlaceSmallGenericPickup(data, storageSlot.Keycard, num);
				}
				break;
			case 10:
				if ((Object)(object)storageSlot.Keycard != (Object)null)
				{
					storage.SpawnArtifact(data, storageSlot.Keycard, num);
				}
				break;
			}
		}

		public static string GetPackListString(List<ResourceContainerSpawnData> packs)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder("[");
			for (int i = 0; i < packs.Count - 1; i++)
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 2, stringBuilder2);
				handler.AppendLiteral("(");
				handler.AppendFormatted<eResourceContainerSpawnType>(packs[i].m_type);
				handler.AppendLiteral(":");
				handler.AppendFormatted(packs[i].m_ammo);
				handler.AppendLiteral("),");
				stringBuilder3.Append(ref handler);
			}
			if (packs.Count > 0)
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(3, 2, stringBuilder2);
				handler.AppendLiteral("(");
				handler.AppendFormatted<eResourceContainerSpawnType>(packs[packs.Count - 1].m_type);
				handler.AppendLiteral(":");
				handler.AppendFormatted(packs[packs.Count - 1].m_ammo);
				handler.AppendLiteral(")");
				stringBuilder4.Append(ref handler);
			}
			stringBuilder.Append(']');
			return stringBuilder.ToString();
		}

		public static string GetPackListString(List<ResourceContainerSpawnData> packs)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder("[");
			for (int i = 0; i < packs.Count - 1; i++)
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 2, stringBuilder2);
				handler.AppendLiteral("(");
				handler.AppendFormatted<eResourceContainerSpawnType>(packs[i].m_type);
				handler.AppendLiteral(":");
				handler.AppendFormatted(packs[i].m_ammo);
				handler.AppendLiteral("),");
				stringBuilder3.Append(ref handler);
			}
			if (packs.Count > 0)
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(3, 2, stringBuilder2);
				handler.AppendLiteral("(");
				handler.AppendFormatted<eResourceContainerSpawnType>(packs[packs.Count - 1].m_type);
				handler.AppendLiteral(":");
				handler.AppendFormatted(packs[packs.Count - 1].m_ammo);
				handler.AppendLiteral(")");
				stringBuilder4.Append(ref handler);
			}
			stringBuilder.Append(']');
			return stringBuilder.ToString();
		}
	}
	public class StorageTracker
	{
		private readonly List<(StorageSlot slot, HashSet<IntPtr> alignSet)> _slotAligns;

		private readonly int _maxCount;

		public bool Unused => _slotAligns.Count == _maxCount;

		public int Count => _slotAligns.Count;

		public StorageTracker(LG_ResourceContainer_Storage storage)
		{
			_slotAligns = new List<(StorageSlot, HashSet<IntPtr>)>();
			foreach (StorageSlot item in (Il2CppArrayBase<StorageSlot>)(object)storage.m_storageSlots)
			{
				HashSet<IntPtr> hashSet = new HashSet<IntPtr>();
				_slotAligns.Add((item, hashSet));
				TryAddAlign(item.ResourcePack, hashSet);
				TryAddAlign(item.CommoditySmall, hashSet);
				TryAddAlign(item.CommodityMedium, hashSet);
				TryAddAlign(item.CommodityLarge, hashSet);
				TryAddAlign(item.Consumable, hashSet);
				TryAddAlign(item.Keycard, hashSet);
			}
			_maxCount = _slotAligns.Count;
		}

		private void TryAddAlign(Transform align, HashSet<IntPtr> alignSet)
		{
			if ((Object)(object)align != (Object)null)
			{
				alignSet.Add(((Il2CppObjectBase)align).Pointer);
			}
		}

		public bool RemoveRandomAndCheckSpace(out StorageSlot slot)
		{
			int index = RedistributeUtils.Random.Next(0, Count);
			slot = _slotAligns[index].slot;
			_slotAligns.RemoveAt(index);
			return Count > 0;
		}

		public bool RemoveAndCheckSpace(Transform align)
		{
			Transform align2 = align;
			(StorageSlot, HashSet<IntPtr>) item = _slotAligns.First<(StorageSlot, HashSet<IntPtr>)>(((StorageSlot slot, HashSet<IntPtr> alignSet) pair) => pair.alignSet.Contains(((Il2CppObjectBase)align2).Pointer));
			_slotAligns.Remove(item);
			return Count > 0;
		}
	}
}
namespace ItemSpawnFix.Patches
{
	[HarmonyPatch]
	internal static class LG_DistributionPatches
	{
		private unsafe delegate void d_Enqueue(IntPtr _this, IntPtr item, Il2CppMethodInfo* methodInfo);

		private static bool _inDistribute;

		private static INativeDetour? GetDistributionDetour;

		private static d_Enqueue? orig_Enqueue;

		[HarmonyPatch(typeof(LG_DistributeResourceContainer), "ShouldBeRemoved")]
		[HarmonyPostfix]
		private static void Post_ShouldBeRemoved(ref bool __result)
		{
			__result = false;
		}

		[HarmonyPatch(typeof(LG_Distribute_ResourcePacksPerZone), "Build")]
		[HarmonyPrefix]
		private static void Pre_Build()
		{
			_inDistribute = true;
		}

		[HarmonyPatch(typeof(LG_Distribute_ResourcePacksPerZone), "Build")]
		[HarmonyPostfix]
		private static void Post_Build()
		{
			_inDistribute = false;
		}

		public unsafe static void Init()
		{
			INativeClassStruct val = UnityVersionHandler.Wrap((Il2CppClass*)(void*)Il2CppClassPointerStore<DistributeItemQueueWrapper<LG_DistributeResourceContainer>>.NativeClassPtr);
			for (int i = 0; i < val.MethodCount; i++)
			{
				INativeMethodInfoStruct val2 = UnityVersionHandler.Wrap(val.Methods[i]);
				if (Marshal.PtrToStringAnsi(val2.Name) == "Enqueue")
				{
					GetDistributionDetour = INativeDetour.CreateAndApply<d_Enqueue>(val2.MethodPointer, (d_Enqueue)EnqueuePatch, ref orig_Enqueue);
					break;
				}
			}
		}

		private unsafe static void EnqueuePatch(IntPtr _this, IntPtr item, Il2CppMethodInfo* methodInfo)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			orig_Enqueue(_this, item, methodInfo);
			if (_inDistribute)
			{
				LG_DistributeItem val = new LG_DistributeItem(item);
				val.m_assignedNode.FunctionDistributionPerAreaLookup[val.m_function].Add(val);
				if (Configuration.ShowDebugMessages)
				{
					DinoLogger.Log($"New distribution created for {((Object)val.m_assignedNode.m_zone.NavInfo).ToString()} {((Object)val.m_assignedNode.m_area.m_navInfo).ToString()} of type {val.m_function} added to lookup");
				}
			}
		}
	}
	[HarmonyPatch(typeof(LG_PopulateFunctionMarkersInZoneJob))]
	internal static class LG_PopulatePatches
	{
		private unsafe delegate void d_BuildFunc(IntPtr _this, IntPtr builder, IntPtr distItem, out IntPtr deepestSpawner, bool debug, Il2CppMethodInfo* methodInfo);

		private static readonly List<AIG_CourseNode> _validNodes = new List<AIG_CourseNode>();

		private static int _currZoneID = -1;

		private static INativeDetour? TriggerFunctionBuilderDetour;

		private static d_BuildFunc? orig_TriggerFunctionBuilder;

		[HarmonyPatch("Build")]
		[HarmonyPostfix]
		private static void PostBuild(bool __result)
		{
			if (__result)
			{
				RedistributeUtils.OnZoneFinished();
			}
		}

		[HarmonyPatch("BuildBothFunctionAndPropMarkerAndRemoveSurplus")]
		[HarmonyWrapSafe]
		[HarmonyPriority(200)]
		[HarmonyPrefix]
		private static bool OverrideFallbackLogic(LG_PopulateFunctionMarkersInZoneJob __instance, LG_FunctionMarkerBuilder builder, LG_DistributeItem distItem)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_002d: Expected I4, but got Unknown
			if (!__instance.m_fallbackMode)
			{
				return true;
			}
			ExpeditionFunction function = distItem.m_function;
			switch (function - 8)
			{
			default:
				return true;
			case 0:
			case 2:
			case 4:
			{
				LG_MarkerSpawner val = default(LG_MarkerSpawner);
				__instance.TriggerFunctionBuilder(builder, distItem, ref val, false);
				return false;
			}
			}
		}

		[HarmonyPatch("Build")]
		[HarmonyWrapSafe]
		[HarmonyPriority(200)]
		[HarmonyPrefix]
		private static bool OverrideBuildOrder(LG_PopulateFunctionMarkersInZoneJob __instance, ref bool __result)
		{
			if (!SettingsManager.ActiveSettings.RaiseObjectSpawnPriority)
			{
				return true;
			}
			__result = false;
			if (!__instance.BuildGenericFunctionItems((eDistributionQueue)1))
			{
				return false;
			}
			if (!__instance.BuildGateKeyItems())
			{
				return false;
			}
			if (!__instance.BuildGenericFunctionItems((eDistributionQueue)0))
			{
				return false;
			}
			if (!__instance.BuildPickupItems())
			{
				return false;
			}
			if (!__instance.BuildResourceContainers())
			{
				return false;
			}
			__result = true;
			return false;
		}

		[HarmonyPatch("BuildGenericFunctionItems")]
		[HarmonyWrapSafe]
		[HarmonyPriority(200)]
		[HarmonyPrefix]
		private static bool AllowRedistributeGeneric(LG_PopulateFunctionMarkersInZoneJob __instance, eDistributionQueue queue, ref bool __result)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			if (!SettingsManager.ActiveSettings.AllowRedistributeObjects)
			{
				return true;
			}
			DistributeItemQueueWrapper<LG_DistributeItem> val = (((int)queue != 0) ? __instance.m_distributionData.PrioritizedClusterItems : __instance.m_distributionData.GenericFunctionItems);
			if (val.Count != 0)
			{
				LG_DistributeItem val2 = val.m_itemQueue.Dequeue();
				__result = false;
				LG_FunctionMarkerBuilder val3 = new LG_FunctionMarkerBuilder(val2.m_assignedNode, val2.m_function, val2.m_isWardenObjective, val2.m_wardenObjectiveChainIndex, val2.m_assignedGate, val2.m_localTerminalLogFiles, val2.m_terminalStartStateData, val2.m_terminalPlacementData);
				LG_MarkerSpawner val4 = default(LG_MarkerSpawner);
				__instance.TriggerFunctionBuilder(val3, val2, ref val4, false);
				return false;
			}
			__result = true;
			return false;
		}

		public unsafe static void Init()
		{
			TriggerFunctionBuilderDetour = INativeDetour.CreateAndApply<d_BuildFunc>((IntPtr)(nint)Il2CppAPI.GetIl2CppMethod<LG_PopulateFunctionMarkersInZoneJob>("TriggerFunctionBuilder", typeof(void).Name, false, new string[4]
			{
				"LG_FunctionMarkerBuilder",
				"LG_DistributeItem",
				typeof(LG_MarkerSpawner).MakeByRefType().FullName,
				typeof(bool).Name
			}), (d_BuildFunc)TriggerFunctionBuilderPatch, ref orig_TriggerFunctionBuilder);
			LevelAPI.OnBuildStart += delegate
			{
				_currZoneID = -1;
			};
		}

		private unsafe static void TriggerFunctionBuilderPatch(IntPtr _this, IntPtr builder, IntPtr distItem, out IntPtr deepestSpawner, bool debug, Il2CppMethodInfo* methodInfo)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//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)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Invalid comparison between Unknown and I4
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Invalid comparison between Unknown and I4
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
			LG_PopulateFunctionMarkersInZoneJob val = new LG_PopulateFunctionMarkersInZoneJob(_this);
			LG_FunctionMarkerBuilder val2 = new LG_FunctionMarkerBuilder(builder);
			LG_DistributeItem val3 = new LG_DistributeItem(distItem);
			ExpeditionFunction val4 = (RedistributeUtils.DistributeFunction = val3.m_function);
			bool flag = (int)val4 == 10;
			LG_DistributeResourceContainer val5 = ((!flag) ? ((LG_DistributeResourceContainer)null) : new LG_DistributeResourceContainer(distItem));
			bool flag2 = (flag ? (val5.m_packs.Count == 0) : val3.ShouldBeRemoved());
			if (val.m_fallbackMode)
			{
				if ((int)val4 == 20)
				{
					if (!flag2)
					{
						orig_TriggerFunctionBuilder(_this, builder, distItem, out deepestSpawner, debug, methodInfo);
					}
					else
					{
						deepestSpawner = IntPtr.Zero;
					}
					RedistributeUtils.DistributeFunction = (ExpeditionFunction)0;
					return;
				}
				RedistributeUtils.SetSeed(Builder.BuildSeedRandom.Range(0, int.MaxValue, "NO_TAG"));
				AIG_CourseNode assignedNode = val3.m_assignedNode;
				string value = ((Object)assignedNode.m_area.m_navInfo).ToString();
				string value2 = ((Object)assignedNode.m_zone.NavInfo).ToString();
				if (!flag2 && Configuration.ShowDebugMessages)
				{
					DinoLogger.Log($"Creating {val4} with floor fallback in {value2} {value}");
				}
				if (flag2)
				{
					deepestSpawner = IntPtr.Zero;
				}
				else if (flag && TryRedistributeItems(val3.m_assignedNode, val5, empty: false))
				{
					deepestSpawner = IntPtr.Zero;
				}
				else
				{
					orig_TriggerFunctionBuilder(_this, builder, distItem, out deepestSpawner, debug, methodInfo);
				}
				RedistributeUtils.DistributeFunction = (ExpeditionFunction)0;
				return;
			}
			if ((int)val4 != 20)
			{
				val3.m_allowFunctionFallback = false;
			}
			orig_TriggerFunctionBuilder(_this, builder, distItem, out deepestSpawner, debug, methodInfo);
			if (flag2 || (int)val4 == 20)
			{
				RedistributeUtils.DistributeFunction = (ExpeditionFunction)0;
				return;
			}
			if (deepestSpawner == IntPtr.Zero)
			{
				RedistributeUtils.SetSeed(Builder.BuildSeedRandom.Range(0, int.MaxValue, "NO_TAG"));
				AIG_CourseNode node = val3.m_assignedNode;
				string value3 = ((Object)node.m_area.m_navInfo).ToString();
				LG_Zone zone = node.m_zone;
				string text = ((Object)zone.NavInfo).ToString();
				if (Configuration.ShowDebugMessages)
				{
					DinoLogger.Log($"No markers remaining for distribute {val4} in {text} {value3} trying to redistribute");
				}
				if (flag && TryRedistributeItems(node, val5, empty: true))
				{
					deepestSpawner = IntPtr.Zero;
					RedistributeUtils.DistributeFunction = (ExpeditionFunction)0;
					return;
				}
				if (_currZoneID != zone.ID)
				{
					_currZoneID = zone.ID;
					_validNodes.Clear();
					Enumerator<LG_Area> enumerator = zone.m_areas.GetEnumerator();
					while (enumerator.MoveNext())
					{
						LG_Area current = enumerator.Current;
						_validNodes.Add(current.m_courseNode);
					}
				}
				int num = _validNodes.FindLastIndex((AIG_CourseNode n) => n.NodeID == node.NodeID);
				if (num >= 0)
				{
					_validNodes.RemoveAt(num);
				}
				while (_validNodes.Count > 0)
				{
					int index = RedistributeUtils.Random.Next(0, _validNodes.Count);
					val2.m_node = _validNodes[index];
					val3.m_assignedNode = _validNodes[index];
					orig_TriggerFunctionBuilder(_this, builder, distItem, out deepestSpawner, debug, methodInfo);
					if (deepestSpawner == IntPtr.Zero)
					{
						_validNodes.RemoveAt(index);
						continue;
					}
					if (Configuration.ShowDebugMessages)
					{
						DinoLogger.Log($"Redistributed {val4} to {text} {((Object)_validNodes[index].m_area.m_navInfo).ToString()} (orig: {value3})");
					}
					RedistributeUtils.DistributeFunction = (ExpeditionFunction)0;
					return;
				}
				if (Configuration.ShowDebugMessages)
				{
					DinoLogger.Log("No markers available in " + text);
				}
				if (flag && TryRedistributeItems(node, val5, empty: false))
				{
					deepestSpawner = IntPtr.Zero;
					RedistributeUtils.DistributeFunction = (ExpeditionFunction)0;
					return;
				}
				val2.m_node = node;
				val3.m_assignedNode = node;
				if (Configuration.ShowDebugMessages)
				{
					DinoLogger.Log($"Unable to redistribute {val4} in {text}, moving to floor fallback in {value3}");
				}
				AddToFallbackQueue(val, val3);
			}
			RedistributeUtils.DistributeFunction = (ExpeditionFunction)0;
		}

		private static bool TryRedistributeItems(AIG_CourseNode node, LG_DistributeResourceContainer distRes, bool empty)
		{
			string text = ((Object)node.m_zone.NavInfo).ToString();
			if (RedistributeUtils.TryRedistributeItems(node, distRes.m_packs, out List<ResourceContainerSpawnData> remainingItems, empty))
			{
				if (empty)
				{
					DinoLogger.Log("Redistributed " + RedistributeUtils.GetPackListString(distRes.m_packs) + " to empty containers in " + text);
				}
				else
				{
					DinoLogger.Log("Redistributed " + RedistributeUtils.GetPackListString(distRes.m_packs) + " to containers in " + text);
				}
				return true;
			}
			if (Configuration.ShowDebugMessages)
			{
				if (empty)
				{
					DinoLogger.Log("Not enough empty containers in " + text + ", sending remaining items to new container spawns: " + RedistributeUtils.GetPackListString(remainingItems));
				}
				else
				{
					DinoLogger.Log("Not enough containers in " + text + ", sending remaining items to floor container spawns: " + RedistributeUtils.GetPackListString(remainingItems));
				}
			}
			distRes.m_packs.Clear();
			foreach (ResourceContainerSpawnData item in remainingItems)
			{
				distRes.m_packs.Add(item);
			}
			return false;
		}

		private static void AddToFallbackQueue(LG_PopulateFunctionMarkersInZoneJob job, LG_DistributeItem distItem)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			LG_ZoneDistribution distributionDataFallback = job.m_zone.DistributionDataFallback;
			if ((int)distItem.m_function == 10)
			{
				distributionDataFallback.ResourceContainerItems.Enqueue(((Il2CppObjectBase)distItem).Cast<LG_DistributeResourceContainer>());
			}
			else if ((int)distItem.m_function == 8 || (int)distItem.m_function == 12)
			{
				distributionDataFallback.PickupItems.Enqueue(((Il2CppObjectBase)distItem).Cast<LG_DistributePickUpItem>());
			}
			else
			{
				distributionDataFallback.GenericFunctionItems.Enqueue(distItem);
			}
		}
	}
	[HarmonyPatch(typeof(LG_ResourceContainer_Storage))]
	internal static class LG_ResourceContainerPatches
	{
		[HarmonyPatch("Setup")]
		[HarmonyPostfix]
		private static void Post_Setup(LG_ResourceContainer_Storage __instance)
		{
			RedistributeUtils.OnContainerStorageSpawned(__instance);
		}

		[HarmonyPatch("SpawnResourcePack")]
		[HarmonyPatch("SpawnCommodity")]
		[HarmonyPatch("SpawnConsumable")]
		[HarmonyPatch("PlaceKeyCard")]
		[HarmonyPatch("PlaceSmallGenericPickup")]
		[HarmonyPatch("SpawnArtifact")]
		[HarmonyPostfix]
		private static void Post_SpawnItem(LG_ResourceContainer_Storage __instance, Transform align)
		{
			RedistributeUtils.OnContainerItemSpawned(__instance, align);
		}
	}
}
namespace ItemSpawnFix.JSON
{
	public static class ISFJson
	{
		private static readonly JsonSerializerOptions _setting = new JsonSerializerOptions
		{
			ReadCommentHandling = JsonCommentHandling.Skip,
			IncludeFields = true,
			PropertyNameCaseInsensitive = true,
			WriteIndented = true,
			IgnoreReadOnlyProperties = true
		};

		public static T? Deserialize<T>(string json)
		{
			return JsonSerializer.Deserialize<T>(json, _setting);
		}

		public static T? Deserialize<T>(ref Utf8JsonReader reader)
		{
			return JsonSerializer.Deserialize<T>(ref reader, _setting);
		}

		public static object? Deserialize(Type type, string json)
		{
			return JsonSerializer.Deserialize(json, type, _setting);
		}

		public static string Serialize<T>(T value)
		{
			return JsonSerializer.Serialize(value, _setting);
		}

		public static void Serialize<T>(Utf8JsonWriter writer, T value)
		{
			JsonSerializer.Serialize(writer, value, _setting);
		}

		public static void Serialize<T>(Utf8JsonWriter writer, string name, T value)
		{
			writer.WritePropertyName(name);
			JsonSerializer.Serialize(writer, value, _setting);
		}
	}
}
namespace ItemSpawnFix.JSON.Converters
{
	public sealed class LevelTargetConverter : JsonConverter<LevelTarget>
	{
		public override LevelTarget? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			LevelTarget levelTarget = new LevelTarget();
			if (ParseTarget(ref reader, levelTarget, options))
			{
				return levelTarget;
			}
			throw new JsonException("Expected level target to be a tier, tierindex, or level layout ID");
		}

		private static bool ParseTarget(ref Utf8JsonReader reader, LevelTarget target, JsonSerializerOptions options)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Invalid comparison between Unknown and I4
			if (reader.TokenType == JsonTokenType.Null)
			{
				return true;
			}
			if (reader.TokenType == JsonTokenType.String)
			{
				string @string = reader.GetString();
				if (@string.Length >= 5)
				{
					target.Tier = @string.Substring(0, 5).ToEnum<eRundownTier>((eRundownTier)99);
				}
				else
				{
					target.Tier = ("Tier" + @string[0]).ToEnum<eRundownTier>((eRundownTier)99);
				}
				int num = ((@string.Length < 5) ? 1 : 5);
				if ((int)target.Tier != 99 && @string.Length > num)
				{
					string text = @string;
					int num2 = num;
					if (int.TryParse(text.Substring(num2, text.Length - num2), out var result))
					{
						target.TierIndex = result - 1;
					}
					else
					{
						target.Tier = (eRundownTier)99;
					}
				}
				if ((int)target.Tier == 99)
				{
					target.LevelLayoutID = JsonSerializer.Deserialize<uint>(ref reader, options);
				}
				return true;
			}
			if (reader.TokenType == JsonTokenType.Number)
			{
				target.LevelLayoutID = reader.GetUInt32();
				return true;
			}
			return false;
		}

		public override void Write(Utf8JsonWriter writer, LevelTarget? value, JsonSerializerOptions options)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//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)
			if (value != null)
			{
				if (value.LevelLayoutID == 0 && (int)value.Tier == 99)
				{
					writer.WriteNullValue();
					return;
				}
				if (value.LevelLayoutID != 0)
				{
					writer.WriteNumberValue(value.LevelLayoutID);
					return;
				}
				eRundownTier tier = value.Tier;
				string? text = ((object)(eRundownTier)(ref tier)).ToString();
				writer.WriteStringValue(text[text.Length - 1] + ((value.TierIndex >= 0) ? (value.TierIndex + 1).ToString() : ""));
			}
		}
	}
	public sealed class SettingsDataConverter : JsonConverter<SettingsData>
	{
		public override SettingsData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			if (reader.TokenType == JsonTokenType.Null)
			{
				return null;
			}
			SettingsData settingsData = new SettingsData();
			if (reader.TokenType != JsonTokenType.StartObject)
			{
				throw new JsonException("Expected Trigger Coordinator to be either a string or object");
			}
			while (reader.Read())
			{
				if (reader.TokenType == JsonTokenType.EndObject)
				{
					return settingsData;
				}
				if (reader.TokenType != JsonTokenType.PropertyName)
				{
					throw new JsonException("Expected PropertyName token");
				}
				string? @string = reader.GetString();
				reader.Read();
				switch (@string.ToLowerInvariant())
				{
				case "levels":
				case "level":
					if (reader.TokenType == JsonTokenType.StartArray)
					{
						settingsData.Levels = JsonSerializer.Deserialize<LevelTarget[]>(ref reader, options);
					}
					else if (reader.TokenType != JsonTokenType.Null)
					{
						settingsData.Levels = new LevelTarget[1] { JsonSerializer.Deserialize<LevelTarget>(ref reader, options) };
					}
					break;
				case "raiseobjectspawnpriority":
					settingsData.RaiseObjectSpawnPriority = reader.GetBoolean();
					break;
				case "allowredistributeobjects":
					settingsData.AllowRedistributeObjects = reader.GetBoolean();
					break;
				}
			}
			throw new JsonException("Expected EndObject token");
		}

		public override void Write(Utf8JsonWriter writer, SettingsData? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
				return;
			}
			writer.WriteStartObject();
			writer.WritePropertyName("Levels");
			if (value.Levels.Length == 0)
			{
				writer.WriteNullValue();
			}
			else if (value.Levels.Length == 1)
			{
				JsonSerializer.Serialize(writer, value.Levels[0], options);
			}
			else
			{
				JsonSerializer.Serialize(writer, value.Levels, options);
			}
			writer.WriteNumber("RundownID", value.RundownID);
			writer.WriteBoolean("RaiseObjectSpawnPriority", value.RaiseObjectSpawnPriority);
			writer.WriteBoolean("AllowRedistributeObjects", value.AllowRedistributeObjects);
			writer.WriteEndObject();
		}
	}
}
namespace ItemSpawnFix.Dependencies
{
	internal static class MTFOWrapper
	{
		public const string PLUGIN_GUID = "com.dak.MTFO";

		public static readonly bool HasMTFO;

		public static string GameDataPath
		{
			get
			{
				if (!HasMTFO)
				{
					return "";
				}
				return GameDataPath_Unsafe();
			}
		}

		public static string CustomPath
		{
			get
			{
				if (!HasMTFO)
				{
					return "";
				}
				return CustomPath_Unsafe();
			}
		}

		public static bool HasCustomContent
		{
			get
			{
				if (!HasMTFO)
				{
					return false;
				}
				return HasCustomContent_Unsafe();
			}
		}

		static MTFOWrapper()
		{
			HasMTFO = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.ContainsKey("com.dak.MTFO");
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static string GameDataPath_Unsafe()
		{
			return MTFOPathAPI.RundownPath;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static string CustomPath_Unsafe()
		{
			return MTFOPathAPI.CustomPath;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool HasCustomContent_Unsafe()
		{
			return MTFOPathAPI.HasRundownPath;
		}
	}
}
namespace ItemSpawnFix.CustomSettings
{
	[JsonConverter(typeof(LevelTargetConverter))]
	public sealed class LevelTarget
	{
		public uint LevelLayoutID { get; set; }

		public eRundownTier Tier { get; set; } = (eRundownTier)99;


		public int TierIndex { get; set; } = -1;


		public bool IsMatch(uint layoutID, uint rundownID, eRundownTier tier, int tierIndex)
		{
			//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)
			if (layoutID == LevelLayoutID)
			{
				return true;
			}
			if (Tier == tier && (TierIndex == -1 || TierIndex == tierIndex))
			{
				return true;
			}
			return false;
		}
	}
	[JsonConverter(typeof(SettingsDataConverter))]
	public sealed class SettingsData
	{
		public static readonly SettingsData Default = new SettingsData();

		public static readonly SettingsData[] Template = new SettingsData[3]
		{
			new SettingsData
			{
				Levels = new LevelTarget[1]
				{
					new LevelTarget
					{
						LevelLayoutID = 420u
					}
				}
			},
			new SettingsData
			{
				Levels = new LevelTarget[1]
				{
					new LevelTarget
					{
						Tier = (eRundownTier)1
					}
				}
			},
			new SettingsData
			{
				Levels = new LevelTarget[2]
				{
					new LevelTarget
					{
						LevelLayoutID = 4115u
					},
					new LevelTarget
					{
						Tier = (eRundownTier)2,
						TierIndex = 0
					}
				}
			}
		};

		public uint RundownID;

		public LevelTarget[] Levels { get; set; } = Array.Empty<LevelTarget>();


		public bool RaiseObjectSpawnPriority { get; set; }

		public bool AllowRedistributeObjects { get; set; }
	}
	public sealed class SettingsManager
	{
		public static readonly SettingsManager Current;

		private static (eRundownTier tier, int tierIndex) _currentLevel;

		private readonly Dictionary<string, List<SettingsData>> _fileToData = new Dictionary<string, List<SettingsData>>();

		private readonly LiveEditListener _liveEditListener;

		public static SettingsData ActiveSettings { get; set; }

		private void FileChanged(LiveEditEventArgs e)
		{
			LiveEditEventArgs e2 = e;
			DinoLogger.Warning("LiveEdit File Changed: " + e2.FileName);
			LiveEdit.TryReadFileContent(e2.FullPath, (Action<string>)delegate(string content)
			{
				ReadFileContent(e2.FullPath, content);
			});
		}

		private void FileDeleted(LiveEditEventArgs e)
		{
			DinoLogger.Warning("LiveEdit File Removed: " + e.FileName);
			_fileToData.Remove(e.FullPath);
			RefreshSettings();
		}

		private void FileCreated(LiveEditEventArgs e)
		{
			LiveEditEventArgs e2 = e;
			DinoLogger.Warning("LiveEdit File Created: " + e2.FileName);
			LiveEdit.TryReadFileContent(e2.FullPath, (Action<string>)delegate(string content)
			{
				ReadFileContent(e2.FullPath, content);
			});
		}

		private void ReadFileContent(string file, string content)
		{
			_fileToData.Remove(file);
			List<SettingsData> list = null;
			try
			{
				list = ISFJson.Deserialize<List<SettingsData>>(content);
			}
			catch (JsonException ex)
			{
				DinoLogger.Error("Error parsing settings json " + file);
				DinoLogger.Error(ex.Message);
			}
			if (list != null)
			{
				_fileToData[file] = list;
				RefreshSettings();
			}
		}

		private static uint ActiveRundownID()
		{
			string activeRundownKey = RundownManager.ActiveRundownKey;
			uint result = default(uint);
			if (!RundownManager.RundownProgressionReady || !RundownManager.TryGetIdFromLocalRundownKey(activeRundownKey, ref result))
			{
				return 0u;
			}
			return result;
		}

		private static void RefreshSettings()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			SettingsData activeSettings = ActiveSettings;
			ActiveSettings = SettingsData.Default;
			uint num = ActiveRundownID();
			if (num == 0)
			{
				return;
			}
			pActiveExpedition activeExpeditionData = RundownManager.GetActiveExpeditionData();
			if ((int)activeExpeditionData.tier == 99)
			{
				return;
			}
			if (_currentLevel.tier == activeExpeditionData.tier && _currentLevel.tierIndex == activeExpeditionData.expeditionIndex)
			{
				ActiveSettings = activeSettings;
				return;
			}
			uint levelLayoutData = RundownManager.ActiveExpedition.LevelLayoutData;
			IEnumerator<SettingsData> enumerator = Current.GetEnumerator();
			while (enumerator.MoveNext())
			{
				SettingsData current = enumerator.Current;
				if (current.RundownID != 0 && current.RundownID != num)
				{
					continue;
				}
				LevelTarget[] levels = current.Levels;
				for (int i = 0; i < levels.Length; i++)
				{
					if (levels[i].IsMatch(levelLayoutData, num, activeExpeditionData.tier, activeExpeditionData.expeditionIndex))
					{
						ActiveSettings = current;
						return;
					}
				}
			}
		}

		private SettingsManager()
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			if (!MTFOWrapper.HasCustomContent)
			{
				DinoLogger.Log($"No custom path detected! Has MTFO? {MTFOWrapper.HasMTFO}");
				return;
			}
			string text = Path.Combine(MTFOWrapper.CustomPath, "ItemSpawnFix");
			if (!Directory.Exists(text))
			{
				DinoLogger.Log("No settings directory detected. Creating template.");
				Directory.CreateDirectory(text);
				StreamWriter streamWriter = File.CreateText(Path.Combine(text, "Template.json"));
				streamWriter.WriteLine(ISFJson.Serialize(SettingsData.Template));
				streamWriter.Flush();
				streamWriter.Close();
			}
			else
			{
				DinoLogger.Log("SettingsData directory detected.");
			}
			foreach (string item in Directory.EnumerateFiles(text, "*.json", SearchOption.AllDirectories))
			{
				string content = File.ReadAllText(item);
				ReadFileContent(item, content);
			}
			_liveEditListener = LiveEdit.CreateListener(text, "*.json", true);
			_liveEditListener.FileCreated += new LiveEditEventHandler(FileCreated);
			_liveEditListener.FileChanged += new LiveEditEventHandler(FileChanged);
			_liveEditListener.FileDeleted += new LiveEditEventHandler(FileDeleted);
		}

		static SettingsManager()
		{
			ActiveSettings = SettingsData.Default;
			_currentLevel = ((eRundownTier)99, 0);
			Current = new SettingsManager();
		}

		internal static void Init()
		{
			LevelAPI.OnBuildStart += RefreshSettings;
		}

		public List<SettingsData> GetSettingsData()
		{
			List<SettingsData> list2 = new List<SettingsData>(_fileToData.Values.Sum((List<SettingsData> list) => list.Count));
			IEnumerator<SettingsData> enumerator = GetEnumerator();
			while (enumerator.MoveNext())
			{
				list2.Add(enumerator.Current);
			}
			return list2;
		}

		public IEnumerator<SettingsData> GetEnumerator()
		{
			return new DictListEnumerator<SettingsData>(_fileToData);
		}
	}
}