Decompiled source of Gundomizer v1.1.0

AssetsTools.NET.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using AssetsTools.NET.Extra;
using AssetsTools.NET.Extra.Decompressors.LZ4;
using LZ4ps;
using SevenZip;
using SevenZip.Compression.LZ;
using SevenZip.Compression.LZMA;
using SevenZip.Compression.RangeCoder;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("AssetsTools.NET")]
[assembly: AssemblyDescription("A remake and port of SeriousCache's AssetTools")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("nesrak1")]
[assembly: AssemblyProduct("AssetsTools.NET")]
[assembly: AssemblyCopyright("Written by nes")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e09d5ac2-1a2e-4ec1-94ad-3f5e22f17658")]
[assembly: AssemblyFileVersion("3.0.0.0")]
[assembly: AssemblyVersion("3.0.0.0")]
namespace SevenZip
{
	internal class CRC
	{
		public static readonly uint[] Table;

		private uint _value = uint.MaxValue;

		static CRC()
		{
			Table = new uint[256];
			for (uint num = 0u; num < 256; num++)
			{
				uint num2 = num;
				for (int i = 0; i < 8; i++)
				{
					num2 = (((num2 & 1) == 0) ? (num2 >> 1) : ((num2 >> 1) ^ 0xEDB88320u));
				}
				Table[num] = num2;
			}
		}

		public void Init()
		{
			_value = uint.MaxValue;
		}

		public void UpdateByte(byte b)
		{
			_value = Table[(byte)_value ^ b] ^ (_value >> 8);
		}

		public void Update(byte[] data, uint offset, uint size)
		{
			for (uint num = 0u; num < size; num++)
			{
				_value = Table[(byte)_value ^ data[offset + num]] ^ (_value >> 8);
			}
		}

		public uint GetDigest()
		{
			return _value ^ 0xFFFFFFFFu;
		}

		private static uint CalculateDigest(byte[] data, uint offset, uint size)
		{
			CRC cRC = new CRC();
			cRC.Update(data, offset, size);
			return cRC.GetDigest();
		}

		private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
		{
			return CalculateDigest(data, offset, size) == digest;
		}
	}
	internal class DataErrorException : ApplicationException
	{
		public DataErrorException()
			: base("Data Error")
		{
		}
	}
	internal class InvalidParamException : ApplicationException
	{
		public InvalidParamException()
			: base("Invalid Parameter")
		{
		}
	}
	public interface ICodeProgress
	{
		void SetProgress(long inSize, long outSize);
	}
	public interface ICoder
	{
		void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress);
	}
	public enum CoderPropID
	{
		DefaultProp,
		DictionarySize,
		UsedMemorySize,
		Order,
		BlockSize,
		PosStateBits,
		LitContextBits,
		LitPosBits,
		NumFastBytes,
		MatchFinder,
		MatchFinderCycles,
		NumPasses,
		Algorithm,
		NumThreads,
		EndMarker
	}
	public interface ISetCoderProperties
	{
		void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
	}
	public interface IWriteCoderProperties
	{
		void WriteCoderProperties(Stream outStream);
	}
	public interface ISetDecoderProperties
	{
		void SetDecoderProperties(byte[] properties);
	}
}
namespace SevenZip.Compression.RangeCoder
{
	internal class Encoder
	{
		public const uint kTopValue = 16777216u;

		private Stream Stream;

		public ulong Low;

		public uint Range;

		private uint _cacheSize;

		private byte _cache;

		private long StartPosition;

		public void SetStream(Stream stream)
		{
			Stream = stream;
		}

		public void ReleaseStream()
		{
			Stream = null;
		}

		public void Init()
		{
			StartPosition = Stream.Position;
			Low = 0uL;
			Range = uint.MaxValue;
			_cacheSize = 1u;
			_cache = 0;
		}

		public void FlushData()
		{
			for (int i = 0; i < 5; i++)
			{
				ShiftLow();
			}
		}

		public void FlushStream()
		{
			Stream.Flush();
		}

		public void CloseStream()
		{
			Stream.Close();
		}

		public void Encode(uint start, uint size, uint total)
		{
			Low += start * (Range /= total);
			Range *= size;
			while (Range < 16777216)
			{
				Range <<= 8;
				ShiftLow();
			}
		}

		public void ShiftLow()
		{
			if ((uint)Low < 4278190080u || (int)(Low >> 32) == 1)
			{
				byte b = _cache;
				do
				{
					Stream.WriteByte((byte)(b + (Low >> 32)));
					b = byte.MaxValue;
				}
				while (--_cacheSize != 0);
				_cache = (byte)((uint)Low >> 24);
			}
			_cacheSize++;
			Low = (uint)((int)Low << 8);
		}

		public void EncodeDirectBits(uint v, int numTotalBits)
		{
			for (int num = numTotalBits - 1; num >= 0; num--)
			{
				Range >>= 1;
				if (((v >> num) & 1) == 1)
				{
					Low += Range;
				}
				if (Range < 16777216)
				{
					Range <<= 8;
					ShiftLow();
				}
			}
		}

		public void EncodeBit(uint size0, int numTotalBits, uint symbol)
		{
			uint num = (Range >> numTotalBits) * size0;
			if (symbol == 0)
			{
				Range = num;
			}
			else
			{
				Low += num;
				Range -= num;
			}
			while (Range < 16777216)
			{
				Range <<= 8;
				ShiftLow();
			}
		}

		public long GetProcessedSizeAdd()
		{
			return _cacheSize + Stream.Position - StartPosition + 4;
		}
	}
	internal class Decoder
	{
		public const uint kTopValue = 16777216u;

		public uint Range;

		public uint Code;

		public Stream Stream;

		public void Init(Stream stream)
		{
			Stream = stream;
			Code = 0u;
			Range = uint.MaxValue;
			for (int i = 0; i < 5; i++)
			{
				Code = (Code << 8) | (byte)Stream.ReadByte();
			}
		}

		public void ReleaseStream()
		{
			Stream = null;
		}

		public void CloseStream()
		{
			Stream.Close();
		}

		public void Normalize()
		{
			while (Range < 16777216)
			{
				Code = (Code << 8) | (byte)Stream.ReadByte();
				Range <<= 8;
			}
		}

		public void Normalize2()
		{
			if (Range < 16777216)
			{
				Code = (Code << 8) | (byte)Stream.ReadByte();
				Range <<= 8;
			}
		}

		public uint GetThreshold(uint total)
		{
			return Code / (Range /= total);
		}

		public void Decode(uint start, uint size, uint total)
		{
			Code -= start * Range;
			Range *= size;
			Normalize();
		}

		public uint DecodeDirectBits(int numTotalBits)
		{
			uint num = Range;
			uint num2 = Code;
			uint num3 = 0u;
			for (int num4 = numTotalBits; num4 > 0; num4--)
			{
				num >>= 1;
				uint num5 = num2 - num >> 31;
				num2 -= num & (num5 - 1);
				num3 = (num3 << 1) | (1 - num5);
				if (num < 16777216)
				{
					num2 = (num2 << 8) | (byte)Stream.ReadByte();
					num <<= 8;
				}
			}
			Range = num;
			Code = num2;
			return num3;
		}

		public uint DecodeBit(uint size0, int numTotalBits)
		{
			uint num = (Range >> numTotalBits) * size0;
			uint result;
			if (Code < num)
			{
				result = 0u;
				Range = num;
			}
			else
			{
				result = 1u;
				Code -= num;
				Range -= num;
			}
			Normalize();
			return result;
		}
	}
	internal struct BitEncoder
	{
		public const int kNumBitModelTotalBits = 11;

		public const uint kBitModelTotal = 2048u;

		private const int kNumMoveBits = 5;

		private const int kNumMoveReducingBits = 2;

		public const int kNumBitPriceShiftBits = 6;

		private uint Prob;

		private static uint[] ProbPrices;

		public void Init()
		{
			Prob = 1024u;
		}

		public void UpdateModel(uint symbol)
		{
			if (symbol == 0)
			{
				Prob += 2048 - Prob >> 5;
			}
			else
			{
				Prob -= Prob >> 5;
			}
		}

		public void Encode(Encoder encoder, uint symbol)
		{
			uint num = (encoder.Range >> 11) * Prob;
			if (symbol == 0)
			{
				encoder.Range = num;
				Prob += 2048 - Prob >> 5;
			}
			else
			{
				encoder.Low += num;
				encoder.Range -= num;
				Prob -= Prob >> 5;
			}
			if (encoder.Range < 16777216)
			{
				encoder.Range <<= 8;
				encoder.ShiftLow();
			}
		}

		static BitEncoder()
		{
			ProbPrices = new uint[512];
			for (int num = 8; num >= 0; num--)
			{
				int num2 = 1 << 9 - num - 1;
				uint num3 = (uint)(1 << 9 - num);
				for (uint num4 = (uint)num2; num4 < num3; num4++)
				{
					ProbPrices[num4] = (uint)(num << 6) + (num3 - num4 << 6 >> 9 - num - 1);
				}
			}
		}

		public uint GetPrice(uint symbol)
		{
			return ProbPrices[(((Prob - symbol) ^ (int)(0 - symbol)) & 0x7FF) >> 2];
		}

		public uint GetPrice0()
		{
			return ProbPrices[Prob >> 2];
		}

		public uint GetPrice1()
		{
			return ProbPrices[2048 - Prob >> 2];
		}
	}
	internal struct BitDecoder
	{
		public const int kNumBitModelTotalBits = 11;

		public const uint kBitModelTotal = 2048u;

		private const int kNumMoveBits = 5;

		private uint Prob;

		public void UpdateModel(int numMoveBits, uint symbol)
		{
			if (symbol == 0)
			{
				Prob += 2048 - Prob >> numMoveBits;
			}
			else
			{
				Prob -= Prob >> numMoveBits;
			}
		}

		public void Init()
		{
			Prob = 1024u;
		}

		public uint Decode(Decoder rangeDecoder)
		{
			uint num = (rangeDecoder.Range >> 11) * Prob;
			if (rangeDecoder.Code < num)
			{
				rangeDecoder.Range = num;
				Prob += 2048 - Prob >> 5;
				if (rangeDecoder.Range < 16777216)
				{
					rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
					rangeDecoder.Range <<= 8;
				}
				return 0u;
			}
			rangeDecoder.Range -= num;
			rangeDecoder.Code -= num;
			Prob -= Prob >> 5;
			if (rangeDecoder.Range < 16777216)
			{
				rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
				rangeDecoder.Range <<= 8;
			}
			return 1u;
		}
	}
	internal struct BitTreeEncoder
	{
		private BitEncoder[] Models;

		private int NumBitLevels;

		public BitTreeEncoder(int numBitLevels)
		{
			NumBitLevels = numBitLevels;
			Models = new BitEncoder[1 << numBitLevels];
		}

		public void Init()
		{
			for (uint num = 1u; num < 1 << NumBitLevels; num++)
			{
				Models[num].Init();
			}
		}

		public void Encode(Encoder rangeEncoder, uint symbol)
		{
			uint num = 1u;
			int num2 = NumBitLevels;
			while (num2 > 0)
			{
				num2--;
				uint num3 = (symbol >> num2) & 1;
				Models[num].Encode(rangeEncoder, num3);
				num = (num << 1) | num3;
			}
		}

		public void ReverseEncode(Encoder rangeEncoder, uint symbol)
		{
			uint num = 1u;
			for (uint num2 = 0u; num2 < NumBitLevels; num2++)
			{
				uint num3 = symbol & 1;
				Models[num].Encode(rangeEncoder, num3);
				num = (num << 1) | num3;
				symbol >>= 1;
			}
		}

		public uint GetPrice(uint symbol)
		{
			uint num = 0u;
			uint num2 = 1u;
			int num3 = NumBitLevels;
			while (num3 > 0)
			{
				num3--;
				uint num4 = (symbol >> num3) & 1;
				num += Models[num2].GetPrice(num4);
				num2 = (num2 << 1) + num4;
			}
			return num;
		}

		public uint ReverseGetPrice(uint symbol)
		{
			uint num = 0u;
			uint num2 = 1u;
			for (int num3 = NumBitLevels; num3 > 0; num3--)
			{
				uint num4 = symbol & 1;
				symbol >>= 1;
				num += Models[num2].GetPrice(num4);
				num2 = (num2 << 1) | num4;
			}
			return num;
		}

		public static uint ReverseGetPrice(BitEncoder[] Models, uint startIndex, int NumBitLevels, uint symbol)
		{
			uint num = 0u;
			uint num2 = 1u;
			for (int num3 = NumBitLevels; num3 > 0; num3--)
			{
				uint num4 = symbol & 1;
				symbol >>= 1;
				num += Models[startIndex + num2].GetPrice(num4);
				num2 = (num2 << 1) | num4;
			}
			return num;
		}

		public static void ReverseEncode(BitEncoder[] Models, uint startIndex, Encoder rangeEncoder, int NumBitLevels, uint symbol)
		{
			uint num = 1u;
			for (int i = 0; i < NumBitLevels; i++)
			{
				uint num2 = symbol & 1;
				Models[startIndex + num].Encode(rangeEncoder, num2);
				num = (num << 1) | num2;
				symbol >>= 1;
			}
		}
	}
	internal struct BitTreeDecoder
	{
		private BitDecoder[] Models;

		private int NumBitLevels;

		public BitTreeDecoder(int numBitLevels)
		{
			NumBitLevels = numBitLevels;
			Models = new BitDecoder[1 << numBitLevels];
		}

		public void Init()
		{
			for (uint num = 1u; num < 1 << NumBitLevels; num++)
			{
				Models[num].Init();
			}
		}

		public uint Decode(Decoder rangeDecoder)
		{
			uint num = 1u;
			for (int num2 = NumBitLevels; num2 > 0; num2--)
			{
				num = (num << 1) + Models[num].Decode(rangeDecoder);
			}
			return num - (uint)(1 << NumBitLevels);
		}

		public uint ReverseDecode(Decoder rangeDecoder)
		{
			uint num = 1u;
			uint num2 = 0u;
			for (int i = 0; i < NumBitLevels; i++)
			{
				uint num3 = Models[num].Decode(rangeDecoder);
				num <<= 1;
				num += num3;
				num2 |= num3 << i;
			}
			return num2;
		}

		public static uint ReverseDecode(BitDecoder[] Models, uint startIndex, Decoder rangeDecoder, int NumBitLevels)
		{
			uint num = 1u;
			uint num2 = 0u;
			for (int i = 0; i < NumBitLevels; i++)
			{
				uint num3 = Models[startIndex + num].Decode(rangeDecoder);
				num <<= 1;
				num += num3;
				num2 |= num3 << i;
			}
			return num2;
		}
	}
}
namespace SevenZip.Compression.LZ
{
	internal interface IInWindowStream
	{
		void SetStream(Stream inStream);

		void Init();

		void ReleaseStream();

		byte GetIndexByte(int index);

		uint GetMatchLen(int index, uint distance, uint limit);

		uint GetNumAvailableBytes();
	}
	internal interface IMatchFinder : IInWindowStream
	{
		void Create(uint historySize, uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter);

		uint GetMatches(uint[] distances);

		void Skip(uint num);
	}
	public class BinTree : InWindow, IMatchFinder, IInWindowStream
	{
		private uint _cyclicBufferPos;

		private uint _cyclicBufferSize;

		private uint _matchMaxLen;

		private uint[] _son;

		private uint[] _hash;

		private uint _cutValue = 255u;

		private uint _hashMask;

		private uint _hashSizeSum;

		private bool HASH_ARRAY = true;

		private const uint kHash2Size = 1024u;

		private const uint kHash3Size = 65536u;

		private const uint kBT2HashSize = 65536u;

		private const uint kStartMaxLen = 1u;

		private const uint kHash3Offset = 1024u;

		private const uint kEmptyHashValue = 0u;

		private const uint kMaxValForNormalize = 2147483647u;

		private uint kNumHashDirectBytes;

		private uint kMinMatchCheck = 4u;

		private uint kFixHashSize = 66560u;

		public void SetType(int numHashBytes)
		{
			HASH_ARRAY = numHashBytes > 2;
			if (HASH_ARRAY)
			{
				kNumHashDirectBytes = 0u;
				kMinMatchCheck = 4u;
				kFixHashSize = 66560u;
			}
			else
			{
				kNumHashDirectBytes = 2u;
				kMinMatchCheck = 3u;
				kFixHashSize = 0u;
			}
		}

		public new void SetStream(Stream stream)
		{
			base.SetStream(stream);
		}

		public new void ReleaseStream()
		{
			base.ReleaseStream();
		}

		public new void Init()
		{
			base.Init();
			for (uint num = 0u; num < _hashSizeSum; num++)
			{
				_hash[num] = 0u;
			}
			_cyclicBufferPos = 0u;
			ReduceOffsets(-1);
		}

		public new void MovePos()
		{
			if (++_cyclicBufferPos >= _cyclicBufferSize)
			{
				_cyclicBufferPos = 0u;
			}
			base.MovePos();
			if (_pos == int.MaxValue)
			{
				Normalize();
			}
		}

		public new byte GetIndexByte(int index)
		{
			return base.GetIndexByte(index);
		}

		public new uint GetMatchLen(int index, uint distance, uint limit)
		{
			return base.GetMatchLen(index, distance, limit);
		}

		public new uint GetNumAvailableBytes()
		{
			return base.GetNumAvailableBytes();
		}

		public void Create(uint historySize, uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter)
		{
			if (historySize > 2147483391)
			{
				throw new Exception();
			}
			_cutValue = 16 + (matchMaxLen >> 1);
			uint keepSizeReserv = (historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + 256;
			Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, keepSizeReserv);
			_matchMaxLen = matchMaxLen;
			uint num = historySize + 1;
			if (_cyclicBufferSize != num)
			{
				_son = new uint[(_cyclicBufferSize = num) * 2];
			}
			uint num2 = 65536u;
			if (HASH_ARRAY)
			{
				num2 = historySize - 1;
				num2 |= num2 >> 1;
				num2 |= num2 >> 2;
				num2 |= num2 >> 4;
				num2 |= num2 >> 8;
				num2 >>= 1;
				num2 |= 0xFFFF;
				if (num2 > 16777216)
				{
					num2 >>= 1;
				}
				_hashMask = num2;
				num2++;
				num2 += kFixHashSize;
			}
			if (num2 != _hashSizeSum)
			{
				_hash = new uint[_hashSizeSum = num2];
			}
		}

		public uint GetMatches(uint[] distances)
		{
			uint num;
			if (_pos + _matchMaxLen <= _streamPos)
			{
				num = _matchMaxLen;
			}
			else
			{
				num = _streamPos - _pos;
				if (num < kMinMatchCheck)
				{
					MovePos();
					return 0u;
				}
			}
			uint num2 = 0u;
			uint num3 = ((_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0u);
			uint num4 = _bufferOffset + _pos;
			uint num5 = 1u;
			uint num6 = 0u;
			uint num7 = 0u;
			uint num10;
			if (HASH_ARRAY)
			{
				uint num8 = CRC.Table[_bufferBase[num4]] ^ _bufferBase[num4 + 1];
				num6 = num8 & 0x3FF;
				int num9 = (int)num8 ^ (_bufferBase[num4 + 2] << 8);
				num7 = (uint)(num9 & 0xFFFF);
				num10 = ((uint)num9 ^ (CRC.Table[_bufferBase[num4 + 3]] << 5)) & _hashMask;
			}
			else
			{
				num10 = (uint)(_bufferBase[num4] ^ (_bufferBase[num4 + 1] << 8));
			}
			uint num11 = _hash[kFixHashSize + num10];
			if (HASH_ARRAY)
			{
				uint num12 = _hash[num6];
				uint num13 = _hash[1024 + num7];
				_hash[num6] = _pos;
				_hash[1024 + num7] = _pos;
				if (num12 > num3 && _bufferBase[_bufferOffset + num12] == _bufferBase[num4])
				{
					num5 = (distances[num2++] = 2u);
					distances[num2++] = _pos - num12 - 1;
				}
				if (num13 > num3 && _bufferBase[_bufferOffset + num13] == _bufferBase[num4])
				{
					if (num13 == num12)
					{
						num2 -= 2;
					}
					num5 = (distances[num2++] = 3u);
					distances[num2++] = _pos - num13 - 1;
					num12 = num13;
				}
				if (num2 != 0 && num12 == num11)
				{
					num2 -= 2;
					num5 = 1u;
				}
			}
			_hash[kFixHashSize + num10] = _pos;
			uint num14 = (_cyclicBufferPos << 1) + 1;
			uint num15 = _cyclicBufferPos << 1;
			uint val2;
			uint val = (val2 = kNumHashDirectBytes);
			if (kNumHashDirectBytes != 0 && num11 > num3 && _bufferBase[_bufferOffset + num11 + kNumHashDirectBytes] != _bufferBase[num4 + kNumHashDirectBytes])
			{
				num5 = (distances[num2++] = kNumHashDirectBytes);
				distances[num2++] = _pos - num11 - 1;
			}
			uint cutValue = _cutValue;
			while (true)
			{
				if (num11 <= num3 || cutValue-- == 0)
				{
					_son[num14] = (_son[num15] = 0u);
					break;
				}
				uint num16 = _pos - num11;
				uint num17 = ((num16 <= _cyclicBufferPos) ? (_cyclicBufferPos - num16) : (_cyclicBufferPos - num16 + _cyclicBufferSize)) << 1;
				uint num18 = _bufferOffset + num11;
				uint num19 = Math.Min(val, val2);
				if (_bufferBase[num18 + num19] == _bufferBase[num4 + num19])
				{
					while (++num19 != num && _bufferBase[num18 + num19] == _bufferBase[num4 + num19])
					{
					}
					if (num5 < num19)
					{
						num5 = (distances[num2++] = num19);
						distances[num2++] = num16 - 1;
						if (num19 == num)
						{
							_son[num15] = _son[num17];
							_son[num14] = _son[num17 + 1];
							break;
						}
					}
				}
				if (_bufferBase[num18 + num19] < _bufferBase[num4 + num19])
				{
					_son[num15] = num11;
					num15 = num17 + 1;
					num11 = _son[num15];
					val2 = num19;
				}
				else
				{
					_son[num14] = num11;
					num14 = num17;
					num11 = _son[num14];
					val = num19;
				}
			}
			MovePos();
			return num2;
		}

		public void Skip(uint num)
		{
			do
			{
				uint num2;
				if (_pos + _matchMaxLen <= _streamPos)
				{
					num2 = _matchMaxLen;
				}
				else
				{
					num2 = _streamPos - _pos;
					if (num2 < kMinMatchCheck)
					{
						MovePos();
						continue;
					}
				}
				uint num3 = ((_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0u);
				uint num4 = _bufferOffset + _pos;
				uint num9;
				if (HASH_ARRAY)
				{
					uint num5 = CRC.Table[_bufferBase[num4]] ^ _bufferBase[num4 + 1];
					uint num6 = num5 & 0x3FF;
					_hash[num6] = _pos;
					int num7 = (int)num5 ^ (_bufferBase[num4 + 2] << 8);
					uint num8 = (uint)(num7 & 0xFFFF);
					_hash[1024 + num8] = _pos;
					num9 = ((uint)num7 ^ (CRC.Table[_bufferBase[num4 + 3]] << 5)) & _hashMask;
				}
				else
				{
					num9 = (uint)(_bufferBase[num4] ^ (_bufferBase[num4 + 1] << 8));
				}
				uint num10 = _hash[kFixHashSize + num9];
				_hash[kFixHashSize + num9] = _pos;
				uint num11 = (_cyclicBufferPos << 1) + 1;
				uint num12 = _cyclicBufferPos << 1;
				uint val2;
				uint val = (val2 = kNumHashDirectBytes);
				uint cutValue = _cutValue;
				while (true)
				{
					if (num10 <= num3 || cutValue-- == 0)
					{
						_son[num11] = (_son[num12] = 0u);
						break;
					}
					uint num13 = _pos - num10;
					uint num14 = ((num13 <= _cyclicBufferPos) ? (_cyclicBufferPos - num13) : (_cyclicBufferPos - num13 + _cyclicBufferSize)) << 1;
					uint num15 = _bufferOffset + num10;
					uint num16 = Math.Min(val, val2);
					if (_bufferBase[num15 + num16] == _bufferBase[num4 + num16])
					{
						while (++num16 != num2 && _bufferBase[num15 + num16] == _bufferBase[num4 + num16])
						{
						}
						if (num16 == num2)
						{
							_son[num12] = _son[num14];
							_son[num11] = _son[num14 + 1];
							break;
						}
					}
					if (_bufferBase[num15 + num16] < _bufferBase[num4 + num16])
					{
						_son[num12] = num10;
						num12 = num14 + 1;
						num10 = _son[num12];
						val2 = num16;
					}
					else
					{
						_son[num11] = num10;
						num11 = num14;
						num10 = _son[num11];
						val = num16;
					}
				}
				MovePos();
			}
			while (--num != 0);
		}

		private void NormalizeLinks(uint[] items, uint numItems, uint subValue)
		{
			for (uint num = 0u; num < numItems; num++)
			{
				uint num2 = items[num];
				num2 = ((num2 > subValue) ? (num2 - subValue) : 0u);
				items[num] = num2;
			}
		}

		private void Normalize()
		{
			uint subValue = _pos - _cyclicBufferSize;
			NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
			NormalizeLinks(_hash, _hashSizeSum, subValue);
			ReduceOffsets((int)subValue);
		}

		public void SetCutValue(uint cutValue)
		{
			_cutValue = cutValue;
		}
	}
	public class InWindow
	{
		public byte[] _bufferBase;

		private Stream _stream;

		private uint _posLimit;

		private bool _streamEndWasReached;

		private uint _pointerToLastSafePosition;

		public uint _bufferOffset;

		public uint _blockSize;

		public uint _pos;

		private uint _keepSizeBefore;

		private uint _keepSizeAfter;

		public uint _streamPos;

		public void MoveBlock()
		{
			uint num = _bufferOffset + _pos - _keepSizeBefore;
			if (num != 0)
			{
				num--;
			}
			uint num2 = _bufferOffset + _streamPos - num;
			for (uint num3 = 0u; num3 < num2; num3++)
			{
				_bufferBase[num3] = _bufferBase[num + num3];
			}
			_bufferOffset -= num;
		}

		public virtual void ReadBlock()
		{
			if (_streamEndWasReached)
			{
				return;
			}
			while (true)
			{
				int num = (int)(0 - _bufferOffset + _blockSize - _streamPos);
				if (num == 0)
				{
					return;
				}
				int num2 = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), num);
				if (num2 == 0)
				{
					break;
				}
				_streamPos += (uint)num2;
				if (_streamPos >= _pos + _keepSizeAfter)
				{
					_posLimit = _streamPos - _keepSizeAfter;
				}
			}
			_posLimit = _streamPos;
			if (_bufferOffset + _posLimit > _pointerToLastSafePosition)
			{
				_posLimit = _pointerToLastSafePosition - _bufferOffset;
			}
			_streamEndWasReached = true;
		}

