Decompiled source of SafehouseProgressionModeCode Beta v0.1.10

NGA.SHPlibs.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using Atlas;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NGA.EventSys;
using NGA.ItemShop;
using Sodalite.Api;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyCompany("NGA")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Persistent player progression! Raid, stash loot, and deploy with seemless scene/loadout saving.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("NGA.SHPlibs")]
[assembly: AssemblyTitle("BepInEx Plugin Title")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[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;
		}
	}
}
public class BaseViewModel
{
	public event Action Changed;

	protected void NotifyListeners()
	{
		this.Changed?.Invoke();
	}

	public virtual void Initialize()
	{
	}

	public virtual void Dispose()
	{
	}
}
public class ViewModelRegistry : MonoBehaviour
{
	private static ViewModelRegistry _instance;

	private readonly Dictionary<Type, object> _map = new Dictionary<Type, object>();

	private void Awake()
	{
		if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
			return;
		}
		_instance = this;
		Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
	}

	private static void EnsureInstance()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		if (!((Object)(object)_instance != (Object)null))
		{
			GameObject val = new GameObject("ViewModelRegistry");
			_instance = val.AddComponent<ViewModelRegistry>();
			Object.DontDestroyOnLoad((Object)(object)val);
		}
	}

	public static T Get<T>() where T : BaseViewModel, new()
	{
		EnsureInstance();
		Type typeFromHandle = typeof(T);
		if (!_instance._map.TryGetValue(typeFromHandle, out var value))
		{
			T val = new T();
			val.Initialize();
			_instance._map[typeFromHandle] = val;
			value = val;
		}
		return (T)value;
	}

	public static void Prewarm<T>() where T : BaseViewModel, new()
	{
		Get<T>();
	}

	public static void Ensure()
	{
		EnsureInstance();
	}

	public static void Register<T>(T instance) where T : BaseViewModel
	{
		EnsureInstance();
		_instance._map[typeof(T)] = instance;
	}

	public static void DisposeAll()
	{
		EnsureInstance();
		foreach (KeyValuePair<Type, object> item in _instance._map)
		{
			((BaseViewModel)item.Value).Dispose();
		}
		_instance._map.Clear();
	}
}
public class UIElementAnimator
{
	public static IEnumerator AnimateRoutine(Transform rect, Transform targetTransform, float duration)
	{
		Vector3 startPos = rect.position;
		Quaternion startRot = rect.rotation;
		Vector3 targetPos = targetTransform.position;
		Quaternion targetRot = targetTransform.rotation;
		float t = 0f;
		while (t < duration)
		{
			t += Time.deltaTime;
			float lerpT = Mathf.Clamp01(t / duration);
			rect.position = Vector3.Lerp(startPos, targetPos, lerpT);
			rect.rotation = Quaternion.Lerp(startRot, targetRot, lerpT);
			yield return null;
		}
		rect.position = targetPos;
		rect.rotation = targetRot;
	}
}
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 NGA
{
	public sealed class BankEventsBridge
	{
		private readonly BankService _svc;

		private string _subRankTierReachedId;

		public BankEventsBridge(BankService svc)
		{
			_svc = svc;
		}

		public void Start()
		{
			if (!((Object)(object)SHGM.Instance == (Object)null) && SHGM.Instance.eventBus != null)
			{
				EventSubscriptionSpec eventSubscriptionSpec = new EventSubscriptionSpec
				{
					Channel = "Player"
				};
				eventSubscriptionSpec.TypesExact.Add("rank_tier_reached");
				_subRankTierReachedId = SHGM.Instance.eventBus.Subscribe(eventSubscriptionSpec, (Action<EventView>)OnRankTierReachedEvent);
			}
		}

		public void Stop()
		{
			SHGM.Instance.eventBus.Unsubscribe(_subRankTierReachedId);
			_subRankTierReachedId = null;
		}

		private void OnRankTierReachedEvent(EventView ev)
		{
			Debug.LogWarning((object)("||=> Recieved OnRankTierEvent bank: " + ev));
			if (ev == null)
			{
				Debug.LogError((object)"OnRankTierEvent was null");
				return;
			}
			RankTierReachedEvent rankTierReachedEvent = null;
			if (ev.Payload != null && ev.Payload.TryGetValue("event", out var value))
			{
				rankTierReachedEvent = value as RankTierReachedEvent;
			}
			if (rankTierReachedEvent == null || rankTierReachedEvent.rewards == null)
			{
				Debug.LogError((object)("Either payload " + rankTierReachedEvent?.ToString() + " or rewards are null " + rankTierReachedEvent?.rewards));
				return;
			}
			for (int i = 0; i < rankTierReachedEvent.rewards.Count; i++)
			{
				RewardDef rewardDef = rankTierReachedEvent.rewards[i];
				if (rewardDef.rewardType != 1)
				{
					continue;
				}
				CurrencyReward currencyReward = rewardDef?.currency;
				if (currencyReward == null || currencyReward.amount == 0 || string.IsNullOrEmpty(currencyReward.currencyId))
				{
					Debug.LogWarning((object)("Award was null " + currencyReward?.ToString() + " Amount was zero " + currencyReward?.amount + " or currency id null or empty: " + currencyReward?.currencyId));
					continue;
				}
				string currencyId = currencyReward.currencyId;
				string text = currencyId;
				if (!(text == "bitties"))
				{
					if (text == "spades")
					{
						_svc.AddSpades(currencyReward.amount);
					}
				}
				else
				{
					_svc.ProcessTransaction(new ShBank.TransactionRecord(currencyReward.amount, "Level-reached award"));
				}
			}
		}
	}
	public sealed class BankService : ShService
	{
		private BankEventsBridge _eventBridge;

		public override void Initialize(ShMetaState meta, ShSessionManager session)
		{
			base.Initialize(meta, session);
			StartEventBridge();
		}

		public override void BindToProfile(ShProfileState profile)
		{
			StopEventBridge();
			base.BindToProfile(profile);
			StartEventBridge();
		}

		public override void Dispose()
		{
			base.Dispose();
		}

		private void EnsureProfileBankState()
		{
			if (BoundProfile.bank == null)
			{
				BoundProfile.bank = new ShBank();
			}
			BoundProfile.bank.EnsureInit();
		}

		private ShBank GetBank()
		{
			if (BoundProfile == null)
			{
				return null;
			}
			EnsureProfileBankState();
			return BoundProfile.bank;
		}

		public int GetBalance()
		{
			return GetBank()?.playerBalance ?? 0;
		}

		public int GetSpades()
		{
			return GetBank()?.playerSpades ?? 0;
		}

		public void AddSpades(int amount)
		{
			if (amount == 0)
			{
				return;
			}
			ShBank bank = GetBank();
			if (bank == null)
			{
				Debug.LogWarning((object)"Spades: No current profile found");
				return;
			}
			bank.AddSpades(amount);
			if ((Object)(object)SHGM.Instance != (Object)null && SHGM.Instance.eventBus != null)
			{
				EventPublishSpec eventPublishSpec = new EventPublishSpec();
				eventPublishSpec.Type = "spades_awarded";
				eventPublishSpec.Channels.Add("Player");
				eventPublishSpec.Payload["event"] = new SpadesAwardedEvent(amount, null);
				SHGM.Instance.eventBus.Publish(eventPublishSpec);
			}
		}

		public bool TrySpendSpades(int amount)
		{
			if (amount <= 0)
			{
				return true;
			}
			ShBank bank = GetBank();
			if (bank == null)
			{
				Debug.LogWarning((object)"Spades: No current profile found");
				return false;
			}
			if (bank.playerSpades < amount)
			{
				return false;
			}
			bank.SubtractSpades(amount);
			return true;
		}

		public void ForceSpendSpades(int amount)
		{
			if (amount != 0)
			{
				ShBank bank = GetBank();
				if (bank == null)
				{
					Debug.LogWarning((object)"Spades: No current profile found");
				}
				else
				{
					bank.SubtractSpades(amount);
				}
			}
		}

		public void AddBalance(int amount, string description = null)
		{
			if (amount != 0)
			{
				ShBank bank = GetBank();
				if (bank == null)
				{
					Debug.LogWarning((object)"Bitties: No current profile found");
					return;
				}
				ShBank.TransactionRecord transaction = new ShBank.TransactionRecord(Math.Abs(amount), description);
				bank.AddBalance(Math.Abs(amount));
				bank.AddTransaction(transaction);
			}
		}

		public bool TrySpendBalance(int amount, string description = null)
		{
			if (amount <= 0)
			{
				return true;
			}
			ShBank bank = GetBank();
			if (bank == null)
			{
				Debug.LogWarning((object)"Bitties: No current profile found");
				return false;
			}
			if (bank.playerBalance < amount)
			{
				return false;
			}
			ShBank.TransactionRecord transaction = new ShBank.TransactionRecord(-amount, description);
			bank.SubtractBalance(amount);
			bank.AddTransaction(transaction);
			return true;
		}

		public void ForceSpendBalance(int amount, string description = null)
		{
			if (amount != 0)
			{
				ShBank bank = GetBank();
				if (bank == null)
				{
					Debug.LogWarning((object)"Bitties: No current profile found");
					return;
				}
				ShBank.TransactionRecord transaction = new ShBank.TransactionRecord(-Math.Abs(amount), description);
				bank.SubtractBalance(Math.Abs(amount));
				bank.AddTransaction(transaction);
			}
		}

		public bool ProcessTransaction(ShBank.TransactionRecord transaction, bool forceDecrement = false)
		{
			ShBank bank = GetBank();
			if (bank == null)
			{
				Debug.LogWarning((object)"Try buy: No current profile found");
				return false;
			}
			if (transaction == null)
			{
				return false;
			}
			int amount = transaction.amount;
			if (amount < 0)
			{
				int num = -amount;
				if (!forceDecrement && bank.playerBalance < num)
				{
					return false;
				}
				bank.SubtractBalance(num);
			}
			else if (amount > 0)
			{
				bank.AddBalance(amount);
			}
			bank.AddTransaction(transaction);
			return true;
		}

		private void StartEventBridge()
		{
			if (_eventBridge == null)
			{
				_eventBridge = new BankEventsBridge(this);
			}
			_eventBridge.Start();
		}

		private void StopEventBridge()
		{
			if (_eventBridge != null)
			{
				_eventBridge.Stop();
			}
		}
	}
	[Serializable]
	public sealed class SpadesAwardedEvent
	{
		public int deltaAmount;

		public string sourceTag;

		public SpadesAwardedEvent(int deltaAmount, string sourceTag)
		{
			this.deltaAmount = deltaAmount;
			this.sourceTag = sourceTag;
		}
	}
	[Serializable]
	public sealed class ShBank
	{
		[Serializable]
		public sealed class TransactionRecord
		{
			public int amount;

			public string description;

			public TransactionRecord(int amount, string description)
			{
				this.amount = amount;
				this.description = description;
			}
		}

		public int playerBalance;

		public List<TransactionRecord> transactions;

		public int playerSpades;

		public ShBank()
		{
			playerBalance = 0;
			transactions = new List<TransactionRecord>();
			playerSpades = 0;
		}

		public void EnsureInit()
		{
			if (transactions == null)
			{
				transactions = new List<TransactionRecord>();
			}
		}

		public void AddBalance(int amount)
		{
			playerBalance += amount;
		}

		public void SubtractBalance(int amount)
		{
			playerBalance -= amount;
		}

		public void AddSpades(int amount)
		{
			playerSpades += amount;
		}

		public void SubtractSpades(int amount)
		{
			playerSpades -= amount;
		}

		public void AddTransaction(TransactionRecord transaction)
		{
			EnsureInit();
			transactions.Insert(0, transaction);
		}

		public void ClearTransactions()
		{
			EnsureInit();
			transactions.Clear();
		}
	}
	public static class BankUtils
	{
		public const string BITTIES_SYMBOL = "₿";

		public const string SPADES_SYMBOL = "♠";

		public const string BITTIES_COLOR = "yellow";

		public const string SPADES_COLOR = "lightblue";

		public static string BITTIES_SYMBOL_COLORED = "<color=yellow>₿</color>";

		public static string SPADES_SYMBOL_COLORED = "<color=lightblue>♠</color>";

		private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture;

		public static string FormatAmount(int amount)
		{
			return amount.ToString("N0", Invariant);
		}

		public static string FormatFromId(string id, int amount, bool bold = true)
		{
			if (!(id == "bitties"))
			{
				if (id == "spades")
				{
					return FormatSpades(amount, bold);
				}
				return FormatAmount(amount);
			}
			return FormatBitties(amount, bold);
		}

		public static string FormatBitties(int amount, bool bold = true)
		{
			string text = FormatAmount(amount);
			string text2 = "<color=yellow>₿</color>" + text;
			return bold ? ("<b>" + text2 + "</b>") : text2;
		}

		public static string FormatBitties(float amount, bool bold = true)
		{
			string text = amount.ToString("N2", Invariant).TrimEnd(new char[1] { '0' }).TrimEnd(new char[1] { Invariant.NumberFormat.NumberDecimalSeparator[0] });
			string text2 = "<color=yellow>₿</color>" + text;
			return bold ? ("<b>" + text2 + "</b>") : text2;
		}

		public static string FormatSpades(int amount, bool bold = true)
		{
			string text = FormatAmount(amount);
			string text2 = "<color=lightblue>♠</color>" + text;
			return bold ? ("<b>" + text2 + "</b>") : text2;
		}

		public static string FormatBoth(int bitties, int spades)
		{
			return FormatBitties(bitties) + "   " + FormatSpades(spades);
		}
	}
	public sealed class BankViewModel : BaseViewModel
	{
		private BankService _service;

		public static BankViewModel Instance => ViewModelRegistry.Get<BankViewModel>();

		public override void Initialize()
		{
			_service = SHGM.Instance?.sessionManager?.GetService<BankService>();
			if (_service != null)
			{
				_service.Changed += HandleServiceChanged;
			}
			NotifyListeners();
		}

		public override void Dispose()
		{
			if (_service != null)
			{
				_service.Changed -= HandleServiceChanged;
			}
			_service = null;
		}

		private void HandleServiceChanged()
		{
			NotifyListeners();
		}

		public bool ProcessTransaction(ShBank.TransactionRecord record)
		{
			if (_service == null)
			{
				return false;
			}
			return _service.ProcessTransaction(record);
		}

		public int GetSpades()
		{
			if (_service == null)
			{
				return 0;
			}
			return _service.GetSpades();
		}

		public void AddSpades(int amount)
		{
			if (_service != null)
			{
				_service.AddSpades(amount);
			}
		}

		public bool TrySpendSpades(int amount)
		{
			if (_service == null)
			{
				return false;
			}
			return _service.TrySpendSpades(amount);
		}

		public void ForceSpendSpades(int amount)
		{
			if (_service != null)
			{
				_service.ForceSpendSpades(amount);
			}
		}

		public int GetBalance()
		{
			if (_service == null)
			{
				return 0;
			}
			return _service.GetBalance();
		}

		public void AddBalance(int amount, string description = null)
		{
			if (_service != null)
			{
				_service.AddBalance(amount, description);
			}
		}

		public bool TrySpendBalance(int amount, string description = null)
		{
			if (_service == null)
			{
				return false;
			}
			return _service.TrySpendBalance(amount, description);
		}

		public void ForceSpendBalance(int amount, string description = null)
		{
			if (_service != null)
			{
				_service.ForceSpendBalance(amount, description);
			}
		}
	}
	public class GiftMate : MonoBehaviour
	{
		public int refreshRate = 30;

		public float timeSinceRefresh = 0f;

		public int selectedIx = 0;

		private ShProfileState CurrentProfile => SHGM.Instance.sessionManager.ActiveProfile;

		public void Start()
		{
			drawGifts();
		}

		public void Update()
		{
			timeSinceRefresh += Time.deltaTime;
			if (timeSinceRefresh >= (float)refreshRate)
			{
				timeSinceRefresh = 0f;
				drawGifts();
			}
		}

		private void drawGifts()
		{
			CurrentProfile.giftsList.giftsQueue.ForEach(delegate
			{
			});
		}

		public void BTN_SpawnSelected()
		{
			ShGiftsList giftsList = CurrentProfile.giftsList;
			if (selectedIx >= 0 && selectedIx < giftsList.giftsQueue.Count)
			{
				giftsList.giftsQueue[selectedIx].idsToSpawn.ForEach(delegate
				{
				});
				giftsList.RemoveGift(giftsList.giftsQueue[selectedIx]);
				drawGifts();
			}
		}
	}
	[Serializable]
	public class ShGift
	{
		public string tinyMessage;

		public List<string> idsToSpawn;

		public ShGift(string tinyMessage, List<string> idsToSpawn)
		{
			this.tinyMessage = tinyMessage;
			this.idsToSpawn = idsToSpawn;
		}
	}
	[Serializable]
	public class ShGiftsList
	{
		public List<ShGift> giftsQueue;

		public ShGiftsList()
		{
			giftsQueue = new List<ShGift>();
		}

		public void AddGift(ShGift g)
		{
			giftsQueue.Add(g);
		}

		public void RemoveGift(ShGift g)
		{
			giftsQueue.Remove(g);
		}
	}
	public interface IShService
	{
		void Initialize(ShMetaState meta, ShSessionManager session);

		void BindToProfile(ShProfileState profile);
	}
	public abstract class ShService : IShService
	{
		protected ShMetaState Meta;

		protected ShSessionManager Session;

		protected ShProfileState BoundProfile;

		public event Action Changed;

		public virtual void Initialize(ShMetaState meta, ShSessionManager session)
		{
			Meta = meta;
			Session = session;
		}

		public virtual void BindToProfile(ShProfileState profile)
		{
			BoundProfile = profile;
			NotifyListeners();
		}

		protected void NotifyListeners()
		{
			this.Changed?.Invoke();
		}

		public virtual void Dispose()
		{
			Meta = null;
			Session = null;
			BoundProfile = null;
		}
	}
	internal static class ItemFeatureExtractor
	{
		internal static void TryEnrichFromFvrObject(ItemIndexRecord rec)
		{
			if (rec != null && !string.IsNullOrEmpty(rec.ItemID))
			{
				if (!IM.OD.TryGetValue(rec.ItemID, out var value) || (Object)(object)value == (Object)null)
				{
					rec.FvrObject = null;
					return;
				}
				rec.FvrObject = value;
				Extract(rec, value);
			}
		}

		private static void Extract(ItemIndexRecord rec, FVRObject fvr)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: 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)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0415: Unknown result type (might be due to invalid IL or missing references)
			rec.StringTags.Clear();
			rec.TagTokenSet.Clear();
			ItemExtractedFeatures itemExtractedFeatures = new ItemExtractedFeatures();
			itemExtractedFeatures.Family = fvr.Family;
			itemExtractedFeatures.Category = fvr.Category;
			itemExtractedFeatures.IsModContent = fvr.IsModContent;
			itemExtractedFeatures.Mass = fvr.Mass;
			itemExtractedFeatures.MagazineCapacity = fvr.MagazineCapacity;
			itemExtractedFeatures.RequiresPicatinnySight = fvr.RequiresPicatinnySight;
			itemExtractedFeatures.TagEra = fvr.TagEra;
			itemExtractedFeatures.TagSet = fvr.TagSet;
			itemExtractedFeatures.TagFirearmSize = fvr.TagFirearmSize;
			itemExtractedFeatures.TagFirearmAction = fvr.TagFirearmAction;
			itemExtractedFeatures.TagFirearmRoundPower = fvr.TagFirearmRoundPower;
			itemExtractedFeatures.TagFirearmCountryOfOrigin = fvr.TagFirearmCountryOfOrigin;
			itemExtractedFeatures.TagFirearmFirstYear = fvr.TagFirearmFirstYear;
			itemExtractedFeatures.TagAttachmentMount = fvr.TagAttachmentMount;
			itemExtractedFeatures.TagAttachmentFeature = fvr.TagAttachmentFeature;
			itemExtractedFeatures.TagMeleeStyle = fvr.TagMeleeStyle;
			itemExtractedFeatures.TagMeleeHandedness = fvr.TagMeleeHandedness;
			itemExtractedFeatures.TagPowerupType = fvr.TagPowerupType;
			itemExtractedFeatures.TagThrownType = fvr.TagThrownType;
			itemExtractedFeatures.TagThrownDamageType = fvr.TagThrownDamageType;
			itemExtractedFeatures.TagFirearmFiringModes = ((fvr.TagFirearmFiringModes != null) ? new List<OTagFirearmFiringMode>(fvr.TagFirearmFiringModes) : null);
			itemExtractedFeatures.TagFirearmFeedOption = ((fvr.TagFirearmFeedOption != null) ? new List<OTagFirearmFeedOption>(fvr.TagFirearmFeedOption) : null);
			itemExtractedFeatures.TagFirearmMounts = ((fvr.TagFirearmMounts != null) ? new List<OTagFirearmMount>(fvr.TagFirearmMounts) : null);
			itemExtractedFeatures.MagazineType = fvr.MagazineType;
			itemExtractedFeatures.ClipType = fvr.ClipType;
			itemExtractedFeatures.UsesRoundTypeFlag = fvr.UsesRoundTypeFlag;
			itemExtractedFeatures.RoundType = fvr.RoundType;
			itemExtractedFeatures.CreditCost = fvr.CreditCost;
			itemExtractedFeatures.CompatibleMagazines = ExtractIds(fvr.CompatibleMagazines);
			itemExtractedFeatures.CompatibleClips = ExtractIds(fvr.CompatibleClips);
			itemExtractedFeatures.CompatibleSpeedLoaders = ExtractIds(fvr.CompatibleSpeedLoaders);
			itemExtractedFeatures.CompatibleSingleRounds = ExtractIds(fvr.CompatibleSingleRounds);
			itemExtractedFeatures.BespokeAttachments = ExtractIds(fvr.BespokeAttachments);
			itemExtractedFeatures.RequiredSecondaryPieces = ExtractIds(fvr.RequiredSecondaryPieces);
			rec.Features = itemExtractedFeatures;
			AddEnumTag(rec, "Era", itemExtractedFeatures.TagEra);
			AddEnumTag(rec, "Set", itemExtractedFeatures.TagSet);
			AddEnumTag(rec, "FirearmSize", itemExtractedFeatures.TagFirearmSize);
			AddEnumTag(rec, "FirearmAction", itemExtractedFeatures.TagFirearmAction);
			AddEnumTag(rec, "FirearmRoundPower", itemExtractedFeatures.TagFirearmRoundPower);
			AddEnumTag(rec, "Country", itemExtractedFeatures.TagFirearmCountryOfOrigin);
			AddEnumTag(rec, "AttachmentMount", itemExtractedFeatures.TagAttachmentMount);
			AddEnumTag(rec, "AttachmentFeature", itemExtractedFeatures.TagAttachmentFeature);
			AddEnumTag(rec, "MeleeStyle", itemExtractedFeatures.TagMeleeStyle);
			AddEnumTag(rec, "MeleeHandedness", itemExtractedFeatures.TagMeleeHandedness);
			AddEnumTag(rec, "PowerupType", itemExtractedFeatures.TagPowerupType);
			AddEnumTag(rec, "ThrownType", itemExtractedFeatures.TagThrownType);
			AddEnumTag(rec, "ThrownDamage", itemExtractedFeatures.TagThrownDamageType);
			if (itemExtractedFeatures.TagFirearmFirstYear > 0)
			{
				AddStringTag(rec, "Year_" + itemExtractedFeatures.TagFirearmFirstYear);
			}
			if (itemExtractedFeatures.TagFirearmFiringModes != null)
			{
				for (int i = 0; i < itemExtractedFeatures.TagFirearmFiringModes.Count; i++)
				{
					AddEnumTag(rec, "FiringMode", itemExtractedFeatures.TagFirearmFiringModes[i]);
				}
			}
			if (itemExtractedFeatures.TagFirearmFeedOption != null)
			{
				for (int j = 0; j < itemExtractedFeatures.TagFirearmFeedOption.Count; j++)
				{
					AddEnumTag(rec, "FeedOption", itemExtractedFeatures.TagFirearmFeedOption[j]);
				}
			}
			if (itemExtractedFeatures.TagFirearmMounts != null)
			{
				for (int k = 0; k < itemExtractedFeatures.TagFirearmMounts.Count; k++)
				{
					AddEnumTag(rec, "FirearmMount", itemExtractedFeatures.TagFirearmMounts[k]);
				}
			}
			AddStringTag(rec, "RoundType_" + ((object)Unsafe.As<FireArmRoundType, FireArmRoundType>(ref itemExtractedFeatures.RoundType)/*cast due to .constrained prefix*/).ToString());
			AddStringTag(rec, "MagazineType_" + ((object)Unsafe.As<FireArmMagazineType, FireArmMagazineType>(ref itemExtractedFeatures.MagazineType)/*cast due to .constrained prefix*/).ToString());
			AddStringTag(rec, "ClipType_" + ((object)Unsafe.As<FireArmClipType, FireArmClipType>(ref itemExtractedFeatures.ClipType)/*cast due to .constrained prefix*/).ToString());
			AddStringTag(rec, "AttachmentMount_" + ((object)Unsafe.As<OTagFirearmMount, OTagFirearmMount>(ref itemExtractedFeatures.TagAttachmentMount)/*cast due to .constrained prefix*/).ToString());
			if (rec.Data != null)
			{
				rec.Data.Tags.Clear();
				rec.Data.Tags.AddRange(rec.StringTags);
			}
		}

		private static List<string> ExtractIds(List<FVRObject> objs)
		{
			if (objs == null || objs.Count == 0)
			{
				return null;
			}
			List<string> list = new List<string>(objs.Count);
			for (int i = 0; i < objs.Count; i++)
			{
				FVRObject val = objs[i];
				if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.ItemID))
				{
					list.Add(val.ItemID);
				}
			}
			return list;
		}

		private static void AddEnumTag(ItemIndexRecord rec, string prefix, object enumValue)
		{
			if (enumValue != null)
			{
				string text = enumValue.ToString();
				if (!string.Equals(text, "None", StringComparison.OrdinalIgnoreCase))
				{
					AddStringTag(rec, prefix + "_" + text);
				}
			}
		}

		private static void AddStringTag(ItemIndexRecord rec, string tag)
		{
			if (!string.IsNullOrEmpty(tag))
			{
				string text = tag.Trim();
				if (text.Length != 0)
				{
					rec.StringTags.Add(text);
					rec.TagTokenSet.Add(ItemToken.StableToken(text));
				}
			}
		}
	}
	internal static class ItemQueryEngine
	{
		internal static List<BaseItemData> Query(ItemIndex.FilterRequest request)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (request == null)
			{
				return new List<BaseItemData>(0);
			}
			HashSet<string> hashSet = null;
			if (request.Category.HasValue)
			{
				hashSet = ItemIndexStore.IntersectCandidates(hashSet, ItemIndexStore.GetByCategory(request.Category.Value));
			}
			if (!string.IsNullOrEmpty(request.Family))
			{
				hashSet = ItemIndexStore.IntersectCandidates(hashSet, ItemIndexStore.GetByFamily(request.Family));
			}
			if (request.RequireAllStringTags != null && request.RequireAllStringTags.Count > 0)
			{
				for (int i = 0; i < request.RequireAllStringTags.Count; i++)
				{
					int tok = ItemToken.StableToken(request.RequireAllStringTags[i]);
					hashSet = ItemIndexStore.IntersectCandidates(hashSet, ItemIndexStore.GetByTagToken(tok));
					if (hashSet != null && hashSet.Count == 0)
					{
						break;
					}
				}
			}
			if (hashSet == null)
			{
				hashSet = ItemIndexStore.GetAllIds();
			}
			List<BaseItemData> list = new List<BaseItemData>(Math.Max(0, request.MaxResults));
			foreach (string item in hashSet)
			{
				if (ItemIndexStore.TryGet(item, out var rec) && Matches(request, rec))
				{
					if (rec.Data != null)
					{
						list.Add(rec.Data);
					}
					if (list.Count >= request.MaxResults)
					{
						break;
					}
				}
			}
			return list;
		}

		private static bool Matches(ItemIndex.FilterRequest req, ItemIndexRecord rec)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: 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_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			//IL_043e: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_049e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a4: Unknown result type (might be due to invalid IL or missing references)
			ItemExtractedFeatures features = rec.Features;
			if (!string.IsNullOrEmpty(req.ItemID) && !string.Equals(req.ItemID, rec.ItemID, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (!string.IsNullOrEmpty(req.Family) && !string.Equals(req.Family, features.Family, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (req.Category.HasValue && req.Category.Value != features.Category)
			{
				return false;
			}
			if (req.IsModContent.HasValue && req.IsModContent.Value != features.IsModContent)
			{
				return false;
			}
			if (req.TagEra.HasValue && req.TagEra.Value != features.TagEra)
			{
				return false;
			}
			if (req.TagSet.HasValue && req.TagSet.Value != features.TagSet)
			{
				return false;
			}
			if (req.TagFirearmSize.HasValue && req.TagFirearmSize.Value != features.TagFirearmSize)
			{
				return false;
			}
			if (req.TagFirearmAction.HasValue && req.TagFirearmAction.Value != features.TagFirearmAction)
			{
				return false;
			}
			if (req.TagFirearmRoundPower.HasValue && req.TagFirearmRoundPower.Value != features.TagFirearmRoundPower)
			{
				return false;
			}
			if (req.TagFirearmCountryOfOrigin.HasValue && req.TagFirearmCountryOfOrigin.Value != features.TagFirearmCountryOfOrigin)
			{
				return false;
			}
			if (req.TagAttachmentMount.HasValue && req.TagAttachmentMount.Value != features.TagAttachmentMount)
			{
				return false;
			}
			if (req.TagAttachmentFeature.HasValue && req.TagAttachmentFeature.Value != features.TagAttachmentFeature)
			{
				return false;
			}
			if (req.TagMeleeStyle.HasValue && req.TagMeleeStyle.Value != features.TagMeleeStyle)
			{
				return false;
			}
			if (req.TagMeleeHandedness.HasValue && req.TagMeleeHandedness.Value != features.TagMeleeHandedness)
			{
				return false;
			}
			if (req.TagPowerupType.HasValue && req.TagPowerupType.Value != features.TagPowerupType)
			{
				return false;
			}
			if (req.TagThrownType.HasValue && req.TagThrownType.Value != features.TagThrownType)
			{
				return false;
			}
			if (req.TagThrownDamageType.HasValue && req.TagThrownDamageType.Value != features.TagThrownDamageType)
			{
				return false;
			}
			if (req.FirearmFirstYearMin.HasValue && features.TagFirearmFirstYear < req.FirearmFirstYearMin.Value)
			{
				return false;
			}
			if (req.FirearmFirstYearMax.HasValue && features.TagFirearmFirstYear > req.FirearmFirstYearMax.Value)
			{
				return false;
			}
			if (req.MassMin.HasValue && features.Mass < req.MassMin.Value)
			{
				return false;
			}
			if (req.MassMax.HasValue && features.Mass > req.MassMax.Value)
			{
				return false;
			}
			if (req.RoundType.HasValue && req.RoundType.Value != features.RoundType)
			{
				return false;
			}
			if (req.MagazineType.HasValue && req.MagazineType.Value != features.MagazineType)
			{
				return false;
			}
			if (req.ClipType.HasValue && req.ClipType.Value != features.ClipType)
			{
				return false;
			}
			if (req.RequireAnyFiringModes != null && req.RequireAnyFiringModes.Count > 0)
			{
				if (features.TagFirearmFiringModes == null || features.TagFirearmFiringModes.Count == 0)
				{
					return false;
				}
				if (!OverlapsAny(req.RequireAnyFiringModes, features.TagFirearmFiringModes))
				{
					return false;
				}
			}
			if (req.RequireAnyFeedOptions != null && req.RequireAnyFeedOptions.Count > 0)
			{
				if (features.TagFirearmFeedOption == null || features.TagFirearmFeedOption.Count == 0)
				{
					return false;
				}
				if (!OverlapsAny(req.RequireAnyFeedOptions, features.TagFirearmFeedOption))
				{
					return false;
				}
			}
			if (req.RequireAnyFirearmMounts != null && req.RequireAnyFirearmMounts.Count > 0)
			{
				if (features.TagFirearmMounts == null || features.TagFirearmMounts.Count == 0)
				{
					return false;
				}
				if (!OverlapsAny(req.RequireAnyFirearmMounts, features.TagFirearmMounts))
				{
					return false;
				}
			}
			if (req.RequireAnyStringTags != null && req.RequireAnyStringTags.Count > 0)
			{
				bool flag = false;
				for (int i = 0; i < req.RequireAnyStringTags.Count; i++)
				{
					int item = ItemToken.StableToken(req.RequireAnyStringTags[i]);
					if (rec.TagTokenSet.Contains(item))
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					return false;
				}
			}
			if (req.RequireAllStringTags != null && req.RequireAllStringTags.Count > 0)
			{
				for (int j = 0; j < req.RequireAllStringTags.Count; j++)
				{
					int item2 = ItemToken.StableToken(req.RequireAllStringTags[j]);
					if (!rec.TagTokenSet.Contains(item2))
					{
						return false;
					}
				}
			}
			return true;
		}

		private static bool OverlapsAny<T>(List<T> requiredAny, List<T> actual)
		{
			for (int i = 0; i < requiredAny.Count; i++)
			{
				T x = requiredAny[i];
				for (int j = 0; j < actual.Count; j++)
				{
					if (EqualityComparer<T>.Default.Equals(x, actual[j]))
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	internal static class ItemSimilarityEngine
	{
		internal static List<ItemIndex.SimilarityResult> FindNearestNeighbors(string seedItemId, int k)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(seedItemId))
			{
				return new List<ItemIndex.SimilarityResult>(0);
			}
			if (!ItemIndexStore.TryGet(seedItemId, out var rec))
			{
				ItemIndex.EnsureIndexed(seedItemId);
				if (!ItemIndexStore.TryGet(seedItemId, out rec))
				{
					return new List<ItemIndex.SimilarityResult>(0);
				}
			}
			ItemSimilarityProfile profile = GetProfile(rec);
			HashSet<string> hashSet = null;
			if (profile.RequireSameCategory)
			{
				hashSet = ItemIndexStore.IntersectCandidates(hashSet, ItemIndexStore.GetByCategory(rec.Features.Category));
			}
			if ((Object)(object)rec.FvrObject != (Object)null)
			{
				if (profile.RequireSameRoundTypeForFirearms)
				{
					hashSet = ItemIndexStore.IntersectCandidates(hashSet, ItemIndexStore.GetByTagToken(ItemToken.StableToken("RoundType_" + ((object)Unsafe.As<FireArmRoundType, FireArmRoundType>(ref rec.Features.RoundType)/*cast due to .constrained prefix*/).ToString())));
				}
				if (profile.RequireSameAttachmentMountForAttachments)
				{
					hashSet = ItemIndexStore.IntersectCandidates(hashSet, ItemIndexStore.GetByTagToken(ItemToken.StableToken("AttachmentMount_" + ((object)Unsafe.As<OTagFirearmMount, OTagFirearmMount>(ref rec.Features.TagAttachmentMount)/*cast due to .constrained prefix*/).ToString())));
				}
			}
			if (hashSet == null)
			{
				hashSet = ItemIndexStore.GetAllIds();
			}
			List<ItemIndex.SimilarityResult> list = new List<ItemIndex.SimilarityResult>(Mathf.Min(Mathf.Max(8, k * 8), hashSet.Count));
			foreach (string item in hashSet)
			{
				if (!string.Equals(item, seedItemId, StringComparison.OrdinalIgnoreCase) && ItemIndexStore.TryGet(item, out var rec2))
				{
					float num = ScoreSimilarity(rec, rec2, profile);
					if (!(num <= 0f))
					{
						list.Add(new ItemIndex.SimilarityResult
						{
							ItemID = item,
							Score = num,
							Data = rec2.Data
						});
					}
				}
			}
			list.Sort((ItemIndex.SimilarityResult a, ItemIndex.SimilarityResult b) => b.Score.CompareTo(a.Score));
			if (k < 1)
			{
				k = 1;
			}
			if (list.Count > k)
			{
				list.RemoveRange(k, list.Count - k);
			}
			return list;
		}

		internal static float PredictPrice(string seedItemId, int k = 3)
		{
			List<ItemIndex.SimilarityResult> list = FindNearestNeighbors(seedItemId, Mathf.Max(1, k * 3));
			float num = 0f;
			int num2 = 0;
			for (int i = 0; i < list.Count; i++)
			{
				BaseItemData data = list[i].Data;
				if (data != null && !(data.Price <= 0f))
				{
					num += data.Price;
					num2++;
					if (num2 >= k)
					{
						break;
					}
				}
			}
			return (num2 == 0) ? 0f : (num / (float)num2);
		}

		private static ItemSimilarityProfile GetProfile(ItemIndexRecord seed)
		{
			return ItemSimilarityPolicy.Default;
		}

		private static float ScoreSimilarity(ItemIndexRecord a, ItemIndexRecord b, ItemSimilarityProfile p)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			if (a.Features.Category == b.Features.Category)
			{
				num += p.WeightCategory;
			}
			if (!string.IsNullOrEmpty(a.Features.Family) && string.Equals(a.Features.Family, b.Features.Family, StringComparison.OrdinalIgnoreCase))
			{
				num += p.WeightFamily;
			}
			ref OTagEra tagEra = ref a.Features.TagEra;
			object obj = b.Features.TagEra;
			if (((object)Unsafe.As<OTagEra, OTagEra>(ref tagEra)/*cast due to .constrained prefix*/).Equals(obj))
			{
				num += p.WeightEra;
			}
			ref OTagSet tagSet = ref a.Features.TagSet;
			object obj2 = b.Features.TagSet;
			if (((object)Unsafe.As<OTagSet, OTagSet>(ref tagSet)/*cast due to .constrained prefix*/).Equals(obj2))
			{
				num += p.WeightSet;
			}
			ref OTagFirearmAction tagFirearmAction = ref a.Features.TagFirearmAction;
			object obj3 = b.Features.TagFirearmAction;
			if (((object)Unsafe.As<OTagFirearmAction, OTagFirearmAction>(ref tagFirearmAction)/*cast due to .constrained prefix*/).Equals(obj3))
			{
				num += p.WeightAction;
			}
			ref OTagFirearmSize tagFirearmSize = ref a.Features.TagFirearmSize;
			object obj4 = b.Features.TagFirearmSize;
			if (((object)Unsafe.As<OTagFirearmSize, OTagFirearmSize>(ref tagFirearmSize)/*cast due to .constrained prefix*/).Equals(obj4))
			{
				num += p.WeightSize;
			}
			ref OTagFirearmRoundPower tagFirearmRoundPower = ref a.Features.TagFirearmRoundPower;
			object obj5 = b.Features.TagFirearmRoundPower;
			if (((object)Unsafe.As<OTagFirearmRoundPower, OTagFirearmRoundPower>(ref tagFirearmRoundPower)/*cast due to .constrained prefix*/).Equals(obj5))
			{
				num += p.WeightRoundPower;
			}
			ref OTagFirearmCountryOfOrigin tagFirearmCountryOfOrigin = ref a.Features.TagFirearmCountryOfOrigin;
			object obj6 = b.Features.TagFirearmCountryOfOrigin;
			if (((object)Unsafe.As<OTagFirearmCountryOfOrigin, OTagFirearmCountryOfOrigin>(ref tagFirearmCountryOfOrigin)/*cast due to .constrained prefix*/).Equals(obj6))
			{
				num += p.WeightCountry;
			}
			ref OTagFirearmMount tagAttachmentMount = ref a.Features.TagAttachmentMount;
			object obj7 = b.Features.TagAttachmentMount;
			if (((object)Unsafe.As<OTagFirearmMount, OTagFirearmMount>(ref tagAttachmentMount)/*cast due to .constrained prefix*/).Equals(obj7))
			{
				num += p.WeightAttachmentMount;
			}
			ref FireArmRoundType roundType = ref a.Features.RoundType;
			object obj8 = b.Features.RoundType;
			if (((object)Unsafe.As<FireArmRoundType, FireArmRoundType>(ref roundType)/*cast due to .constrained prefix*/).Equals(obj8))
			{
				num += p.WeightRoundType;
			}
			if (a.Features.TagFirearmFirstYear > 0 && b.Features.TagFirearmFirstYear > 0)
			{
				int num2 = Mathf.Abs(a.Features.TagFirearmFirstYear - b.Features.TagFirearmFirstYear);
				float num3 = 1f / (1f + (float)num2 / Mathf.Max(1f, p.FirstYearScale));
				num += num3 * p.WeightFirstYear;
			}
			num += OverlapScore(a.Features.TagFirearmFiringModes, b.Features.TagFirearmFiringModes) * p.WeightFiringModes;
			num += OverlapScore(a.Features.TagFirearmFeedOption, b.Features.TagFirearmFeedOption) * p.WeightFeedOptions;
			num += OverlapScore(a.Features.TagFirearmMounts, b.Features.TagFirearmMounts) * p.WeightMounts;
			num += CompatibilityOverlapScore(a.Features, b.Features) * p.WeightCompatibility;
			if (a.TagTokenSet.Count > 0 && b.TagTokenSet.Count > 0)
			{
				int num4 = 0;
				if (a.TagTokenSet.Count <= b.TagTokenSet.Count)
				{
					foreach (int item in a.TagTokenSet)
					{
						if (b.TagTokenSet.Contains(item))
						{
							num4++;
						}
					}
				}
				else
				{
					foreach (int item2 in b.TagTokenSet)
					{
						if (a.TagTokenSet.Contains(item2))
						{
							num4++;
						}
					}
				}
				int num5 = Mathf.Max(1, Mathf.Min(a.TagTokenSet.Count, b.TagTokenSet.Count));
				float num6 = (float)num4 / (float)num5;
				num += num6 * p.WeightStringTags;
			}
			return num;
		}

		private static float OverlapScore<T>(List<T> a, List<T> b)
		{
			if (a == null || b == null)
			{
				return 0f;
			}
			if (a.Count == 0 || b.Count == 0)
			{
				return 0f;
			}
			int num = 0;
			for (int i = 0; i < a.Count; i++)
			{
				T x = a[i];
				for (int j = 0; j < b.Count; j++)
				{
					if (EqualityComparer<T>.Default.Equals(x, b[j]))
					{
						num++;
						break;
					}
				}
			}
			int num2 = Mathf.Max(1, Mathf.Min(a.Count, b.Count));
			return (float)num / (float)num2;
		}

		private static float CompatibilityOverlapScore(ItemExtractedFeatures a, ItemExtractedFeatures b)
		{
			int num = 0;
			int denom = 0;
			num += OverlapCount(a.CompatibleMagazines, b.CompatibleMagazines, ref denom);
			num += OverlapCount(a.CompatibleClips, b.CompatibleClips, ref denom);
			num += OverlapCount(a.CompatibleSpeedLoaders, b.CompatibleSpeedLoaders, ref denom);
			num += OverlapCount(a.CompatibleSingleRounds, b.CompatibleSingleRounds, ref denom);
			num += OverlapCount(a.BespokeAttachments, b.BespokeAttachments, ref denom);
			return (denom <= 0) ? 0f : ((float)num / (float)denom);
		}

		private static int OverlapCount(List<string> a, List<string> b, ref int denom)
		{
			if (a == null || b == null)
			{
				return 0;
			}
			if (a.Count == 0 || b.Count == 0)
			{
				return 0;
			}
			denom += Mathf.Max(1, Mathf.Min(a.Count, b.Count));
			int num = 0;
			for (int i = 0; i < a.Count; i++)
			{
				string a2 = a[i];
				for (int j = 0; j < b.Count; j++)
				{
					if (string.Equals(a2, b[j], StringComparison.OrdinalIgnoreCase))
					{
						num++;
						break;
					}
				}
			}
			return num;
		}
	}
	public static class ItemIndex
	{
		[Serializable]
		public sealed class FilterRequest
		{
			public string ItemID;

			public string Family;

			public ObjectCategory? Category;

			public OTagEra? TagEra;

			public OTagSet? TagSet;

			public OTagFirearmSize? TagFirearmSize;

			public OTagFirearmAction? TagFirearmAction;

			public OTagFirearmRoundPower? TagFirearmRoundPower;

			public OTagFirearmCountryOfOrigin? TagFirearmCountryOfOrigin;

			public OTagFirearmMount? TagAttachmentMount;

			public OTagAttachmentFeature? TagAttachmentFeature;

			public OTagMeleeStyle? TagMeleeStyle;

			public OTagMeleeHandedness? TagMeleeHandedness;

			public OTagPowerupType? TagPowerupType;

			public OTagThrownType? TagThrownType;

			public OTagThrownDamageType? TagThrownDamageType;

			public int? FirearmFirstYearMin;

			public int? FirearmFirstYearMax;

			public float? MassMin;

			public float? MassMax;

			public FireArmRoundType? RoundType;

			public FireArmMagazineType? MagazineType;

			public FireArmClipType? ClipType;

			public List<OTagFirearmFiringMode> RequireAnyFiringModes;

			public List<OTagFirearmFeedOption> RequireAnyFeedOptions;

			public List<OTagFirearmMount> RequireAnyFirearmMounts;

			public List<string> RequireAllStringTags;

			public List<string> RequireAnyStringTags;

			public bool? IsModContent;

			public int MaxResults = 100;
		}

		public struct SimilarityResult
		{
			public string ItemID;

			public float Score;

			public BaseItemData Data;
		}

		public static void Clear()
		{
			ItemIndexStore.Clear();
		}

		public static void AddOrUpdateItem(BaseItemData item)
		{
			if (item != null && !string.IsNullOrEmpty(item.ObjectID))
			{
				ItemIndexRecord orCreate = ItemIndexStore.GetOrCreate(item.ObjectID);
				orCreate.Data = item;
				ItemFeatureExtractor.TryEnrichFromFvrObject(orCreate);
				ItemIndexStore.Commit(orCreate);
			}
		}

		public static void AddOrUpdateItem(string itemId)
		{
			if (!string.IsNullOrEmpty(itemId))
			{
				ItemIndexRecord orCreate = ItemIndexStore.GetOrCreate(itemId);
				if (orCreate.Data == null)
				{
					orCreate.Data = new BaseItemData(itemId, 0f);
				}
				ItemFeatureExtractor.TryEnrichFromFvrObject(orCreate);
				ItemIndexStore.Commit(orCreate);
			}
		}

		public static void AddItems(List<string> objectIds)
		{
			if (objectIds != null)
			{
				for (int i = 0; i < objectIds.Count; i++)
				{
					AddOrUpdateItem(objectIds[i]);
				}
			}
		}

		public static void AddItems(List<BaseItemData> items)
		{
			if (items != null)
			{
				for (int i = 0; i < items.Count; i++)
				{
					AddOrUpdateItem(items[i]);
				}
			}
		}

		public static void EnsureIndexed(string itemId)
		{
			if (!string.IsNullOrEmpty(itemId) && !ItemIndexStore.Contains(itemId))
			{
				AddOrUpdateItem(new BaseItemData(itemId, 0f));
			}
		}

		public static ItemExtractedFeatures GetItemFeatures(string itemId)
		{
			if (string.IsNullOrEmpty(itemId))
			{
				return null;
			}
			ItemIndexStore.TryGet(itemId, out var rec);
			return rec?.Features;
		}

		public static List<BaseItemData> Query(FilterRequest request)
		{
			return ItemQueryEngine.Query(request);
		}

		public static List<SimilarityResult> FindNearestNeighbors(string seedItemId, int k = 10)
		{
			return ItemSimilarityEngine.FindNearestNeighbors(seedItemId, k);
		}

		public static float PredictPrice(string seedItemId, int k = 5)
		{
			return ItemSimilarityEngine.PredictPrice(seedItemId, k);
		}

		public static List<BaseItemData> FindByItemId(string itemId)
		{
			if (string.IsNullOrEmpty(itemId))
			{
				return new List<BaseItemData>(0);
			}
			return Query(new FilterRequest
			{
				ItemID = itemId,
				MaxResults = 1
			});
		}

		public static List<BaseItemData> FindByCategory(ObjectCategory category, int maxResults = 100)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Query(new FilterRequest
			{
				Category = category,
				MaxResults = maxResults
			});
		}

		public static List<BaseItemData> FindByFamily(string family, int maxResults = 100)
		{
			return Query(new FilterRequest
			{
				Family = family,
				MaxResults = maxResults
			});
		}

		public static List<BaseItemData> FindByEra(OTagEra era, int maxResults = 100)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Query(new FilterRequest
			{
				TagEra = era,
				MaxResults = maxResults
			});
		}

		public static List<BaseItemData> FindBySet(OTagSet set, int maxResults = 100)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Query(new FilterRequest
			{
				TagSet = set,
				MaxResults = maxResults
			});
		}

		public static List<BaseItemData> FindByRoundType(FireArmRoundType roundType, int maxResults = 100)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Query(new FilterRequest
			{
				RoundType = roundType,
				MaxResults = maxResults
			});
		}

		public static List<BaseItemData> FindByMagazineType(FireArmMagazineType magazineType, int maxResults = 100)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Query(new FilterRequest
			{
				MagazineType = magazineType,
				MaxResults = maxResults
			});
		}

		public static List<BaseItemData> FindByClipType(FireArmClipType clipType, int maxResults = 100)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Query(new FilterRequest
			{
				ClipType = clipType,
				MaxResults = maxResults
			});
		}

		public static List<BaseItemData> FindByFirstYearRange(int minInclusive, int maxInclusive, int maxResults = 100)
		{
			return Query(new FilterRequest
			{
				FirearmFirstYearMin = minInclusive,
				FirearmFirstYearMax = maxInclusive,
				MaxResults = maxResults
			});
		}

		public static List<BaseItemData> FindByTagsAll(int maxResults, params string[] tags)
		{
			FilterRequest filterRequest = new FilterRequest
			{
				MaxResults = maxResults,
				RequireAllStringTags = new List<string>()
			};
			if (tags != null)
			{
				for (int i = 0; i < tags.Length; i++)
				{
					if (!string.IsNullOrEmpty(tags[i]))
					{
						filterRequest.RequireAllStringTags.Add(tags[i]);
					}
				}
			}
			if (filterRequest.RequireAllStringTags.Count == 0)
			{
				filterRequest.RequireAllStringTags = null;
			}
			return Query(filterRequest);
		}

		public static List<BaseItemData> FindByTagsAny(int maxResults, params string[] tags)
		{
			FilterRequest filterRequest = new FilterRequest
			{
				MaxResults = maxResults,
				RequireAnyStringTags = new List<string>()
			};
			if (tags != null)
			{
				for (int i = 0; i < tags.Length; i++)
				{
					if (!string.IsNullOrEmpty(tags[i]))
					{
						filterRequest.RequireAnyStringTags.Add(tags[i]);
					}
				}
			}
			if (filterRequest.RequireAnyStringTags.Count == 0)
			{
				filterRequest.RequireAnyStringTags = null;
			}
			return Query(filterRequest);
		}

		public static List<BaseItemData> FindByAnyFiringMode(int maxResults, params OTagFirearmFiringMode[] modes)
		{
			FilterRequest filterRequest = new FilterRequest
			{
				MaxResults = maxResults,
				RequireAnyFiringModes = new List<OTagFirearmFiringMode>()
			};
			if (modes != null)
			{
				for (int i = 0; i < modes.Length; i++)
				{
					filterRequest.RequireAnyFiringModes.Add(modes[i]);
				}
			}
			if (filterRequest.RequireAnyFiringModes.Count == 0)
			{
				filterRequest.RequireAnyFiringModes = null;
			}
			return Query(filterRequest);
		}

		public static HashSet<string> GetIdsByCategoryCopy(ObjectCategory category)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> byCategory = ItemIndexStore.GetByCategory(category);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (string item in byCategory)
			{
				hashSet.Add(item);
			}
			return hashSet;
		}

		public static HashSet<string> GetIdsByFamilyCopy(string family)
		{
			HashSet<string> byFamily = ItemIndexStore.GetByFamily(family);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (string item in byFamily)
			{
				hashSet.Add(item);
			}
			return hashSet;
		}

		public static HashSet<string> GetIdsByStringTagCopy(string tag)
		{
			int tok = ItemToken.StableToken(tag);
			HashSet<string> byTagToken = ItemIndexStore.GetByTagToken(tok);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (string item in byTagToken)
			{
				hashSet.Add(item);
			}
			return hashSet;
		}

		public static bool TryGetIndexedPrice(string itemId, out float price)
		{
			price = 0f;
			if (string.IsNullOrEmpty(itemId))
			{
				return false;
			}
			if (!ItemIndexStore.TryGet(itemId, out var rec))
			{
				return false;
			}
			if (rec.Data == null)
			{
				return false;
			}
			price = rec.Data.Price;
			return true;
		}

		public static void OverrideIndexedPrice(string itemId, float newPrice)
		{
			if (!string.IsNullOrEmpty(itemId))
			{
				ItemIndexRecord orCreate = ItemIndexStore.GetOrCreate(itemId);
				if (orCreate.Data == null)
				{
					orCreate.Data = new BaseItemData(itemId, newPrice);
					ItemIndexStore.Commit(orCreate);
				}
				else
				{
					orCreate.Data.Price = newPrice;
					ItemIndexStore.Commit(orCreate);
				}
			}
		}
	}
	[Serializable]
	public class BaseItemData
	{
		public float Price;

		public List<string> Tags = new List<string>();

		public string ObjectID { get; protected set; }

		public BaseItemData(string objectId, float price)
		{
			ObjectID = objectId;
			Price = price;
		}

		public override string ToString()
		{
			return string.Format("[Base Item Data] ID: {0}, Price: {1:C}, Tags: {2}", ObjectID, Price, string.Join(", ", Tags.ToArray()));
		}
	}
	public class ItemExtractedFeatures
	{
		public string Family;

		public ObjectCategory Category;

		public bool IsModContent;

		public float Mass;

		public int MagazineCapacity;

		public bool RequiresPicatinnySight;

		public OTagEra TagEra;

		public OTagSet TagSet;

		public OTagFirearmSize TagFirearmSize;

		public OTagFirearmAction TagFirearmAction;

		public OTagFirearmRoundPower TagFirearmRoundPower;

		public OTagFirearmCountryOfOrigin TagFirearmCountryOfOrigin;

		public int TagFirearmFirstYear;

		public OTagFirearmMount TagAttachmentMount;

		public OTagAttachmentFeature TagAttachmentFeature;

		public OTagMeleeStyle TagMeleeStyle;

		public OTagMeleeHandedness TagMeleeHandedness;

		public OTagPowerupType TagPowerupType;

		public OTagThrownType TagThrownType;

		public OTagThrownDamageType TagThrownDamageType;

		public List<OTagFirearmFiringMode> TagFirearmFiringModes;

		public List<OTagFirearmFeedOption> TagFirearmFeedOption;

		public List<OTagFirearmMount> TagFirearmMounts;

		public FireArmMagazineType MagazineType;

		public FireArmClipType ClipType;

		public bool UsesRoundTypeFlag;

		public FireArmRoundType RoundType;

		public List<string> CompatibleMagazines;

		public List<string> CompatibleClips;

		public List<string> CompatibleSpeedLoaders;

		public List<string> CompatibleSingleRounds;

		public List<string> BespokeAttachments;

		public List<string> RequiredSecondaryPieces;

		public int CreditCost;
	}
	internal sealed class ItemIndexRecord
	{
		public string ItemID;

		public BaseItemData Data;

		public FVRObject FvrObject;

		public ItemExtractedFeatures Features;

		public readonly List<string> StringTags = new List<string>(32);

		public readonly HashSet<int> TagTokenSet = new HashSet<int>();
	}
	internal sealed class ItemSimilarityProfile
	{
		public bool RequireSameCategory = true;

		public bool RequireSameRoundTypeForFirearms = false;

		public bool RequireSameAttachmentMountForAttachments = false;

		public float WeightCategory = 5f;

		public float WeightFamily = 4f;

		public float WeightSet = 4f;

		public float WeightRoundPower = 3f;

		public float WeightRoundType = 3f;

		public float WeightFirstYear = 2f;

		public float FirstYearScale = 25f;

		public float WeightEra = 2f;

		public float WeightStringTags = 2f;

		public float WeightAction = 2f;

		public float WeightFiringModes = 2f;

		public float WeightCountry = 1f;

		public float WeightFeedOptions = 1f;

		public float WeightMounts = 1f;

		public float WeightCompatibility = 0f;

		public float WeightAttachmentMount = 0f;

		public float WeightSize = 0f;
	}
	internal static class ItemSimilarityPolicy
	{
		internal static readonly ItemSimilarityProfile Default = new ItemSimilarityProfile();
	}
	internal static class ItemIndexStore
	{
		private static readonly Dictionary<string, ItemIndexRecord> _recordsById = new Dictionary<string, ItemIndexRecord>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<ObjectCategory, HashSet<string>> _byCategory = new Dictionary<ObjectCategory, HashSet<string>>();

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

		private static readonly Dictionary<int, HashSet<string>> _byTagToken = new Dictionary<int, HashSet<string>>();

		internal static void Clear()
		{
			_recordsById.Clear();
			_byCategory.Clear();
			_byFamily.Clear();
			_byTagToken.Clear();
		}

		internal static bool Contains(string itemId)
		{
			return _recordsById.ContainsKey(itemId);
		}

		internal static bool TryGet(string itemId, out ItemIndexRecord rec)
		{
			return _recordsById.TryGetValue(itemId, out rec);
		}

		internal static ItemIndexRecord GetOrCreate(string itemId)
		{
			if (_recordsById.TryGetValue(itemId, out var value))
			{
				return value;
			}
			value = new ItemIndexRecord
			{
				ItemID = itemId
			};
			_recordsById[itemId] = value;
			return value;
		}

		internal static void Commit(ItemIndexRecord rec)
		{
			_recordsById[rec.ItemID] = rec;
			ReindexAppendOnly(rec);
		}

		internal static IEnumerable<KeyValuePair<string, ItemIndexRecord>> EnumerateAll()
		{
			return _recordsById;
		}

		internal static HashSet<string> GetAllIds()
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (KeyValuePair<string, ItemIndexRecord> item in _recordsById)
			{
				hashSet.Add(item.Key);
			}
			return hashSet;
		}

		internal static HashSet<string> GetByCategory(ObjectCategory cat)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> value;
			return _byCategory.TryGetValue(cat, out value) ? value : new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		}

		internal static HashSet<string> GetByFamily(string family)
		{
			if (string.IsNullOrEmpty(family))
			{
				return new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			}
			HashSet<string> value;
			return _byFamily.TryGetValue(family, out value) ? value : new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		}

		internal static HashSet<string> GetByTagToken(int tok)
		{
			HashSet<string> value;
			return _byTagToken.TryGetValue(tok, out value) ? value : new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		}

		internal static HashSet<string> IntersectCandidates(HashSet<string> current, HashSet<string> next)
		{
			if (current == null)
			{
				HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
				foreach (string item in next)
				{
					hashSet.Add(item);
				}
				return hashSet;
			}
			if (current.Count == 0)
			{
				return current;
			}
			List<string> list = new List<string>();
			foreach (string item2 in current)
			{
				if (!next.Contains(item2))
				{
					list.Add(item2);
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				current.Remove(list[i]);
			}
			return current;
		}

		private static void ReindexAppendOnly(ItemIndexRecord rec)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (rec == null)
			{
				return;
			}
			ItemExtractedFeatures features = rec.Features;
			string itemID = rec.ItemID;
			if (string.IsNullOrEmpty(itemID))
			{
				return;
			}
			if (features != null)
			{
				ObjectCategory category = features.Category;
				if (!_byCategory.TryGetValue(category, out var value))
				{
					value = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
					_byCategory[category] = value;
				}
				value.Add(itemID);
			}
			string text = features?.Family;
			if (!string.IsNullOrEmpty(text))
			{
				if (!_byFamily.TryGetValue(text, out var value2))
				{
					value2 = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
					_byFamily[text] = value2;
				}
				value2.Add(itemID);
			}
			HashSet<int> tagTokenSet = rec.TagTokenSet;
			if (tagTokenSet == null)
			{
				return;
			}
			foreach (int item in tagTokenSet)
			{
				if (!_byTagToken.TryGetValue(item, out var value3))
				{
					value3 = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
					_byTagToken[item] = value3;
				}
				value3.Add(itemID);
			}
		}
	}
	internal static class ItemToken
	{
		internal static int StableToken(string s)
		{
			if (s == null)
			{
				return 0;
			}
			int num = 23;
			for (int i = 0; i < s.Length; i++)
			{
				char c = char.ToLowerInvariant(s[i]);
				num = num * 31 + c;
			}
			return num;
		}
	}
	public static class CsvItemPriceLoader
	{
		public const string itemPriceFilePrefix = "shItmPr_";

		public static Dictionary<string, float> LoadAllItemPrices()
		{
			Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);
			List<string> list = ShFileIoHandler.LoadAllModCsvPaths("shItmPr_");
			if (list == null || list.Count == 0)
			{
				return dictionary;
			}
			list.Sort(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < list.Count; i++)
			{
				TryMergeFromFile(dictionary, list[i]);
			}
			return dictionary;
		}

		private static void TryMergeFromFile(Dictionary<string, float> prices, string fullPath)
		{
			if (string.IsNullOrEmpty(fullPath) || !File.Exists(fullPath))
			{
				return;
			}
			int num = 0;
			string fileName = Path.GetFileName(fullPath);
			try
			{
				string[] array = File.ReadAllLines(fullPath);
				string[] array2 = array;
				foreach (string text in array2)
				{
					num++;
					string text2 = text?.Trim() ?? string.Empty;
					if (string.IsNullOrEmpty(text2) || text2.StartsWith("#") || text2.StartsWith("//"))
					{
						continue;
					}
					string[] array3 = text2.Split(new char[1] { ',' });
					if (array3.Length < 2)
					{
						continue;
					}
					string text3 = array3[0].Trim();
					if (!string.IsNullOrEmpty(text3))
					{
						if (!float.TryParse(array3[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
						{
							Debug.LogError((object)$"[{fileName}] Invalid price on line {num}: '{array3[1]}'");
						}
						else
						{
							prices[text3] = result;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)$"[{fileName}] CSV load failure on line {num}: {ex.Message}");
			}
		}

		public static List<BaseItemData> LoadBaseItems(string relativePath)
		{
			List<BaseItemData> list = new List<BaseItemData>();
			string path = Path.Combine(ShFileIoHandler.GetShAssetsModFolder(), relativePath);
			if (!File.Exists(path))
			{
				return list;
			}
			int num = 0;
			try
			{
				string[] array = File.ReadAllLines(path);
				string[] array2 = array;
				foreach (string text in array2)
				{
					num++;
					string text2 = text.Trim();
					if (string.IsNullOrEmpty(text2))
					{
						continue;
					}
					string[] array3 = text2.Split(new char[1] { ',' });
					if (array3.Length >= 2)
					{
						string text3 = array3[0].Trim();
						if (!string.IsNullOrEmpty(text3) && float.TryParse(array3[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
						{
							list.Add(new BaseItemData(text3, result));
						}
					}
				}
			}
			catch
			{
				list.Clear();
			}
			return list;
		}
	}
	public static class ItemPricesManager
	{
		private static readonly Dictionary<string, float> _priceCache = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		public static float CHEAPEND_SELL_PRICE = 0.1f;

		public static float SELL_DISCOUNT = 0.95f;

		public static List<ObjectCategory> sellCheapenedCategories = new List<ObjectCategory>
		{
			(ObjectCategory)2,
			(ObjectCategory)4,
			(ObjectCategory)3,
			(ObjectCategory)8,
			(ObjectCategory)64
		};

		public static void LoadAndApplyCsvPrices()
		{
			_priceCache.Clear();
			Dictionary<string, float> dictionary = CsvItemPriceLoader.LoadAllItemPrices();
			if (dictionary == null || dictionary.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<string, float> item in dictionary)
			{
				string key = item.Key;
				float value = item.Value;
				if (!string.IsNullOrEmpty(key))
				{
					ItemIndex.EnsureIndexed(key);
					ItemIndex.OverrideIndexedPrice(key, value);
					_priceCache[key] = value;
				}
			}
		}

		public static float GetPrice(string objectId, int k = 3)
		{
			if (string.IsNullOrEmpty(objectId))
			{
				Debug.LogError((object)"GetPrice called with null or empty objectId.");
				return 0f;
			}
			if (_priceCache.TryGetValue(objectId, out var value))
			{
				return value;
			}
			if (ItemIndex.TryGetIndexedPrice(objectId, out var price) && price > 0f)
			{
				_priceCache[objectId] = price;
				return price;
			}
			float num = ItemIndex.PredictPrice(objectId, Mathf.Max(1, k));
			_priceCache[objectId] = num;
			return num;
		}

		public static float GetSellPrice(string objectId)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(objectId))
			{
				Debug.LogError((object)"GetSellPrice called with null or empty objectId.");
				return 0f;
			}
			ItemExtractedFeatures itemFeatures = ItemIndex.GetItemFeatures(objectId);
			if (itemFeatures != null && sellCheapenedCategories.Contains(itemFeatures.Category))
			{
				return CHEAPEND_SELL_PRICE;
			}
			float price = GetPrice(objectId);
			return price * SELL_DISCOUNT;
		}

		public static void ClearCache()
		{
			_priceCache.Clear();
		}
	}
	public sealed class LoadoutsService : ShService
	{
		private ShLoadoutRack CurrentRack => (BoundProfile != null) ? BoundProfile.loadoutRack : null;

		public override void Initialize(ShMetaState meta, ShSessionManager session)
		{
			base.Initialize(meta, session);
		}

		public override void BindToProfile(ShProfileState profile)
		{
			base.BindToProfile(profile);
		}

		public bool IsAnyProfileActive()
		{
			return BoundProfile != null;
		}

		private void EnsureRack()
		{
			if (BoundProfile.loadoutRack == null)
			{
				BoundProfile.loadoutRack = new ShLoadoutRack();
			}
			BoundProfile.loadoutRack.Init();
		}

		public ShLoadout CreateEmptyLoadout()
		{
			if (!IsAnyProfileActive())
			{
				return null;
			}
			EnsureRack();
			return ShLoadoutRackRules.CreateEmptyLoadout(CurrentRack);
		}

		public ShLoadout EnsureExtractionLoadout()
		{
			if (!IsAnyProfileActive())
			{
				return null;
			}
			EnsureRack();
			return ShLoadoutRackRules.EnsureExtractionLoadout(CurrentRack);
		}

		public List<ShLoadout> listLoadysSorted()
		{
			if (!IsAnyProfileActive())
			{
				return new List<ShLoadout>();
			}
			EnsureRack();
			return new List<ShLoadout>(ShLoadoutRackRules.ListLoadoutsSortedByUpdateTime(CurrentRack));
		}

		public List<ShLoadout> listLoadys()
		{
			if (!IsAnyProfileActive())
			{
				return new List<ShLoadout>();
			}
			EnsureRack();
			return new List<ShLoadout>(ShLoadoutRackRules.ListLoadoutsUnsorted(CurrentRack));
		}

		public void DeleteLoadout(string uid)
		{
			if (IsAnyProfileActive())
			{
				EnsureRack();
				ShLoadout loadout = CurrentRack.GetLoadout(uid);
				if (loadout != null)
				{
					ShLoadoutsPersistence.TryDelete(BoundProfile, loadout, uid, out var _);
					CurrentRack.ConsumeLoadout(uid);
				}
			}
		}

		public bool EquipLoadout(string loadyUid)
		{
			string text;
			if (!IsAnyProfileActive())
			{
				text = "No profile selected.";
				return false;
			}
			EnsureRack();
			ShLoadout loadout = CurrentRack.GetLoadout(loadyUid);
			bool flag = ShLoadoutsPersistence.TryLoad(BoundProfile, loadout, loadyUid, out text);
			if (flag && SafehouseProgressionMPatchy.ConsumeLoadoutsOnSpawn.Value)
			{
				DeleteLoadout(loadyUid);
			}
			return flag;
		}

		public bool SaveWornToLoadout(string loadyUid)
		{
			if (!IsAnyProfileActive())
			{
				return false;
			}
			EnsureRack();
			if (!ShLoadoutsPersistence.TrySaveCustom(BoundProfile, loadyUid, out var _, out var error))
			{
				Debug.LogError((object)("SaveWornToLoadout: Error while trying to save custom loady: " + error));
				return false;
			}
			CurrentRack.GetLoadout(loadyUid)?.UpdateLastSavedTime();
			GM.CurrentPlayerBody.WipeQuickbeltContents();
			return true;
		}

		public bool SaveWornToExtractionLoady()
		{
			string text;
			if (!IsAnyProfileActive())
			{
				text = "No profile is active, can't save!";
				return false;
			}
			if (!ShLoadoutsPersistence.TrySaveExtraction(BoundProfile, out text))
			{
				Debug.LogError((object)("SaveWornToExtractionLoady: Error while trying to save custom loady: " + text));
				return false;
			}
			GM.CurrentPlayerBody.WipeQuickbeltContents();
			return true;
		}

		public bool RenameLoadout(string loadyUid, string newName)
		{
			if (!IsAnyProfileActive())
			{
				return false;
			}
			EnsureRack();
			ShLoadout loadout = CurrentRack.GetLoadout(loadyUid);
			if (loadout == null)
			{
				Debug.LogError((object)("RenameLoadout: ShLoadout for uid " + loadyUid + " is null!"));
				return false;
			}
			loadout.ChangeDisplayName(newName);
			return true;
		}

		public ShLoadout GetLoadoutForSelection(string loadyUid)
		{
			if (!IsAnyProfileActive())
			{
				return null;
			}
			EnsureRack();
			ShLoadout loadout = CurrentRack.GetLoadout(loadyUid);
			if (loadout == null)
			{
				Debug.LogError((object)("SelectLoadout: ShLoadout for uid " + loadyUid + " is null!"));
				return null;
			}
			return loadout;
		}

		public ShLoadout GetExtractionLoadoutForSelection()
		{
			if (!IsAnyProfileActive())
			{
				return null;
			}
			EnsureRack();
			ShLoadout shLoadout = EnsureExtractionLoadout();
			if (shLoadout == null)
			{
				Debug.LogError((object)"SelectLoadout: ShLoadout for uid EXTRACTIOn is null!");
				return null;
			}
			return shLoadout;
		}

		public VaultFile GetLoadoutVaultFile(string loadyUid)
		{
			if (!IsAnyProfileActive())
			{
				return null;
			}
			EnsureRack();
			ShLoadout loadout = CurrentRack.GetLoadout(loadyUid);
			if (loadout == null)
			{
				Debug.LogError((object)("GetLoadoutVaultFile: Bad loady UID not found: " + loadyUid));
				return null;
			}
			string error;
			VaultFile val = ShLoadoutsPersistence.TryGetVaultFile(BoundProfile, loadout, loadyUid, out error);
			if (val == null && !loadout.IsOfficialExtract)
			{
				Debug.LogError((object)("GetLoadoutVaultFile: Could not get VaultFile for given loadyUid: " + loadyUid));
			}
			return val;
		}

		public VaultFile GetExtractionLoadoutVaultFile()
		{
			if (!IsAnyProfileActive())
			{
				return null;
			}
			string error;
			VaultFile val = ShLoadoutsPersistence.TryGetExtractionVaultFile(BoundProfile, out error);
			if (val == null)
			{
				return null;
			}
			return val;
		}
	}
	[Serializable]
	public class ShLoadout
	{
		public string displayName;

		public string uid;

		public string fullFileName;

		public string lastUsedorSaved;

		public bool IsOfficialExtract;

		private ShLoadout(string displayName, bool isOfficialExtract)
		{
			uid = Guid.NewGuid().ToString();
			this.displayName = displayName;
			fullFileName = "";
			lastUsedorSaved = ShTimeCalculator.dateTimeToString(DateTime.UtcNow);
			IsOfficialExtract = isOfficialExtract;
		}

		internal static ShLoadout Create(string displayName, bool isOfficialExtract)
		{
			return new ShLoadout(displayName, isOfficialExtract);
		}

		public void UpdateLastSavedTime()
		{
			lastUsedorSaved = ShTimeCalculator.dateTimeToString(DateTime.UtcNow);
		}

		public void ChangeDisplayName(string newname)
		{
			displayName = newname;
		}
	}
	public static class ShLoadoutFactory
	{
		private const string DEFAULT_NAME = "Unnamed Loadout";

		private const string DEFAULT_EXTRACT_NAME = "Extracted Loadout";

		public static ShLoadout CreateDefault()
		{
			return ShLoadout.Create("Unnamed Loadout", isOfficialExtract: false);
		}

		public static ShLoadout CreateNamed(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				name = "Unnamed Loadout";
			}
			return ShLoadout.Create(name, isOfficialExtract: false);
		}

		public static ShLoadout CreateOfficialExtract()
		{
			return ShLoadout.Create("Extracted Loadout", isOfficialExtract: true);
		}
	}
	[Serializable]
	public class ShLoadoutRack
	{
		public List<ShLoadout> loadouts;

		public ShLoadoutRack()
		{
			Init();
		}

		public void Init()
		{
			if (loadouts == null)
			{
				loadouts = new List<ShLoadout>();
			}
		}

		public ShLoadout GetLoadout(string uid)
		{
			if (loadouts == null)
			{
				return null;
			}
			foreach (ShLoadout loadout in loadouts)
			{
				if (loadout.uid == uid)
				{
					return loadout;
				}
			}
			return null;
		}

		public void ConsumeLoadout(string uid)
		{
			if (loadouts == null)
			{
				return;
			}
			for (int num = loadouts.Count - 1; num >= 0; num--)
			{
				ShLoadout shLoadout = loadouts[num];
				if (shLoadout != null && shLoadout.uid == uid)
				{
					loadouts.RemoveAt(num);
					break;
				}
			}
		}
	}
	public static class ShLoadoutsPersistence
	{
		public static bool TryDelete(ShProfileState profile, ShLoadout loadout, string loadyUid, out string error)
		{
			if (loadout != null && loadout.IsOfficialExtract)
			{
				return ShLoadoutsVault.TryDeleteExtractionLoady(profile.uid, out error);
			}
			return ShLoadoutsVault.TryDeleteCustomLoady(profile.uid, loadyUid, out error);
		}

		public static bool TryLoad(ShProfileState profile, ShLoadout loadout, string loadyUid, out string error)
		{
			if (loadout != null && loadout.IsOfficialExtract)
			{
				return ShLoadoutsVault.TryLoadExtractionLoady(profile.uid, out error);
			}
			return ShLoadoutsVault.TryLoadCustomLoady(profile.uid, loadyUid, out error);
		}

		public static bool TrySaveCustom(ShProfileState profile, string loadyUid, out string fullFileName, out string error)
		{
			return ShLoadoutsVault.TrySaveCustomLoady(profile.uid, loadyUid, out fullFileName, out error);
		}

		public static bool TrySaveExtraction(ShProfileState profile, out string error)
		{
			return ShLoadoutsVault.TrySaveExtractionLoady(profile.uid, out error);
		}

		public static VaultFile TryGetVaultFile(ShProfileState profile, ShLoadout loadout, string loadyUid, out string error)
		{
			if (loadout != null && loadout.IsOfficialExtract)
			{
				return ShLoadoutsVault.TryGetExtractionLoadyVault(profile.uid, out error);
			}
			return ShLoadoutsVault.TryGetCustomLoadyFile(profile.uid, loadyUid, out error);
		}

		public static VaultFile TryGetExtractionVaultFile(ShProfileState profile, out string error)
		{
			return ShLoadoutsVault.TryGetExtractionLoadyVault(profile.uid, out error);
		}
	}
	public static class ShLoadoutRackRules
	{
		public static ShLoadout CreateEmptyLoadout(ShLoadoutRack rack)
		{
			if (rack.loadouts == null)
			{
				rack.loadouts = new List<ShLoadout>();
			}
			int num = 0;
			foreach (ShLoadout loadout in rack.loadouts)
			{
				if (loadout != null && !loadout.IsOfficialExtract)
				{
					num++;
				}
			}
			int num2 = num + 1;
			string name = $"Loadout {num2}";
			ShLoadout shLoadout = ShLoadoutFactory.CreateNamed(name);
			rack.loadouts.Add(shLoadout);
			return shLoadout;
		}

		public static ShLoadout EnsureExtractionLoadout(ShLoadoutRack rack)
		{
			if (rack.loadouts == null)
			{
				rack.loadouts = new List<ShLoadout>();
			}
			List<ShLoadout> list = new List<ShLoadout>();
			foreach (ShLoadout loadout in rack.loadouts)
			{
				if (loadout != null && loadout.IsOfficialExtract)
				{
					list.Add(loadout);
				}
			}
			if (list.Count == 0)
			{
				ShLoadout shLoadout = ShLoadoutFactory.CreateOfficialExtract();
				rack.loadouts.Add(shLoadout);
				return shLoadout;
			}
			if (list.Count == 1)
			{
				return list[0];
			}
			ShLoadout shLoadout2 = list[0];
			DateTime dateTime = ShTimeCalculator.stringToDateTime(shLoadout2.lastUsedorSaved);
			for (int i = 1; i < list.Count; i++)
			{
				DateTime dateTime2 = ShTimeCalculator.stringToDateTime(list[i].lastUsedorSaved);
				if (dateTime2 > dateTime)
				{
					shLoadout2 = list[i];
					dateTime = dateTime2;
				}
			}
			for (int num = rack.loadouts.Count - 1; num >= 0; num--)
			{
				ShLoadout shLoadout3 = rack.loadouts[num];
				if (shLoadout3 != null && shLoadout3.IsOfficialExtract && shLoadout3 != shLoadout2)
				{
					rack.loadouts.RemoveAt(num);
				}
			}
			return shLoadout2;
		}

		public static List<ShLoadout> ListLoadoutsSortedByUpdateTime(ShLoadoutRack rack)
		{
			ShLoadout item = EnsureExtractionLoadout(rack);
			rack.loadouts.Sort(delegate(ShLoadout a, ShLoadout b)
			{
				if (a == null && b == null)
				{
					return 0;
				}
				if (a == null)
				{
					return 1;
				}
				if (b == null)
				{
					return -1;
				}
				DateTime value = ShTimeCalculator.stringToDateTime(a.lastUsedorSaved);
				return ShTimeCalculator.stringToDateTime(b.lastUsedorSaved).CompareTo(value);
			});
			for (int num = rack.loadouts.Count - 1; num >= 0; num--)
			{
				ShLoadout shLoadout = rack.loadouts[num];
				if (shLoadout != null && shLoadout.IsOfficialExtract)
				{
					rack.loadouts.RemoveAt(num);
				}
			}
			rack.loadouts.Insert(0, item);
			return rack.loadouts;
		}

		public static List<ShLoadout> ListLoadoutsUnsorted(ShLoadoutRack rack)
		{
			ShLoadout item = EnsureExtractionLoadout(rack);
			for (int num = rack.loadouts.Count - 1; num >= 0; num--)
			{
				ShLoadout shLoadout = rack.loadouts[num];
				if (shLoadout != null && shLoadout.IsOfficialExtract)
				{
					rack.loadouts.RemoveAt(num);
				}
			}
			rack.loadouts.Insert(0, item);
			return rack.loadouts;
		}
	}
	public static class ShLoadoutsVault
	{
		private const string LOADOUTS_FOLDER = "Loadouts";

		private const string EXTR_LOADY_FILE = "ExtractionLoady.json";

		private const string LOADY_EXT = "_.json";

		public static string GetVaultProfileRoot(string profileUid)
		{
			return Path.Combine(Path.Combine(ShFileIoHandler.GetH3SaveFolder(), ShFileIoHandler.rootSaveFolder), profileUid);
		}

		public static string GetLoadoutsFolder(string profileUid)
		{
			return Path.Combine(GetVaultProfileRoot(profileUid), "Loadouts");
		}

		public static string GetExtractionLoadyFile(string profileUid)
		{
			return Path.Combine(GetLoadoutsFolder(profileUid), "ExtractionLoady.json");
		}

		public static string GetLoadyFileFromUid(string profileUid, string loadyUid)
		{
			return Path.Combine(GetLoadoutsFolder(profileUid), loadyUid + "_.json");
		}

		public static bool TrySaveExtractionLoady(string profileUid, out string error)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			error = null;
			VaultFile vf = new VaultFile();
			if (!TryScanCurrentLoadout(out vf, out error))
			{
				error = "[TrySaveExtractionLoady] Scanning quickbelt failed.";
				return false;
			}
			string extractionLoadyFile = GetExtractionLoadyFile(profileUid);
			ShFileIoHandler.EnsureFile(extractionLoadyFile);
			if (!ShFileIoHandler.TrySaveJson(vf, extractionLoadyFile, out error))
			{
				error = "[TrySaveExtractionLoady] Failed to save w error: " + error;
				return false;
			}
			return true;
		}

		public static VaultFile TryGetExtractionLoadyVault(string profileUid, out string error)
		{
			string extractionLoadyFile = GetExtractionLoadyFile(profileUid);
			ShFileIoHandler.EnsureFile(extractionLoadyFile);
			if (!ShFileIoHandler.TryLoadJson<VaultFile>(extractionLoadyFile, out VaultFile obj, out error))
			{
				if (error == "File was empty")
				{
					return null;
				}
				error = "[TryGetExtractionLoady]: Failed to parse json w: " + error + " on file " + extractionLoadyFile;
				return null;
			}
			return obj;
		}

		public static bool TryLoadExtractionLoady(string profileUid, out string error)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			string extractionLoadyFile = GetExtractionLoadyFile(profileUid);
			ShFileIoHandler.EnsureDirectory(Path.GetDirectoryName(extractionLoadyFile));
			if (!ShFileIoHandler.TryLoadJson<VaultFile>(extractionLoadyFile, out VaultFile obj, out error))
			{
				error = "[TryLoadExtractionLoady]: Failed to parse json w: " + error + " on file " + extractionLoadyFile;
				return false;
			}
			Transform transform = ((Component)GM.CurrentPlayerBody).transform;
			return VaultSystem.SpawnObjects((VaultFileType)2, obj, ref error, transform, Vector3.zero);
		}

		public static bool TryClearExtractionLoadyFile(string profileUid, out string error)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			VaultFile obj = new VaultFile();
			string extractionLoadyFile = GetExtractionLoadyFile(profileUid);
			ShFileIoHandler.EnsureDirectory(Path.GetDirectoryName(extractionLoadyFile));
			if (!ShFileIoHandler.TrySaveJson(obj, extractionLoadyFile, out error))
			{
				Debug.LogError((object)("[TrySaveExtractionLoady] Failed to save w error: " + error));
				return false;
			}
			return true;
		}

		public static bool TrySaveCustomLoady(string profileUid, string loadyUid, out string fullFileName, out string error)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			error = null;
			fullFileName = null;
			VaultFile vf = new VaultFile();
			if (!TryScanCurrentLoadout(out vf, out error))
			{
				Debug.LogError((object)"[TrySaveCustomLoady] Scanning quickbelt failed.");
				return false;
			}
			string loadyFileFromUid = GetLoadyFileFromUid(profileUid, loadyUid);
			ShFileIoHandler.EnsureDirectory(Path.GetDirectoryName(loadyFileFromUid));
			if (!ShFileIoHandler.TrySaveJson(vf, loadyFileFromUid, out error))
			{
				Debug.LogError((object)("[TrySaveCustomLoady] Failed to save w error: " + error));
				return false;
			}
			fullFileName = loadyFileFromUid;
			return true;
		}

		public static VaultFile TryGetCustomLoadyFile(string profileUid, string loadyUid, out string error)
		{
			string loadyFileFromUid = GetLoadyFileFromUid(profileUid, loadyUid);
			ShFileIoHandler.EnsureDirectory(Path.GetDirectoryName(loadyFileFromUid));
			if (!ShFileIoHandler.TryLoadJson<VaultFile>(loadyFileFromUid, out VaultFile obj, out error))
			{
				error = "[TryGetCustomLoadyFile]: Failed to parse json w: " + error + " on file " + loadyFileFromUid;
				return null;
			}
			return obj;
		}

		public static bool TryLoadCustomLoady(string profileUid, string loadyUid, out string error)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			string loadyFileFromUid = GetLoadyFileFromUid(profileUid, loadyUid);
			ShFileIoHandler.EnsureDirectory(Path.GetDirectoryName(loadyFileFromUid));
			if (!ShFileIoHandler.TryLoadJson<VaultFile>(loadyFileFromUid, out VaultFile obj, out error))
			{
				error = "[TryLoadCustomLoady]: Failed to parse json w: " + error + " on file " + loadyFileFromUid;
				return false;
			}
			Transform transform = ((Component)GM.CurrentPlayerBody).transform;
			return VaultSystem.SpawnObjects((VaultFileType)2, obj, ref error, transform, Vector3.zero);
		}

		public static bool TryDeleteCustomLoady(string profileUid, string loadyUid, out string error)
		{
			error = null;
			string loadyFileFromUid = GetLoadyFileFromUid(profileUid, loadyUid);
			ShFileIoHandler.EnsureDirectory(Path.GetDirectoryName(loadyFileFromUid));
			try
			{
				if (File.Exists(loadyFileFromUid))
				{
					File.Delete(loadyFileFromUid);
				}
				return true;
			}
			catch (Exception ex)
			{
				error = ex.Message;
				Debug.LogError((object)("[TryDeleteCustomLoady]: Failed to delete w: " + error + " on file " + loadyFileFromUid));
				return false;
			}
		}

		public static bool TryDeleteExtractionLoady(string profileUid, out string error)
		{
			error = null;
			string extractionLoadyFile = GetExtractionLoadyFile(profileUid);
			try
			{
				if (File.Exists(extractionLoadyFile))
				{
					File.Delete(extractionLoadyFile);
				}
				return true;
			}
			catch (Exception ex)
			{
				error = ex.Message;
				Debug.LogError((object)("[TryDeleteExtractionLoady]: Failed to delete w: " + error + " on file " + extractionLoadyFile));
				return false;
			}
		}

		private static bool TryScanCurrentLoadout(out VaultFile vf, out string error)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			vf = new VaultFile();
			error = null;
			if (!VaultSystem.FindAndScanObjectsInQuickbelt(vf))
			{
				error = "Loady scan failed.";
				return false;
			}
			return true;
		}
	}
	public class LoadoutsViewModel : BaseViewModel
	{
		public ShLoadout uiSelectedLoadout;

		private LoadoutsService _service;

		public static LoadoutsViewModel Instance => ViewModelRegistry.Get<LoadoutsViewModel>();

		public override void Initialize()
		{
			_service = SHGM.Instance?.sessionManager?.GetService<LoadoutsService>();
			if (_service != null)
			{
				_service.Changed += HandleServiceChanged;
			}
			NotifyListeners();
		}

		public override void Dispose()
		{
			if (_service != null)
			{
				_service.Changed -= HandleServiceChanged;
			}
			_service = null;
		}

		private void HandleServiceChanged()
		{
			uiSelectedLoadout = null;
			NotifyListeners();
		}

		public bool IsAnyProfileActive()
		{
			return _service != null && _service.IsAnyProfileActive();
		}

		public string GetCurrentLoadyUid()
		{
			if (!IsAnyProfileActive())
			{
				return "";
			}
			if (uiSelectedLoadout == null)
			{
				return "";
			}
			return uiSelectedLoadout.uid;
		}

		public List<ShLoadout> listLoadysSorted()
		{
			if (!IsAnyProfileActive())
			{
				return new List<ShLoadout>();
			}
			return _service.listLoadysSorted();
		}

		public List<ShLoadout> listLoadys()
		{
			if (!IsAnyProfileActive())
			{
				return new List<ShLoadout>();
			}
			return _service.listLoadys();
		}

		public void DeleteLoadout(string uid)
		{
			if (IsAnyProfileActive())
			{
				_service.DeleteLoadout(uid);
				if (uiSelectedLoadout != null && uiSelectedLoadout.uid == uid)
				{
					uiSelectedLoadout = null;
				}
				NotifyListeners();
			}
		}

		public void AddNewCustomLoadout()
		{
			if (IsAnyProfileActive())
			{
				ShLoadout shLoadout = _service.CreateEmptyLoadout();
				uiSelectedLoadout = shLoadout;
				NotifyListeners();
			}
		}

		public bool EquipLoadout(string loadyUid)
		{
			if (!IsAnyProfileActive())
			{
				return false;
			}
			bool flag = _service.EquipLoadout(loadyUid);
			if (flag)
			{
				if (uiSelectedLoadout != null && uiSelectedLoadout.uid == loadyUid)
				{
					uiSelectedLoadout = null;
				}
				NotifyListeners();
			}
			return flag;
		}

		public bool SaveWornToLoadout(string loadyUid)
		{
			if (!IsAnyProfileActive())
			{
				return false;
			}
			bool flag = _service.SaveWornToLoadout(loadyUid);
			if (flag)
			{
				NotifyListeners();
			}
			return flag;
		}

		public bool SaveWornToExtractionLoady()
		{
			if (!IsAnyProfileActive())
			{
				return false;
			}
			bool flag = _service.SaveWornToExtractionLoady();
			if (flag)
			{
				NotifyListeners();
			}
			return flag;
		}

		public bool RenameLoadout(string loadyUid, string newName)
		{
			if (!IsAnyProfileActive())
			{
				return false;
			}
			bool flag = _service.RenameLoadout(loadyUid, newName);
			if (flag)
			{
				NotifyListeners();
			}
			return flag;
		}

		public bool SelectLoadout(string loadyUid)
		{
			if (!IsAnyProfileActive())
			{
				return false;
			}
			ShLoadout loadoutForSelection = _service.GetLoadoutForSelection(loadyUid);
			if (loadoutForSelection == null)
			{
				return false;
			}
			uiSelectedLoadout = loadoutForSelection;
			NotifyListeners();
			return true;
		}

		public bool SelectExtractionLoadout()
		{
			if (!IsAnyProfileActive())
			{
				return false;
			}
			ShLoadout extractionLoadoutForSelection = _service.GetExtractionLoadoutForSelection();
			if (extractionLoadoutForSelection == null)
			{
				return false;
			}
			uiSelectedLoadout = extractionLoadoutForSelection;
			NotifyListeners();
			return true;
		}

		public VaultFile GetLoadoutVaultFile(string loadyUid)
		{
			if (!IsAnyProfileActive())
			{
				return null;
			}
			return _service.GetLoadoutVaultFile(loadyUid);
		}

		public VaultFile GetExtractionLoadoutVaultFile()
		{
			if (!IsAnyProfileActive())
			{
				return null;
			}
			return _service.GetExtractionLoadoutVaultFile();
		}
	}
	public class LootCalculator
	{
		public static List<string> GetOrderedItemsIDs(List<ObjectCategory> orderedCategories)
		{
			int count = orderedCategories?.Count ?? 0;
			List<string> result = NewBlankResultList(count);
			Dictionary<int, string> firearmAtIndex = new Dictionary<int, string>();
			string lastFirearmId = string.Empty;
			PlaceFirearms(orderedCategories, result, firearmAtIndex, ref lastFirearmId);
			FillNonFirearms(orderedCategories, result, firearmAtIndex, ref lastFirearmId);
			return result;
		}

		private static List<string> NewBlankResultList(int count)
		{
			List<string> list = new List<string>(count);
			for (int i = 0; i < count; i++)
			{
				list.Add(string.Empty);
			}
			return list;
		}

		private static void PlaceFirearms(List<ObjectCategory> cats, List<string> result, Dictionary<int, string> firearmAtIndex, ref string lastFirearmId)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			for (int i = 0; i < cats.Count; i++)
			{
				ObjectCategory val = cats[i];
				if (!IsAnyCategory(val) && (int)val == 1)
				{
					FVRObject obj = PickRandomFromCategory((ObjectCategory)1);
					string text = (result[i] = ToItemId(obj));
					if (!string.IsNullOrEmpty(text))
					{
						firearmAtIndex[i] = text;
						lastFirearmId = text;
					}
				}
			}
		}

		private static void FillNonFirearms(List<ObjectCategory> cats, List<string> result, Dictionary<int, string> firearmAtIndex, ref string lastFirearmId)
		{
			//IL_0023: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < cats.Count; i++)
			{
				if (!string.IsNullOrEmpty(result[i]))
				{
					continue;
				}
				ObjectCategory cat = cats[i];
				cat = ResolveAnyCategory(cat);
				if (IsAmmoCategory(cat))
				{
					result[i] = GetAmmoItemId(i, cats.Count, firearmAtIndex, ref lastFirearmId);
				}
				else if ((int)cat == 1)
				{
					FVRObject obj = PickRandomFromCategory((ObjectCategory)1);
					result[i] = ToItemId(obj);
					if (!string.IsNullOrEmpty(result[i]))
					{
						lastFirearmId = result[i];
					}
				}
				else
				{
					result[i] = ToItemId(PickRandomFromCategory(cat));
				}
			}
		}

		private static bool IsAnyCategory(ObjectCategory cat)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			return (int)cat == 0;
		}

		private static ObjectCategory ResolveAnyCategory(ObjectCategory cat)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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)
			if (!IsAnyCategory(cat))
			{
				return cat;
			}
			Dictionary<ObjectCategory, List<FVRObject>> odicTagCategory = ManagerSingleton<IM>.Instance.odicTagCategory;
			if (odicTagCategory == null || odicTagCategory.Count == 0)
			{
				return (ObjectCategory)0;
			}
			List<ObjectCategory> list = new List<ObjectCategory>(odicTagCategory.Keys);
			list.Remove((ObjectCategory)0);
			return list[Random.Range(0, list.Count)];
		}

		private static bool IsAmmoCategory(ObjectCategory cat)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			return (int)cat == 2 || (int)cat == 6 || (int)cat == 3 || (int)cat == 4;
		}

		private static string GetAmmoItemId(int index, int totalCount, Dictionary<int, string> firearmAtIndex, ref string lastFirearmId)
		{
			string text = ((!string.IsNullOrEmpty(lastFirearmId)) ? lastFirearmId : FindWeaponAhead(index, totalCount, firearmAtIndex));
			if (!string.IsNullOrEmpty(text))
			{
				FVRObject val = IM.OD[text];
				FVRObject randomAmmoObject = FVRObject.GetRandomAmmoObject(val, (List<OTagEra>)null, -1, -1, (List<OTagSet>)null, (List<FireArmRoundClass>)null);
				string text2 = ToItemId(randomAmmoObject);
				if (!string.IsNullOrEmpty(text2))
				{
					return text2;
				}
			}
			return ToItemId(PickRandomFromCategory((ObjectCategory)2));
		}

		private static string FindWeaponAhead(int idx, int totalCount, Dictionary<int, string> firearmAtIndex)
		{
			for (int i = idx + 1; i < totalCount; i++)
			{
				if (firearmAtIndex.TryGetValue(i, out var value))
				{
					return value;
				}
			}
			return string.Empty;
		}

		private unsafe static FVRObject PickRandomFromCategory(ObjectCategory cat)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ObjectCategory, List<FVRObject>> odicTagCategory = ManagerSingleton<IM>.Instance.odicTagCategory;
			if (odicTagCategory == null)
			{
				Debug.LogError((object)"PickRandomFromCategory: failed get odicTagCategory at all");
				return null;
			}
			if (!odicTagCategory.TryGetValue(cat, out var value) || value == null || value.Count == 0)
			{
				Debug.LogError((object)("PickRandomFromCategory: failed get category " + ((object)(*(ObjectCategory*)(&cat))/*cast due to .constrained prefix*/).ToString()));
				return null;
			}
			return value[Random.Range(0, value.Count)];
		}

		private static string ToItemId(FVRObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				Debug.LogError((object)"ToItemId: obj in put is null");
				return string.Empty;
			}
			try
			{
				if (!string.IsNullOrEmpty(obj.ItemID))
				{
					return obj.ItemID;
				}
			}
			catch
			{
				Debug.LogError((object)"ToItemId: ItemID is not present in the object");
				return string.Empty;
			}
			return string.Empty;
		}
	}
	public class ShowLootUiOnInteract : MonoBehaviour
	{
		private bool ready = false;

		private SosigLink slink;

		private SLinkLootController controller;

		public void Init(SosigLink Slink, SLinkLootController Controller)
		{
			ready = true;
			slink = Slink;
			controller = Controller;
		}

		private void Update()
		{
			if (ready)
			{
				controlle