		private void Free()
		{
			_bufferBase = null;
		}

		public void Create(uint keepSizeBefore, uint keepSizeAfter, uint keepSizeReserv)
		{
			_keepSizeBefore = keepSizeBefore;
			_keepSizeAfter = keepSizeAfter;
			uint num = keepSizeBefore + keepSizeAfter + keepSizeReserv;
			if (_bufferBase == null || _blockSize != num)
			{
				Free();
				_blockSize = num;
				_bufferBase = new byte[_blockSize];
			}
			_pointerToLastSafePosition = _blockSize - keepSizeAfter;
		}

		public void SetStream(Stream stream)
		{
			_stream = stream;
		}

		public void ReleaseStream()
		{
			_stream = null;
		}

		public void Init()
		{
			_bufferOffset = 0u;
			_pos = 0u;
			_streamPos = 0u;
			_streamEndWasReached = false;
			ReadBlock();
		}

		public void MovePos()
		{
			_pos++;
			if (_pos > _posLimit)
			{
				if (_bufferOffset + _pos > _pointerToLastSafePosition)
				{
					MoveBlock();
				}
				ReadBlock();
			}
		}

		public byte GetIndexByte(int index)
		{
			return _bufferBase[_bufferOffset + _pos + index];
		}

		public uint GetMatchLen(int index, uint distance, uint limit)
		{
			if (_streamEndWasReached && _pos + index + limit > _streamPos)
			{
				limit = _streamPos - (uint)(int)(_pos + index);
			}
			distance++;
			uint num = _bufferOffset + _pos + (uint)index;
			uint num2;
			for (num2 = 0u; num2 < limit && _bufferBase[num + num2] == _bufferBase[num + num2 - distance]; num2++)
			{
			}
			return num2;
		}

		public uint GetNumAvailableBytes()
		{
			return _streamPos - _pos;
		}

		public void ReduceOffsets(int subValue)
		{
			_bufferOffset += (uint)subValue;
			_posLimit -= (uint)subValue;
			_pos -= (uint)subValue;
			_streamPos -= (uint)subValue;
		}
	}
	public class OutWindow
	{
		private byte[] _buffer;

		private uint _pos;

		private uint _windowSize;

		private uint _streamPos;

		private Stream _stream;

		public uint TrainSize;

		public void Create(uint windowSize)
		{
			if (_windowSize != windowSize)
			{
				_buffer = new byte[windowSize];
			}
			_windowSize = windowSize;
			_pos = 0u;
			_streamPos = 0u;
		}

		public void Init(Stream stream, bool solid)
		{
			ReleaseStream();
			_stream = stream;
			if (!solid)
			{
				_streamPos = 0u;
				_pos = 0u;
				TrainSize = 0u;
			}
		}

		public bool Train(Stream stream)
		{
			long length = stream.Length;
			uint num = (TrainSize = (uint)((length < _windowSize) ? length : _windowSize));
			stream.Position = length - num;
			_streamPos = (_pos = 0u);
			while (num != 0)
			{
				uint num2 = _windowSize - _pos;
				if (num < num2)
				{
					num2 = num;
				}
				int num3 = stream.Read(_buffer, (int)_pos, (int)num2);
				if (num3 == 0)
				{
					return false;
				}
				num -= (uint)num3;
				_pos += (uint)num3;
				_streamPos += (uint)num3;
				if (_pos == _windowSize)
				{
					_streamPos = (_pos = 0u);
				}
			}
			return true;
		}

		public void ReleaseStream()
		{
			Flush();
			_stream = null;
		}

		public void Flush()
		{
			uint num = _pos - _streamPos;
			if (num != 0)
			{
				_stream.Write(_buffer, (int)_streamPos, (int)num);
				if (_pos >= _windowSize)
				{
					_pos = 0u;
				}
				_streamPos = _pos;
			}
		}

		public void CopyBlock(uint distance, uint len)
		{
			uint num = _pos - distance - 1;
			if (num >= _windowSize)
			{
				num += _windowSize;
			}
			while (len != 0)
			{
				if (num >= _windowSize)
				{
					num = 0u;
				}
				_buffer[_pos++] = _buffer[num++];
				if (_pos >= _windowSize)
				{
					Flush();
				}
				len--;
			}
		}

		public void PutByte(byte b)
		{
			_buffer[_pos++] = b;
			if (_pos >= _windowSize)
			{
				Flush();
			}
		}

		public byte GetByte(uint distance)
		{
			uint num = _pos - distance - 1;
			if (num >= _windowSize)
			{
				num += _windowSize;
			}
			return _buffer[num];
		}
	}
}
namespace SevenZip.Compression.LZMA
{
	internal abstract class Base
	{
		public struct State
		{
			public uint Index;

			public void Init()
			{
				Index = 0u;
			}

			public void UpdateChar()
			{
				if (Index < 4)
				{
					Index = 0u;
				}
				else if (Index < 10)
				{
					Index -= 3u;
				}
				else
				{
					Index -= 6u;
				}
			}

			public void UpdateMatch()
			{
				Index = ((Index < 7) ? 7u : 10u);
			}

			public void UpdateRep()
			{
				Index = ((Index < 7) ? 8u : 11u);
			}

			public void UpdateShortRep()
			{
				Index = ((Index < 7) ? 9u : 11u);
			}

			public bool IsCharState()
			{
				return Index < 7;
			}
		}

		public const uint kNumRepDistances = 4u;

		public const uint kNumStates = 12u;

		public const int kNumPosSlotBits = 6;

		public const int kDicLogSizeMin = 0;

		public const int kNumLenToPosStatesBits = 2;

		public const uint kNumLenToPosStates = 4u;

		public const uint kMatchMinLen = 2u;

		public const int kNumAlignBits = 4;

		public const uint kAlignTableSize = 16u;

		public const uint kAlignMask = 15u;

		public const uint kStartPosModelIndex = 4u;

		public const uint kEndPosModelIndex = 14u;

		public const uint kNumPosModels = 10u;

		public const uint kNumFullDistances = 128u;

		public const uint kNumLitPosStatesBitsEncodingMax = 4u;

		public const uint kNumLitContextBitsMax = 8u;

		public const int kNumPosStatesBitsMax = 4;

		public const uint kNumPosStatesMax = 16u;

		public const int kNumPosStatesBitsEncodingMax = 4;

		public const uint kNumPosStatesEncodingMax = 16u;

		public const int kNumLowLenBits = 3;

		public const int kNumMidLenBits = 3;

		public const int kNumHighLenBits = 8;

		public const uint kNumLowLenSymbols = 8u;

		public const uint kNumMidLenSymbols = 8u;

		public const uint kNumLenSymbols = 272u;

		public const uint kMatchMaxLen = 273u;

		public static uint GetLenToPosState(uint len)
		{
			len -= 2;
			if (len < 4)
			{
				return len;
			}
			return 3u;
		}
	}
	public class Decoder : ICoder, ISetDecoderProperties
	{
		private class LenDecoder
		{
			private BitDecoder m_Choice;

			private BitDecoder m_Choice2;

			private BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[16];

			private BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[16];

			private BitTreeDecoder m_HighCoder = new BitTreeDecoder(8);

			private uint m_NumPosStates;

			public void Create(uint numPosStates)
			{
				for (uint num = m_NumPosStates; num < numPosStates; num++)
				{
					m_LowCoder[num] = new BitTreeDecoder(3);
					m_MidCoder[num] = new BitTreeDecoder(3);
				}
				m_NumPosStates = numPosStates;
			}

			public void Init()
			{
				m_Choice.Init();
				for (uint num = 0u; num < m_NumPosStates; num++)
				{
					m_LowCoder[num].Init();
					m_MidCoder[num].Init();
				}
				m_Choice2.Init();
				m_HighCoder.Init();
			}

			public uint Decode(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, uint posState)
			{
				if (m_Choice.Decode(rangeDecoder) == 0)
				{
					return m_LowCoder[posState].Decode(rangeDecoder);
				}
				uint num = 8u;
				if (m_Choice2.Decode(rangeDecoder) == 0)
				{
					return num + m_MidCoder[posState].Decode(rangeDecoder);
				}
				num += 8;
				return num + m_HighCoder.Decode(rangeDecoder);
			}
		}

		private class LiteralDecoder
		{
			private struct Decoder2
			{
				private BitDecoder[] m_Decoders;

				public void Create()
				{
					m_Decoders = new BitDecoder[768];
				}

				public void Init()
				{
					for (int i = 0; i < 768; i++)
					{
						m_Decoders[i].Init();
					}
				}

				public byte DecodeNormal(SevenZip.Compression.RangeCoder.Decoder rangeDecoder)
				{
					uint num = 1u;
					do
					{
						num = (num << 1) | m_Decoders[num].Decode(rangeDecoder);
					}
					while (num < 256);
					return (byte)num;
				}

				public byte DecodeWithMatchByte(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, byte matchByte)
				{
					uint num = 1u;
					do
					{
						uint num2 = (uint)((matchByte >> 7) & 1);
						matchByte <<= 1;
						uint num3 = m_Decoders[(1 + num2 << 8) + num].Decode(rangeDecoder);
						num = (num << 1) | num3;
						if (num2 != num3)
						{
							while (num < 256)
							{
								num = (num << 1) | m_Decoders[num].Decode(rangeDecoder);
							}
							break;
						}
					}
					while (num < 256);
					return (byte)num;
				}
			}

			private Decoder2[] m_Coders;

			private int m_NumPrevBits;

			private int m_NumPosBits;

			private uint m_PosMask;

			public void Create(int numPosBits, int numPrevBits)
			{
				if (m_Coders == null || m_NumPrevBits != numPrevBits || m_NumPosBits != numPosBits)
				{
					m_NumPosBits = numPosBits;
					m_PosMask = (uint)((1 << numPosBits) - 1);
					m_NumPrevBits = numPrevBits;
					uint num = (uint)(1 << m_NumPrevBits + m_NumPosBits);
					m_Coders = new Decoder2[num];
					for (uint num2 = 0u; num2 < num; num2++)
					{
						m_Coders[num2].Create();
					}
				}
			}

			public void Init()
			{
				uint num = (uint)(1 << m_NumPrevBits + m_NumPosBits);
				for (uint num2 = 0u; num2 < num; num2++)
				{
					m_Coders[num2].Init();
				}
			}

			private uint GetState(uint pos, byte prevByte)
			{
				return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> 8 - m_NumPrevBits);
			}

			public byte DecodeNormal(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
			{
				return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder);
			}

			public byte DecodeWithMatchByte(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
			{
				return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte);
			}
		}

		private OutWindow m_OutWindow = new OutWindow();

		private SevenZip.Compression.RangeCoder.Decoder m_RangeDecoder = new SevenZip.Compression.RangeCoder.Decoder();

		private BitDecoder[] m_IsMatchDecoders = new BitDecoder[192];

		private BitDecoder[] m_IsRepDecoders = new BitDecoder[12];

		private BitDecoder[] m_IsRepG0Decoders = new BitDecoder[12];

		private BitDecoder[] m_IsRepG1Decoders = new BitDecoder[12];

		private BitDecoder[] m_IsRepG2Decoders = new BitDecoder[12];

		private BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[192];

		private BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[4];

		private BitDecoder[] m_PosDecoders = new BitDecoder[114];

		private BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(4);

		private LenDecoder m_LenDecoder = new LenDecoder();

		private LenDecoder m_RepLenDecoder = new LenDecoder();

		private LiteralDecoder m_LiteralDecoder = new LiteralDecoder();

		private uint m_DictionarySize;

		private uint m_DictionarySizeCheck;

		private uint m_PosStateMask;

		private bool _solid;

		public Decoder()
		{
			m_DictionarySize = uint.MaxValue;
			for (int i = 0; (long)i < 4L; i++)
			{
				m_PosSlotDecoder[i] = new BitTreeDecoder(6);
			}
		}

		private void SetDictionarySize(uint dictionarySize)
		{
			if (m_DictionarySize != dictionarySize)
			{
				m_DictionarySize = dictionarySize;
				m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1u);
				uint windowSize = Math.Max(m_DictionarySizeCheck, 4096u);
				m_OutWindow.Create(windowSize);
			}
		}

		private void SetLiteralProperties(int lp, int lc)
		{
			if (lp > 8)
			{
				throw new InvalidParamException();
			}
			if (lc > 8)
			{
				throw new InvalidParamException();
			}
			m_LiteralDecoder.Create(lp, lc);
		}

		private void SetPosBitsProperties(int pb)
		{
			if (pb > 4)
			{
				throw new InvalidParamException();
			}
			uint num = (uint)(1 << pb);
			m_LenDecoder.Create(num);
			m_RepLenDecoder.Create(num);
			m_PosStateMask = num - 1;
		}

		private void Init(Stream inStream, Stream outStream)
		{
			m_RangeDecoder.Init(inStream);
			m_OutWindow.Init(outStream, _solid);
			for (uint num = 0u; num < 12; num++)
			{
				for (uint num2 = 0u; num2 <= m_PosStateMask; num2++)
				{
					uint num3 = (num << 4) + num2;
					m_IsMatchDecoders[num3].Init();
					m_IsRep0LongDecoders[num3].Init();
				}
				m_IsRepDecoders[num].Init();
				m_IsRepG0Decoders[num].Init();
				m_IsRepG1Decoders[num].Init();
				m_IsRepG2Decoders[num].Init();
			}
			m_LiteralDecoder.Init();
			for (uint num = 0u; num < 4; num++)
			{
				m_PosSlotDecoder[num].Init();
			}
			for (uint num = 0u; num < 114; num++)
			{
				m_PosDecoders[num].Init();
			}
			m_LenDecoder.Init();
			m_RepLenDecoder.Init();
			m_PosAlignDecoder.Init();
		}

		public void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress)
		{
			Init(inStream, outStream);
			Base.State state = default(Base.State);
			state.Init();
			uint num = 0u;
			uint num2 = 0u;
			uint num3 = 0u;
			uint num4 = 0u;
			ulong num5 = 0uL;
			if (num5 < (ulong)outSize)
			{
				if (m_IsMatchDecoders[state.Index << 4].Decode(m_RangeDecoder) != 0)
				{
					throw new DataErrorException();
				}
				state.UpdateChar();
				byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0u, 0);
				m_OutWindow.PutByte(b);
				num5++;
			}
			while (num5 < (ulong)outSize)
			{
				uint num6 = (uint)(int)num5 & m_PosStateMask;
				if (m_IsMatchDecoders[(state.Index << 4) + num6].Decode(m_RangeDecoder) == 0)
				{
					byte prevByte = m_OutWindow.GetByte(0u);
					byte b2 = (state.IsCharState() ? m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)num5, prevByte) : m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, (uint)num5, prevByte, m_OutWindow.GetByte(num)));
					m_OutWindow.PutByte(b2);
					state.UpdateChar();
					num5++;
					continue;
				}
				uint num8;
				if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
				{
					if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
					{
						if (m_IsRep0LongDecoders[(state.Index << 4) + num6].Decode(m_RangeDecoder) == 0)
						{
							state.UpdateShortRep();
							m_OutWindow.PutByte(m_OutWindow.GetByte(num));
							num5++;
							continue;
						}
					}
					else
					{
						uint num7;
						if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
						{
							num7 = num2;
						}
						else
						{
							if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
							{
								num7 = num3;
							}
							else
							{
								num7 = num4;
								num4 = num3;
							}
							num3 = num2;
						}
						num2 = num;
						num = num7;
					}
					num8 = m_RepLenDecoder.Decode(m_RangeDecoder, num6) + 2;
					state.UpdateRep();
				}
				else
				{
					num4 = num3;
					num3 = num2;
					num2 = num;
					num8 = 2 + m_LenDecoder.Decode(m_RangeDecoder, num6);
					state.UpdateMatch();
					uint num9 = m_PosSlotDecoder[Base.GetLenToPosState(num8)].Decode(m_RangeDecoder);
					if (num9 >= 4)
					{
						int num10 = (int)((num9 >> 1) - 1);
						num = (2 | (num9 & 1)) << num10;
						if (num9 < 14)
						{
							num += BitTreeDecoder.ReverseDecode(m_PosDecoders, num - num9 - 1, m_RangeDecoder, num10);
						}
						else
						{
							num += m_RangeDecoder.DecodeDirectBits(num10 - 4) << 4;
							num += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
						}
					}
					else
					{
						num = num9;
					}
				}
				if (num >= m_OutWindow.TrainSize + num5 || num >= m_DictionarySizeCheck)
				{
					if (num == uint.MaxValue)
					{
						break;
					}
					throw new DataErrorException();
				}
				m_OutWindow.CopyBlock(num, num8);
				num5 += num8;
			}
			m_OutWindow.Flush();
			m_OutWindow.ReleaseStream();
			m_RangeDecoder.ReleaseStream();
		}

		public void SetDecoderProperties(byte[] properties)
		{
			if (properties.Length < 5)
			{
				throw new InvalidParamException();
			}
			int lc = properties[0] % 9;
			int num = properties[0] / 9;
			int lp = num % 5;
			int num2 = num / 5;
			if (num2 > 4)
			{
				throw new InvalidParamException();
			}
			uint num3 = 0u;
			for (int i = 0; i < 4; i++)
			{
				num3 += (uint)(properties[1 + i] << i * 8);
			}
			SetDictionarySize(num3);
			SetLiteralProperties(lp, lc);
			SetPosBitsProperties(num2);
		}

		public bool Train(Stream stream)
		{
			_solid = true;
			return m_OutWindow.Train(stream);
		}
	}
	public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
	{
		private enum EMatchFinderType
		{
			BT2,
			BT4
		}

		private class LiteralEncoder
		{
			public struct Encoder2
			{
				private BitEncoder[] m_Encoders;

				public void Create()
				{
					m_Encoders = new BitEncoder[768];
				}

				public void Init()
				{
					for (int i = 0; i < 768; i++)
					{
						m_Encoders[i].Init();
					}
				}

				public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte symbol)
				{
					uint num = 1u;
					for (int num2 = 7; num2 >= 0; num2--)
					{
						uint num3 = (uint)((symbol >> num2) & 1);
						m_Encoders[num].Encode(rangeEncoder, num3);
						num = (num << 1) | num3;
					}
				}

				public void EncodeMatched(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol)
				{
					uint num = 1u;
					bool flag = true;
					for (int num2 = 7; num2 >= 0; num2--)
					{
						uint num3 = (uint)((symbol >> num2) & 1);
						uint num4 = num;
						if (flag)
						{
							uint num5 = (uint)((matchByte >> num2) & 1);
							num4 += 1 + num5 << 8;
							flag = num5 == num3;
						}
						m_Encoders[num4].Encode(rangeEncoder, num3);
						num = (num << 1) | num3;
					}
				}

				public uint GetPrice(bool matchMode, byte matchByte, byte symbol)
				{
					uint num = 0u;
					uint num2 = 1u;
					int num3 = 7;
					if (matchMode)
					{
						while (num3 >= 0)
						{
							uint num4 = (uint)((matchByte >> num3) & 1);
							uint num5 = (uint)((symbol >> num3) & 1);
							num += m_Encoders[(1 + num4 << 8) + num2].GetPrice(num5);
							num2 = (num2 << 1) | num5;
							if (num4 != num5)
							{
								num3--;
								break;
							}
							num3--;
						}
					}
					while (num3 >= 0)
					{
						uint num6 = (uint)((symbol >> num3) & 1);
						num += m_Encoders[num2].GetPrice(num6);
						num2 = (num2 << 1) | num6;
						num3--;
					}
					return num;
				}
			}

			private Encoder2[] m_Coders;

			private int m_NumPrevBits;

			private int m_NumPosBits;

			private uint m_PosMask;

			public void Create(int numPosBits, int numPrevBits)
			{
				if (m_Coders == null || m_NumPrevBits != numPrevBits || m_NumPosBits != numPosBits)
				{
					m_NumPosBits = numPosBits;
					m_PosMask = (uint)((1 << numPosBits) - 1);
					m_NumPrevBits = numPrevBits;
					uint num = (uint)(1 << m_NumPrevBits + m_NumPosBits);
					m_Coders = new Encoder2[num];
					for (uint num2 = 0u; num2 < num; num2++)
					{
						m_Coders[num2].Create();
					}
				}
			}

			public void Init()
			{
				uint num = (uint)(1 << m_NumPrevBits + m_NumPosBits);
				for (uint num2 = 0u; num2 < num; num2++)
				{
					m_Coders[num2].Init();
				}
			}

			public Encoder2 GetSubCoder(uint pos, byte prevByte)
			{
				return m_Coders[(int)((pos & m_PosMask) << m_NumPrevBits) + (prevByte >> 8 - m_NumPrevBits)];
			}
		}

		private class LenEncoder
		{
			private BitEncoder _choice;

			private BitEncoder _choice2;

			private BitTreeEncoder[] _lowCoder = new BitTreeEncoder[16];

			private BitTreeEncoder[] _midCoder = new BitTreeEncoder[16];

			private BitTreeEncoder _highCoder = new BitTreeEncoder(8);

			public LenEncoder()
			{
				for (uint num = 0u; num < 16; num++)
				{
					_lowCoder[num] = new BitTreeEncoder(3);
					_midCoder[num] = new BitTreeEncoder(3);
				}
			}

			public void Init(uint numPosStates)
			{
				_choice.Init();
				_choice2.Init();
				for (uint num = 0u; num < numPosStates; num++)
				{
					_lowCoder[num].Init();
					_midCoder[num].Init();
				}
				_highCoder.Init();
			}

			public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, uint symbol, uint posState)
			{
				if (symbol < 8)
				{
					_choice.Encode(rangeEncoder, 0u);
					_lowCoder[posState].Encode(rangeEncoder, symbol);
					return;
				}
				symbol -= 8;
				_choice.Encode(rangeEncoder, 1u);
				if (symbol < 8)
				{
					_choice2.Encode(rangeEncoder, 0u);
					_midCoder[posState].Encode(rangeEncoder, symbol);
				}
				else
				{
					_choice2.Encode(rangeEncoder, 1u);
					_highCoder.Encode(rangeEncoder, symbol - 8);
				}
			}

			public void SetPrices(uint posState, uint numSymbols, uint[] prices, uint st)
			{
				uint price = _choice.GetPrice0();
				uint price2 = _choice.GetPrice1();
				uint num = price2 + _choice2.GetPrice0();
				uint num2 = price2 + _choice2.GetPrice1();
				uint num3 = 0u;
				for (num3 = 0u; num3 < 8; num3++)
				{
					if (num3 >= numSymbols)
					{
						return;
					}
					prices[st + num3] = price + _lowCoder[posState].GetPrice(num3);
				}
				for (; num3 < 16; num3++)
				{
					if (num3 >= numSymbols)
					{
						return;
					}
					prices[st + num3] = num + _midCoder[posState].GetPrice(num3 - 8);
				}
				for (; num3 < numSymbols; num3++)
				{
					prices[st + num3] = num2 + _highCoder.GetPrice(num3 - 8 - 8);
				}
			}
		}

		private class LenPriceTableEncoder : LenEncoder
		{
			private uint[] _prices = new uint[4352];

			private uint _tableSize;

			private uint[] _counters = new uint[16];

			public void SetTableSize(uint tableSize)
			{
				_tableSize = tableSize;
			}

			public uint GetPrice(uint symbol, uint posState)
			{
				return _prices[posState * 272 + symbol];
			}

			private void UpdateTable(uint posState)
			{
				SetPrices(posState, _tableSize, _prices, posState * 272);
				_counters[posState] = _tableSize;
			}

			public void UpdateTables(uint numPosStates)
			{
				for (uint num = 0u; num < numPosStates; num++)
				{
					UpdateTable(num);
				}
			}

			public new void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, uint symbol, uint posState)
			{
				base.Encode(rangeEncoder, symbol, posState);
				if (--_counters[posState] == 0)
				{
					UpdateTable(posState);
				}
			}
		}

		private class Optimal
		{
			public Base.State State;

			public bool Prev1IsChar;

			public bool Prev2;

			public uint PosPrev2;

			public uint BackPrev2;

			public uint Price;

			public uint PosPrev;

			public uint BackPrev;

			public uint Backs0;

			public uint Backs1;

			public uint Backs2;

			public uint Backs3;

			public void MakeAsChar()
			{
				BackPrev = uint.MaxValue;
				Prev1IsChar = false;
			}

			public void MakeAsShortRep()
			{
				BackPrev = 0u;
				Prev1IsChar = false;
			}

			public bool IsShortRep()
			{
				return BackPrev == 0;
			}
		}

		private const uint kIfinityPrice = 268435455u;

		private static byte[] g_FastPos;

		private Base.State _state;

		private byte _previousByte;

		private uint[] _repDistances = new uint[4];

		private const int kDefaultDictionaryLogSize = 22;

		private const uint kNumFastBytesDefault = 32u;

		private const uint kNumLenSpecSymbols = 16u;

		private const uint kNumOpts = 4096u;

		private Optimal[] _optimum = new Optimal[4096];

		private IMatchFinder _matchFinder;

		private SevenZip.Compression.RangeCoder.Encoder _rangeEncoder = new SevenZip.Compression.RangeCoder.Encoder();

		private BitEncoder[] _isMatch = new BitEncoder[192];

		private BitEncoder[] _isRep = new BitEncoder[12];

		private BitEncoder[] _isRepG0 = new BitEncoder[12];

		private BitEncoder[] _isRepG1 = new BitEncoder[12];

		private BitEncoder[] _isRepG2 = new BitEncoder[12];

		private BitEncoder[] _isRep0Long = new BitEncoder[192];

		private BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[4];

		private BitEncoder[] _posEncoders = new BitEncoder[114];

		private BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(4);

		private LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();

		private LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();

		private LiteralEncoder _literalEncoder = new LiteralEncoder();

		private uint[] _matchDistances = new uint[548];

		private uint _numFastBytes = 32u;

		private uint _longestMatchLength;

		private uint _numDistancePairs;

		private uint _additionalOffset;

		private uint _optimumEndIndex;

		private uint _optimumCurrentIndex;

		private bool _longestMatchWasFound;

		private uint[] _posSlotPrices = new uint[256];

		private uint[] _distancesPrices = new uint[512];

		private uint[] _alignPrices = new uint[16];

		private uint _alignPriceCount;

		private uint _distTableSize = 44u;

		private int _posStateBits = 2;

		private uint _posStateMask = 3u;

		private int _numLiteralPosStateBits;

		private int _numLiteralContextBits = 3;

		private uint _dictionarySize = 4194304u;

		private uint _dictionarySizePrev = uint.MaxValue;

		private uint _numFastBytesPrev = uint.MaxValue;

		private long nowPos64;

		private bool _finished;

		private Stream _inStream;

		private EMatchFinderType _matchFinderType = EMatchFinderType.BT4;

		private bool _writeEndMark;

		private bool _needReleaseMFStream;

		private uint[] reps = new uint[4];

		private uint[] repLens = new uint[4];

		private const int kPropSize = 5;

		private byte[] properties = new byte[5];

		private uint[] tempPrices = new uint[128];

		private uint _matchPriceCount;

		private static string[] kMatchFinderIDs;

		private uint _trainSize;

		static Encoder()
		{
			g_FastPos = new byte[2048];
			kMatchFinderIDs = new string[2] { "BT2", "BT4" };
			int num = 2;
			g_FastPos[0] = 0;
			g_FastPos[1] = 1;
			for (byte b = 2; b < 22; b++)
			{
				uint num2 = (uint)(1 << (b >> 1) - 1);
				uint num3 = 0u;
				while (num3 < num2)
				{
					g_FastPos[num] = b;
					num3++;
					num++;
				}
			}
		}

		private static uint GetPosSlot(uint pos)
		{
			if (pos < 2048)
			{
				return g_FastPos[pos];
			}
			if (pos < 2097152)
			{
				return (uint)(g_FastPos[pos >> 10] + 20);
			}
			return (uint)(g_FastPos[pos >> 20] + 40);
		}

		private static uint GetPosSlot2(uint pos)
		{
			if (pos < 131072)
			{
				return (uint)(g_FastPos[pos >> 6] + 12);
			}
			if (pos < 134217728)
			{
				return (uint)(g_FastPos[pos >> 16] + 32);
			}
			return (uint)(g_FastPos[pos >> 26] + 52);
		}

		private void BaseInit()
		{
			_state.Init();
			_previousByte = 0;
			for (uint num = 0u; num < 4; num++)
			{
				_repDistances[num] = 0u;
			}
		}

		private void Create()
		{
			if (_matchFinder == null)
			{
				BinTree binTree = new BinTree();
				int type = 4;
				if (_matchFinderType == EMatchFinderType.BT2)
				{
					type = 2;
				}
				binTree.SetType(type);
				_matchFinder = binTree;
			}
			_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
			if (_dictionarySize != _dictionarySizePrev || _numFastBytesPrev != _numFastBytes)
			{
				_matchFinder.Create(_dictionarySize, 4096u, _numFastBytes, 274u);
				_dictionarySizePrev = _dictionarySize;
				_numFastBytesPrev = _numFastBytes;
			}
		}

		public Encoder()
		{
			for (int i = 0; (long)i < 4096L; i++)
			{
				_optimum[i] = new Optimal();
			}
			for (int j = 0; (long)j < 4L; j++)
			{
				_posSlotEncoder[j] = new BitTreeEncoder(6);
			}
		}

		private void SetWriteEndMarkerMode(bool writeEndMarker)
		{
			_writeEndMark = writeEndMarker;
		}

		private void Init()
		{
			BaseInit();
			_rangeEncoder.Init();
			for (uint num = 0u; num < 12; num++)
			{
				for (uint num2 = 0u; num2 <= _posStateMask; num2++)
				{
					uint num3 = (num << 4) + num2;
					_isMatch[num3].Init();
					_isRep0Long[num3].Init();
				}
				_isRep[num].Init();
				_isRepG0[num].Init();
				_isRepG1[num].Init();
				_isRepG2[num].Init();
			}
			_literalEncoder.Init();
			for (uint num = 0u; num < 4; num++)
			{
				_posSlotEncoder[num].Init();
			}
			for (uint num = 0u; num < 114; num++)
			{
				_posEncoders[num].Init();
			}
			_lenEncoder.Init((uint)(1 << _posStateBits));
			_repMatchLenEncoder.Init((uint)(1 << _posStateBits));
			_posAlignEncoder.Init();
			_longestMatchWasFound = false;
			_optimumEndIndex = 0u;
			_optimumCurrentIndex = 0u;
			_additionalOffset = 0u;
		}

		private void ReadMatchDistances(out uint lenRes, out uint numDistancePairs)
		{
			lenRes = 0u;
			numDistancePairs = _matchFinder.GetMatches(_matchDistances);
			if (numDistancePairs != 0)
			{
				lenRes = _matchDistances[numDistancePairs - 2];
				if (lenRes == _numFastBytes)
				{
					lenRes += _matchFinder.GetMatchLen((int)(lenRes - 1), _matchDistances[numDistancePairs - 1], 273 - lenRes);
				}
			}
			_additionalOffset++;
		}

		private void MovePos(uint num)
		{
			if (num != 0)
			{
				_matchFinder.Skip(num);
				_additionalOffset += num;
			}
		}

		private uint GetRepLen1Price(Base.State state, uint posState)
		{
			return _isRepG0[state.Index].GetPrice0() + _isRep0Long[(state.Index << 4) + posState].GetPrice0();
		}

		private uint GetPureRepPrice(uint repIndex, Base.State state, uint posState)
		{
			uint price;
			if (repIndex == 0)
			{
				price = _isRepG0[state.Index].GetPrice0();
				return price + _isRep0Long[(state.Index << 4) + posState].GetPrice1();
			}
			price = _isRepG0[state.Index].GetPrice1();
			if (repIndex == 1)
			{
				return price + _isRepG1[state.Index].GetPrice0();
			}
			price += _isRepG1[state.Index].GetPrice1();
			return price + _isRepG2[state.Index].GetPrice(repIndex - 2);
		}

		private uint GetRepPrice(uint repIndex, uint len, Base.State state, uint posState)
		{
			return _repMatchLenEncoder.GetPrice(len - 2, posState) + GetPureRepPrice(repIndex, state, posState);
		}

		private uint GetPosLenPrice(uint pos, uint len, uint posState)
		{
			uint lenToPosState = Base.GetLenToPosState(len);
			uint num = ((pos >= 128) ? (_posSlotPrices[(lenToPosState << 6) + GetPosSlot2(pos)] + _alignPrices[pos & 0xF]) : _distancesPrices[lenToPosState * 128 + pos]);
			return num + _lenEncoder.GetPrice(len - 2, posState);
		}

		private uint Backward(out uint backRes, uint cur)
		{
			_optimumEndIndex = cur;
			uint posPrev = _optimum[cur].PosPrev;
			uint backPrev = _optimum[cur].BackPrev;
			do
			{
				if (_optimum[cur].Prev1IsChar)
				{
					_optimum[posPrev].MakeAsChar();
					_optimum[posPrev].PosPrev = posPrev - 1;
					if (_optimum[cur].Prev2)
					{
						_optimum[posPrev - 1].Prev1IsChar = false;
						_optimum[posPrev - 1].PosPrev = _optimum[cur].PosPrev2;
						_optimum[posPrev - 1].BackPrev = _optimum[cur].BackPrev2;
					}
				}
				uint num = posPrev;
				uint backPrev2 = backPrev;
				backPrev = _optimum[num].BackPrev;
				posPrev = _optimum[num].PosPrev;
				_optimum[num].BackPrev = backPrev2;
				_optimum[num].PosPrev = cur;
				cur = num;
			}
			while (cur != 0);
			backRes = _optimum[0].BackPrev;
			_optimumCurrentIndex = _optimum[0].PosPrev;
			return _optimumCurrentIndex;
		}

		private uint GetOptimum(uint position, out uint backRes)
		{
			if (_optimumEndIndex != _optimumCurrentIndex)
			{
				uint result = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
				backRes = _optimum[_optimumCurrentIndex].BackPrev;
				_optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
				return result;
			}
			_optimumCurrentIndex = (_optimumEndIndex = 0u);
			uint lenRes;
			uint numDistancePairs;
			if (!_longestMatchWasFound)
			{
				ReadMatchDistances(out lenRes, out numDistancePairs);
			}
			else
			{
				lenRes = _longestMatchLength;
				numDistancePairs = _numDistancePairs;
				_longestMatchWasFound = false;
			}
			uint num = _matchFinder.GetNumAvailableBytes() + 1;
			if (num < 2)
			{
				backRes = uint.MaxValue;
				return 1u;
			}
			if (num > 273)
			{
				num = 273u;
			}
			uint num2 = 0u;
			for (uint num3 = 0u; num3 < 4; num3++)
			{
				reps[num3] = _repDistances[num3];
				repLens[num3] = _matchFinder.GetMatchLen(-1, reps[num3], 273u);
				if (repLens[num3] > repLens[num2])
				{
					num2 = num3;
				}
			}
			if (repLens[num2] >= _numFastBytes)
			{
				backRes = num2;
				uint num4 = repLens[num2];
				MovePos(num4 - 1);
				return num4;
			}
			if (lenRes >= _numFastBytes)
			{
				backRes = _matchDistances[numDistancePairs - 1] + 4;
				MovePos(lenRes - 1);
				return lenRes;
			}
			byte indexByte = _matchFinder.GetIndexByte(-1);
			byte indexByte2 = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - 1));
			if (lenRes < 2 && indexByte != indexByte2 && repLens[num2] < 2)
			{
				backRes = uint.MaxValue;
				return 1u;
			}
			_optimum[0].State = _state;
			uint num5 = position & _posStateMask;
			_optimum[1].Price = _isMatch[(_state.Index << 4) + num5].GetPrice0() + _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), indexByte2, indexByte);
			_optimum[1].MakeAsChar();
			uint price = _isMatch[(_state.Index << 4) + num5].GetPrice1();
			uint num6 = price + _isRep[_state.Index].GetPrice1();
			if (indexByte2 == indexByte)
			{
				uint num7 = num6 + GetRepLen1Price(_state, num5);
				if (num7 < _optimum[1].Price)
				{
					_optimum[1].Price = num7;
					_optimum[1].MakeAsShortRep();
				}
			}
			uint num8 = ((lenRes >= repLens[num2]) ? lenRes : repLens[num2]);
			if (num8 < 2)
			{
				backRes = _optimum[1].BackPrev;
				return 1u;
			}
			_optimum[1].PosPrev = 0u;
			_optimum[0].Backs0 = reps[0];
			_optimum[0].Backs1 = reps[1];
			_optimum[0].Backs2 = reps[2];
			_optimum[0].Backs3 = reps[3];
			uint num9 = num8;
			do
			{
				_optimum[num9--].Price = 268435455u;
			}
			while (num9 >= 2);
			for (uint num3 = 0u; num3 < 4; num3++)
			{
				uint num10 = repLens[num3];
				if (num10 < 2)
				{
					continue;
				}
				uint num11 = num6 + GetPureRepPrice(num3, _state, num5);
				do
				{
					uint num12 = num11 + _repMatchLenEncoder.GetPrice(num10 - 2, num5);
					Optimal optimal = _optimum[num10];
					if (num12 < optimal.Price)
					{
						optimal.Price = num12;
						optimal.PosPrev = 0u;
						optimal.BackPrev = num3;
						optimal.Prev1IsChar = false;
					}
				}
				while (--num10 >= 2);
			}
			uint num13 = price + _isRep[_state.Index].GetPrice0();
			num9 = ((repLens[0] >= 2) ? (repLens[0] + 1) : 2u);
			if (num9 <= lenRes)
			{
				uint num14;
				for (num14 = 0u; num9 > _matchDistances[num14]; num14 += 2)
				{
				}
				while (true)
				{
					uint num15 = _matchDistances[num14 + 1];
					uint num16 = num13 + GetPosLenPrice(num15, num9, num5);
					Optimal optimal2 = _optimum[num9];
					if (num16 < optimal2.Price)
					{
						optimal2.Price = num16;
						optimal2.PosPrev = 0u;
						optimal2.BackPrev = num15 + 4;
						optimal2.Prev1IsChar = false;
					}
					if (num9 == _matchDistances[num14])
					{
						num14 += 2;
						if (num14 == numDistancePairs)
						{
							break;
						}
					}
					num9++;
				}
			}
			uint num17 = 0u;
			uint lenRes2;
			while (true)
			{
				num17++;
				if (num17 == num8)
				{
					return Backward(out backRes, num17);
				}
				ReadMatchDistances(out lenRes2, out numDistancePairs);
				if (lenRes2 >= _numFastBytes)
				{
					break;
				}
				position++;
				uint num18 = _optimum[num17].PosPrev;
				Base.State state;
				if (_optimum[num17].Prev1IsChar)
				{
					num18--;
					if (_optimum[num17].Prev2)
					{
						state = _optimum[_optimum[num17].PosPrev2].State;
						if (_optimum[num17].BackPrev2 < 4)
						{
							state.UpdateRep();
						}
						else
						{
							state.UpdateMatch();
						}
					}
					else
					{
						state = _optimum[num18].State;
					}
					state.UpdateChar();
				}
				else
				{
					state = _optimum[num18].State;
				}
				if (num18 == num17 - 1)
				{
					if (_optimum[num17].IsShortRep())
					{
						state.UpdateShortRep();
					}
					else
					{
						state.UpdateChar();
					}
				}
				else
				{
					uint num19;
					if (_optimum[num17].Prev1IsChar && _optimum[num17].Prev2)
					{
						num18 = _optimum[num17].PosPrev2;
						num19 = _optimum[num17].BackPrev2;
						state.UpdateRep();
					}
					else
					{
						num19 = _optimum[num17].BackPrev;
						if (num19 < 4)
						{
							state.UpdateRep();
						}
						else
						{
							state.UpdateMatch();
						}
					}
					Optimal optimal3 = _optimum[num18];
					switch (num19)
					{
					case 0u:
						reps[0] = optimal3.Backs0;
						reps[1] = optimal3.Backs1;
						reps[2] = optimal3.Backs2;
						reps[3] = optimal3.Backs3;
						break;
					case 1u:
						reps[0] = optimal3.Backs1;
						reps[1] = optimal3.Backs0;
						reps[2] = optimal3.Backs2;
						reps[3] = optimal3.Backs3;
						break;
					case 2u:
						reps[0] = optimal3.Backs2;
						reps[1] = optimal3.Backs0;
						reps[2] = optimal3.Backs1;
						reps[3] = optimal3.Backs3;
						break;
					case 3u:
						reps[0] = optimal3.Backs3;
						reps[1] = optimal3.Backs0;
						reps[2] = optimal3.Backs1;
						reps[3] = optimal3.Backs2;
						break;
					default:
						reps[0] = num19 - 4;
						reps[1] = optimal3.Backs0;
						reps[2] = optimal3.Backs1;
						reps[3] = optimal3.Backs2;
						break;
					}
				}
				_optimum[num17].State = state;
				_optimum[num17].Backs0 = reps[0];
				_optimum[num17].Backs1 = reps[1];
				_optimum[num17].Backs2 = reps[2];
				_optimum[num17].Backs3 = reps[3];
				uint price2 = _optimum[num17].Price;
				indexByte = _matchFinder.GetIndexByte(-1);
				indexByte2 = _matchFinder.GetIndexByte((int)(0 - reps[0] - 1 - 1));
				num5 = position & _posStateMask;
				uint num20 = price2 + _isMatch[(state.Index << 4) + num5].GetPrice0() + _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(-2)).GetPrice(!state.IsCharState(), indexByte2, indexByte);
				Optimal optimal4 = _optimum[num17 + 1];
				bool flag = false;
				if (num20 < optimal4.Price)
				{
					optimal4.Price = num20;
					optimal4.PosPrev = num17;
					optimal4.MakeAsChar();
					flag = true;
				}
				price = price2 + _isMatch[(state.Index << 4) + num5].GetPrice1();
				num6 = price + _isRep[state.Index].GetPrice1();
				if (indexByte2 == indexByte && (optimal4.PosPrev >= num17 || optimal4.BackPrev != 0))
				{
					uint num21 = num6 + GetRepLen1Price(state, num5);
					if (num21 <= optimal4.Price)
					{
						optimal4.Price = num21;
						optimal4.PosPrev = num17;
						optimal4.MakeAsShortRep();
						flag = true;
					}
				}
				uint val = _matchFinder.GetNumAvailableBytes() + 1;
				val = Math.Min(4095 - num17, val);
				num = val;
				if (num < 2)
				{
					continue;
				}
				if (num > _numFastBytes)
				{
					num = _numFastBytes;
				}
				if (!flag && indexByte2 != indexByte)
				{
					uint limit = Math.Min(val - 1, _numFastBytes);
					uint matchLen = _matchFinder.GetMatchLen(0, reps[0], limit);
					if (matchLen >= 2)
					{
						Base.State state2 = state;
						state2.UpdateChar();
						uint num22 = (position + 1) & _posStateMask;
						uint num23 = num20 + _isMatch[(state2.Index << 4) + num22].GetPrice1() + _isRep[state2.Index].GetPrice1();
						uint num24 = num17 + 1 + matchLen;
						while (num8 < num24)
						{
							_optimum[++num8].Price = 268435455u;
						}
						uint num25 = num23 + GetRepPrice(0u, matchLen, state2, num22);
						Optimal optimal5 = _optimum[num24];
						if (num25 < optimal5.Price)
						{
							optimal5.Price = num25;
							optimal5.PosPrev = num17 + 1;
							optimal5.BackPrev = 0u;
							optimal5.Prev1IsChar = true;
							optimal5.Prev2 = false;
						}
					}
				}
				uint num26 = 2u;
				for (uint num27 = 0u; num27 < 4; num27++)
				{
					uint num28 = _matchFinder.GetMatchLen(-1, reps[num27], num);
					if (num28 < 2)
					{
						continue;
					}
					uint num29 = num28;
					while (true)
					{
						if (num8 < num17 + num28)
						{
							_optimum[++num8].Price = 268435455u;
							continue;
						}
						uint num30 = num6 + GetRepPrice(num27, num28, state, num5);
						Optimal optimal6 = _optimum[num17 + num28];
						if (num30 < optimal6.Price)
						{
							optimal6.Price = num30;
							optimal6.PosPrev = num17;
							optimal6.BackPrev = num27;
							optimal6.Prev1IsChar = false;
						}
						if (--num28 < 2)
						{
							break;
						}
					}
					num28 = num29;
					if (num27 == 0)
					{
						num26 = num28 + 1;
					}
					if (num28 >= val)
					{
						continue;
					}
					uint limit2 = Math.Min(val - 1 - num28, _numFastBytes);
					uint matchLen2 = _matchFinder.GetMatchLen((int)num28, reps[num27], limit2);
					if (matchLen2 >= 2)
					{
						Base.State state3 = state;
						state3.UpdateRep();
						uint num31 = (position + num28) & _posStateMask;
						uint num32 = num6 + GetRepPrice(num27, num28, state, num5) + _isMatch[(state3.Index << 4) + num31].GetPrice0() + _literalEncoder.GetSubCoder(position + num28, _matchFinder.GetIndexByte((int)(num28 - 1 - 1))).GetPrice(matchMode: true, _matchFinder.GetIndexByte((int)(num28 - 1 - (reps[num27] + 1))), _matchFinder.GetIndexByte((int)(num28 - 1)));
						state3.UpdateChar();
						num31 = (position + num28 + 1) & _posStateMask;
						uint num33 = num32 + _isMatch[(state3.Index << 4) + num31].GetPrice1() + _isRep[state3.Index].GetPrice1();
						uint num34 = num28 + 1 + matchLen2;
						while (num8 < num17 + num34)
						{
							_optimum[++num8].Price = 268435455u;
						}
						uint num35 = num33 + GetRepPrice(0u, matchLen2, state3, num31);
						Optimal optimal7 = _optimum[num17 + num34];
						if (num35 < optimal7.Price)
						{
							optimal7.Price = num35;
							optimal7.PosPrev = num17 + num28 + 1;
							optimal7.BackPrev = 0u;
							optimal7.Prev1IsChar = true;
							optimal7.Prev2 = true;
							optimal7.PosPrev2 = num17;
							optimal7.BackPrev2 = num27;
						}
					}
				}
				if (lenRes2 > num)
				{
					lenRes2 = num;
					for (numDistancePairs = 0u; lenRes2 > _matchDistances[numDistancePairs]; numDistancePairs += 2)
					{
					}
					_matchDistances[numDistancePairs] = lenRes2;
					numDistancePairs += 2;
				}
				if (lenRes2 < num26)
				{
					continue;
				}
				num13 = price + _isRep[state.Index].GetPrice0();
				while (num8 < num17 + lenRes2)
				{
					_optimum[++num8].Price = 268435455u;
				}
				uint num36;
				for (num36 = 0u; num26 > _matchDistances[num36]; num36 += 2)
				{
				}
				uint num37 = num26;
				while (true)
				{
					uint num38 = _matchDistances[num36 + 1];
					uint num39 = num13 + GetPosLenPrice(num38, num37, num5);
					Optimal optimal8 = _optimum[num17 + num37];
					if (num39 < optimal8.Price)
					{
						optimal8.Price = num39;
						optimal8.PosPrev = num17;
						optimal8.BackPrev = num38 + 4;
						optimal8.Prev1IsChar = false;
					}
					if (num37 == _matchDistances[num36])
					{
						if (num37 < val)
						{
							uint limit3 = Math.Min(val - 1 - num37, _numFastBytes);
							uint matchLen3 = _matchFinder.GetMatchLen((int)num37, num38, limit3);
							if (matchLen3 >= 2)
							{
								Base.State state4 = state;
								state4.UpdateMatch();
								uint num40 = (position + num37) & _posStateMask;
								uint num41 = num39 + _isMatch[(state4.Index << 4) + num40].GetPrice0() + _literalEncoder.GetSubCoder(position + num37, _matchFinder.GetIndexByte((int)(num37 - 1 - 1))).GetPrice(matchMode: true, _matchFinder.GetIndexByte((int)(num37 - (num38 + 1) - 1)), _matchFinder.GetIndexByte((int)(num37 - 1)));
								state4.UpdateChar();
								num40 = (position + num37 + 1) & _posStateMask;
								uint num42 = num41 + _isMatch[(state4.Index << 4) + num40].GetPrice1() + _isRep[state4.Index].GetPrice1();
								uint num43 = num37 + 1 + matchLen3;
								while (num8 < num17 + num43)
								{
									_optimum[++num8].Price = 268435455u;
								}
								num39 = num42 + GetRepPrice(0u, matchLen3, state4, num40);
								optimal8 = _optimum[num17 + num43];
								if (num39 < optimal8.Price)
								{
									optimal8.Price = num39;
									optimal8.PosPrev = num17 + num37 + 1;
									optimal8.BackPrev = 0u;
									optimal8.Prev1IsChar = true;
									optimal8.Prev2 = true;
									optimal8.PosPrev2 = num17;
									optimal8.BackPrev2 = num38 + 4;
								}
							}
						}
						num36 += 2;
						if (num36 == numDistancePairs)
						{
							break;
						}
					}
					num37++;
				}
			}
			_numDistancePairs = numDistancePairs;
			_longestMatchLength = lenRes2;
			_longestMatchWasFound = true;
			return Backward(out backRes, num17);
		}

		private bool ChangePair(uint smallDist, uint bigDist)
		{
			if (smallDist < 33554432)
			{
				return bigDist >= smallDist << 7;
			}
			return false;
		}

		private void WriteEndMarker(uint posState)
		{
			if (_writeEndMark)
			{
				_isMatch[(_state.Index << 4) + posState].Encode(_rangeEncoder, 1u);
				_isRep[_state.Index].Encode(_rangeEncoder, 0u);
				_state.UpdateMatch();
				uint num = 2u;
				_lenEncoder.Encode(_rangeEncoder, num - 2, posState);
				uint symbol = 63u;
				uint lenToPosState = Base.GetLenToPosState(num);
				_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, symbol);
				int num2 = 30;
				uint num3 = (uint)((1 << num2) - 1);
				_rangeEncoder.EncodeDirectBits(num3 >> 4, num2 - 4);
				_posAlignEncoder.ReverseEncode(_rangeEncoder, num3 & 0xF);
			}
		}

		private void Flush(uint nowPos)
		{
			ReleaseMFStream();
			WriteEndMarker(nowPos & _posStateMask);
			_rangeEncoder.FlushData();
			_rangeEncoder.FlushStream();
		}

		public void CodeOneBlock(out long inSize, out long outSize, out bool finished)
		{
			inSize = 0L;
			outSize = 0L;
			finished = true;
			if (_inStream != null)
			{
				_matchFinder.SetStream(_inStream);
				_matchFinder.Init();
				_needReleaseMFStream = true;
				_inStream = null;
				if (_trainSize != 0)
				{
					_matchFinder.Skip(_trainSize);
				}
			}
			if (_finished)
			{
				return;
			}
			_finished = true;
			long num = nowPos64;
			if (nowPos64 == 0L)
			{
				if (_matchFinder.GetNumAvailableBytes() == 0)
				{
					Flush((uint)nowPos64);
					return;
				}
				ReadMatchDistances(out var _, out var _);
				uint num2 = (uint)(int)nowPos64 & _posStateMask;
				_isMatch[(_state.Index << 4) + num2].Encode(_rangeEncoder, 0u);
				_state.UpdateChar();
				byte indexByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
				_literalEncoder.GetSubCoder((uint)nowPos64, _previousByte).Encode(_rangeEncoder, indexByte);
				_previousByte = indexByte;
				_additionalOffset--;
				nowPos64++;
			}
			if (_matchFinder.GetNumAvailableBytes() == 0)
			{
				Flush((uint)nowPos64);
				return;
			}
			while (true)
			{
				uint backRes;
				uint optimum = GetOptimum((uint)nowPos64, out backRes);
				uint num3 = (uint)(int)nowPos64 & _posStateMask;
				uint num4 = (_state.Index << 4) + num3;
				if (optimum == 1 && backRes == uint.MaxValue)
				{
					_isMatch[num4].Encode(_rangeEncoder, 0u);
					byte indexByte2 = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
					LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((uint)nowPos64, _previousByte);
					if (!_state.IsCharState())
					{
						byte indexByte3 = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));
						subCoder.EncodeMatched(_rangeEncoder, indexByte3, indexByte2);
					}
					else
					{
						subCoder.Encode(_rangeEncoder, indexByte2);
					}
					_previousByte = indexByte2;
					_state.UpdateChar();
				}
				else
				{
					_isMatch[num4].Encode(_rangeEncoder, 1u);
					if (backRes < 4)
					{
						_isRep[_state.Index].Encode(_rangeEncoder, 1u);
						if (backRes == 0)
						{
							_isRepG0[_state.Index].Encode(_rangeEncoder, 0u);
							if (optimum == 1)
							{
								_isRep0Long[num4].Encode(_rangeEncoder, 0u);
							}
							else
							{
								_isRep0Long[num4].Encode(_rangeEncoder, 1u);
							}
						}
						else
						{
							_isRepG0[_state.Index].Encode(_rangeEncoder, 1u);
							if (backRes == 1)
							{
								_isRepG1[_state.Index].Encode(_rangeEncoder, 0u);
							}
							else
							{
								_isRepG1[_state.Index].Encode(_rangeEncoder, 1u);
								_isRepG2[_state.Index].Encode(_rangeEncoder, backRes - 2);
							}
						}
						if (optimum == 1)
						{
							_state.UpdateShortRep();
						}
						else
						{
							_repMatchLenEncoder.Encode(_rangeEncoder, optimum - 2, num3);
							_state.UpdateRep();
						}
						uint num5 = _repDistances[backRes];
						if (backRes != 0)
						{
							for (uint num6 = backRes; num6 >= 1; num6--)
							{
								_repDistances[num6] = _repDistances[num6 - 1];
							}
							_repDistances[0] = num5;
						}
					}
					else
					{
						_isRep[_state.Index].Encode(_rangeEncoder, 0u);
						_state.UpdateMatch();
						_lenEncoder.Encode(_rangeEncoder, optimum - 2, num3);
						backRes -= 4;
						uint posSlot = GetPosSlot(backRes);
						uint lenToPosState = Base.GetLenToPosState(optimum);
						_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
						if (posSlot >= 4)
						{
							int num7 = (int)((posSlot >> 1) - 1);
							uint num8 = (2 | (posSlot & 1)) << num7;
							uint num9 = backRes - num8;
							if (posSlot < 14)
							{
								BitTreeEncoder.ReverseEncode(_posEncoders, num8 - posSlot - 1, _rangeEncoder, num7, num9);
							}
							else
							{
								_rangeEncoder.EncodeDirectBits(num9 >> 4, num7 - 4);
								_posAlignEncoder.ReverseEncode(_rangeEncoder, num9 & 0xF);
								_alignPriceCount++;
							}
						}
						uint num10 = backRes;
						for (uint num11 = 3u; num11 >= 1; num11--)
						{
							_repDistances[num11] = _repDistances[num11 - 1];
						}
						_repDistances[0] = num10;
						_matchPriceCount++;
					}
					_previousByte = _matchFinder.GetIndexByte((int)(optimum - 1 - _additionalOffset));
				}
				_additionalOffset -= optimum;
				nowPos64 += optimum;
				if (_additionalOffset == 0)
				{
					if (_matchPriceCount >= 128)
					{
						FillDistancesPrices();
					}
					if (_alignPriceCount >= 16)
					{
						FillAlignPrices();
					}
					inSize = nowPos64;
					outSize = _rangeEncoder.GetProcessedSizeAdd();
					if (_matchFinder.GetNumAvailableBytes() == 0)
					{
						Flush((uint)nowPos64);
						return;
					}
					if (nowPos64 - num >= 4096)
					{
						break;
					}
				}
			}
			_finished = false;
			finished = false;
		}

		private void ReleaseMFStream()
		{
			if (_matchFinder != null && _needReleaseMFStream)
			{
				_matchFinder.ReleaseStream();
				_needReleaseMFStream = false;
			}
		}

		private void SetOutStream(Stream outStream)
		{
			_rangeEncoder.SetStream(outStream);
		}

		private void ReleaseOutStream()
		{
			_rangeEncoder.ReleaseStream();
		}

		private void ReleaseStreams()
		{
			ReleaseMFStream();
			ReleaseOutStream();
		}

		private void SetStreams(Stream inStream, Stream outStream, long inSize, long outSize)
		{
			_inStream = inStream;
			_finished = false;
			Create();
			SetOutStream(outStream);
			Init();
			FillDistancesPrices();
			FillAlignPrices();
			_lenEncoder.SetTableSize(_numFastBytes + 1 - 2);
			_lenEncoder.UpdateTables((uint)(1 << _posStateBits));
			_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - 2);
			_repMatchLenEncoder.UpdateTables((uint)(1 << _posStateBits));
			nowPos64 = 0L;
		}

		public void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress)
		{
			_needReleaseMFStream = false;
			try
			{
				SetStreams(inStream, outStream, inSize, outSize);
				while (true)
				{
					CodeOneBlock(out var inSize2, out var outSize2, out var finished);
					if (finished)
					{
						break;
					}
					progress?.SetProgress(inSize2, outSize2);
				}
			}
			finally
			{
				ReleaseStreams();
			}
		}

		public void WriteCoderProperties(Stream outStream)
		{
			properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
			for (int i = 0; i < 4; i++)
			{
				properties[1 + i] = (byte)((_dictionarySize >> 8 * i) & 0xFF);
			}
			outStream.Write(properties, 0, 5);
		}

		private void FillDistancesPrices()
		{
			for (uint num = 4u; num < 128; num++)
			{
				uint posSlot = GetPosSlot(num);
				int num2 = (int)((posSlot >> 1) - 1);
				uint num3 = (2 | (posSlot & 1)) << num2;
				tempPrices[num] = BitTreeEncoder.ReverseGetPrice(_posEncoders, num3 - posSlot - 1, num2, num - num3);
			}
			for (uint num4 = 0u; num4 < 4; num4++)
			{
				BitTreeEncoder bitTreeEncoder = _posSlotEncoder[num4];
				uint num5 = num4 << 6;
				for (uint num6 = 0u; num6 < _distTableSize; num6++)
				{
					_posSlotPrices[num5 + num6] = bitTreeEncoder.GetPrice(num6);
				}
				for (uint num6 = 14u; num6 < _distTableSize; num6++)
				{
					_posSlotPrices[num5 + num6] += (num6 >> 1) - 1 - 4 << 6;
				}
				uint num7 = num4 * 128;
				uint num8;
				for (num8 = 0u; num8 < 4; num8++)
				{
					_distancesPrices[num7 + num8] = _posSlotPrices[num5 + num8];
				}
				for (; num8 < 128; num8++)
				{
					_distancesPrices[num7 + num8] = _posSlotPrices[num5 + GetPosSlot(num8)] + tempPrices[num8];
				}
			}
			_matchPriceCount = 0u;
		}

		private void FillAlignPrices()
		{
			for (uint num = 0u; num < 16; num++)
			{
				_alignPrices[num] = _posAlignEncoder.ReverseGetPrice(num);
			}
			_alignPriceCount = 0u;
		}

		private static int FindMatchFinder(string s)
		{
			for (int i = 0; i < kMatchFinderIDs.Length; i++)
			{
				if (s == kMatchFinderIDs[i])
				{
					return i;
				}
			}
			return -1;
		}

		public void SetCoderProperties(CoderPropID[] propIDs, object[] properties)
		{
			for (uint num = 0u; num < properties.Length; num++)
			{
				object obj = properties[num];
				switch (propIDs[num])
				{
				case CoderPropID.NumFastBytes:
					if (!(obj is int num2))
					{
						throw new InvalidParamException();
					}
					if (num2 < 5 || (long)num2 > 273L)
					{
						throw new InvalidParamException();
					}
					_numFastBytes = (uint)num2;
					break;
				case CoderPropID.MatchFinder:
				{
					if (!(obj is string))
					{
						throw new InvalidParamException();
					}
					EMatchFinderType matchFinderType = _matchFinderType;
					int num6 = FindMatchFinder(((string)obj).ToUpper());
					if (num6 < 0)
					{
						throw new InvalidParamException();
					}
					_matchFinderType = (EMatchFinderType)num6;
					if (_matchFinder != null && matchFinderType != _matchFinderType)
					{
						_dictionarySizePrev = uint.MaxValue;
						_matchFinder = null;
					}
					break;
				}
				case CoderPropID.DictionarySize:
				{
					if (!(obj is int num7))
					{
						throw new InvalidParamException();
					}
					if ((long)num7 < 1L || (long)num7 > 1073741824L)
					{
						throw new InvalidParamException();
					}
					_dictionarySize = (uint)num7;
					int i;
					for (i = 0; (long)i < 30L && num7 > (uint)(1 << i); i++)
					{
					}
					_distTableSize = (uint)(i * 2);
					break;
				}
				case CoderPropID.PosStateBits:
					if (!(obj is int num3))
					{
						throw new InvalidParamException();
					}
					if (num3 < 0 || (long)num3 > 4L)
					{
						throw new InvalidParamException();
					}
					_posStateBits = num3;
					_posStateMask = (uint)((1 << _posStateBits) - 1);
					break;
				case CoderPropID.LitPosBits:
					if (!(obj is int num5))
					{
						throw new InvalidParamException();
					}
					if (num5 < 0 || (long)num5 > 4L)
					{
						throw new InvalidParamException();
					}
					_numLiteralPosStateBits = num5;
					break;
				case CoderPropID.LitContextBits:
					if (!(obj is int num4))
					{
						throw new InvalidParamException();
					}
					if (num4 < 0 || (long)num4 > 8L)
					{
						throw new InvalidParamException();
					}
					_numLiteralContextBits = num4;
					break;
				case CoderPropID.EndMarker:
					if (!(obj is bool))
					{
						throw new InvalidParamException();
					}
					SetWriteEndMarkerMode((bool)obj);
					break;
				default:
					throw new InvalidParamException();
				case CoderPropID.Algorithm:
					break;
				}
			}
		}

		public void SetTrainSize(uint trainSize)
		{
			_trainSize = trainSize;
		}
	}
	public static class SevenZipHelper
	{
		private static CoderPropID[] propIDs = new CoderPropID[8]
		{
			CoderPropID.DictionarySize,
			CoderPropID.PosStateBits,
			CoderPropID.LitContextBits,
			CoderPropID.LitPosBits,
			CoderPropID.Algorithm,
			CoderPropID.NumFastBytes,
			CoderPropID.MatchFinder,
			CoderPropID.EndMarker
		};

		private static object[] properties = new object[8] { 2097152, 2, 3, 0, 2, 32, "bt4", false };

		public static byte[] Compress(byte[] inputBytes, ICodeProgress progress = null)
		{
			MemoryStream inStream = new MemoryStream(inputBytes);
			MemoryStream memoryStream = new MemoryStream();
			Compress(inStream, memoryStream, progress);
			return memoryStream.ToArray();
		}

		public static void Compress(Stream inStream, Stream outStream, ICodeProgress progress = null)
		{
			Encoder encoder = new Encoder();
			encoder.SetCoderProperties(propIDs, properties);
			encoder.WriteCoderProperties(outStream);
			encoder.Code(inStream, outStream, -1L, -1L, progress);
		}

		public static byte[] Decompress(byte[] inputBytes)
		{
			MemoryStream memoryStream = new MemoryStream(inputBytes);
			Decoder decoder = new Decoder();
			memoryStream.Seek(0L, SeekOrigin.Begin);
			MemoryStream memoryStream2 = new MemoryStream();
			byte[] array = new byte[5];
			if (memoryStream.Read(array, 0, 5) != 5)
			{
				throw new Exception("input .lzma is too short");
			}
			long num = 0L;
			for (int i = 0; i < 8; i++)
			{
				int num2 = memoryStream.ReadByte();
				if (num2 < 0)
				{
					throw new Exception("Can't Read 1");
				}
				num |= (long)((ulong)(byte)num2 << 8 * i);
			}
			decoder.SetDecoderProperties(array);
			long inSize = memoryStream.Length - memoryStream.Position;
			decoder.Code(memoryStream, memoryStream2, inSize, num, null);
			return memoryStream2.ToArray();
		}

		public static MemoryStream StreamDecompress(MemoryStream newInStream)
		{
			Decoder decoder = new Decoder();
			newInStream.Seek(0L, SeekOrigin.Begin);
			MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[5];
			if (newInStream.Read(array, 0, 5) != 5)
			{
				throw new Exception("input .lzma is too short");
			}
			long num = 0L;
			for (int i = 0; i < 8; i++)
			{
				int num2 = newInStream.ReadByte();
				if (num2 < 0)
				{
					throw new Exception("Can't Read 1");
				}
				num |= (long)((ulong)(byte)num2 << 8 * i);
			}
			decoder.SetDecoderProperties(array);
			long inSize = newInStream.Length - newInStream.Position;
			decoder.Code(newInStream, memoryStream, inSize, num, null);
			memoryStream.Position = 0L;
			return memoryStream;
		}

		public static MemoryStream StreamDecompress(MemoryStream newInStream, long outSize)
		{
			Decoder decoder = new Decoder();
			newInStream.Seek(0L, SeekOrigin.Begin);
			MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[5];
			if (newInStream.Read(array, 0, 5) != 5)
			{
				throw new Exception("input .lzma is too short");
			}
			decoder.SetDecoderProperties(array);
			long inSize = newInStream.Length - newInStream.Position;
			decoder.Code(newInStream, memoryStream, inSize, outSize, null);
			memoryStream.Position = 0L;
			return memoryStream;
		}

		public static void StreamDecompress(Stream compressedStream, Stream decompressedStream, long compressedSize, long decompressedSize)
		{
			long position = compressedStream.Position;
			Decoder decoder = new Decoder();
			byte[] array = new byte[5];
			if (compressedStream.Read(array, 0, 5) != 5)
			{
				throw new Exception("input .lzma is too short");
			}
			decoder.SetDecoderProperties(array);
			decoder.Code(compressedStream, decompressedStream, compressedSize - 5, decompressedSize, null);
			compressedStream.Position = position + compressedSize;
		}
	}
}
namespace SevenZip.Buffer
{
	public class InBuffer
	{
		private byte[] m_Buffer;

		private uint m_Pos;

		private uint m_Limit;

		private uint m_BufferSize;

		private Stream m_Stream;

		private bool m_StreamWasExhausted;

		private ulong m_ProcessedSize;

		public InBuffer(uint bufferSize)
		{
			m_Buffer = new byte[bufferSize];
			m_BufferSize = bufferSize;
		}

		public void Init(Stream stream)
		{
			m_Stream = stream;
			m_ProcessedSize = 0uL;
			m_Limit = 0u;
			m_Pos = 0u;
			m_StreamWasExhausted = false;
		}

		public bool ReadBlock()
		{
			if (m_StreamWasExhausted)
			{
				return false;
			}
			m_ProcessedSize += m_Pos;
			int num = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
			m_Pos = 0u;
			m_Limit = (uint)num;
			m_StreamWasExhausted = num == 0;
			return !m_StreamWasExhausted;
		}

		public void ReleaseStream()
		{
			m_Stream = null;
		}

		public bool ReadByte(byte b)
		{
			if (m_Pos >= m_Limit && !ReadBlock())
			{
				return false;
			}
			b = m_Buffer[m_Pos++];
			return true;
		}

		public byte ReadByte()
		{
			if (m_Pos >= m_Limit && !ReadBlock())
			{
				return byte.MaxValue;
			}
			return m_Buffer[m_Pos++];
		}

		public ulong GetProcessedSize()
		{
			return m_ProcessedSize + m_Pos;
		}
	}
	public class OutBuffer
	{
		private byte[] m_Buffer;

		private uint m_Pos;

		private uint m_BufferSize;

		private Stream m_Stream;

		private ulong m_ProcessedSize;

		public OutBuffer(uint bufferSize)
		{
			m_Buffer = new byte[bufferSize];
			m_BufferSize = bufferSize;
		}

		public void SetStream(Stream stream)
		{
			m_Stream = stream;
		}

		public void FlushStream()
		{
			m_Stream.Flush();
		}

		public void CloseStream()
		{
			m_Stream.Close();
		}

		public void ReleaseStream()
		{
			m_Stream = null;
		}

		public void Init()
		{
			m_ProcessedSize = 0uL;
			m_Pos = 0u;
		}

		public void WriteByte(byte b)
		{
			m_Buffer[m_Pos++] = b;
			if (m_Pos >= m_BufferSize)
			{
				FlushData();
			}
		}

		public void FlushData()
		{
			if (m_Pos != 0)
			{
				m_Stream.Write(m_Buffer, 0, (int)m_Pos);
				m_Pos = 0u;
			}
		}

		public ulong GetProcessedSize()
		{
			return m_ProcessedSize + m_Pos;
		}
	}
}
namespace SevenZip.CommandLineParser
{
	public enum SwitchType
	{
		Simple,
		PostMinus,
		LimitedPostString,
		UnLimitedPostString,
		PostChar
	}
	public class SwitchForm
	{
		public string IDString;

		public SwitchType Type;

		public bool Multi;

		public int MinLen;

		public int MaxLen;

		public string PostCharSet;

		public SwitchForm(string idString, SwitchType type, bool multi, int minLen, int maxLen, string postCharSet)
		{
			IDString = idString;
			Type = type;
			Multi = multi;
			MinLen = minLen;
			MaxLen = maxLen;
			PostCharSet = postCharSet;
		}

		public SwitchForm(string idString, SwitchType type, bool multi, int minLen)
			: this(idString, type, multi, minLen, 0, "")
		{
		}

		public SwitchForm(string idString, SwitchType type, bool multi)
			: this(idString, type, multi, 0)
		{
		}
	}
	public class SwitchResult
	{
		public bool ThereIs;

		public bool WithMinus;

		public ArrayList PostStrings = new ArrayList();

		public int PostCharIndex;

		public SwitchResult()
		{
			ThereIs = false;
		}
	}
	public class Parser
	{
		public ArrayList NonSwitchStrings = new ArrayList();

		private SwitchResult[] _switches;

		private const char kSwitchID1 = '-';

		private const char kSwitchID2 = '/';

		private const char kSwitchMinus = '-';

		private const string kStopSwitchParsing = "--";

		public SwitchResult this[int index] => _switches[index];

		public Parser(int numSwitches)
		{
			_switches = new SwitchResult[numSwitches];
			for (int i = 0; i < numSwitches; i++)
			{
				_switches[i] = new SwitchResult();
			}
		}

		private bool ParseString(string srcString, SwitchForm[] switchForms)
		{
			int length = srcString.Length;
			if (length == 0)
			{
				return false;
			}
			int num = 0;
			if (!IsItSwitchChar(srcString[num]))
			{
				return false;
			}
			while (num < length)
			{
				if (IsItSwitchChar(srcString[num]))
				{
					num++;
				}
				int num2 = 0;
				int num3 = -1;
				for (int i = 0; i < _switches.Length; i++)
				{
					int length2 = switchForms[i].IDString.Length;
					if (length2 > num3 && num + length2 <= length && string.Compare(switchForms[i].IDString, 0, srcString, num, length2, ignoreCase: true) == 0)
					{
						num2 = i;
						num3 = length2;
					}
				}
				if (num3 == -1)
				{
					throw new Exception("maxLen == kNoLen");
				}
				SwitchResult switchResult = _switches[num2];
				SwitchForm switchForm = switchForms[num2];
				if (!switchForm.Multi && switchResult.ThereIs)
				{
					throw new Exception("switch must be single");
				}
				switchResult.ThereIs = true;
				num += num3;
				int num4 = length - num;
				SwitchType type = switchForm.Type;
				switch (type)
				{
				case SwitchType.PostMinus:
					if (num4 == 0)
					{
						switchResult.WithMinus = false;
						break;
					}
					switchResult.WithMinus = srcString[num] == '-';
					if (switchResult.WithMinus)
					{
						num++;
					}
					break;
				case SwitchType.PostChar:
				{
					if (num4 < switchForm.MinLen)
					{
						throw new Exception("switch is not full");
					}
					string postCharSet = switchForm.PostCharSet;
					if (num4 == 0)
					{
						switchResult.PostCharIndex = -1;
						break;
					}
					int num6 = postCharSet.IndexOf(srcString[num]);
					if (num6 < 0)
					{
						switchResult.PostCharIndex = -1;
						break;
					}
					switchResult.PostCharIndex = num6;
					num++;
					break;
				}
				case SwitchType.LimitedPostString:
				case SwitchType.UnLimitedPostString:
				{
					int minLen = switchForm.MinLen;
					if (num4 < minLen)
					{
						throw new Exception("switch is not full");
					}
					if (type == SwitchType.UnLimitedPostString)
					{
						switchResult.PostStrings.Add(srcString.Substring(num));
						return true;
					}
					string text = srcString.Substring(num, minLen);
					num += minLen;
					int num5 = minLen;
					while (num5 < switchForm.MaxLen && num < length)
					{
						char c = srcString[num];
						if (IsItSwitchChar(c))
						{
							break;
						}
						text += c;
						num5++;
						num++;
					}
					switchResult.PostStrings.Add(text);
					break;
				}
				}
			}
			return true;
		}

		public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
		{
			int num = commandStrings.Length;
			bool flag = false;
			for (int i = 0; i < num; i++)
			{
				string text = commandStrings[i];
				if (flag)
				{
					NonSwitchStrings.Add(text);
				}
				else if (text == "--")
				{
					flag = true;
				}
				else if (!ParseString(text, switchForms))
				{
					NonSwitchStrings.Add(text);
				}
			}
		}

		public static int ParseCommand(CommandForm[] commandForms, string commandString, out string postString)
		{
			for (int i = 0; i < commandForms.Length; i++)
			{
				string iDString = commandForms[i].IDString;
				if (commandForms[i].PostStringMode)
				{
					if (commandString.IndexOf(iDString) == 0)
					{
						postString = commandString.Substring(iDString.Length);
						return i;
					}
				}
				else if (commandString == iDString)
				{
					postString = "";
					return i;
				}
			}
			postString = "";
			return -1;
		}

		private static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms, string commandString, ArrayList indices)
		{
			indices.Clear();
			int num = 0;
			for (int i = 0; i < numForms; i++)
			{
				CommandSubCharsSet commandSubCharsSet = forms[i];
				int num2 = -1;
				int length = commandSubCharsSet.Chars.Length;
				for (int j = 0; j < length; j++)
				{
					char value = commandSubCharsSet.Chars[j];
					int num3 = commandString.IndexOf(value);
					if (num3 >= 0)
					{
						if (num2 >= 0)
						{
							return false;
						}
						if (commandString.IndexOf(value, num3 + 1) >= 0)
						{
							return false;
						}
						num2 = j;
						num++;
					}
				}
				if (num2 == -1 && !commandSubCharsSet.EmptyAllowed)
				{
					return false;
				}
				indices.Add(num2);
			}
			return num == commandString.Length;
		}

		private static bool IsItSwitchChar(char c)
		{
			if (c != '-')
			{
				return c == '/';
			}
			return true;
		}
	}
	public class CommandForm
	{
		public string IDString = "";

		public bool PostStringMode;

		public CommandForm(string idString, bool postStringMode)
		{
			IDString = idString;
			PostStringMode = postStringMode;
		}
	}
	internal class CommandSubCharsSet
	{
		public string Chars = "";

		public bool EmptyAllowed;
	}
}
namespace LZ4ps
{
	public static class LZ4Codec
	{
		private class LZ4HC_Data_Structure
		{
			public byte[] src;

			public int src_base;

			public int src_end;

			public int src_LASTLITERALS;

			public byte[] dst;

			public int dst_base;

			public int dst_len;

			public int dst_end;

			public int[] hashTable;

			public ushort[] chainTable;

			public int nextToUpdate;
		}

		private const int MEMORY_USAGE = 14;

		private const int NOTCOMPRESSIBLE_DETECTIONLEVEL = 6;

		private const int BLOCK_COPY_LIMIT = 16;

		private const int MINMATCH = 4;

		private const int SKIPSTRENGTH = 6;

		private const int COPYLENGTH = 8;

		private const int LASTLITERALS = 5;

		private const int MFLIMIT = 12;

		private const int MINLENGTH = 13;

		private const int MAXD_LOG = 16;

		private const int MAXD = 65536;

		private const int MAXD_MASK = 65535;

		private const int MAX_DISTANCE = 65535;

		private const int ML_BITS = 4;

		private const int ML_MASK = 15;

		private const int RUN_BITS = 4;

		private const int RUN_MASK = 15;

		private const int STEPSIZE_64 = 8;

		private const int STEPSIZE_32 = 4;

		private const int LZ4_64KLIMIT = 65547;

		private const int HASH_LOG = 12;

		private const int HASH_TABLESIZE = 4096;

		private const int HASH_ADJUST = 20;

		private const int HASH64K_LOG = 13;

		private const int HASH64K_TABLESIZE = 8192;

		private const int HASH64K_ADJUST = 19;

		private const int HASHHC_LOG = 15;

		private const int HASHHC_TABLESIZE = 32768;

		private const int HASHHC_ADJUST = 17;

		private static readonly int[] DECODER_TABLE_32 = new int[8] { 0, 3, 2, 3, 0, 0, 0, 0 };

		private static readonly int[] DECODER_TABLE_64 = new int[8] { 0, 0, 0, -1, 0, 1, 2, 3 };

		private static readonly int[] DEBRUIJN_TABLE_32 = new int[32]
		{
			0, 0, 3, 0, 3, 1, 3, 0, 3, 2,
			2, 1, 3, 2, 0, 1, 3, 3, 1, 2,
			2, 2, 2, 0, 3, 1, 2, 0, 1, 0,
			1, 1
		};

		private static readonly int[] DEBRUIJN_TABLE_64 = new int[64]
		{
			0, 0, 0, 0, 0, 1, 1, 2, 0, 3,
			1, 3, 1, 4, 2, 7, 0, 2, 3, 6,
			1, 5, 3, 5, 1, 3, 4, 4, 2, 5,
			6, 7, 7, 0, 1, 2, 3, 3, 4, 6,
			2, 6, 5, 5, 3, 4, 5, 6, 7, 1,
			2, 4, 6, 4, 4, 5, 7, 2, 6, 5,
			7, 6, 7, 7
		};

		private const int MAX_NB_ATTEMPTS = 256;

		private const int OPTIMAL_ML = 18;

		public static int MaximumOutputLength(int inputLength)
		{
			return inputLength + inputLength / 255 + 16;
		}

		internal static void CheckArguments(byte[] input, int inputOffset, ref int inputLength, byte[] output, int outputOffset, ref int outputLength)
		{
			if (inputLength < 0)
			{
				inputLength = input.Length - inputOffset;
			}
			if (inputLength == 0)
			{
				outputLength = 0;
				return;
			}
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (inputOffset < 0 || inputOffset + inputLength > input.Length)
			{
				throw new ArgumentException("inputOffset and inputLength are invalid for given input");
			}
			if (outputLength < 0)
			{
				outputLength = output.Length - outputOffset;
			}
			if (output == null)
			{
				throw new ArgumentNullException("output");
			}
			if (outputOffset >= 0 && outputOffset + outputLength <= output.Length)
			{
				return;
			}
			throw new ArgumentException("outputOffset and outputLength are invalid for given output");
		}

		[Conditional("DEBUG")]
		private static void Assert(bool condition, string errorMessage)
		{
			if (!condition)
			{
				throw new ArgumentException(errorMessage);
			}
		}

		internal static void Poke2(byte[] buffer, int offset, ushort value)
		{
			buffer[offset] = (byte)value;
			buffer[offset + 1] = (byte)(value >> 8);
		}

		internal static ushort Peek2(byte[] buffer, int offset)
		{
			return (ushort)(buffer[offset] | (buffer[offset + 1] << 8));
		}

		internal static uint Peek4(byte[] buffer, int offset)
		{
			return (uint)(buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24));
		}

		private static uint Xor4(byte[] buffer, int offset1, int offset2)
		{
			int num = buffer[offset1] | (buffer[offset1 + 1] << 8) | (buffer[offset1 + 2] << 16) | (buffer[offset1 + 3] << 24);
			uint num2 = (uint)(buffer[offset2] | (buffer[offset2 + 1] << 8) | (buffer[offset2 + 2] << 16) | (buffer[offset2 + 3] << 24));
			return (uint)num ^ num2;
		}

		private static ulong Xor8(byte[] buffer, int offset1, int offset2)
		{
			ulong num = buffer[offset1] | ((ulong)buffer[offset1 + 1] << 8) | ((ulong)buffer[offset1 + 2] << 16) | ((ulong)buffer[offset1 + 3] << 24) | ((ulong)buffer[offset1 + 4] << 32) | ((ulong)buffer[offset1 + 5] << 40) | ((ulong)buffer[offset1 + 6] << 48) | ((ulong)buffer[offset1 + 7] << 56);
			ulong num2 = buffer[offset2] | ((ulong)buffer[offset2 + 1] << 8) | ((ulong)buffer[offset2 + 2] << 16) | ((ulong)buffer[offset2 + 3] << 24) | ((ulong)buffer[offset2 + 4] << 32) | ((ulong)buffer[offset2 + 5] << 40) | ((ulong)buffer[offset2 + 6] << 48) | ((ulong)buffer[offset2 + 7] << 56);
			return num ^ num2;
		}

		private static bool Equal2(byte[] buffer, int offset1, int offset2)
		{
			if (buffer[offset1] != buffer[offset2])
			{
				return false;
			}
			return buffer[offset1 + 1] == buffer[offset2 + 1];
		}

		private static bool Equal4(byte[] buffer, int offset1, int offset2)
		{
			if (buffer[offset1] != buffer[offset2])
			{
				return false;
			}
			if (buffer[offset1 + 1] != buffer[offset2 + 1])
			{
				return false;
			}
			if (buffer[offset1 + 2] != buffer[offset2 + 2])
			{
				return false;
			}
			return buffer[offset1 + 3] == buffer[offset2 + 3];
		}

		private static void Copy4(byte[] buf, int src, int dst)
		{
			buf[dst + 3] = buf[src + 3];
			buf[dst + 2] = buf[src + 2];
			buf[dst + 1] = buf[src + 1];
			buf[dst] = buf[src];
		}

		private static void Copy8(byte[] buf, int src, int dst)
		{
			buf[dst + 7] = buf[src + 7];
			buf[dst + 6] = buf[src + 6];
			buf[dst + 5] = buf[src + 5];
			buf[dst + 4] = buf[src + 4];
			buf[dst + 3] = buf[src + 3];
			buf[dst + 2] = buf[src + 2];
			buf[dst + 1] = buf[src + 1];
			buf[dst] = buf[src];
		}

		private static void BlockCopy(byte[] src, int src_0, byte[] dst, int dst_0, int len)
		{
			if (len >= 16)
			{
				Buffer.BlockCopy(src, src_0, dst, dst_0, len);
				return;
			}
			while (len >= 8)
			{
				dst[dst_0] = src[src_0];
				dst[dst_0 + 1] = src[src_0 + 1];
				dst[dst_0 + 2] = src[src_0 + 2];
				dst[dst_0 + 3] = src[src_0 + 3];
				dst[dst_0 + 4] = src[src_0 + 4];
				dst[dst_0 + 5] = src[src_0 + 5];
				dst[dst_0 + 6] = src[src_0 + 6];
				dst[dst_0 + 7] = src[src_0 + 7];
				len -= 8;
				src_0 += 8;
				dst_0 += 8;
			}
			while (len >= 4)
			{
				dst[dst_0] = src[src_0];
				dst[dst_0 + 1] = src[src_0 + 1];
				dst[dst_0 + 2] = src[src_0 + 2];
				dst[dst_0 + 3] = src[src_0 + 3];
				len -= 4;
				src_0 += 4;
				dst_0 += 4;
			}
			while (len-- > 0)
			{
				dst[dst_0++] = src[src_0++];
			}
		}

		private static int WildCopy(byte[] src, int src_0, byte[] dst, int dst_0, int dst_end)
		{
			int num = dst_end - dst_0;
			if (num >= 16)
			{
				Buffer.BlockCopy(src, src_0, dst, dst_0, num);
			}
			else
			{
				while (num >= 4)
				{
					dst[dst_0] = src[src_0];
					dst[dst_0 + 1] = src[src_0 + 1];
					dst[dst_0 + 2] = src[src_0 + 2];
					dst[dst_0 + 3] = src[src_0 + 3];
					num -= 4;
					src_0 += 4;
					dst_0 += 4;
				}
				while (num-- > 0)
				{
					dst[dst_0++] = src[src_0++];
				}
			}
			return num;
		}

		private static int SecureCopy(byte[] buffer, int src, int dst, int dst_end)
		{
			int num = dst - src;
			int num2 = dst_end - dst;
			int num3 = num2;
			if (num >= 16)
			{
				if (num >= num2)
				{
					Buffer.BlockCopy(buffer, src, buffer, dst, num2);
					return num2;
				}
				do
				{
					Buffer.BlockCopy(buffer, src, buffer, dst, num);
					src += num;
					dst += num;
					num3 -= num;
				}
				while (num3 >= num);
			}
			while (num3 >= 4)
			{
				buffer[dst] = buffer[src];
				buffer[dst + 1] = buffer[src + 1];
				buffer[dst + 2] = buffer[src + 2];
				buffer[dst + 3] = buffer[src + 3];
				dst += 4;
				src += 4;
				num3 -= 4;
			}
			while (num3-- > 0)
			{
				buffer[dst++] = buffer[src++];
			}
			return num2;
		}

		public static int Encode32(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
		{
			CheckArguments(input, inputOffset, ref inputLength, output, outputOffset, ref outputLength);
			if (outputLength == 0)
			{
				return 0;
			}
			if (inputLength < 65547)
			{
				return LZ4_compress64kCtx_safe32(new ushort[8192], input, output, inputOffset, outputOffset, inputLength, outputLength);
			}
			return LZ4_compressCtx_safe32(new int[4096], input, output, inputOffset, outputOffset, inputLength, outputLength);
		}

		public static byte[] Encode32(byte[] input, int inputOffset, int inputLength)
		{
			if (inputLength < 0)
			{
				inputLength = input.Length - inputOffset;
			}
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (inputOffset < 0 || inputOffset + inputLength > input.Length)
			{
				throw new ArgumentException("inputOffset and inputLength are invalid for given input");
			}
			byte[] array = new byte[MaximumOutputLength(inputLength)];
			int num = Encode32(input, inputOffset, inputLength, array, 0, array.Length);
			if (num != array.Length)
			{
				if (num < 0)
				{
					throw new InvalidOperationException("Compression has been corrupted");
				}
				byte[] array2 = new byte[num];
				Buffer.BlockCopy(array, 0, array2, 0, num);
				return array2;
			}
			return array;
		}

		public static int Encode64(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
		{
			CheckArguments(input, inputOffset, ref inputLength, output, outputOffset, ref outputLength);
			if (outputLength == 0)
			{
				return 0;
			}
			if (inputLength < 65547)
			{
				return LZ4_compress64kCtx_safe64(new ushort[8192], input, output, inputOffset, outputOffset, inputLength, outputLength);
			}
			return LZ4_compressCtx_safe64(new int[4096], input, output, inputOffset, outputOffset, inputLength, outputLength);
		}

		public static byte[] Encode64(byte[] input, int inputOffset, int inputLength)
		{
			if (inputLength < 0)
			{
				inputLength = input.Length - inputOffset;
			}
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			if (inputOffset < 0 || inputOffset + inputLength > input.Length)
			{
				throw new ArgumentException("inputOffset and inputLength are invalid for given input");
			}
			byte[] array = new byte[MaximumOutputLength(inputLength)];
			int num = Encode64(input, inputOffset, inputLength, array, 0, array.Length);
			if (num != array.Length)
			{
				if (num < 0)
				{
					throw new InvalidOperationException("Compression has been corrupted");
				}
				byte[] array2 = new byte[num];
				Buffer.BlockCopy(array, 0, array2, 0, num);
				return array2;
			}
			return array;
		}

		public static int Decode32(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength, bool knownOutputLength)
		{
			CheckArguments(input, inputOffset, ref inputLength, output, outputOffset, ref outputLength);
			if (outputLength == 0)
			{
				return 0;
			}
			if (knownOutputLength)
			{
				if (LZ4_uncompress_safe32(input, output, inputOffset, outputOffset, outputLength) != inpu

quaternion.gundomizer.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Anvil;
using AssetsTools.NET;
using AssetsTools.NET.Extra;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using Gundomizer.Indexing;
using HarmonyLib;
using LZ4ps;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("quaternion")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Random and held-item-compatible spawning in Item Spawner V2.")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("quaternion.gundomizer")]
[assembly: AssemblyTitle("Gundomizer")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace Gundomizer
{
	internal static class AmmoCatalog
	{
		internal sealed class Variant
		{
			internal FireArmRoundType Type;

			internal FireArmRoundClass Class;

			internal string Key;

			internal string Name;

			internal string Caliber;

			internal string Properties;

			internal ItemSpawnerID Entry;
		}

		internal static HashSet<FireArmRoundType> Types(FVRPhysicalObject held)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			HashSet<FireArmRoundType> hashSet = new HashSet<FireArmRoundType>();
			if ((Object)(object)held == (Object)null)
			{
				return hashSet;
			}
			foreach (FVRPhysicalObject item in Compatibility.Objects(held))
			{
				FVRFireArm val = (FVRFireArm)(object)((item is FVRFireArm) ? item : null);
				if ((Object)(object)val != (Object)null && !(val is FlintlockWeapon))
				{
					hashSet.Add(val.RoundType);
					List<FVRFireArmChamber> chambers = val.GetChambers();
					if (chambers != null)
					{
						foreach (FVRFireArmChamber item2 in chambers)
						{
							if ((Object)(object)item2 != (Object)null)
							{
								hashSet.Add(item2.RoundType);
							}
						}
					}
					AttachableFirearm integratedAttachableFirearm = val.GetIntegratedAttachableFirearm();
					if ((Object)(object)integratedAttachableFirearm != (Object)null)
					{
						hashSet.Add(integratedAttachableFirearm.RoundType);
					}
				}
				AttachableFirearmPhysicalObject val2 = (AttachableFirearmPhysicalObject)(object)((item is AttachableFirearmPhysicalObject) ? item : null);
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.FA != (Object)null)
				{
					hashSet.Add(val2.FA.RoundType);
				}
				FVRFireArmMagazine val3 = (FVRFireArmMagazine)(object)((item is FVRFireArmMagazine) ? item : null);
				if ((Object)(object)val3 != (Object)null)
				{
					hashSet.Add(val3.RoundType);
				}
				FVRFireArmClip val4 = (FVRFireArmClip)(object)((item is FVRFireArmClip) ? item : null);
				if ((Object)(object)val4 != (Object)null)
				{
					hashSet.Add(val4.RoundType);
				}
				Speedloader val5 = (Speedloader)(object)((item is Speedloader) ? item : null);
				if ((Object)(object)val5 != (Object)null && val5.Chambers != null)
				{
					foreach (SpeedloaderChamber chamber in val5.Chambers)
					{
						if ((Object)(object)chamber != (Object)null)
						{
							hashSet.Add(chamber.Type);
						}
					}
				}
				FVRFireArmRound val6 = (FVRFireArmRound)(object)((item is FVRFireArmRound) ? item : null);
				if ((Object)(object)val6 != (Object)null)
				{
					hashSet.Add(val6.RoundType);
				}
			}
			return hashSet;
		}

		internal unsafe static List<Variant> Read(HashSet<FireArmRoundType> types)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: 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_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Expected I4, but got Unknown
			//IL_024e: Expected I4, but got Unknown
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			List<Variant> list = new List<Variant>();
			foreach (FireArmRoundType type in types)
			{
				if (!AM.STypeDic.TryGetValue(type, out var value))
				{
					continue;
				}
				FVRFireArmRoundDisplayData value2;
				string caliber = (AM.SRoundDisplayDataDic.TryGetValue(type, out value2) ? value2.DisplayName : ((object)(*(FireArmRoundType*)(&type))/*cast due to .constrained prefix*/).ToString());
				foreach (KeyValuePair<FireArmRoundClass, DisplayDataClass> item in value)
				{
					DisplayDataClass value3 = item.Value;
					if (value3 == null || (Object)(object)value3.ObjectID == (Object)null)
					{
						continue;
					}
					FVRObject objectID = value3.ObjectID;
					ItemSpawnerID val = (OtherLoaderBridge.Active ? OtherLoaderBridge.Resolve(objectID.ItemID) : null);
					if ((Object)(object)val == (Object)null && !string.IsNullOrEmpty(objectID.SpawnedFromId) && IM.HasSpawnedID(objectID.SpawnedFromId))
					{
						val = IM.GetSpawnerID(objectID.SpawnedFromId);
					}
					if ((Object)(object)val == (Object)null)
					{
						val = AmmoSpawnerEntries.Get(objectID, caliber, string.IsNullOrEmpty(value3.Name) ? ((object)item.Key/*cast due to .constrained prefix*/).ToString() : value3.Name);
					}
					if (!SpawnerBridge.IsAvailable(val) || ((Object)(object)val.MainObject != (Object)(object)objectID && (!OtherLoaderBridge.Active || string.IsNullOrEmpty(objectID.ItemID) || !string.Equals(val.MainObject.ItemID, objectID.ItemID, StringComparison.Ordinal))))
					{
						continue;
					}
					List<string> list2 = new List<string>();
					foreach (KeyValuePair<FireArmRoundPropertyTag, Dictionary<FireArmRoundType, List<FireArmRoundClass>>> item2 in AM.TagDic)
					{
						if ((int)item2.Key != 0 && item2.Value != null && item2.Value.TryGetValue(type, out var value4) && value4 != null && value4.Contains(item.Key))
						{
							list2.Add(Regex.Replace(((object)item2.Key/*cast due to .constrained prefix*/).ToString(), "([a-z])([A-Z])", "$1 $2").Replace('_', ' '));
						}
					}
					list2.Sort(StringComparer.Ordinal);
					list.Add(new Variant
					{
						Type = type,
						Class = item.Key,
						Key = AmmoSelection.Key((int)type, (int)item.Key),
						Name = (string.IsNullOrEmpty(value3.Name) ? ((object)item.Key/*cast due to .constrained prefix*/).ToString() : value3.Name),
						Caliber = caliber,
						Properties = string.Join(", ", list2.ToArray()),
						Entry = val
					});
				}
			}
			list.Sort(delegate(Variant a, Variant b)
			{
				int num = string.CompareOrdinal(a.Caliber, b.Caliber);
				return (num == 0) ? string.CompareOrdinal(a.Name, b.Name) : num;
			});
			return list;
		}

		internal static bool Matches(FVRPhysicalObject held, GameObject prefab, Variant variant)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			FVRFireArmRound val = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<FVRFireArmRound>());
			if ((Object)(object)val != (Object)null && val.RoundType == variant.Type && val.RoundClass == variant.Class && Types(held).Contains(variant.Type))
			{
				return AmmoSelection.Shared.Includes(variant.Key);
			}
			return false;
		}
	}
	internal sealed class AmmoFill
	{
		private readonly FVRFireArmRound round;

		private readonly HashSet<Component> visited = new HashSet<Component>();

		internal int Filled { get; private set; }

		internal int Failed { get; private set; }

		private AmmoFill(FVRFireArmRound round)
		{
			this.round = round;
		}

		internal static AmmoFill Apply(FVRPhysicalObject held, FVRFireArmRound round)
		{
			//IL_00d4: 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)
			AmmoFill ammoFill = new AmmoFill(round);
			if ((Object)(object)held == (Object)null || (Object)(object)round == (Object)null || round.IsSpent)
			{
				return ammoFill;
			}
			try
			{
				foreach (FVRPhysicalObject item in Compatibility.Objects(held))
				{
					ammoFill.Magazine((FVRFireArmMagazine)(object)((item is FVRFireArmMagazine) ? item : null));
					ammoFill.Clip((FVRFireArmClip)(object)((item is FVRFireArmClip) ? item : null));
					Speedloader val = (Speedloader)(object)((item is Speedloader) ? item : null);
					if ((Object)(object)val != (Object)null && val.Chambers != null)
					{
						foreach (SpeedloaderChamber chamber in val.Chambers)
						{
							if ((Object)(object)chamber != (Object)null && chamber.Type == round.RoundType)
							{
								ammoFill.Try((Component)(object)chamber, delegate
								{
									//IL_0011: Unknown result type (might be due to invalid IL or missing references)
									chamber.Load(round.RoundClass, false);
								});
							}
						}
					}
					ammoFill.Firearm((FVRFireArm)(object)((item is FVRFireArm) ? item : null));
					AttachableFirearmPhysicalObject val2 = (AttachableFirearmPhysicalObject)(object)((item is AttachableFirearmPhysicalObject) ? item : null);
					if ((Object)(object)val2 != (Object)null)
					{
						ammoFill.Attachable(val2.FA);
					}
				}
			}
			catch (Exception ex)
			{
				ammoFill.Report(ex);
			}
			return ammoFill;
		}

		private void Magazine(FVRFireArmMagazine magazine)
		{
			//IL_0028: 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 ((Object)(object)magazine != (Object)null && magazine.RoundType == round.RoundType)
			{
				Try((Component)(object)magazine, delegate
				{
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					magazine.ReloadMagWithType(round.RoundClass);
				});
			}
		}

		private void Clip(FVRFireArmClip clip)
		{
			//IL_0028: 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 ((Object)(object)clip != (Object)null && clip.RoundType == round.RoundType)
			{
				Try((Component)(object)clip, delegate
				{
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					clip.ReloadClipWithType(round.RoundClass);
				});
			}
		}

		private void Chamber(FVRFireArmChamber chamber)
		{
			//IL_0028: 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 ((Object)(object)chamber != (Object)null && chamber.RoundType == round.RoundType)
			{
				Try((Component)(object)chamber, delegate
				{
					chamber.SetRound(round, false);
				});
			}
		}

		private void Firearm(FVRFireArm firearm)
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)firearm == (Object)null || !visited.Add((Component)(object)firearm))
			{
				return;
			}
			Magazine(firearm.Magazine);
			if (firearm.SecondaryMagazineSlots != null)
			{
				SecondaryMagazineSlot[] secondaryMagazineSlots = firearm.SecondaryMagazineSlots;
				foreach (SecondaryMagazineSlot val in secondaryMagazineSlots)
				{
					if (val != null)
					{
						Magazine(val.Magazine);
					}
				}
			}
			Clip(firearm.Clip);
			List<FVRFireArmChamber> chambers = firearm.GetChambers();
			if (chambers != null)
			{
				foreach (FVRFireArmChamber item in chambers)
				{
					Chamber(item);
				}
			}
			Attachable(firearm.GetIntegratedAttachableFirearm());
			if (firearm.RoundType != round.RoundType || !firearm.UsesBelts || !((Object)(object)firearm.BeltDD != (Object)null))
			{
				return;
			}
			Try((Component)(object)firearm.BeltDD, delegate
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: 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_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
				foreach (FVRLoadedRound beltRound in firearm.BeltDD.BeltRounds)
				{
					beltRound.LR_Class = round.RoundClass;
					beltRound.LR_Mesh = AM.GetRoundMesh(round.RoundType, round.RoundClass);
					beltRound.LR_Material = AM.GetRoundMaterial(round.RoundType, round.RoundClass);
					beltRound.LR_ObjectWrapper = AM.GetRoundSelfPrefab(round.RoundType, round.RoundClass);
				}
				firearm.BeltDD.UpdateProxyRounds(0);
			});
		}

		private void Attachable(AttachableFirearm firearm)
		{
			if ((Object)(object)firearm == (Object)null || !visited.Add((Component)(object)firearm))
			{
				return;
			}
			Firearm(firearm.OverrideFA);
			Magazine(firearm.Magazine);
			if (firearm.SecondaryMagazineSlots != null)
			{
				SecondaryMagazineSlot[] secondaryMagazineSlots = firearm.SecondaryMagazineSlots;
				foreach (SecondaryMagazineSlot val in secondaryMagazineSlots)
				{
					if (val != null)
					{
						Magazine(val.Magazine);
					}
				}
			}
			Clip(firearm.Clip);
			FVRFireArmChamber[] componentsInChildren = ((Component)firearm).GetComponentsInChildren<FVRFireArmChamber>(true);
			foreach (FVRFireArmChamber val2 in componentsInChildren)
			{
				if ((Object)(object)((Component)val2).GetComponentInParent<AttachableFirearm>() == (Object)(object)firearm)
				{
					Chamber(val2);
				}
			}
		}

		private void Try(Component component, Action fill)
		{
			if (!visited.Add(component))
			{
				return;
			}
			try
			{
				fill();
				int filled = Filled + 1;
				Filled = filled;
			}
			catch (Exception ex)
			{
				Report(ex);
			}
		}

		private void Report(Exception ex)
		{
			int failed = Failed + 1;
			Failed = failed;
			Plugin.Log.LogWarning((object)("Ammo spawned, but a held-item refill failed: " + ex));
		}
	}
	internal sealed class AmmoPanel
	{
		internal const float GroupWidth = 200f;

		private const int PageSize = 7;

		private const float Width = 1200f;

		private const float Height = 850f;

		private readonly RandomizerController owner;

		private readonly GameObject template;

		private readonly RectTransform popup;

		private readonly RandomizerButton rollButton;

		private readonly RandomizerButton toggleButton;

		private readonly List<RandomizerButton> rows = new List<RandomizerButton>();

		private readonly Text title;

		private readonly Text hint;

		private readonly Text pageText;

		private readonly RandomizerButton previous;

		private readonly RandomizerButton next;

		private List<AmmoCatalog.Variant> variants = new List<AmmoCatalog.Variant>();

		private HashSet<FireArmRoundType> types = new HashSet<FireArmRoundType>();

		private FVRPhysicalObject held;

		private int page;

		private int revision;

		private int enabledCount;

		internal bool IsOpen => ((Component)popup).gameObject.activeSelf;

		internal RandomizerButton RollButton => rollButton;

		internal string Tooltip
		{
			get
			{
				if (!rollButton.Hovered)
				{
					if (!toggleButton.Hovered)
					{
						return null;
					}
					return "Choose ammo variants for " + Compatibility.Name(held);
				}
				if (enabledCount != 0)
				{
					return "Random compatible ammo for " + Compatibility.Name(held) + " (" + enabledCount + " variants enabled)";
				}
				return "Hold an ammo-using item and enable at least one ammo variant.";
			}
		}

		internal AmmoPanel(RandomizerController owner, ItemSpawnerV2 spawner, RectTransform root, GameObject template, float left, float y)
		{
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Expected O, but got Unknown
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0497: Unknown result type (might be due to invalid IL or missing references)
			AmmoPanel ammoPanel = this;
			this.owner = owner;
			this.template = template;
			rollButton = owner.CloneButton(template, root, "Ammo", compatible: false, left + 60f, y, 120f);
			rollButton.Icon.Ammo = true;
			((Graphic)rollButton.Icon).SetVerticesDirty();
			rollButton.NeedsHeldContext = true;
			rollButton.Ready = () => owner.CanClick(compatible: true) && ammoPanel.enabledCount > 0;
			rollButton.Handler = owner.ClickAmmo;
			toggleButton = owner.CloneButton(template, root, "Ammo choices", compatible: false, left + 160f, y, 80f);
			toggleButton.Icon.Dropdown = true;
			((Graphic)toggleButton.Icon).SetVerticesDirty();
			toggleButton.Rainbow = false;
			((RawImage)toggleButton.Background).texture = (Texture)(object)Texture2D.whiteTexture;
			((Graphic)toggleButton.Background).color = new Color(0.13f, 0.16f, 0.19f, 1f);
			rollButton.Background.RoundRight = false;
			toggleButton.Background.RoundLeft = false;
			RectTransform rectTransform = ((Graphic)rollButton.Background).rectTransform;
			rectTransform.offsetMax = new Vector2(0f, rectTransform.offsetMax.y);
			RectTransform rectTransform2 = ((Graphic)toggleButton.Background).rectTransform;
			rectTransform2.offsetMin = new Vector2(0f, rectTransform2.offsetMin.y);
			Image component = new GameObject("Group separator", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			}).GetComponent<Image>();
			((Component)component).gameObject.layer = template.layer;
			((Transform)((Graphic)component).rectTransform).SetParent(((Component)toggleButton).transform, false);
			((Graphic)component).rectTransform.anchorMin = new Vector2(0f, 0f);
			((Graphic)component).rectTransform.anchorMax = new Vector2(0f, 1f);
			((Graphic)component).rectTransform.offsetMin = new Vector2(0f, 4f);
			((Graphic)component).rectTransform.offsetMax = new Vector2(0.75f, -4f);
			RectTransform rectTransform3 = ((Graphic)component).rectTransform;
			((Transform)rectTransform3).localPosition = ((Transform)rectTransform3).localPosition + new Vector3(0f, 0f, -0.015f);
			((Graphic)component).color = new Color(0.65f, 0.68f, 0.7f, 0.6f);
			((Graphic)component).raycastTarget = false;
			toggleButton.NeedsHeldContext = true;
			toggleButton.Ready = () => owner.CanClick(compatible: true) && ammoPanel.variants.Count > 0;
			toggleButton.Handler = delegate
			{
				if (ammoPanel.IsOpen)
				{
					ammoPanel.Hide();
				}
				else
				{
					owner.CloseChoices(openingAmmo: true);
					ammoPanel.Refresh(ammoPanel.held, force: true);
					ammoPanel.Redraw();
					ammoPanel.SetOpen(open: true);
				}
			};
			popup = (RectTransform)new GameObject("Gundomizer Ammo Choices", new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(BoxCollider),
				typeof(FVRPointable)
			}).transform;
			((Component)popup).gameObject.layer = template.layer;
			((Transform)popup).SetParent((Transform)(object)root, false);
			RectTransform obj = popup;
			RectTransform obj2 = popup;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			obj2.anchorMax = val;
			obj.anchorMin = val;
			popup.pivot = Vector2.zero;
			popup.sizeDelta = new Vector2(1200f, 850f);
			((Transform)popup).localPosition = new Vector3(left, y + 95f, -8f);
			Image component2 = ((Component)popup).GetComponent<Image>();
			((Graphic)component2).color = new Color(0.025f, 0.03f, 0.04f, 1f);
			((Graphic)component2).raycastTarget = true;
			BoxCollider component3 = ((Component)popup).GetComponent<BoxCollider>();
			component3.center = new Vector3(600f, 425f, 2f);
			component3.size = new Vector3(1200f, 850f, 1f);
			((Component)popup).GetComponent<FVRPointable>().MaxPointingRange = ((FVRPointable)rollButton).MaxPointingRange;
			title = Label("Title", 32f, 790f, 1010f, 76f, 46);
			hint = Label("Description", 32f, 718f, 1136f, 64f, 32);
			TextButton("Close", "X", 1125f, 790f, 90f, delegate
			{
				ammoPanel.Hide();
			});
			for (int num = 0; num < 7; num++)
			{
				int slot = num;
				RandomizerButton randomizerButton = TextButton("Variant " + num, "", 600f, 640f - (float)num * 84f, 1136f, delegate
				{
					ammoPanel.Toggle(slot);
				});
				randomizerButton.Caption.alignment = (TextAnchor)3;
				rows.Add(randomizerButton);
			}
			TextButton("All", "All", 130f, 48f, 180f, delegate
			{
				ammoPanel.SetAll(include: true);
			});
			TextButton("None", "None", 335f, 48f, 180f, delegate
			{
				ammoPanel.SetAll(include: false);
			});
			previous = TextButton("Previous", "<", 780f, 48f, 140f, delegate
			{
				ammoPanel.page--;
				ammoPanel.Redraw();
			});
			next = TextButton("Next", ">", 1090f, 48f, 140f, delegate
			{
				ammoPanel.page++;
				ammoPanel.Redraw();
			});
			pageText = Label("Page", 860f, 48f, 160f, 70f, 40);
			pageText.alignment = (TextAnchor)4;
			((Component)popup).gameObject.SetActive(false);
		}

		private Text Label(string name, float left, float y, float width, float height, int size)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			Text component = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Text)
			}).GetComponent<Text>();
			((Component)component).gameObject.layer = template.layer;
			((Transform)((Graphic)component).rectTransform).SetParent((Transform)(object)popup, false);
			RectTransform rectTransform = ((Graphic)component).rectTransform;
			Vector2 anchorMin = (((Graphic)component).rectTransform.anchorMax = Vector2.zero);
			rectTransform.anchorMin = anchorMin;
			((Graphic)component).rectTransform.pivot = new Vector2(0f, 0.5f);
			((Graphic)component).rectTransform.sizeDelta = new Vector2(width, height);
			((Transform)((Graphic)component).rectTransform).localPosition = new Vector3(left, y, -1f);
			component.font = template.GetComponent<Text>().font;
			component.fontSize = size;
			component.supportRichText = false;
			((Graphic)component).color = Color.white;
			component.alignment = (TextAnchor)3;
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)0;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private RandomizerButton TextButton(string name, string caption, float x, float y, float width, Action<FVRViveHand> handler)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: 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_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: 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)
			RandomizerButton randomizerButton = owner.CloneButton(template, popup, "Ammo " + name, compatible: false, x, y, width);
			RectTransform val = (RectTransform)((Component)randomizerButton).transform;
			Vector2 anchorMin = (val.anchorMax = Vector2.zero);
			val.anchorMin = anchorMin;
			((Transform)val).localPosition = new Vector3(x, y, -1f);
			BoxCollider component = ((Component)randomizerButton).GetComponent<BoxCollider>();
			component.size = new Vector3(component.size.x, component.size.y * 0.55f, 0.25f);
			val.sizeDelta = new Vector2(val.sizeDelta.x, val.sizeDelta.y * 0.55f);
			((Component)randomizerButton.Icon).gameObject.SetActive(false);
			randomizerButton.Rainbow = false;
			((RawImage)randomizerButton.Background).texture = (Texture)(object)Texture2D.whiteTexture;
			((Graphic)randomizerButton.Background).color = new Color(0.13f, 0.16f, 0.19f, 1f);
			randomizerButton.Ready = () => owner.CanClick(compatible: false);
			randomizerButton.Handler = handler;
			Text component2 = new GameObject("Caption", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Text)
			}).GetComponent<Text>();
			((Component)component2).gameObject.layer = template.layer;
			((Transform)((Graphic)component2).rectTransform).SetParent((Transform)(object)val, false);
			((Graphic)component2).rectTransform.anchorMin = Vector2.zero;
			((Graphic)component2).rectTransform.anchorMax = Vector2.one;
			((Graphic)component2).rectTransform.offsetMin = new Vector2(12f, 0f);
			((Graphic)component2).rectTransform.offsetMax = new Vector2(-12f, 0f);
			RectTransform rectTransform = ((Graphic)component2).rectTransform;
			((Transform)rectTransform).localPosition = ((Transform)rectTransform).localPosition + new Vector3(0f, 0f, -0.02f);
			component2.font = template.GetComponent<Text>().font;
			((Graphic)component2).color = Color.white;
			component2.alignment = (TextAnchor)4;
			((Graphic)component2).raycastTarget = false;
			randomizerButton.Caption = component2;
			component2.text = caption;
			component2.fontSize = 22;
			component2.supportRichText = false;
			component2.horizontalOverflow = (HorizontalWrapMode)0;
			component2.verticalOverflow = (VerticalWrapMode)0;
			return randomizerButton;
		}

		internal void Refresh(FVRPhysicalObject target, bool force = false)
		{
			HashSet<FireArmRoundType> hashSet = AmmoCatalog.Types(target);
			bool flag = (Object)(object)target != (Object)(object)held || !hashSet.SetEquals(types);
			if (force || flag)
			{
				if ((Object)(object)target != (Object)(object)held)
				{
					Hide();
				}
				held = target;
				types = hashSet;
				variants = AmmoCatalog.Read(types);
				if (flag)
				{
					page = 0;
				}
				Redraw();
				if ((Object)(object)held == (Object)null || variants.Count == 0)
				{
					Hide();
				}
			}
		}

		internal List<AmmoCatalog.Variant> EnabledVariants()
		{
			Refresh(held, force: true);
			List<AmmoCatalog.Variant> list = new List<AmmoCatalog.Variant>();
			foreach (AmmoCatalog.Variant variant in variants)
			{
				if (AmmoSelection.Shared.Includes(variant.Key))
				{
					list.Add(variant);
				}
			}
			return list;
		}

		private void SetOpen(bool open)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			((Component)popup).gameObject.SetActive(open);
			((Transform)((Graphic)toggleButton.Icon).rectTransform).localRotation = Quaternion.Euler(0f, 0f, open ? 180f : 0f);
		}

		internal void Hide()
		{
			SetOpen(open: false);
		}

		internal void Update()
		{
			if (revision != AmmoSelection.Shared.Revision)
			{
				Redraw();
			}
			if (!IsOpen)
			{
				return;
			}
			string text = "Choose which ammo variants to include.";
			for (int i = 0; i < rows.Count; i++)
			{
				int num = page * 7 + i;
				if (num < variants.Count && rows[i].Hovered && !string.IsNullOrEmpty(variants[num].Properties))
				{
					text = variants[num].Name + ": " + variants[num].Properties;
				}
			}
			hint.text = text;
		}

		private void Toggle(int slot)
		{
			int num = page * 7 + slot;
			if (num >= 0 && num < variants.Count)
			{
				AmmoCatalog.Variant variant = variants[num];
				AmmoSelection.Shared.Set(variant.Key, !AmmoSelection.Shared.Includes(variant.Key));
				Redraw();
			}
		}

		private void SetAll(bool include)
		{
			foreach (AmmoCatalog.Variant variant in variants)
			{
				AmmoSelection.Shared.Set(variant.Key, include);
			}
			Redraw();
		}

		private void Redraw()
		{
			revision = AmmoSelection.Shared.Revision;
			enabledCount = 0;
			foreach (AmmoCatalog.Variant variant2 in variants)
			{
				if (AmmoSelection.Shared.Includes(variant2.Key))
				{
					enabledCount++;
				}
			}
			int num = Math.Max(1, (variants.Count + 7 - 1) / 7);
			page = Math.Max(0, Math.Min(page, num - 1));
			title.text = ((types.Count == 1 && variants.Count > 0) ? variants[0].Caliber : "Compatible ammo") + "  (" + enabledCount + "/" + variants.Count + ")";
			hint.text = "Choose which ammo variants to include.";
			for (int i = 0; i < rows.Count; i++)
			{
				int num2 = page * 7 + i;
				((Component)rows[i]).gameObject.SetActive(num2 < variants.Count);
				if (num2 < variants.Count)
				{
					AmmoCatalog.Variant variant = variants[num2];
					rows[i].Caption.text = (AmmoSelection.Shared.Includes(variant.Key) ? " [x] " : " [ ] ") + ((types.Count > 1) ? (variant.Caliber + " - ") : "") + variant.Name;
				}
			}
			((Component)previous).gameObject.SetActive(page > 0);
			((Component)next).gameObject.SetActive(page + 1 < num);
			pageText.text = page + 1 + " / " + num;
		}
	}
	internal sealed class AmmoSelection
	{
		internal static readonly AmmoSelection Shared = new AmmoSelection();

		private readonly HashSet<string> excluded = new HashSet<string>(StringComparer.Ordinal);

		internal int Revision { get; private set; }

		internal static string Key(int caliber, int variant)
		{
			return caliber + ":" + variant;
		}

		internal bool Includes(string key)
		{
			return !excluded.Contains(key);
		}

		internal void Set(string key, bool include)
		{
			if (include ? excluded.Remove(key) : excluded.Add(key))
			{
				int revision = Revision + 1;
				Revision = revision;
			}
		}
	}
	internal static class AmmoSpawnerEntries
	{
		private static readonly FieldInfo Registry = AccessTools.Field(typeof(IM), "SpawnerIDDic");

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

		internal static ItemSpawnerID Get(FVRObject source, string caliber, string variant)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null || string.IsNullOrEmpty(source.ItemID) || (int)source.Category != 4 || IM.OD == null || !IM.OD.ContainsKey(source.ItemID) || (object)Registry == null || (Object)(object)ManagerSingleton<IM>.Instance == (Object)null)
			{
				return null;
			}
			string text = "Gundomizer.Ammo/" + source.ItemID;
			Dictionary<string, ItemSpawnerID> dictionary = (Dictionary<string, ItemSpawnerID>)Registry.GetValue(ManagerSingleton<IM>.Instance);
			ItemSpawnerID value2;
			if (dictionary.TryGetValue(text, out var value))
			{
				if (!owned.TryGetValue(text, out value2) || (Object)(object)value2 != (Object)(object)value)
				{
					return null;
				}
			}
			else
			{
				value2 = ScriptableObject.CreateInstance<ItemSpawnerID>();
				((Object)value2).name = text;
				value2.ItemID = text;
				value2.Category = (EItemCategory)11;
				value2.SubCategory = (ESubCategory)0;
				value2.Secondaries = (ItemSpawnerID[])(object)new ItemSpawnerID[0];
				value2.Secondaries_ByStringID = new List<string>();
				value2.TutorialBlocks = new List<string>();
				value2.IsDisplayedInMainEntry = false;
				owned[text] = value2;
				dictionary.Add(text, value2);
			}
			value2.MainObject = source;
			value2.DisplayName = caliber + " — " + variant;
			return value2;
		}

		internal static bool Owns(ItemSpawnerID entry)
		{
			if ((Object)(object)entry != (Object)null && owned.TryGetValue(entry.ItemID, out var value))
			{
				return (Object)(object)entry == (Object)(object)value;
			}
			return false;
		}

		internal static void Clear()
		{
			IM instance = ManagerSingleton<IM>.Instance;
			Dictionary<string, ItemSpawnerID> dictionary = (((Object)(object)instance == (Object)null || (object)Registry == null) ? null : (Registry.GetValue(instance) as Dictionary<string, ItemSpawnerID>));
			foreach (KeyValuePair<string, ItemSpawnerID> item in owned)
			{
				if (dictionary != null && dictionary.TryGetValue(item.Key, out var value) && (Object)(object)value == (Object)(object)item.Value)
				{
					dictionary.Remove(item.Key);
				}
				Object.Destroy((Object)(object)item.Value);
			}
			owned.Clear();
		}
	}
	internal static class AssetAccess
	{
		private static readonly FieldInfo Loading = AccessTools.Field(typeof(AnvilAsset), "m_loadingState");

		private static AnvilCallback<GameObject> outstanding;

		internal static bool LoadPending
		{
			get
			{
				if (outstanding != null)
				{
					return !((AnvilCallbackBase)outstanding).IsCompleted;
				}
				return false;
			}
		}

		internal static AnvilCallback<GameObject> Cached(FVRObject obj)
		{
			if (!((Object)(object)obj == (Object)null) && (object)Loading != null)
			{
				return Loading.GetValue(obj) as AnvilCallback<GameObject>;
			}
			return null;
		}

		internal static GameObject Peek(FVRObject obj)
		{
			AnvilCallback<GameObject> val = Cached(obj);
			if (val == null || !((AnvilCallbackBase)val).IsCompleted)
			{
				return null;
			}
			return val.Result;
		}

		internal static bool TryRequest(FVRObject obj, out AnvilCallback<GameObject> request, out bool started)
		{
			request = Cached(obj);
			started = false;
			if (request != null)
			{
				return true;
			}
			if (LoadPending)
			{
				return false;
			}
			request = ((AnvilAsset)obj).GetGameObjectAsync();
			started = true;
			outstanding = request;
			return true;
		}
	}
	public sealed class ButtonIcon : MaskableGraphic
	{
		internal bool Compatible;

		internal bool Ammo;

		internal bool Dropdown;

		protected override void OnPopulateMesh(VertexHelper mesh)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			mesh.Clear();
			Rect pixelAdjustedRect = ((Graphic)this).GetPixelAdjustedRect();
			float num = Mathf.Min(((Rect)(ref pixelAdjustedRect)).width / 100f, ((Rect)(ref pixelAdjustedRect)).height / 100f);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(((Rect)(ref pixelAdjustedRect)).center.x - 100f * num * 0.5f, ((Rect)(ref pixelAdjustedRect)).center.y + 50f * num);
			IconShape[] array = (Ammo ? IconGeometry.Cartridge : (Dropdown ? IconGeometry.Chevron : (Compatible ? IconGeometry.Link : IconGeometry.Dice)));
			foreach (IconShape iconShape in array)
			{
				int currentVertCount = mesh.currentVertCount;
				Color val2 = (Color)(iconShape.Cutout ? new Color(0.055f, 0.065f, 0.08f, ((Graphic)this).color.a) : ((Graphic)this).color);
				for (int j = 0; j < iconShape.Points.Length; j += 2)
				{
					mesh.AddVert(new Vector3(val.x + iconShape.Points[j] * num, val.y - iconShape.Points[j + 1] * num, 0f), Color32.op_Implicit(val2), Vector2.zero);
				}
				for (int k = 1; k < iconShape.Points.Length / 2 - 1; k++)
				{
					mesh.AddTriangle(currentVertCount, currentVertCount + k, currentVertCount + k + 1);
				}
			}
		}
	}
	public sealed class ButtonSurface : RawImage
	{
		internal bool RoundLeft = true;

		internal bool RoundRight = true;

		private const int Steps = 6;

		protected override void OnPopulateMesh(VertexHelper mesh)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			mesh.Clear();
			Rect pixelAdjustedRect = ((Graphic)this).GetPixelAdjustedRect();
			if (!(((Rect)(ref pixelAdjustedRect)).width <= 2f) && !(((Rect)(ref pixelAdjustedRect)).height <= 2f))
			{
				float num = Mathf.Min(7f, Mathf.Min(((Rect)(ref pixelAdjustedRect)).width, ((Rect)(ref pixelAdjustedRect)).height) * 0.25f);
				Rect rect = default(Rect);
				((Rect)(ref rect))..ctor(((Rect)(ref pixelAdjustedRect)).x + 0.8f, ((Rect)(ref pixelAdjustedRect)).y + 0.8f, ((Rect)(ref pixelAdjustedRect)).width - 1.6f, ((Rect)(ref pixelAdjustedRect)).height - 1.6f);
				AddVertex(mesh, ((Rect)(ref pixelAdjustedRect)).center, pixelAdjustedRect, edge: false);
				int num2 = 28;
				for (int i = 0; i < num2; i++)
				{
					AddVertex(mesh, Outline(rect, num - 0.8f, i), pixelAdjustedRect, edge: false);
					AddVertex(mesh, Outline(pixelAdjustedRect, num, i), pixelAdjustedRect, edge: true);
				}
				for (int j = 0; j < num2; j++)
				{
					int num3 = 1 + j * 2;
					int num4 = 1 + (j + 1) % num2 * 2;
					mesh.AddTriangle(0, num3, num4);
					mesh.AddTriangle(num3, num3 + 1, num4 + 1);
					mesh.AddTriangle(num3, num4 + 1, num4);
				}
			}
		}

		private Vector2 Outline(Rect rect, float radius, int index)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			int num = index / 7;
			bool flag = num < 2;
			bool flag2 = num == 0 || num == 3;
			if (!(flag ? RoundRight : RoundLeft))
			{
				radius = 0f;
			}
			Vector2 val = new Vector2(flag ? (((Rect)(ref rect)).xMax - radius) : (((Rect)(ref rect)).xMin + radius), flag2 ? (((Rect)(ref rect)).yMax - radius) : (((Rect)(ref rect)).yMin + radius));
			float num2 = (90f - (float)num * 90f - (float)(index % 7) * 90f / 6f) * ((float)Math.PI / 180f);
			return val + new Vector2(Mathf.Cos(num2), Mathf.Sin(num2)) * radius;
		}

		private void AddVertex(VertexHelper mesh, Vector2 point, Rect rect, bool edge)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.InverseLerp(((Rect)(ref rect)).yMin, ((Rect)(ref rect)).yMax, point.y);
			float num2 = (edge ? Mathf.Lerp(0.5f, 1.18f, num) : Mathf.Lerp(0.76f, 1f, num));
			Color val = default(Color);
			((Color)(ref val))..ctor(((Graphic)this).color.r * num2, ((Graphic)this).color.g * num2, ((Graphic)this).color.b * num2, ((Graphic)this).color.a);
			Rect uvRect = ((RawImage)this).uvRect;
			float x = ((Rect)(ref uvRect)).x;
			float num3 = (point.x - ((Rect)(ref rect)).xMin) / ((Rect)(ref rect)).width;
			uvRect = ((RawImage)this).uvRect;
			float num4 = x + num3 * ((Rect)(ref uvRect)).width;
			uvRect = ((RawImage)this).uvRect;
			float y = ((Rect)(ref uvRect)).y;
			uvRect = ((RawImage)this).uvRect;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(num4, y + num * ((Rect)(ref uvRect)).height);
			mesh.AddVert(new Vector3(point.x, point.y, 0f), Color32.op_Implicit(val), val2);
		}
	}
	internal static class Compatibility
	{
		internal sealed class Query
		{
			private readonly FVRPhysicalObject target;

			private readonly List<FVRPhysicalObject> objects;

			private readonly List<FVRFireArmAttachmentMount> mounts;

			private readonly List<FVRFireArmReloadTriggerWell> magazineWells = new List<FVRFireArmReloadTriggerWell>();

			private readonly List<FVRFireArmClipTriggerWell> clipWells = new List<FVRFireArmClipTriggerWell>();

			private readonly CompatibilityRequirements requirements = new CompatibilityRequirements();

			private readonly HashSet<int> mountTypes = new HashSet<int>();

			private readonly CompatibleSelection selection;

			internal readonly string Signature;

			internal Query(FVRPhysicalObject held, CompatibleSelection selection = null)
			{
				//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ef: Expected I4, but got Unknown
				//IL_0145: Unknown result type (might be due to invalid IL or missing references)
				//IL_014f: Expected I4, but got Unknown
				//IL_0119: Unknown result type (might be due to invalid IL or missing references)
				//IL_0123: Expected I4, but got Unknown
				//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c1: Expected I4, but got Unknown
				//IL_0312: Unknown result type (might be due to invalid IL or missing references)
				//IL_031c: Expected I4, but got Unknown
				//IL_033a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0344: Expected I4, but got Unknown
				this.selection = selection;
				if ((Object)(object)held == (Object)null)
				{
					throw new ArgumentNullException("held");
				}
				target = held;
				objects = new List<FVRPhysicalObject>(Objects(held));
				mounts = new List<FVRFireArmAttachmentMount>(Mounts(held, objects));
				requirements.HasMount = mounts.Count > 0;
				FVRFireArmReloadTriggerWell[] componentsInChildren = ((Component)held).GetComponentsInChildren<FVRFireArmReloadTriggerWell>(true);
				foreach (FVRFireArmReloadTriggerWell val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null) && BelongsTo(((Component)val).transform, held))
					{
						magazineWells.Add(val);
						if (val.UsesTypeOverride)
						{
							requirements.MagazineTypes.Add((int)val.TypeOverride);
						}
						else if (val.IsAttachableWell && (Object)(object)val.AFireArm != (Object)null)
						{
							requirements.MagazineTypes.Add((int)val.AFireArm.MagazineType);
						}
						else if ((Object)(object)val.FireArm != (Object)null)
						{
							requirements.MagazineTypes.Add((int)val.FireArm.MagazineType);
						}
					}
				}
				FVRFireArmClipTriggerWell[] componentsInChildren2 = ((Component)held).GetComponentsInChildren<FVRFireArmClipTriggerWell>(true);
				foreach (FVRFireArmClipTriggerWell val2 in componentsInChildren2)
				{
					if (!((Object)(object)val2 == (Object)null) && BelongsTo(((Component)val2).transform, held))
					{
						clipWells.Add(val2);
						if ((Object)(object)val2.FireArm != (Object)null)
						{
							requirements.ClipTypes.Add((int)val2.FireArm.ClipType);
						}
					}
				}
				foreach (FVRPhysicalObject @object in objects)
				{
					if (!((Object)(object)@object.ObjectWrapper != (Object)null) || @object.ObjectWrapper.CompatibleSpeedLoaders == null)
					{
						continue;
					}
					foreach (FVRObject compatibleSpeedLoader in @object.ObjectWrapper.CompatibleSpeedLoaders)
					{
						if ((Object)(object)compatibleSpeedLoader != (Object)null)
						{
							requirements.SpeedloaderIds.Add(compatibleSpeedLoader.ItemID);
						}
					}
				}
				requirements.CanMatchFirearm = held is FVRFireArmMagazine || held is FVRFireArmClip || held is Speedloader || held is FVRFireArmAttachment;
				StringBuilder stringBuilder = new StringBuilder();
				foreach (FVRPhysicalObject object2 in objects)
				{
					stringBuilder.Append(((Object)object2).GetInstanceID()).Append(',');
				}
				foreach (FVRFireArmAttachmentMount mount in mounts)
				{
					mountTypes.Add((int)mount.Type);
					stringBuilder.Append('|').Append(((Object)mount).GetInstanceID()).Append(':')
						.Append((int)mount.Type)
						.Append(':')
						.Append((mount.AttachmentsList == null) ? (-1) : mount.AttachmentsList.Count);
				}
				foreach (int magazineType in requirements.MagazineTypes)
				{
					stringBuilder.Append("m").Append(magazineType);
				}
				foreach (int clipType in requirements.ClipTypes)
				{
					stringBuilder.Append("c").Append(clipType);
				}
				foreach (string speedloaderId in requirements.SpeedloaderIds)
				{
					stringBuilder.Append("s").Append(speedloaderId).Append(';');
				}
				Signature = stringBuilder.ToString();
			}

			internal List<CompatibilityKind> AvailableKinds()
			{
				List<CompatibilityKind> list = new List<CompatibilityKind>();
				if (requirements.MagazineTypes.Count > 0)
				{
					list.Add(CompatibilityKind.Magazine);
				}
				if (mountTypes.Count > 0)
				{
					list.Add(CompatibilityKind.Attachment);
				}
				if (requirements.ClipTypes.Count > 0)
				{
					list.Add(CompatibilityKind.Clip);
				}
				if (requirements.SpeedloaderIds.Count > 0)
				{
					list.Add(CompatibilityKind.Speedloader);
				}
				if (requirements.CanMatchFirearm)
				{
					list.Add(CompatibilityKind.Firearm);
				}
				return list;
			}

			internal List<int> Connectors(CompatibilityKind kind)
			{
				List<int> list = new List<int>(kind switch
				{
					CompatibilityKind.Clip => requirements.ClipTypes, 
					CompatibilityKind.Magazine => requirements.MagazineTypes, 
					CompatibilityKind.Attachment => mountTypes, 
					_ => new HashSet<int>(), 
				});
				list.Sort();
				return list;
			}

			private bool Included(CompatibilityKind kind, int? connector = null)
			{
				if (selection == null)
				{
					return true;
				}
				if (!selection.Includes(kind, connector))
				{
					return false;
				}
				if (connector.HasValue)
				{
					return true;
				}
				HashSet<int> hashSet = kind switch
				{
					CompatibilityKind.Clip => requirements.ClipTypes, 
					CompatibilityKind.Magazine => requirements.MagazineTypes, 
					CompatibilityKind.Attachment => mountTypes, 
					_ => null, 
				};
				if (hashSet == null)
				{
					return true;
				}
				foreach (int item in hashSet)
				{
					if (selection.Includes(kind, item))
					{
						return true;
					}
				}
				return false;
			}

			internal void Prefilter(List<ItemSpawnerID> candidates)
			{
				int num = 0;
				for (int i = 0; i < candidates.Count; i++)
				{
					if (CouldMatch(candidates[i], useIndex: true))
					{
						candidates[num++] = candidates[i];
					}
				}
				candidates.RemoveRange(num, candidates.Count - num);
			}

			internal bool CouldMatch(ItemSpawnerID entry, bool useIndex)
			{
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Expected I4, but got Unknown
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Expected I4, but got Unknown
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Expected I4, but got Unknown
				//IL_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c8: Expected I4, but got Unknown
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e6: Expected I4, but got Unknown
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Expected I4, but got Unknown
				//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
				//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
				//IL_021b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0225: Expected I4, but got Unknown
				//IL_020e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0218: Expected I4, but got Unknown
				//IL_023c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0242: Unknown result type (might be due to invalid IL or missing references)
				//IL_0252: Expected I4, but got Unknown
				//IL_0252: Expected I4, but got Unknown
				FVRObject val = (((Object)(object)entry == (Object)null) ? null : entry.MainObject);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				FVRPhysicalObject val2 = (useIndex ? ConnectorIndex.Find(val) : null);
				FVRFireArmAttachment val3 = (FVRFireArmAttachment)(object)((val2 is FVRFireArmAttachment) ? val2 : null);
				if ((Object)(object)val3 != (Object)null)
				{
					if (Included(CompatibilityKind.Attachment, (int)val3.Type))
					{
						return mountTypes.Contains((int)val3.Type);
					}
					return false;
				}
				FVRFireArmMagazine val4 = (FVRFireArmMagazine)(object)((val2 is FVRFireArmMagazine) ? val2 : null);
				if ((Object)(object)val4 != (Object)null)
				{
					if (Included(CompatibilityKind.Magazine, (int)val4.MagazineType) && !val4.IsIntegrated)
					{
						return requirements.MagazineTypes.Contains((int)val4.MagazineType);
					}
					return false;
				}
				FVRFireArmClip val5 = (FVRFireArmClip)(object)((val2 is FVRFireArmClip) ? val2 : null);
				if ((Object)(object)val5 != (Object)null)
				{
					if (Included(CompatibilityKind.Clip, (int)val5.ClipType))
					{
						return requirements.ClipTypes.Contains((int)val5.ClipType);
					}
					return false;
				}
				if (val2 is FVRFireArm)
				{
					if (Included(CompatibilityKind.Firearm))
					{
						return requirements.CanMatchFirearm;
					}
					return false;
				}
				ConnectorFacts connectorFacts = ((useIndex && (Object)(object)val2 == (Object)null) ? PersistentConnectorIndex.Find(val) : null);
				if (connectorFacts != null)
				{
					if (connectorFacts.Kind == ConnectorKind.Attachment)
					{
						if (Included(CompatibilityKind.Attachment, connectorFacts.Connector))
						{
							return mountTypes.Contains(connectorFacts.Connector);
						}
						return false;
					}
					if (connectorFacts.Kind == ConnectorKind.Magazine)
					{
						if (Included(CompatibilityKind.Magazine, connectorFacts.Connector) && !connectorFacts.Integrated)
						{
							return requirements.MagazineTypes.Contains(connectorFacts.Connector);
						}
						return false;
					}
					if (connectorFacts.Kind == ConnectorKind.Clip)
					{
						if (Included(CompatibilityKind.Clip, connectorFacts.Connector))
						{
							return requirements.ClipTypes.Contains(connectorFacts.Connector);
						}
						return false;
					}
				}
				CompatibilityKind compatibilityKind = Kind(val);
				int? connector = ((compatibilityKind == CompatibilityKind.Magazine && (int)val.MagazineType != 0) ? new int?((int)val.MagazineType) : ((compatibilityKind == CompatibilityKind.Clip && (int)val.ClipType != 0) ? new int?((int)val.ClipType) : ((int?)null)));
				if (Included(compatibilityKind, connector))
				{
					return requirements.CouldMatch(compatibilityKind, (int)val.MagazineType, (int)val.ClipType, val.ItemID);
				}
				return false;
			}

			internal bool Matches(GameObject candidate)
			{
				if ((Object)(object)target == (Object)null || (Object)(object)candidate == (Object)null)
				{
					return false;
				}
				FVRPhysicalObject component = candidate.GetComponent<FVRPhysicalObject>();
				if ((Object)(object)component == (Object)null)
				{
					return false;
				}
				if (FitsOnto(component))
				{
					return true;
				}
				if (Included(CompatibilityKind.Firearm) && requirements.CanMatchFirearm && component is FVRFireArm)
				{
					return Capture(component).FitsOnto(target);
				}
				return false;
			}

			private bool FitsOnto(FVRPhysicalObject candidate)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Expected I4, but got Unknown
				//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Expected I4, but got Unknown
				//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d6: Expected I4, but got Unknown
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_0220: Unknown result type (might be due to invalid IL or missing references)
				//IL_022e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0234: Unknown result type (might be due to invalid IL or missing references)
				//IL_0142: 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_014a: Unknown result type (might be due to invalid IL or missing references)
				//IL_015b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0139: Unknown result type (might be due to invalid IL or missing references)
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				//IL_0190: Expected I4, but got Unknown
				//IL_0190: Expected I4, but got Unknown
				FVRFireArmAttachment val = (FVRFireArmAttachment)(object)((candidate is FVRFireArmAttachment) ? candidate : null);
				if ((Object)(object)val != (Object)null && Included(CompatibilityKind.Attachment, (int)val.Type))
				{
					if (!val.CanAttach())
					{
						return false;
					}
					foreach (FVRFireArmAttachmentMount mount in mounts)
					{
						if ((Object)(object)mount != (Object)null && mount.Type == val.Type && mount.isMountableOn(val))
						{
							return true;
						}
					}
				}
				FVRFireArmMagazine val2 = (FVRFireArmMagazine)(object)((candidate is FVRFireArmMagazine) ? candidate : null);
				if ((Object)(object)val2 != (Object)null && Included(CompatibilityKind.Magazine, (int)val2.MagazineType))
				{
					if ((Object)(object)((Component)candidate).GetComponentInChildren<FVRFireArmReloadTriggerMag>(true) == (Object)null)
					{
						return false;
					}
					foreach (FVRFireArmReloadTriggerWell magazineWell in magazineWells)
					{
						if ((Object)(object)magazineWell == (Object)null)
						{
							continue;
						}
						FVRFireArm fireArm = magazineWell.FireArm;
						AttachableFirearm aFireArm = magazineWell.AFireArm;
						if (!(magazineWell.IsAttachableWell ? ((Object)(object)aFireArm == (Object)null) : ((Object)(object)fireArm == (Object)null)))
						{
							FireArmMagazineType val3 = (magazineWell.UsesTypeOverride ? magazineWell.TypeOverride : (magazineWell.IsAttachableWell ? aFireArm.MagazineType : fireArm.MagazineType));
							if (SelectionPolicy.MagazineFits((int)val2.MagazineType, val2.IsIntegrated, val2.IsBeltBox, (int)val3, magazineWell.IsAttachableWell || magazineWell.UsesSecondaryMagSlots, magazineWell.IsBeltBox, (Object)(object)fireArm != (Object)null && fireArm.HasBelt))
							{
								return true;
							}
						}
					}
				}
				FVRFireArmClip val4 = (FVRFireArmClip)(object)((candidate is FVRFireArmClip) ? candidate : null);
				if ((Object)(object)val4 != (Object)null && Included(CompatibilityKind.Clip, (int)val4.ClipType))
				{
					if ((Object)(object)((Component)candidate).GetComponentInChildren<FVRFireArmClipTriggerClip>(true) == (Object)null)
					{
						return false;
					}
					foreach (FVRFireArmClipTriggerWell clipWell in clipWells)
					{
						if ((Object)(object)clipWell != (Object)null && (Object)(object)clipWell.FireArm != (Object)null && (int)val4.ClipType != 0 && clipWell.FireArm.ClipType == val4.ClipType)
						{
							return true;
						}
					}
				}
				Speedloader val5 = (Speedloader)(object)((candidate is Speedloader) ? candidate : null);
				if ((Object)(object)val5 != (Object)null && Included(CompatibilityKind.Speedloader))
				{
					foreach (FVRPhysicalObject @object in objects)
					{
						if ((Object)(object)@object != (Object)null && Contains(((Object)(object)@object.ObjectWrapper == (Object)null) ? null : @object.ObjectWrapper.CompatibleSpeedLoaders, candidate.ObjectWrapper) && LoaderRoundMatches(val5, @object))
						{
							return true;
						}
					}
				}
				return false;
			}
		}

		internal static FVRPhysicalObject HeldItem(FVRViveHand pointingHand = null)
		{
			if ((Object)(object)pointingHand != (Object)null)
			{
				if (!((Object)(object)pointingHand.OtherHand == (Object)null))
				{
					return Resolve(pointingHand.OtherHand.CurrentInteractable);
				}
				return null;
			}
			if ((Object)(object)GM.CurrentMovementManager == (Object)null || GM.CurrentMovementManager.Hands == null)
			{
				return null;
			}
			FVRPhysicalObject val = null;
			FVRViveHand[] hands = GM.CurrentMovementManager.Hands;
			foreach (FVRViveHand val2 in hands)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				FVRPhysicalObject val3 = Resolve(val2.CurrentInteractable);
				if (!((Object)(object)val3 == (Object)null))
				{
					if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)val3)
					{
						return null;
					}
					val = val3;
				}
			}
			return val;
		}

		private static FVRPhysicalObject Resolve(FVRInteractiveObject item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return null;
			}
			return (FVRPhysicalObject)(((object)((item is FVRPhysicalObject) ? item : null)) ?? ((object)((Component)item).GetComponentInParent<FVRPhysicalObject>()));
		}

		internal static string Name(FVRPhysicalObject item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return "none";
			}
			if (!((Object)(object)item.ObjectWrapper != (Object)null) || string.IsNullOrEmpty(item.ObjectWrapper.DisplayName))
			{
				return ((Object)item).name.Replace("(Clone)", "").Trim();
			}
			return item.ObjectWrapper.DisplayName;
		}

		private static CompatibilityKind Kind(FVRObject candidate)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			if ((Object)(object)candidate == (Object)null)
			{
				return CompatibilityKind.Unsupported;
			}
			ObjectCategory category = candidate.Category;
			return (category - 1) switch
			{
				0 => CompatibilityKind.Firearm, 
				4 => CompatibilityKind.Attachment, 
				1 => CompatibilityKind.Magazine, 
				2 => CompatibilityKind.Clip, 
				5 => CompatibilityKind.Speedloader, 
				_ => CompatibilityKind.Unsupported, 
			};
		}

		internal static Query Capture(FVRPhysicalObject held)
		{
			return new Query(held);
		}

		internal static Query CaptureFiltered(FVRPhysicalObject held, CompatibleSelection selection)
		{
			return new Query(held, selection);
		}

		internal static bool Matches(FVRPhysicalObject held, GameObject candidate)
		{
			if ((Object)(object)held != (Object)null && (Object)(object)candidate != (Object)null)
			{
				return Capture(held).Matches(candidate);
			}
			return false;
		}

		private static bool LoaderRoundMatches(Speedloader loader, FVRPhysicalObject target)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (loader.Chambers == null || loader.Chambers.Count == 0)
			{
				return false;
			}
			FVRFireArm val = (FVRFireArm)(object)((target is FVRFireArm) ? target : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			foreach (SpeedloaderChamber chamber in loader.Chambers)
			{
				if ((Object)(object)chamber == (Object)null || chamber.Type != val.RoundType)
				{
					return false;
				}
			}
			return true;
		}

		private static bool Contains(List<FVRObject> objects, FVRObject item)
		{
			if (objects == null || (Object)(object)item == (Object)null)
			{
				return false;
			}
			foreach (FVRObject @object in objects)
			{
				if ((Object)(object)@object != (Object)null && ((Object)(object)@object == (Object)(object)item || @object.ItemID == item.ItemID))
				{
					return true;
				}
			}
			return false;
		}

		internal static IEnumerable<FVRPhysicalObject> Objects(FVRPhysicalObject root)
		{
			Queue<FVRPhysicalObject> queue = new Queue<FVRPhysicalObject>();
			HashSet<FVRPhysicalObject> seen = new HashSet<FVRPhysicalObject>();
			queue.Enqueue(root);
			while (queue.Count != 0)
			{
				FVRPhysicalObject obj = queue.Dequeue();
				if ((Object)(object)obj == (Object)null || !seen.Add(obj))
				{
					continue;
				}
				yield return obj;
				if (obj.Attachments != null)
				{
					foreach (FVRFireArmAttachment attachment in obj.Attachments)
					{
						if ((Object)(object)attachment != (Object)null)
						{
							queue.Enqueue((FVRPhysicalObject)(object)attachment);
						}
					}
				}
				if (obj.AttachmentMounts == null)
				{
					continue;
				}
				foreach (FVRFireArmAttachmentMount attachmentMount in obj.AttachmentMounts)
				{
					if (!((Object)(object)attachmentMount != (Object)null) || attachmentMount.AttachmentsList == null)
					{
						continue;
					}
					foreach (FVRFireArmAttachment attachments in attachmentMount.AttachmentsList)
					{
						if ((Object)(object)attachments != (Object)null)
						{
							queue.Enqueue((FVRPhysicalObject)(object)attachments);
						}
					}
				}
			}
		}

		private static IEnumerable<FVRFireArmAttachmentMount> Mounts(FVRPhysicalObject root, IEnumerable<FVRPhysicalObject> objects)
		{
			Queue<FVRFireArmAttachmentMount> queue = new Queue<FVRFireArmAttachmentMount>();
			HashSet<FVRFireArmAttachmentMount> seen = new HashSet<FVRFireArmAttachmentMount>();
			foreach (FVRPhysicalObject @object in objects)
			{
				if (@object.AttachmentMounts != null)
				{
					foreach (FVRFireArmAttachmentMount attachmentMount in @object.AttachmentMounts)
					{
						queue.Enqueue(attachmentMount);
					}
				}
				FVRFireArmAttachmentMount[] componentsInChildren = ((Component)@object).GetComponentsInChildren<FVRFireArmAttachmentMount>(true);
				foreach (FVRFireArmAttachmentMount val in componentsInChildren)
				{
					if (BelongsTo(((Component)val).transform, root))
					{
						queue.Enqueue(val);
					}
				}
			}
			while (queue.Count != 0)
			{
				FVRFireArmAttachmentMount val2 = queue.Dequeue();
				if ((Object)(object)val2 == (Object)null || !seen.Add(val2))
				{
					continue;
				}
				if (val2.SubMounts != null)
				{
					foreach (FVRFireArmAttachmentMount subMount in val2.SubMounts)
					{
						queue.Enqueue(subMount);
					}
				}
				if (val2.AttachmentsList != null)
				{
					foreach (FVRFireArmAttachment attachments in val2.AttachmentsList)
					{
						if (!((Object)(object)attachments != (Object)null) || ((FVRPhysicalObject)attachments).AttachmentMounts == null)
						{
							continue;
						}
						foreach (FVRFireArmAttachmentMount attachmentMount2 in ((FVRPhysicalObject)attachments).AttachmentMounts)
						{
							queue.Enqueue(attachmentMount2);
						}
					}
				}
				Collider component = ((Component)val2).GetComponent<Collider>();
				if (((Behaviour)val2).enabled && !((Object)(object)component == (Object)null) && component.enabled && ActiveToRoot(((Component)val2).transform, ((Component)root).transform))
				{
					yield return val2;
				}
			}
		}

		private static bool ActiveToRoot(Transform current, Transform root)
		{
			while ((Object)(object)current != (Object)null)
			{
				if (!((Component)current).gameObject.activeSelf)
				{
					return false;
				}
				if ((Object)(object)current == (Object)(object)root)
				{
					return true;
				}
				current = current.parent;
			}
			return false;
		}

		private static bool BelongsTo(Transform current, FVRPhysicalObject root)
		{
			FVRPhysicalObject componentInParent = ((Component)current).GetComponentInParent<FVRPhysicalObject>();
			if ((Object)(object)componentInParent == (Object)(object)root)
			{
				return true;
			}
			FVRFireArmAttachment val = (FVRFireArmAttachment)(object)((componentInParent is FVRFireArmAttachment) ? componentInParent : null);
			if ((Object)(object)val != (Object)null && (Object)(object)val.curMount != (Object)null)
			{
				return (Object)(object)val.GetRootObject() == (Object)(object)root;
			}
			return false;
		}
	}
	internal enum CompatibilityKind
	{
		Unsupported,
		Firearm,
		Attachment,
		Magazine,
		Clip,
		Speedloader
	}
	internal sealed class CompatibilityRequirements
	{
		internal readonly HashSet<int> MagazineTypes = new HashSet<int>();

		internal readonly HashSet<int> ClipTypes = new HashSet<int>();

		internal readonly HashSet<string> SpeedloaderIds = new HashSet<string>(StringComparer.Ordinal);

		internal bool HasMount;

		internal bool CanMatchFirearm;

		internal bool CouldMatch(CompatibilityKind kind, int magazineType, int clipType, string itemId)
		{
			switch (kind)
			{
			case CompatibilityKind.Attachment:
				return HasMount;
			case CompatibilityKind.Magazine:
				if (MagazineTypes.Count > 0)
				{
					if (magazineType != 0)
					{
						return MagazineTypes.Contains(magazineType);
					}
					return true;
				}
				return false;
			case CompatibilityKind.Clip:
				if (ClipTypes.Count > 0)
				{
					if (clipType != 0)
					{
						return ClipTypes.Contains(clipType);
					}
					return true;
				}
				return false;
			case CompatibilityKind.Speedloader:
				if (itemId != null)
				{
					return SpeedloaderIds.Contains(itemId);
				}
				return false;
			case CompatibilityKind.Firearm:
				return CanMatchFirearm;
			default:
				return false;
			}
		}
	}
	internal sealed class CompatiblePanel
	{
		internal const float ToggleWidth = 60f;

		private const float Width = 1200f;

		private const float Height = 1050f;

		private const int PageSize = 4;

		private readonly RandomizerController owner;

		private readonly GameObject template;

		private readonly RectTransform popup;

		private readonly RandomizerButton toggle;

		private readonly RandomizerButton section;

		private readonly RandomizerButton all;

		private readonly RandomizerButton previous;

		private readonly RandomizerButton next;

		private readonly List<RandomizerButton> kinds = new List<RandomizerButton>();

		private readonly List<RandomizerButton> rows = new List<RandomizerButton>();

		private readonly Text heldLabel;

		private readonly Text hint;

		private readonly Text connectorLabel;

		private readonly Text summary;

		private readonly Text pageLabel;

		private readonly List<KeyValuePair<CompatibilityKind, int>> connectors = new List<KeyValuePair<CompatibilityKind, int>>();

		private readonly Dictionary<Transform, Vector3> topPositions = new Dictionary<Transform, Vector3>();

		private List<CompatibilityKind> available = new List<CompatibilityKind>();

		private Compatibility.Query query;

		private FVRPhysicalObject held;

		private string signature;

		private string displayedScope;

		private int page;

		private int revision = -1;

		internal bool IsOpen => ((Component)popup).gameObject.activeSelf;

		internal bool HasChoices { get; private set; }

		internal string ScopeDescription
		{
			get
			{
				if (!CompatibleSelection.Shared.AllItems)
				{
					return owner.ScopeDescription;
				}
				return "across all items";
			}
		}

		internal string Tooltip
		{
			get
			{
				if (!toggle.Hovered)
				{
					return null;
				}
				return "Choose compatible item types and search scope for " + Compatibility.Name(held);
			}
		}

		internal CompatiblePanel(RandomizerController owner, RectTransform root, GameObject template, RandomizerButton roll, float left, float y)
		{
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Expected O, but got Unknown
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0774: Unknown result type (might be due to invalid IL or missing references)
			//IL_077b: Expected O, but got Unknown
			//IL_07d5: Unknown result type (might be due to invalid IL or missing references)
			CompatiblePanel compatiblePanel = this;
			this.owner = owner;
			this.template = template;
			toggle = owner.CloneButton(template, root, "Compatible choices", compatible: false, left + 30f, y, 60f);
			toggle.Icon.Dropdown = true;
			((Graphic)toggle.Icon).SetVerticesDirty();
			toggle.Rainbow = false;
			toggle.NeedsHeldContext = true;
			toggle.Ready = () => owner.CanClick(compatible: true);
			toggle.Handler = delegate
			{
				if (compatiblePanel.IsOpen)
				{
					compatiblePanel.Hide();
				}
				else
				{
					owner.CloseChoices(openingAmmo: false);
					compatiblePanel.SetOpen(open: true);
					compatiblePanel.Redraw();
				}
			};
			roll.Ready = () => owner.CanClick(compatible: true) && compatiblePanel.HasChoices;
			roll.Background.RoundRight = false;
			toggle.Background.RoundLeft = false;
			RectTransform rectTransform = ((Graphic)roll.Background).rectTransform;
			rectTransform.offsetMax = new Vector2(0f, rectTransform.offsetMax.y);
			rectTransform = ((Graphic)toggle.Background).rectTransform;
			rectTransform.offsetMin = new Vector2(0f, rectTransform.offsetMin.y);
			Image component = new GameObject("Group separator", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			}).GetComponent<Image>();
			((Component)component).gameObject.layer = template.layer;
			((Transform)((Graphic)component).rectTransform).SetParent(((Component)toggle).transform, false);
			((Graphic)component).rectTransform.anchorMin = Vector2.zero;
			((Graphic)component).rectTransform.anchorMax = new Vector2(0f, 1f);
			((Graphic)component).rectTransform.offsetMin = new Vector2(0f, 4f);
			((Graphic)component).rectTransform.offsetMax = new Vector2(0.75f, -4f);
			RectTransform rectTransform2 = ((Graphic)component).rectTransform;
			((Transform)rectTransform2).localPosition = ((Transform)rectTransform2).localPosition + new Vector3(0f, 0f, -0.015f);
			((Graphic)component).color = new Color(0.65f, 0.68f, 0.7f, 0.6f);
			((Graphic)component).raycastTarget = false;
			popup = (RectTransform)new GameObject("Gundomizer Compatible Choices", new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(BoxCollider),
				typeof(FVRPointable)
			}).transform;
			((Component)popup).gameObject.layer = template.layer;
			((Transform)popup).SetParent((Transform)(object)root, false);
			RectTransform obj = popup;
			RectTransform obj2 = popup;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			obj2.anchorMax = val;
			obj.anchorMin = val;
			popup.pivot = Vector2.zero;
			popup.sizeDelta = new Vector2(1200f, 1050f);
			RectTransform obj3 = popup;
			Rect rect = ((RectTransform)((Component)roll).transform).rect;
			((Transform)obj3).localPosition = new Vector3(left - ((Rect)(ref rect)).width * Mathf.Abs(((Component)roll).transform.localScale.x), y + 95f, -8f);
			((Graphic)((Component)popup).GetComponent<Image>()).color = new Color(0.025f, 0.03f, 0.04f, 1f);
			BoxCollider component2 = ((Component)popup).GetComponent<BoxCollider>();
			component2.center = new Vector3(600f, 525f, 2f);
			component2.size = new Vector3(1200f, 1050f, 1f);
			((Component)popup).GetComponent<FVRPointable>().MaxPointingRange = ((FVRPointable)roll).MaxPointingRange;
			Label("Title", "Compatible choices", 32f, 990f, 1000f, 70f, 46);
			Button("Close", "X", 1125f, 990f, 90f, delegate
			{
				compatiblePanel.Hide();
			});
			heldLabel = Label("Held", "", 32f, 930f, 1136f, 60f, 34);
			section = Button("Section", "Current section", 305f, 850f, 545f, delegate
			{
				compatiblePanel.SetScope(value: false);
			});
			all = Button("All items", "All items", 895f, 850f, 545f, delegate
			{
				compatiblePanel.SetScope(value: true);
			});
			hint = Label("Scope hint", "", 32f, 790f, 1136f, 65f, 30);
			Label("Include", "Include", 32f, 735f, 1136f, 50f, 34);
			for (int num = 0; num < 5; num++)
			{
				int slot = num;
				kinds.Add(Button("Kind " + num, "", 305 + num % 2 * 590, 675 - num / 2 * 78, 545f, delegate
				{
					compatiblePanel.ToggleKind(slot);
				}));
			}
			connectorLabel = Label("Connectors", "Connector choices", 32f, 430f, 1136f, 50f, 34);
			for (int num2 = 0; num2 < 4; num2++)
			{
				int slot2 = num2;
				RandomizerButton randomizerButton = Button("Connector " + num2, "", 600f, 360 - num2 * 75, 1136f, delegate
				{
					compatiblePanel.ToggleConnector(slot2);
				});
				randomizerButton.Caption.alignment = (TextAnchor)3;
				rows.Add(randomizerButton);
			}
			previous = Button("Previous", "<", 780f, 95f, 140f, delegate
			{
				compatiblePanel.page--;
				compatiblePanel.Redraw();
			});
			next = Button("Next", ">", 1090f, 95f, 140f, delegate
			{
				compatiblePanel.page++;
				compatiblePanel.Redraw();
			});
			pageLabel = Label("Page", "", 860f, 95f, 160f, 60f, 32);
			pageLabel.alignment = (TextAnchor)4;
			summary = Label("Summary", "", 32f, 38f, 1136f, 62f, 29);
			foreach (Transform item in (Transform)popup)
			{
				Transform val2 = item;
				if ((Object)(object)val2 != (Object)(object)((Component)summary).transform && (Object)(object)val2 != (Object)(object)((Component)previous).transform && (Object)(object)val2 != (Object)(object)((Component)next).transform && (Object)(object)val2 != (Object)(object)((Component)pageLabel).transform)
				{
					topPositions.Add(val2, val2.localPosition);
				}
			}
			Hide();
		}

		internal void Refresh(FVRPhysicalObject target)
		{
			Compatibility.Query query = (((Object)(object)target == (Object)null) ? null : Compatibility.Capture(target));
			if (!((Object)(object)target == (Object)(object)held) || !(signature == query?.Signature))
			{
				if ((Object)(object)target != (Object)(object)held)
				{
					Hide();
				}
				held = target;
				this.query = query;
				signature = query?.Signature;
				page = 0;
				available = ((this.query == null) ? new List<CompatibilityKind>() : this.query.AvailableKinds());
				Redraw();
			}
		}

		internal void Update()
		{
			if (revision != CompatibleSelection.Shared.Revision || displayedScope != ScopeDescription)
			{
				Redraw();
			}
			section.Caption.text = (CompatibleSelection.Shared.AllItems ? "[ ] " : "[x] ") + (owner.IsTagMode ? "Current tags" : "Current section");
		}

		internal void Hide()
		{
			SetOpen(open: false);
		}

		private void SetOpen(bool open)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			((Component)popup).gameObject.SetActive(open);
			((Transform)((Graphic)toggle.Icon).rectTransform).localRotation = Quaternion.Euler(0f, 0f, (float)(open ? 180 : 0));
		}

		private void SetScope(bool value)
		{
			CompatibleSelection.Shared.SetScope(value);
			Redraw();
		}

		private void ToggleKind(int slot)
		{
			if (slot < available.Count)
			{
				CompatibilityKind kind = available[slot];
				CompatibleSelection shared = CompatibleSelection.Shared;
				shared.Set(kind, null, !shared.Includes(kind));
				page = 0;
				Redraw();
			}
		}

		private void ToggleConnector(int slot)
		{
			int num = page * 4 + slot;
			if (num < connectors.Count)
			{
				KeyValuePair<CompatibilityKind, int> keyValuePair = connectors[num];
				CompatibleSelection shared = CompatibleSelection.Shared;
				shared.Set(keyValuePair.Key, keyValuePair.Value, !shared.Includes(keyValuePair.Key, keyValuePair.Value));
				Redraw();
			}
		}

		private static string KindName(CompatibilityKind kind)
		{
			return kind switch
			{
				CompatibilityKind.Firearm => "Firearms", 
				CompatibilityKind.Speedloader => "Speedloaders", 
				_ => kind.ToString() + "s", 
			};
		}

		private static string ConnectorName(CompatibilityKind kind, int value)
		{
			string text = Enum.GetName(kind switch
			{
				CompatibilityKind.Magazine => typeof(FVRFireArmMagazine).GetField("MagazineType").FieldType, 
				CompatibilityKind.Attachment => typeof(FVRFireArmAttachment).GetField("Type").FieldType, 
				_ => typeof(FVRFireArmClip).GetField("ClipType").FieldType, 
			}, value);
			if (text == null)
			{
				return "Custom connector " + value;
			}
			if (text.StartsWith("m", StringComparison.Ordinal) && text.Length > 1 && char.IsUpper(text[1]))
			{
				text = text.Substring(1);
			}
			return Regex.Replace(text.Replace('_', ' '), "([a-z])([A-Z])", "$1 $2");
		}

		private void Redraw()
		{
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			CompatibleSelection shared = CompatibleSelection.Shared;
			revision = shared.Revision;
			displayedScope = ScopeDescription;
			heldLabel.text = "Held: " + Compatibility.Name(held);
			hint.text = (shared.AllItems ? "All categories, including modular magazines under Firearms." : "Use the spawner's current section or selected tags.");
			all.Caption.text = (shared.AllItems ? "[x] " : "[ ] ") + "All items";
			connectors.Clear();
			HasChoices = false;
			for (int i = 0; i < kinds.Count; i++)
			{
				((Component)kinds[i]).gameObject.SetActive(i < available.Count);
				if (i >= available.Count)
				{
					continue;
				}
				CompatibilityKind compatibilityKind = available[i];
				bool flag = shared.Includes(compatibilityKind);
				kinds[i].Caption.text = (flag ? "[x] " : "[ ] ") + KindName(compatibilityKind);
				if (!flag)
				{
					continue;
				}
				List<int> list = query.Connectors(compatibilityKind);
				if (list.Count == 0)
				{
					HasChoices = true;
				}
				foreach (int item in list)
				{
					connectors.Add(new KeyValuePair<CompatibilityKind, int>(compatibilityKind, item));
					if (shared.Includes(compatibilityKind, item))
					{
						HasChoices = true;
					}
				}
			}
			int num = Math.Max(1, (connectors.Count + 4 - 1) / 4);
			page = Math.Max(0, Math.Min(page, num - 1));
			int num2 = Math.Min(4, Math.Max(0, connectors.Count - page * 4));
			float num3 = (3 - (available.Count + 1) / 2) * 78 + (4 - num2) * 75;
			popup.sizeDelta = new Vector2(1200f, 1050f - num3);
			BoxCollider component = ((Component)popup).GetComponent<BoxCollider>();
			component.center = new Vector3(600f, (1050f - num3) / 2f, 2f);
			component.size = new Vector3(1200f, 1050f - num3, 1f);
			foreach (KeyValuePair<Transform, Vector3> topPosition in topPositions)
			{
				topPosition.Key.localPosition = topPosition.Value - Vector3.up * num3;
			}
			float num4 = (float)(675 - (available.Count + 1) / 2 * 78) - num3;
			((Transform)((Graphic)connectorLabel).rectTransform).localPosition = new Vector3(32f, num4, -1f);
			((Component)connectorLabel).gameObject.SetActive(connectors.Count > 0);
			for (int j = 0; j < rows.Count; j++)
			{
				int num5 = page * 4 + j;
				((Component)rows[j]).gameObject.SetActive(num5 < connectors.Count);
				if (num5 < connectors.Count)
				{
					KeyValuePair<CompatibilityKind, int> keyValuePair = connectors[num5];
					((Component)rows[j]).transform.localPosition = new Vector3(600f, num4 - 65f - (float)(j * 75), -1f);
					rows[j].Caption.text = (shared.Includes(keyValuePair.Key, keyValuePair.Value) ? " [x] " : " [ ] ") + keyValuePair.Key.ToString() + ": " + ConnectorName(keyValuePair.Key, keyValuePair.Value);
				}
			}
			((Component)previous).gameObject.SetActive(page > 0);
			((Component)next).gameObject.SetActive(page + 1 < num);
			pageLabel.text = ((num > 1) ? (page + 1 + " / " + num) : "");
			summary.text = (HasChoices ? ("Next roll: compatible items " + ScopeDescription + ".") : (((Object)(object)held == (Object)null) ? "Hold an item to see its compatible types." : "No types selected or available. Enable a type to roll."));
		}

		private Text Label(string name, string value, float x, float y, float width, float height, int size)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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)
			Text component = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Text)
			}).GetComponent<Text>();
			((Component)component).gameObject.layer = template.layer;
			((Transform)((Graphic)component).rectTransform).SetParent((Transform)(object)popup, false);
			RectTransform rectTransform = ((Graphic)component).rectTransform;
			Vector2 anchorMin = (((Graphic)component).rectTransform.anchorMax = Vector2.zero);
			rectTransform.anchorMin = anchorMin;
			((Graphic)component).rectTransform.pivot = new Vector2(0f, 0.5f);
			((Graphic)component).rectTransform.sizeDelta = new Vector2(width, height);
			((Transform)((Graphic)component).rectTransform).localPosition = new Vector3(x, y, -1f);
			component.font = template.GetComponent<Text>().font;
			component.fontSize = size;
			component.text = value;
			component.supportRichText = false;
			((Graphic)component).color = Color.white;
			component.alignment = (TextAnchor)3;
			((Graphic)component).raycastTarget = false;
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)0;
			return component;
		}

		private RandomizerButton Button(string name, string value, float x, float y, float width, Action<FVRViveHand> handler)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: 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_01be: 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)
			RandomizerButton randomizerButton = owner.CloneButton(template, popup, "Compatible " + name, compatible: false, x, y, width);
			RectTransform val = (RectTransform)((Component)randomizerButton).transform;
			Vector2 anchorMin = (val.anchorMax = Vector2.zero);
			val.anchorMin = anchorMin;
			((Transform)val).localPosition = new Vector3(x, y, -1f);
			BoxCollider component = ((Component)randomizerButton).GetComponent<BoxCollider>();
			component.size = new Vector3(component.size.x, component.size.y * 0.55f, 0.25f);
			val.sizeDelta = new Vector2(val.sizeDelta.x, val.sizeDelta.y * 0.55f);
			((Component)randomizerButton.Icon).gameObject.SetActive(false);
			randomizerButton.Rainbow = false;
			randomizerButton.Ready = () => owner.CanClick(compatible: false);
			randomizerButton.Handler = handler;
			Text component2 = new GameObject("Caption", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Text)
			}).GetComponent<Text>();
			((Component)component2).gameObject.layer = template.layer;
			((Transform)((Graphic)component2).rectTransform).SetParent((Transform)(object)val, false);
			((Graphic)component2).rectTransform.anchorMin = Vector2.zero;
			((Graphic)component2).rectTransform.anchorMax = Vector2.one;
			((Graphic)component2).rectTransform.offsetMin = new Vector2(12f, 0f);
			((Graphic)component2).rectTransform.offsetMax = new Vector2(-12f, 0f);
			RectTransform rectTransform = ((Graphic)component2).rectTransform;
			((Transform)rectTransform).localPosition = ((Transform)rectTransform).localPosition + new Vector3(0f, 0f, -0.02f);
			component2.font = template.GetComponent<Text>().font;
			component2.fontSize = 22;
			component2.text = value;
			((Graphic)component2).color = Color.white;
			component2.alignment = (TextAnchor)4;
			component2.supportRichText = false;
			((Graphic)component2).raycastTarget = false;
			component2.horizontalOverflow = (HorizontalWrapMode)0;
			component2.verticalOverflow = (VerticalWrapMode)0;
			randomizerButton.Caption = component2;
			return randomizerButton;
		}
	}
	internal sealed class CompatibleSelection
	{
		internal static readonly CompatibleSelection Shared = new CompatibleSelection();

		private readonly HashSet<string> excluded = new HashSet<string>(StringComparer.Ordinal);

		internal bool AllItems { get; private set; }

		internal int Revision { get; private set; }

		private static string Key(CompatibilityKind kind, int? connector)
		{
			return kind.ToString() + ":" + (connector.HasValue ? connector.Value.ToString() : "*");
		}

		internal bool Includes(CompatibilityKind kind, int? connector = null)
		{
			if (!excluded.Contains(Key(kind, null)))
			{
				if (connector.HasValue)
				{
					return !excluded.Contains(Key(kind, connector));
				}
				return true;
			}
			return false;
		}

		internal void Set(CompatibilityKind kind, int? connector, bool include)
		{
			if (include ? excluded.Remove(Key(kind, connector)) : excluded.Add(Key(kind, connector)))
			{
				int revision = Revision + 1;
				Revision = revision;
			}
		}

		internal void SetScope(bool allItems)
		{
			if (AllItems != allItems)
			{
				AllItems = allItems;
				int revision = Revision + 1;
				Revision = revision;
			}
		}

		internal CompatibleSelection Snapshot()
		{
			CompatibleSelection compatibleSelection = new CompatibleSelection
			{
				AllItems = AllItems,
				Revision = Revision
			};
			foreach (string item in excluded)
			{
				compatibleSelection.excluded.Add(item);
			}
			return compatibleSelection;
		}
	}
	internal static class ConnectorIndex
	{
		private sealed class Record
		{
			internal WeakReference Source;

			internal WeakReference Component;

			internal WeakReference Callback;
		}

		internal const int Capacity = 16384;

		private static readonly Dictionary<int, Record> records = new Dictionary<int, Record>();

		private static readonly Queue<int> order = new Queue<int>();

		private static bool running;

		internal static int Sweeps;

		internal static float MaxSliceMilliseconds;

		internal static int Count => records.Count;

		internal static void Observe(FVRObject source, GameObject prefab)
		{
			if ((Object)(object)source == (Object)null || (Object)(object)prefab == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)source).GetInstanceID();
			FVRPhysicalObject component = prefab.GetComponent<FVRPhysicalObject>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			PersistentConnectorIndex.Observe(source, component);
			if (records.TryGetValue(instanceID, out var value))
			{
				value.Source.Target = source;
				value.Component.Target = component;
				value.Callback.Target = AssetAccess.Cached(source);
				return;
			}
			if (records.Count >= 16384)
			{
				records.Remove(order.Dequeue());
			}
			records.Add(instanceID, new Record
			{
				Source = new WeakReference(source),
				Component = new WeakReference(component),
				Callback = new WeakReference(AssetAccess.Cached(source))
			});
			order.Enqueue(instanceID);
		}

		internal static FVRPhysicalObject Find(FVRObject source)
		{
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			GameObject val = AssetAccess.Peek(source);
			if ((Object)(object)val != (Object)null)
			{
				Observe(source, val);
			}
			if (!records.TryGetValue(((Object)source).GetInstanceID(), out var value) || (Object)/*isinst with value type is only supported in some contexts*/ != (Object)(object)source || value.Callback.Target != AssetAccess.Cached(source))
			{
				return null;
			}
			object? target = value.Component.Target;
			FVRPhysicalObject val2 = (FVRPhysicalObject)((target is FVRPhysicalObject) ? target : null);
			if (!((Object)(object)val2 == (Object)null))
			{
				return val2;
			}
			return null;
		}

		internal static void Start(MonoBehaviour host)
		{
			if (!running)
			{
				running = true;
				host.StartCoroutine(Sweep());
			}
		}

		private static IEnumerator Sweep()
		{
			try
			{
				while (true)
				{
					Dictionary<string, FVRObject> dictionary = (((Object)(object)ManagerSingleton<IM>.Instance == (Object)null) ? null : IM.OD);
					if (dictionary != null && !GM.IsAsyncLoading)
					{
						Dictionary<string, FVRObject>.ValueCollection.Enumerator entries = dictionary.Values.GetEnumerator();
						try
						{
							bool more = true;
							while (more)
							{
								float realtimeSinceStartup = Time.realtimeSinceStartup;
								int num = 0;
								do
								{
									try
									{
										more = entries.MoveNext();
									}
									catch (InvalidOperationException)
									{
										more = false;
									}
									if (!more)
									{
										break;
									}
									FVRObject current = entries.Current;
									try
									{
										Observe(current, AssetAccess.Peek(current));
									}
									catch (Exception ex2)
									{
										Plugin.Log.LogDebug((object)("Index entry unavailable: " + ex2.Message));
									}
								}
								while (++num < 32 && Time.realtimeSinceStartup - realtimeSinceStartup < 0.00075f);
								MaxSliceMilliseconds = Mathf.Max(MaxSliceMilliseconds, (Time.realtimeSinceStartup -