Decompiled source of Outward Construction Kit v0.3.1

AssetsTools.NET.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.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: TargetFramework(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]
[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) & 1u;
				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 & 1u;
				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) & 1u;
				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 & 1u;
				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 & 1u;
				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 & 1u;
				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 |= 0xFFFFu;
				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 & 0x3FFu;
				int num9 = (int)num8 ^ (_bufferBase[num4 + 2] << 8);
				num7 = (uint)num9 & 0xFFFFu;
				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 val;
			uint val2 = (val = 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(val2, val);
				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];
					val = num19;
				}
				else
				{
					_son[num14] = num11;
					num14 = num17;
					num11 = _son[num14];
					val2 = 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 & 0x3FFu;
					_hash[num6] = _pos;
					int num7 = (int)num5 ^ (_bufferBase[num4 + 2] << 8);
					uint num8 = (uint)num7 & 0xFFFFu;
					_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 val;
				uint val2 = (val = 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(val2, val);
					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];
						val = num16;
					}
					else
					{
						_son[num11] = num10;
						num11 = num14;
						num10 = _son[num11];
						val2 = 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) & 1u;
						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 @byte = m_OutWindow.GetByte(0u);
					byte b2 = (state.IsCharState() ? m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)num5, @byte) : m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, (uint)num5, @byte, 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) & 1u;
						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) & 1u;
						uint num4 = num;
						if (flag)
						{
							uint num5 = (uint)(matchByte >> num2) & 1u;
							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) & 1u;
							uint num5 = (uint)(symbol >> num3) & 1u;
							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) & 1u;
						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 & 0xFu);
			}
		}

		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 & 0xFu);
								_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) & 0xFFu);
			}
			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 (outp

AssetsTools.NET.MonoCecil.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Mono.Cecil;
using Mono.Cecil.Rocks;
using Mono.Collections.Generic;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]
[assembly: AssemblyCompany("AssetsTools.NET.MonoCecil")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+71e2d120a0637aecbf22cf16c2f990c78c167e68")]
[assembly: AssemblyProduct("AssetsTools.NET.MonoCecil")]
[assembly: AssemblyTitle("AssetsTools.NET.MonoCecil")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace AssetsTools.NET.Extra;

public class MonoCecilTempGenerator : IMonoBehaviourTemplateGenerator
{
	private UnityVersion unityVersion;

	public string managedPath;

	public Dictionary<string, AssemblyDefinition> loadedAssemblies = new Dictionary<string, AssemblyDefinition>();

	public MonoCecilTempGenerator(string managedPath)
	{
		this.managedPath = managedPath;
	}

	public void Dispose()
	{
		lock (loadedAssemblies)
		{
			foreach (AssemblyDefinition value in loadedAssemblies.Values)
			{
				value.Dispose();
			}
			loadedAssemblies.Clear();
		}
	}

	public AssetTypeTemplateField GetTemplateField(AssetTypeTemplateField baseField, string assemblyName, string nameSpace, string className, UnityVersion unityVersion)
	{
		if (!assemblyName.EndsWith(".dll"))
		{
			assemblyName += ".dll";
		}
		string text = Path.Combine(managedPath, assemblyName);
		if (!File.Exists(text))
		{
			return null;
		}
		List<AssetTypeTemplateField> collection = Read(text, nameSpace, className, unityVersion);
		AssetTypeTemplateField obj = baseField.Clone();
		obj.Children.AddRange(collection);
		return obj;
	}

	public List<AssetTypeTemplateField> Read(string assemblyPath, string nameSpace, string typeName, UnityVersion unityVersion)
	{
		AssemblyDefinition assemblyWithDependencies = GetAssemblyWithDependencies(assemblyPath);
		return Read(assemblyWithDependencies, nameSpace, typeName, unityVersion);
	}

	public List<AssetTypeTemplateField> Read(AssemblyDefinition assembly, string nameSpace, string typeName, UnityVersion unityVersion)
	{
		this.unityVersion = unityVersion;
		bool usingManagedReference = false;
		List<AssetTypeTemplateField> list = new List<AssetTypeTemplateField>();
		RecursiveTypeLoad(assembly.MainModule, nameSpace, typeName, list, CommonMonoTemplateHelper.GetSerializationLimit(unityVersion), ref usingManagedReference);
		if (usingManagedReference)
		{
			list.Add(CommonMonoTemplateHelper.ManagedReferencesRegistry("references", unityVersion));
		}
		return list;
	}

	private AssemblyDefinition GetAssemblyWithDependencies(string path)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Expected O, but got Unknown
		//IL_0066: 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_0073: Expected O, but got Unknown
		string fileName = Path.GetFileName(path);
		lock (loadedAssemblies)
		{
			if (loadedAssemblies.ContainsKey(fileName))
			{
				return loadedAssemblies[fileName];
			}
			loadedAssemblies[fileName] = null;
		}
		DefaultAssemblyResolver val = new DefaultAssemblyResolver();
		((BaseAssemblyResolver)val).AddSearchDirectory(Path.GetDirectoryName(path));
		ReaderParameters val2 = new ReaderParameters
		{
			AssemblyResolver = (IAssemblyResolver)(object)val
		};
		AssemblyDefinition val3 = AssemblyDefinition.ReadAssembly(path, val2);
		lock (loadedAssemblies)
		{
			loadedAssemblies[fileName] = val3;
			return val3;
		}
	}

	private void RecursiveTypeLoad(ModuleDefinition module, string nameSpace, string typeName, List<AssetTypeTemplateField> attf, int availableDepth, ref bool usingManagedReference)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		TypeDefinition val;
		if (Enumerable.Contains(typeName, '/'))
		{
			string[] array = typeName.Split(new char[1] { '/' });
			val = new TypeReference(nameSpace, array[0], module, (IMetadataScope)(object)module).Resolve();
			for (int i = 1; i < array.Length; i++)
			{
				val = new TypeReference("", array[i], module, (IMetadataScope)(object)module)
				{
					DeclaringType = (TypeReference)(object)val
				}.Resolve();
			}
		}
		else
		{
			val = new TypeReference(nameSpace, typeName, module, (IMetadataScope)(object)module).Resolve();
		}
		RecursiveTypeLoad((TypeReference)(object)val, attf, availableDepth, isRecursiveCall: true, ref usingManagedReference);
	}

	private void RecursiveTypeLoad(TypeDefWithSelfRef type, List<AssetTypeTemplateField> attf, int availableDepth, bool isRecursiveCall, ref bool usingManagedReference)
	{
		if (!isRecursiveCall)
		{
			availableDepth--;
		}
		string fullName = ((MemberReference)type.typeDef.BaseType).FullName;
		if (fullName != "System.Object" && fullName != "UnityEngine.Object" && fullName != "UnityEngine.MonoBehaviour" && fullName != "UnityEngine.ScriptableObject")
		{
			TypeDefWithSelfRef type2 = type.typeDef.BaseType;
			type2.AssignTypeParams(type);
			RecursiveTypeLoad(type2, attf, availableDepth, isRecursiveCall: true, ref usingManagedReference);
		}
		attf.AddRange(ReadTypes(type, availableDepth, ref usingManagedReference));
	}

	private List<AssetTypeTemplateField> ReadTypes(TypeDefWithSelfRef type, int availableDepth, ref bool usingManagedReference)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Invalid comparison between Unknown and I4
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Expected O, but got Unknown
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Invalid comparison between Unknown and I4
		List<FieldDefinition> acceptableFields = GetAcceptableFields(type, availableDepth);
		List<AssetTypeTemplateField> list = new List<AssetTypeTemplateField>();
		for (int i = 0; i < acceptableFields.Count; i++)
		{
			AssetTypeTemplateField val = new AssetTypeTemplateField();
			FieldDefinition val2 = acceptableFields[i];
			TypeDefWithSelfRef typeDefWithSelfRef = type.SolidifyType(((FieldReference)val2).FieldType);
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			bool flag4 = false;
			bool flag5 = false;
			if ((int)typeDefWithSelfRef.typeRef.MetadataType == 20)
			{
				ArrayType val3 = (ArrayType)typeDefWithSelfRef.typeRef;
				flag = val3.IsVector;
				if (flag)
				{
					typeDefWithSelfRef = type.SolidifyType(((TypeSpecification)val3).ElementType);
				}
			}
			else if (((MemberReference)typeDefWithSelfRef.typeDef).FullName == "System.Collections.Generic.List`1")
			{
				flag = true;
				typeDefWithSelfRef = typeDefWithSelfRef.typeParamToArg.First().Value;
			}
			val.Name = ((MemberReference)val2).Name;
			if (flag2 = typeDefWithSelfRef.typeDef.IsEnum)
			{
				string fullName = ((MemberReference)TypeDefinitionRocks.GetEnumUnderlyingType(typeDefWithSelfRef.typeDef)).FullName;
				val.Type = CommonMonoTemplateHelper.ConvertBaseToPrimitive(fullName);
			}
			else if (flag2 = ((TypeReference)typeDefWithSelfRef.typeDef).IsPrimitive)
			{
				val.Type = CommonMonoTemplateHelper.ConvertBaseToPrimitive(((MemberReference)typeDefWithSelfRef.typeDef).FullName);
			}
			else if (flag5 = ((MemberReference)typeDefWithSelfRef.typeDef).FullName == "System.String")
			{
				val.Type = "string";
			}
			else if (flag3 = DerivesFromUEObject(typeDefWithSelfRef))
			{
				val.Type = "PPtr<$" + ((MemberReference)typeDefWithSelfRef.typeDef).Name + ">";
			}
			else if (flag4 = ((IEnumerable<CustomAttribute>)val2.CustomAttributes).Any((CustomAttribute a) => ((MemberReference)a.AttributeType).Name == "SerializeReference"))
			{
				usingManagedReference = true;
				val.Type = "managedReference";
			}
			else
			{
				val.Type = ((MemberReference)typeDefWithSelfRef.typeDef).Name;
			}
			if (flag2)
			{
				val.Children = new List<AssetTypeTemplateField>();
			}
			else if (((MemberReference)typeDefWithSelfRef.typeDef).FullName == "System.String")
			{
				val.Children = CommonMonoTemplateHelper.String();
			}
			else if (CommonMonoTemplateHelper.IsSpecialUnityType(((MemberReference)typeDefWithSelfRef.typeDef).FullName))
			{
				val.Children = SpecialUnity(typeDefWithSelfRef, availableDepth, ref usingManagedReference);
			}
			else if (flag3)
			{
				val.Children = CommonMonoTemplateHelper.PPtr(unityVersion);
			}
			else if (flag4)
			{
				val.Children = CommonMonoTemplateHelper.ManagedReference(unityVersion);
			}
			else if (typeDefWithSelfRef.typeDef.IsSerializable)
			{
				val.Children = Serialized(typeDefWithSelfRef, availableDepth, ref usingManagedReference);
			}
			val.ValueType = AssetTypeValueField.GetValueTypeByTypeName(val.Type);
			val.IsAligned = CommonMonoTemplateHelper.TypeAligns(val.ValueType);
			val.HasValue = (int)val.ValueType > 0;
			if (flag)
			{
				val = ((!(flag2 || flag5 || flag3)) ? CommonMonoTemplateHelper.VectorWithType(val) : CommonMonoTemplateHelper.Vector(val));
			}
			list.Add(val);
		}
		return list;
	}

	private List<FieldDefinition> GetAcceptableFields(TypeDefWithSelfRef parentType, int availableDepth)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		List<FieldDefinition> list = new List<FieldDefinition>();
		Enumerator<FieldDefinition> enumerator = parentType.typeDef.Fields.GetEnumerator();
		try
		{
			while (enumerator.MoveNext())
			{
				FieldDefinition current = enumerator.Current;
				if ((!Net35Polyfill.HasFlag((Enum)(object)current.Attributes, (Enum)(object)(FieldAttributes)6) && !((IEnumerable<CustomAttribute>)current.CustomAttributes).Any((CustomAttribute a) => ((MemberReference)a.AttributeType).FullName == "UnityEngine.SerializeField" || ((MemberReference)a.AttributeType).FullName == "UnityEngine.SerializeReference")) || Net35Polyfill.HasFlag((Enum)(object)current.Attributes, (Enum)(object)(FieldAttributes)16) || Net35Polyfill.HasFlag((Enum)(object)current.Attributes, (Enum)(object)(FieldAttributes)128) || current.IsInitOnly || current.HasConstant)
				{
					continue;
				}
				TypeDefWithSelfRef fieldType = parentType.SolidifyType(((FieldReference)current).FieldType);
				if (TryGetListOrArrayElement(fieldType, out var elemType))
				{
					if (availableDepth < 0 || TryGetListOrArrayElement(elemType, out var _))
					{
						continue;
					}
					fieldType = parentType.SolidifyType(elemType);
				}
				else if (((MemberReference)parentType.typeDef).FullName == ((MemberReference)fieldType.typeDef).FullName && !DerivesFromUEObject(parentType))
				{
					continue;
				}
				TypeDefinition typeDef = fieldType.typeDef;
				if (typeDef != null && IsValidDef(current, typeDef, availableDepth))
				{
					list.Add(current);
				}
			}
			return list;
		}
		finally
		{
			((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
		}
		bool IsValidDef(FieldDefinition fieldDef, TypeDefinition val, int num)
		{
			if (((TypeReference)val).HasGenericParameters && unityVersion.major < 2020)
			{
				return false;
			}
			if (((TypeReference)val).IsPrimitive || ((MemberReference)val).FullName == "System.String")
			{
				return true;
			}
			if (val.IsEnum)
			{
				string fullName = ((MemberReference)TypeDefinitionRocks.GetEnumUnderlyingType(val)).FullName;
				if (fullName != "System.Int64")
				{
					return fullName != "System.UInt64";
				}
				return false;
			}
			if (num < 0)
			{
				if (((TypeReference)val).IsValueType)
				{
					if (!val.IsSerializable)
					{
						return CommonMonoTemplateHelper.IsSpecialUnityType(((MemberReference)val).FullName);
					}
					return true;
				}
				return false;
			}
			if (DerivesFromUEObject((TypeReference)(object)val) || CommonMonoTemplateHelper.IsSpecialUnityType(((MemberReference)val).FullName))
			{
				return true;
			}
			if (((IEnumerable<CustomAttribute>)fieldDef.CustomAttributes).Any((CustomAttribute a) => ((MemberReference)a.AttributeType).Name == "SerializeReference"))
			{
				if (unityVersion.major == 2019 && unityVersion.minor == 3 && unityVersion.patch < 8 && ((MemberReference)val).FullName == "System.Object")
				{
					return false;
				}
				if (!((TypeReference)val).IsValueType)
				{
					return !((TypeReference)val).HasGenericParameters;
				}
				return false;
			}
			IMetadataScope scope = ((TypeReference)val).Scope;
			IMetadataScope obj = ((scope is ModuleDefinition) ? scope : null);
			if (CommonMonoTemplateHelper.IsAssemblyBlacklisted(((obj != null) ? ((AssemblyNameReference)((ModuleDefinition)obj).Assembly.Name).Name : null) ?? ((TypeReference)val).Scope.Name, unityVersion))
			{
				return false;
			}
			if (!val.IsAbstract)
			{
				return val.IsSerializable;
			}
			return false;
		}
		static bool TryGetListOrArrayElement(TypeDefWithSelfRef typeDefWithSelfRef, out TypeDefWithSelfRef reference)
		{
			TypeReference typeRef = typeDefWithSelfRef.typeRef;
			ArrayType val = (ArrayType)(object)((typeRef is ArrayType) ? typeRef : null);
			if (val != null)
			{
				reference = ((TypeSpecification)val).ElementType;
				return true;
			}
			TypeReference typeRef2 = typeDefWithSelfRef.typeRef;
			GenericInstanceType val2 = (GenericInstanceType)(object)((typeRef2 is GenericInstanceType) ? typeRef2 : null);
			if (val2 != null && ((MemberReference)((TypeSpecification)val2).ElementType).FullName == "System.Collections.Generic.List`1")
			{
				reference = typeDefWithSelfRef.typeParamToArg["T"];
				return true;
			}
			reference = default(TypeDefWithSelfRef);
			return false;
		}
	}

	private bool DerivesFromUEObject(TypeDefWithSelfRef typeDef)
	{
		if (typeDef.typeDef.BaseType == null)
		{
			return false;
		}
		if (typeDef.typeDef.IsInterface)
		{
			return false;
		}
		if (((MemberReference)typeDef.typeDef.BaseType).FullName == "UnityEngine.Object" || ((MemberReference)typeDef.typeDef).FullName == "UnityEngine.Object")
		{
			return true;
		}
		if (((MemberReference)typeDef.typeDef.BaseType).FullName != "System.Object")
		{
			return DerivesFromUEObject((TypeReference)(object)typeDef.typeDef.BaseType.Resolve());
		}
		return false;
	}

	private List<AssetTypeTemplateField> Serialized(TypeDefWithSelfRef type, int availableDepth, ref bool usingManagedReference)
	{
		List<AssetTypeTemplateField> list = new List<AssetTypeTemplateField>();
		RecursiveTypeLoad(type, list, availableDepth, isRecursiveCall: false, ref usingManagedReference);
		return list;
	}

	private List<AssetTypeTemplateField> SpecialUnity(TypeDefWithSelfRef type, int availableDepth, ref bool usingManagedReference)
	{
		return ((MemberReference)type.typeDef).Name switch
		{
			"Gradient" => CommonMonoTemplateHelper.Gradient(unityVersion), 
			"AnimationCurve" => CommonMonoTemplateHelper.AnimationCurve(unityVersion), 
			"LayerMask" => CommonMonoTemplateHelper.BitField(), 
			"Bounds" => CommonMonoTemplateHelper.AABB(), 
			"BoundsInt" => CommonMonoTemplateHelper.BoundsInt(), 
			"Rect" => CommonMonoTemplateHelper.Rectf(), 
			"RectOffset" => CommonMonoTemplateHelper.RectOffset(), 
			"Color32" => CommonMonoTemplateHelper.RGBAi(), 
			"GUIStyle" => CommonMonoTemplateHelper.GUIStyle(unityVersion), 
			"Vector2Int" => CommonMonoTemplateHelper.Vector2Int(), 
			"Vector3Int" => CommonMonoTemplateHelper.Vector3Int(), 
			"PropertyName" => CommonMonoTemplateHelper.PropertyName(unityVersion), 
			"SphericalHarmonicsL2" => CommonMonoTemplateHelper.SphericalHarmonicsL2(unityVersion), 
			_ => Serialized(type, availableDepth, ref usingManagedReference), 
		};
	}
}
internal struct TypeDefWithSelfRef
{
	public TypeReference typeRef;

	public TypeDefinition typeDef;

	public Dictionary<string, TypeDefWithSelfRef> typeParamToArg;

	public TypeDefWithSelfRef(TypeReference typeRef)
	{
		this.typeRef = typeRef;
		typeDef = typeRef.Resolve();
		typeParamToArg = new Dictionary<string, TypeDefWithSelfRef>();
		TypeReference val = typeRef;
		ArrayType val2 = (ArrayType)(object)((val is ArrayType) ? val : null);
		if (val2 != null)
		{
			val = ((TypeSpecification)val2).ElementType;
		}
		GenericInstanceType val3 = (GenericInstanceType)(object)((val is GenericInstanceType) ? val : null);
		if (val3 != null && val3.HasGenericArguments)
		{
			for (int i = 0; i < val3.GenericArguments.Count; i++)
			{
				typeParamToArg.Add(((MemberReference)((TypeReference)typeDef).GenericParameters[i]).Name, new TypeDefWithSelfRef(val3.GenericArguments[i]));
			}
		}
	}

	public void AssignTypeParams(TypeDefWithSelfRef parentTypeDef)
	{
		if (parentTypeDef.typeParamToArg.Count <= 0)
		{
			return;
		}
		TypeReference obj = typeRef;
		GenericInstanceType val = (GenericInstanceType)(object)((obj is GenericInstanceType) ? obj : null);
		if (val == null)
		{
			return;
		}
		for (int i = 0; i < val.GenericArguments.Count; i++)
		{
			TypeDefWithSelfRef value = new TypeDefWithSelfRef(val.GenericArguments[i]);
			if (value.typeRef.IsGenericParameter)
			{
				if (parentTypeDef.typeParamToArg.TryGetValue(((MemberReference)value.typeRef).Name, out var value2))
				{
					typeParamToArg[((MemberReference)((TypeReference)typeDef).GenericParameters[i]).Name] = value2;
				}
			}
			else
			{
				value.AssignTypeParams(parentTypeDef);
				typeParamToArg[((MemberReference)((TypeReference)typeDef).GenericParameters[i]).Name] = value;
			}
		}
	}

	public TypeDefWithSelfRef SolidifyType(TypeDefWithSelfRef typeDef)
	{
		typeDef.AssignTypeParams(this);
		if (typeParamToArg.TryGetValue(((MemberReference)typeDef.typeRef).Name, out var value))
		{
			return value;
		}
		return typeDef;
	}

	public static implicit operator TypeDefWithSelfRef(TypeReference typeReference)
	{
		return new TypeDefWithSelfRef(typeReference);
	}
}

OutwardConstructionKit.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using OutwardConstructionKit.Extractor;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
using UnityEngine.Profiling;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("OCK.Runtime.Tests")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace OutwardConstructionKit.Runtime;

internal static class AssetCache
{
	private const string FOLDER = "OCK_Cache";

	private const string FAILED_SUFFIX = ".failed";

	private const string SHADER_FOLDER = "#shaders";

	private static string s_root;

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

	private static readonly Dictionary<string, AssetBundle> s_open = new Dictionary<string, AssetBundle>();

	private static readonly Dictionary<string, GameObject> s_prefabs = new Dictionary<string, GameObject>();

	private static string FileFor(string scene, string path)
	{
		using SHA1 sHA = SHA1.Create();
		string path2 = BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(scene + "|" + path))).Replace("-", "").ToLowerInvariant();
		return Path.Combine(Path.Combine(s_root, scene), path2);
	}

	public static bool Has(string scene, string path)
	{
		if (s_root != null)
		{
			return File.Exists(FileFor(scene, path));
		}
		return false;
	}

	public static void BuildMissing()
	{
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Expected O, but got Unknown
		if (!KitPlugin.Instance.UseCache.Value)
		{
			return;
		}
		string dataPath = Application.dataPath;
		s_root = Path.Combine(Path.Combine(Paths.BepInExRootPath, "OCK_Cache"), CacheName());
		RemoveOutdated();
		for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++)
		{
			s_levelFiles[Path.GetFileNameWithoutExtension(SceneUtility.GetScenePathByBuildIndex(i))] = "level" + i;
		}
		var list = (from w in Region.All.SelectMany((Region r) => r.Manifest.props.Select((RegionManifest.PropReference p) => new { p.scene, p.path }).Concat(new RegionManifest.PropReference[1] { r.Manifest.doorModel ?? RegionManifest.DefaultDoorModel }.Select((RegionManifest.PropReference d) => new { d.scene, d.path })).Concat(r.Manifest.enemies.Select((RegionManifest.EnemyReference e) => new { e.scene, e.path }))
				.Concat(from part in RegionManifest.EnvironmentParts
					where !string.IsNullOrEmpty(r.Manifest.environmentDonor)
					select new
					{
						scene = r.Manifest.environmentDonor,
						path = part
					})
				.Concat(r.Manifest.water.Select((RegionManifest.WaterReference w) => new
				{
					scene = w.scene,
					path = "#water"
				}))
				.Concat(r.Manifest.water.Select((RegionManifest.WaterReference w) => new
				{
					scene = w.scene,
					path = "#watersource"
				}))
				.Concat(r.Manifest.groundLayers.Select((RegionManifest.GroundLayer g) => new
				{
					scene = g.scene,
					path = RegionManifest.TextureKey(g.diffuse)
				}))
				.Concat(from g in r.Manifest.groundLayers
					where g.normal.Length > 0
					select new
					{
						scene = g.scene,
						path = RegionManifest.TextureKey(g.normal)
					})).Distinct()
			where !File.Exists(FileFor(w.scene, w.path)) && !File.Exists(FileFor(w.scene, w.path) + ".failed")
			select w).ToList();
		if (list.Count == 0)
		{
			return;
		}
		Stopwatch stopwatch = Stopwatch.StartNew();
		int num = 0;
		int num2 = 0;
		long num3 = 0L;
		BundleBuilder val = new BundleBuilder(dataPath);
		foreach (var item in list)
		{
			string text = FileFor(item.scene, item.path);
			try
			{
				if (!s_levelFiles.TryGetValue(item.scene, out var value))
				{
					throw new FileNotFoundException("No scene named " + item.scene);
				}
				num3 = ((item.path == "#environment") ? (num3 + val.BuildPruned(value, "Environment", EnvironmentDonor.KeepChildren, "Season", text).Bytes) : ((item.path == "#water") ? (num3 + val.BuildScriptHolder(value, "WaterRender", true, text).Bytes) : ((item.path == "#watersource") ? (num3 + val.BuildScriptHolder(value, "WaterSource", false, text).Bytes) : ((!RegionManifest.IsTextureKey(item.path, out var name)) ? (num3 + val.Build(value, item.path, text).Bytes) : (num3 + val.BuildTexturePointer(value, name, text).Bytes)))));
				num++;
			}
			catch (Exception ex)
			{
				num2++;
				KitPlugin.Log.LogWarning((object)("Couldn't cache '" + item.path + "' from " + item.scene + ", so it'll come from its donor scene: " + ex.Message));
				Directory.CreateDirectory(Path.GetDirectoryName(text));
				File.WriteAllText(text + ".failed", ex.ToString());
			}
		}
		KitPlugin.Log.LogMessage((object)$"Asset cache: built {num} in {stopwatch.ElapsedMilliseconds} ms, {num3 / 1024} KB, and {num2} couldn't be built. It's only built once per game version.");
	}

	private static string CacheName()
	{
		string text = RegionManifest.GameFingerprint();
		using SHA1 sHA = SHA1.Create();
		string text2 = BitConverter.ToString(sHA.ComputeHash(File.ReadAllBytes(typeof(BundleBuilder).Assembly.Location))).Replace("-", "");
		return ((text.Length > 12) ? text.Substring(0, 12) : text) + "-" + text2.Substring(0, 12);
	}

	private static void RemoveOutdated()
	{
		string directoryName = Path.GetDirectoryName(s_root);
		if (!Directory.Exists(directoryName))
		{
			return;
		}
		foreach (string item in from f in Directory.GetDirectories(directoryName)
			where f != s_root
			select f)
		{
			try
			{
				Directory.Delete(item, recursive: true);
			}
			catch (IOException ex)
			{
				KitPlugin.Log.LogWarning((object)("Couldn't remove the outdated cache " + item + ": " + ex.Message));
			}
		}
	}

	public static GameObject Load(string scene, string path)
	{
		if (!Has(scene, path))
		{
			return null;
		}
		string text = FileFor(scene, path);
		if (s_prefabs.TryGetValue(text, out var value))
		{
			return value;
		}
		AssetBundle val = AssetBundle.LoadFromFile(text);
		if ((Object)(object)val == (Object)null)
		{
			KitPlugin.Log.LogError((object)("Unity refused the cached copy of '" + path + "'. Deleting the OCK_Cache folder rebuilds it."));
			return null;
		}
		value = val.LoadAsset<GameObject>("assets/ock/extracted.prefab");
		s_open[text] = val;
		s_prefabs[text] = value;
		return value;
	}

	public static Texture2D LoadTexture(string scene, string textureName)
	{
		string path = RegionManifest.TextureKey(textureName);
		if (!Has(scene, path))
		{
			return null;
		}
		return LoadPointer<Texture2D>(FileFor(scene, path), textureName);
	}

	public static Shader LoadShader(string shaderName)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		if (s_root == null)
		{
			return null;
		}
		string text = FileFor("#shaders", shaderName);
		if (File.Exists(text + ".failed"))
		{
			return null;
		}
		if (!File.Exists(text))
		{
			try
			{
				new BundleBuilder(Application.dataPath).BuildShaderPointer(shaderName, text);
			}
			catch (Exception ex)
			{
				KitPlugin.Log.LogWarning((object)("Couldn't find shader '" + shaderName + "': " + ex.Message));
				Directory.CreateDirectory(Path.GetDirectoryName(text));
				File.WriteAllText(text + ".failed", ex.ToString());
				return null;
			}
		}
		return LoadPointer<Shader>(text, shaderName);
	}

	private static T LoadPointer<T>(string file, string name) where T : Object
	{
		if (!s_open.TryGetValue(file, out var value))
		{
			value = AssetBundle.LoadFromFile(file);
			if ((Object)(object)value == (Object)null)
			{
				KitPlugin.Log.LogError((object)("Unity refused the cached pointer to '" + name + "'. Deleting the OCK_Cache folder rebuilds it."));
				return default(T);
			}
			s_open[file] = value;
		}
		return value.LoadAsset<T>("assets/ock/extracted.pointer");
	}

	public static void ReleaseAll()
	{
		foreach (AssetBundle value in s_open.Values)
		{
			if ((Object)(object)value != (Object)null)
			{
				value.Unload(true);
			}
		}
		s_open.Clear();
		s_prefabs.Clear();
	}
}
internal static class CoopGuard
{
	[HarmonyPatch(typeof(NetworkLevelLoader), "OnJoinedRoom")]
	private static class JoinedRoomPatch
	{
		private static void Prefix()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_004a: Expected O, but got Unknown
			try
			{
				PhotonPlayer player = PhotonNetwork.player;
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)val).Add((object)"ock_regions", (object)Describe(Region.All.Select((Region r) => r.Signature)));
				player.SetCustomProperties(val, (Hashtable)null, false);
			}
			catch (Exception ex)
			{
				KitPlugin.Log.LogError((object)("Couldn't tell the room which regions are installed: " + ex));
			}
		}
	}

	[HarmonyPatch(typeof(NetworkLevelLoader), "OnPhotonPlayerConnected")]
	private static class PlayerConnectedPatch
	{
		private static void Postfix(PhotonPlayer _newPlayer)
		{
			//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)
			if (PhotonNetwork.isMasterClient)
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (Region.ForScene(((Scene)(ref activeScene)).name) != null)
				{
					((MonoBehaviour)KitPlugin.Instance).StartCoroutine(CheckGuestSoon(_newPlayer));
				}
			}
		}
	}

	[HarmonyPatch(typeof(CharacterManager), "RequestAreaSwitch")]
	private static class AreaSwitchPatch
	{
		private static bool Prefix(Area _areaToSwitchTo)
		{
			Region region = ((_areaToSwitchTo != null) ? Region.ForScene(_areaToSwitchTo.SceneName) : null);
			if (region == null)
			{
				return true;
			}
			List<string> list = (from p in PhotonNetwork.otherPlayers
				where Lacks(p, region)
				select p.NickName).ToList();
			if (list.Count == 0)
			{
				return true;
			}
			Tell(string.Join(", ", list.ToArray()) + " can't come to " + region.DisplayName + ", because they don't have this version of it.");
			return false;
		}
	}

	private const string PROPERTY = "ock_regions";

	private const char SEPARATOR = ';';

	private const float SECONDS_TO_HEAR_FROM_GUEST = 8f;

	public static void Patch(Harmony harmony)
	{
		harmony.PatchAll(typeof(JoinedRoomPatch));
		harmony.PatchAll(typeof(PlayerConnectedPatch));
		harmony.PatchAll(typeof(AreaSwitchPatch));
	}

	internal static string Describe(IEnumerable<string> regionSignatures)
	{
		return string.Join(';'.ToString(), regionSignatures.ToArray());
	}

	internal static bool Has(string description, string regionSignature)
	{
		if (!string.IsNullOrEmpty(description))
		{
			return UnityEngineExtensions.Contains<string>(description.Split(new char[1] { ';' }), regionSignature);
		}
		return false;
	}

	private static bool Lacks(PhotonPlayer player, Region region)
	{
		return !Has(player.CustomProperties[(object)"ock_regions"] as string, region.Signature);
	}

	private static void Tell(string message)
	{
		KitPlugin.Log.LogWarning((object)message);
		Character val = (((Object)(object)CharacterManager.Instance != (Object)null) ? CharacterManager.Instance.GetFirstLocalCharacter() : null);
		if ((Object)(object)val != (Object)null && (Object)(object)val.CharacterUI != (Object)null)
		{
			val.CharacterUI.ShowInfoNotification(message);
		}
	}

	private static IEnumerator CheckGuestSoon(PhotonPlayer guest)
	{
		yield return (object)new WaitForSecondsRealtime(8f);
		Scene activeScene = SceneManager.GetActiveScene();
		Region region = Region.ForScene(((Scene)(ref activeScene)).name);
		if (region != null && PhotonNetwork.isMasterClient && UnityEngineExtensions.Contains<PhotonPlayer>(PhotonNetwork.playerList, guest) && Lacks(guest, region))
		{
			Tell(guest.NickName + " doesn't have this version of " + region.DisplayName + ", so they couldn't join.");
			PhotonNetwork.CloseConnection(guest);
		}
	}
}
internal static class DeathReturn
{
	[HarmonyPatch(typeof(DefeatScenariosManager), "FailSafeDefeat")]
	private static class FailSafePatch
	{
		private static void Prefix()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			bool flag = Region.ForScene(((Scene)(ref activeScene)).name) != null;
			s_returning = !PhotonNetwork.isNonMasterClientInRoom && flag;
			if (PhotonNetwork.isNonMasterClientInRoom && flag)
			{
				ShowDefeatScreen(null);
			}
		}
	}

	[HarmonyPatch(typeof(NetworkLevelLoader), "RequestReloadLevel")]
	private static class ReloadPatch
	{
		private static bool Prefix(NetworkLevelLoader __instance)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			if (!s_returning)
			{
				return true;
			}
			s_returning = false;
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			Region region = Region.ForScene(name);
			if (region == null)
			{
				return true;
			}
			string destination = Destination(s_cameFrom, region.EntranceScene);
			int spawnPoint = ((destination == region.EntranceScene && region.ReturnSpawnIndex.Value >= 0) ? region.ReturnSpawnIndex.Value : 0);
			KitPlugin.Log.LogMessage((object)$"Defeated in {name}, so returning to {destination}, at spawn {spawnPoint}.");
			ShowDefeatScreen((UnityAction)delegate
			{
				__instance.RequestSwitchArea(destination, spawnPoint, 1.5f, false);
			});
			return false;
		}
	}

	private const string FALLBACK_SCENE = "CierzoNewTerrain";

	private const string TRANSITION_SCENE = "LowMemory_TransitionScene";

	private const string MENU_SCENE_PREFIX = "MainMenu";

	private const string DEFEAT_TEXT = "You were injured badly, and left the space to nurse yourself to health.";

	private static string s_cameFrom;

	private static bool s_returning;

	public static void Patch(Harmony harmony)
	{
		harmony.PatchAll(typeof(FailSafePatch));
		harmony.PatchAll(typeof(ReloadPatch));
	}

	public static void OnSceneLoaded(string scene)
	{
		if (Region.ForScene(scene) == null && scene != "LowMemory_TransitionScene" && !scene.StartsWith("MainMenu"))
		{
			s_cameFrom = scene;
		}
	}

	internal static string Destination(string cameFrom, string entranceScene)
	{
		if (string.IsNullOrEmpty(cameFrom))
		{
			if (string.IsNullOrEmpty(entranceScene))
			{
				return "CierzoNewTerrain";
			}
			return entranceScene;
		}
		return cameFrom;
	}

	private static void ShowDefeatScreen(UnityAction then)
	{
		//IL_000d: 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_001e: Expected O, but got Unknown
		try
		{
			MenuManager.Instance.ShowProloguePanel((ContextScreen[])(object)new ContextScreen[1]
			{
				new ContextScreen
				{
					DefaultText = "You were injured badly, and left the space to nurse yourself to health."
				}
			}, then);
		}
		catch (Exception ex)
		{
			KitPlugin.Log.LogError((object)("Couldn't show the defeat screen: " + ex));
			if (then != null)
			{
				then.Invoke();
			}
		}
	}
}
internal class AssetCensus
{
	private class ReferenceComparer : IEqualityComparer<object>
	{
		public static readonly ReferenceComparer Instance = new ReferenceComparer();

		bool IEqualityComparer<object>.Equals(object a, object b)
		{
			return a == b;
		}

		int IEqualityComparer<object>.GetHashCode(object o)
		{
			return RuntimeHelpers.GetHashCode(o);
		}
	}

	private const int TOP_COUNT = 10;

	private const int MAX_OBJECTS_WALKED = 3000000;

	private const int TOP_HOLDERS = 15;

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

	private readonly Dictionary<string, int> m_countsByType = new Dictionary<string, int>();

	private readonly long[] m_memoryBefore = ReadMemory();

	public static AssetCensus Take()
	{
		AssetCensus assetCensus = new AssetCensus();
		foreach (Object item in All())
		{
			assetCensus.m_seen.Add(item.GetInstanceID());
		}
		Character[] array = Resources.FindObjectsOfTypeAll<Character>();
		foreach (Character val in array)
		{
			assetCensus.m_seen.Add(((Object)val).GetInstanceID());
		}
		foreach (IGrouping<string, Object> item2 in from o in Resources.FindObjectsOfTypeAll<Object>()
			group o by ((object)o).GetType().Name)
		{
			assetCensus.m_countsByType[item2.Key] = item2.Count();
		}
		return assetCensus;
	}

	private static long[] ReadMemory()
	{
		return new long[5]
		{
			Profiler.GetTotalAllocatedMemoryLong(),
			Profiler.GetTotalReservedMemoryLong(),
			Profiler.GetTotalUnusedReservedMemoryLong(),
			Profiler.GetMonoUsedSizeLong(),
			Profiler.GetMonoHeapSizeLong()
		};
	}

	public void LogReport()
	{
		LogDifference();
		LogHolders();
	}

	private void LogHolders()
	{
		//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)
		long[] array = ReadMemory();
		string[] array2 = new string[5] { "Unity allocated", "Unity reserved", "Unity reserved but free", "script used", "script heap" };
		for (int i = 0; i < array2.Length; i++)
		{
			KitPlugin.Log.LogMessage((object)$"Memory, {array2[i]}: {array[i] / 1048576} MB, {(array[i] - m_memoryBefore[i]) / 1048576:+0;-0;0} MB since before the donors.");
		}
		IEnumerable<string> source = from g in (from o in Resources.FindObjectsOfTypeAll<Object>()
				group o by ((object)o).GetType().Name into g
				select new
				{
					Key = g.Key,
					Added = g.Count() - (m_countsByType.ContainsKey(g.Key) ? m_countsByType[g.Key] : 0)
				} into g
				where g.Added > 0
				orderby g.Added descending
				select g).Take(15)
			select g.Key + " +" + g.Added;
		KitPlugin.Log.LogMessage((object)("Objects added, by type: " + string.Join(", ", source.ToArray())));
		Dictionary<int, Texture> dictionary = (from t in Resources.FindObjectsOfTypeAll<Texture>()
			where !m_seen.Contains(((Object)t).GetInstanceID())
			select t).ToDictionary((Texture t) => ((Object)t).GetInstanceID());
		HashSet<int> claimed = new HashSet<int>();
		Dictionary<string, HashSet<int>> tally = new Dictionary<string, HashSet<int>>();
		Renderer[] array3 = Resources.FindObjectsOfTypeAll<Renderer>();
		foreach (Renderer val in array3)
		{
			Scene scene = ((Component)val).gameObject.scene;
			string owner = (((Scene)(ref scene)).IsValid() ? "" : "asset ") + ((Object)((Component)val).transform.root).name;
			Material[] sharedMaterials = val.sharedMaterials;
			for (int num2 = 0; num2 < sharedMaterials.Length; num2++)
			{
				Claim(sharedMaterials[num2], dictionary, owner, tally, claimed);
			}
		}
		LogTallies("Held by renderers under", tally, dictionary);
		Dictionary<string, HashSet<int>> tally2 = new Dictionary<string, HashSet<int>>();
		Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
		int num3 = WalkScripts(dictionary, tally2, dictionary2, claimed);
		LogTallies("Held by script field", tally2, dictionary);
		KitPlugin.Log.LogMessage((object)string.Format("Walked {0} script objects. Destroyed objects still referenced: {1}", num3, string.Join(", ", (from d in dictionary2.OrderByDescending((KeyValuePair<string, int> d) => d.Value).Take(15)
			select d.Key + " " + d.Value).ToArray())));
		List<Texture> list = dictionary.Values.Where((Texture t) => !claimed.Contains(((Object)t).GetInstanceID())).OrderByDescending(Estimate).ToList();
		KitPlugin.Log.LogMessage((object)string.Format("Kept textures nothing was found holding: {0}, about {1} MB. Largest: {2}", list.Count, ((IEnumerable<Texture>)list).Sum((Func<Texture, long>)Estimate) / 1048576, string.Join(", ", (from t in list.Take(10)
			select ((Object)t).name).ToArray())));
	}

	private static void Claim(Material material, Dictionary<int, Texture> kept, string owner, Dictionary<string, HashSet<int>> tally, HashSet<int> claimed)
	{
		if (!((Object)(object)material == (Object)null))
		{
			string[] texturePropertyNames = material.GetTexturePropertyNames();
			foreach (string text in texturePropertyNames)
			{
				Claim(material.GetTexture(text), kept, owner, tally, claimed);
			}
		}
	}

	private static void Claim(Texture texture, Dictionary<int, Texture> kept, string owner, Dictionary<string, HashSet<int>> tally, HashSet<int> claimed)
	{
		if (!((Object)(object)texture == (Object)null) && kept.ContainsKey(((Object)texture).GetInstanceID()))
		{
			if (!tally.TryGetValue(owner, out var value))
			{
				value = (tally[owner] = new HashSet<int>());
			}
			value.Add(((Object)texture).GetInstanceID());
			claimed.Add(((Object)texture).GetInstanceID());
		}
	}

	private static void LogTallies(string title, Dictionary<string, HashSet<int>> tally, Dictionary<int, Texture> kept)
	{
		foreach (KeyValuePair<string, HashSet<int>> item in tally.OrderByDescending((KeyValuePair<string, HashSet<int>> e) => e.Value.Sum((int id) => Estimate((Object)(object)kept[id]))).Take(15))
		{
			KitPlugin.Log.LogMessage((object)string.Format("{0} {1}: {2} textures, about {3} MB, including {4}.", title, item.Key, item.Value.Count, item.Value.Sum((int id) => Estimate((Object)(object)kept[id])) / 1048576, string.Join(", ", (from id in item.Value.Take(3)
				select ((Object)kept[id]).name).ToArray())));
		}
	}

	private static int WalkScripts(Dictionary<int, Texture> kept, Dictionary<string, HashSet<int>> tally, Dictionary<string, int> destroyed, HashSet<int> claimed)
	{
		HashSet<object> hashSet = new HashSet<object>(ReferenceComparer.Instance);
		Stack<object> stack = new Stack<object>();
		foreach (Assembly item in AppDomain.CurrentDomain.GetAssemblies().Where(IsScriptAssembly))
		{
			foreach (Type item2 in from t in AccessTools.GetTypesFromAssembly(item)
				where !t.ContainsGenericParameters
				select t)
			{
				FieldInfo[] fields = item2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsLiteral && IsWalkable(fieldInfo.FieldType))
					{
						object obj = null;
						try
						{
							obj = fieldInfo.GetValue(null);
						}
						catch (Exception)
						{
							continue;
						}
						if (obj != null)
						{
							Walk(obj, item2.Name + "." + fieldInfo.Name, hashSet, stack, kept, tally, destroyed, claimed);
						}
					}
				}
			}
		}
		MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>();
		foreach (MonoBehaviour val in array)
		{
			Walk(val, "script on " + ((Object)((Component)val).transform.root).name + ": " + ((object)val).GetType().Name, hashSet, stack, kept, tally, destroyed, claimed);
		}
		return hashSet.Count;
	}

	private static void Walk(object start, string owner, HashSet<object> visited, Stack<object> stack, Dictionary<int, Texture> kept, Dictionary<string, HashSet<int>> tally, Dictionary<string, int> destroyed, HashSet<int> claimed)
	{
		stack.Push(start);
		while (stack.Count > 0 && visited.Count < 3000000)
		{
			object obj = stack.Pop();
			Type type = obj.GetType();
			if (!IsWalkable(type) || (!type.IsValueType && !visited.Add(obj)))
			{
				continue;
			}
			if ((Object)((obj is Object) ? obj : null) != (Object)null)
			{
				Texture val = (Texture)((obj is Texture) ? obj : null);
				Material val2 = (Material)((obj is Material) ? obj : null);
				Renderer val3 = (Renderer)((obj is Renderer) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					Claim(val, kept, owner, tally, claimed);
				}
				else if ((Object)(object)val2 != (Object)null)
				{
					Claim(val2, kept, owner, tally, claimed);
				}
				else if ((Object)(object)val3 != (Object)null)
				{
					Material[] sharedMaterials = val3.sharedMaterials;
					for (int i = 0; i < sharedMaterials.Length; i++)
					{
						Claim(sharedMaterials[i], kept, owner, tally, claimed);
					}
				}
			}
			else if (obj is Object)
			{
				destroyed.TryGetValue(type.Name, out var value);
				destroyed[type.Name] = value + 1;
			}
			if (obj is Object && !(obj is MonoBehaviour) && !(obj is ScriptableObject))
			{
				continue;
			}
			if (obj is Array array)
			{
				if (!IsWalkable(type.GetElementType()))
				{
					continue;
				}
				foreach (object item in array)
				{
					if (item != null)
					{
						stack.Push(item);
					}
				}
				continue;
			}
			Type type2 = type;
			while (type2 != null && type2 != typeof(object) && type2 != typeof(MonoBehaviour) && type2 != typeof(ScriptableObject))
			{
				FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (IsWalkable(fieldInfo.FieldType))
					{
						object value2 = fieldInfo.GetValue(obj);
						if (value2 != null)
						{
							stack.Push(value2);
						}
					}
				}
				type2 = type2.BaseType;
			}
		}
	}

	private static bool IsScriptAssembly(Assembly assembly)
	{
		string name = assembly.GetName().Name;
		if (!name.StartsWith("System") && !name.StartsWith("mscorlib") && !name.StartsWith("Mono") && !name.StartsWith("UnityEngine"))
		{
			return !name.StartsWith("netstandard");
		}
		return false;
	}

	private static bool IsWalkable(Type type)
	{
		if (type.IsPrimitive || type.IsEnum || type.IsPointer || type == typeof(string) || type == typeof(decimal) || type == typeof(IntPtr) || type == typeof(UIntPtr))
		{
			return false;
		}
		if (typeof(Type).IsAssignableFrom(type) || typeof(MemberInfo).IsAssignableFrom(type) || typeof(Assembly).IsAssignableFrom(type) || typeof(Thread).IsAssignableFrom(type))
		{
			return false;
		}
		if (type.IsValueType && type.Namespace != null)
		{
			return !type.Namespace.StartsWith("UnityEngine");
		}
		return true;
	}

	private static IEnumerable<Object> All()
	{
		return Resources.FindObjectsOfTypeAll<Texture>().Cast<Object>().Concat((IEnumerable<Object>)(object)Resources.FindObjectsOfTypeAll<Mesh>())
			.Concat((IEnumerable<Object>)(object)Resources.FindObjectsOfTypeAll<AudioClip>());
	}

	private void LogDifference()
	{
		List<Object> source = (from a in All()
			where !m_seen.Contains(a.GetInstanceID())
			select a).ToList();
		foreach (IGrouping<string, Object> item in source.GroupBy(Kind))
		{
			KitPlugin.Log.LogMessage((object)$"Kept {item.Key}: {item.Count()} assets, about {((IEnumerable<Object>)item).Sum((Func<Object, long>)Estimate) / 1048576} MB.");
		}
		string text = string.Join(", ", (from a in source.OrderByDescending(Estimate).Take(10)
			select $"{a.name} ({Estimate(a) / 1048576} MB)").ToArray());
		KitPlugin.Log.LogMessage((object)("Largest kept: " + text));
		List<Character> list = Resources.FindObjectsOfTypeAll<Character>().Where(delegate(Character c)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!m_seen.Contains(((Object)c).GetInstanceID()))
			{
				Scene scene = ((Component)c).gameObject.scene;
				return ((Scene)(ref scene)).IsValid();
			}
			return false;
		}).ToList();
		KitPlugin.Log.LogMessage((object)string.Format("Characters left behind by donors: {0}. {1}", list.Count, string.Join(", ", (from c in list.Take(10)
			select ((Object)c).name).ToArray())));
	}

	private static string Kind(Object asset)
	{
		if (!(asset is Mesh))
		{
			if (!(asset is AudioClip))
			{
				return "textures";
			}
			return "audio";
		}
		return "meshes";
	}

	private static long Estimate(Object asset)
	{
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Expected O, but got Unknown
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		Mesh val = (Mesh)(object)((asset is Mesh) ? asset : null);
		if ((Object)(object)val != (Object)null)
		{
			return (long)val.vertexCount * 32L;
		}
		AudioClip val2 = (AudioClip)(object)((asset is AudioClip) ? asset : null);
		if ((Object)(object)val2 != (Object)null)
		{
			return (long)val2.samples * (long)val2.channels * 2;
		}
		Cubemap val3 = (Cubemap)(object)((asset is Cubemap) ? asset : null);
		if ((Object)(object)val3 != (Object)null)
		{
			return (long)((Texture)val3).width * (long)((Texture)val3).height * 6 * 4 / 3 * BytesPerPixelTimesTwo(val3.format) / 2;
		}
		Texture2D val4 = (Texture2D)(object)((asset is Texture2D) ? asset : null);
		if ((Object)(object)val4 != (Object)null)
		{
			return (long)((Texture)val4).width * (long)((Texture)val4).height * 4 / 3 * BytesPerPixelTimesTwo(val4.format) / 2;
		}
		Texture val5 = (Texture)asset;
		return (long)val5.width * (long)val5.height * 4;
	}

	private static long BytesPerPixelTimesTwo(TextureFormat format)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Invalid comparison between Unknown and I4
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected I4, but got Unknown
		if ((int)format != 10)
		{
			if ((int)format == 12)
			{
				goto IL_0044;
			}
			switch (format - 17)
			{
			case 9:
				break;
			case 7:
			case 8:
			case 10:
				goto IL_0044;
			case 0:
				return 16L;
			case 3:
				return 32L;
			default:
				return 8L;
			}
		}
		return 1L;
		IL_0044:
		return 2L;
	}
}
internal static class AutoTest
{
	private class StartingNotice : MonoBehaviour
	{
		private const string TEXT = "Starting your test. There's no need to click anything.";

		private const int FONT_SIZE = 30;

		private const float HEIGHT = 80f;

		private const float SCREEN_POSITION = 0.2f;

		private void OnGUI()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = new GUIStyle(GUI.skin.box)
			{
				fontSize = 30,
				alignment = (TextAnchor)4
			};
			GUI.Box(new Rect(0f, (float)Screen.height * 0.2f, (float)Screen.width, 80f), "Starting your test. There's no need to click anything.", val);
		}
	}

	private const string REQUEST_FILE = "OCK_AutoTest.txt";

	private const string RESULTS_FOLDER = "OCK_AutoTest";

	private const float STEP_TIMEOUT_SECONDS = 240f;

	private const float CHECKS_SECONDS = 12f;

	private const string TEST_SHADER = "Custom/Water/CustomWater";

	private const float GROUND_SEARCH_DISTANCE = 6f;

	private const string TRANSITION_SCENE = "LowMemory_TransitionScene";

	private const string VISIT = "visit ";

	private const string CHARACTER_ID = "characterid ";

	public static bool Begin(KitPlugin plugin)
	{
		string path = Path.Combine(Paths.BepInExRootPath, "OCK_AutoTest.txt");
		if (!File.Exists(path))
		{
			return false;
		}
		string[] array = File.ReadAllLines(path);
		File.Delete(path);
		if (!array.Any((string l) => l.StartsWith("visit ")))
		{
			plugin.SelfCheck.Value = true;
		}
		Application.runInBackground = true;
		((MonoBehaviour)plugin).StartCoroutine(Run(array));
		return true;
	}

	private static void SetMenuInput(bool on)
	{
		CanvasGroup masterCanvas = MenuManager.Instance.MasterCanvas;
		masterCanvas.interactable = on;
		masterCanvas.blocksRaycasts = on;
	}

	private static void Log(string message)
	{
		KitPlugin.Log.LogMessage((object)("[AUTOTEST] " + message));
	}

	private static IEnumerator WaitFor(Func<bool> condition, string what, Action<bool> done)
	{
		float waited = 0f;
		while (!condition())
		{
			if (waited > 240f)
			{
				Log("FAIL timed out waiting for " + what + ".");
				done(obj: false);
				yield break;
			}
			waited += Time.unscaledDeltaTime;
			yield return null;
		}
		Log($"{what}, after {waited:0} s.");
		done(obj: true);
	}

	private static IEnumerator Run(string[] request)
	{
		string[] regions = (from l in request
			where l.StartsWith("region ")
			select l.Substring(7).Trim()).ToArray();
		bool quit = !UnityEngineExtensions.Contains<string>(request, "stay");
		bool ok = false;
		Action<bool> result = delegate(bool r)
		{
			ok = r;
		};
		MainScreen menu = null;
		Button continueButton = null;
		yield return WaitFor(delegate
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			menu = ((IEnumerable<MainScreen>)Resources.FindObjectsOfTypeAll<MainScreen>()).FirstOrDefault((Func<MainScreen, bool>)((MainScreen m) => ((Component)m).gameObject.activeInHierarchy));
			if ((Object)(object)menu == (Object)null || SaveManager.Instance == null || !SaveManager.Instance.SaveRetrieved)
			{
				return false;
			}
			continueButton = (Button)AccessTools.Field(typeof(MainScreen), "m_btnContinue").GetValue(menu);
			if (StartupVideo.StartupVideoWillPlay || MenuManager.Instance.IsStartupVideoActive)
			{
				return false;
			}
			return (Object)(object)continueButton != (Object)null && ((Component)continueButton).gameObject.activeInHierarchy && ((Selectable)continueButton).interactable;
		}, "the main menu is ready", result);
		if (!ok)
		{
			yield break;
		}
		SetMenuInput(on: false);
		StartingNotice notice = ((Component)KitPlugin.Instance).gameObject.AddComponent<StartingNotice>();
		yield return (object)new WaitForSecondsRealtime(2f);
		Log("Pressing Continue.");
		((UnityEvent)continueButton.onClick).Invoke();
		yield return (object)new WaitForSecondsRealtime(2f);
		string wantedId = (from l in request
			where l.StartsWith("characterid ")
			select l.Substring("characterid ".Length).Trim()).FirstOrDefault();
		string wanted = (from l in request
			where l.StartsWith("character ")
			select l.Substring(10).Trim()).FirstOrDefault();
		List<CharacterSaveInstanceHolder> list = SaveManager.Instance.CharacterSaves.Where((CharacterSaveInstanceHolder s) => s.MostRecentInstance != null).ToList();
		SetMenuInput(on: true);
		Object.Destroy((Object)(object)notice);
		CharacterSaveInstanceHolder val = (CharacterSaveInstanceHolder)((wantedId != null) ? ((IEnumerable<CharacterSaveInstanceHolder>)list).FirstOrDefault((Func<CharacterSaveInstanceHolder, bool>)((CharacterSaveInstanceHolder s) => s.CharacterUID == wantedId)) : ((wanted != null) ? ((object)((IEnumerable<CharacterSaveInstanceHolder>)list).FirstOrDefault((Func<CharacterSaveInstanceHolder, bool>)((CharacterSaveInstanceHolder s) => s.MostRecentInstance.CharSave.PSave.Name == wanted))) : ((object)UnityEngineExtensions.FirstOrDefault<CharacterSaveInstanceHolder>((IList<CharacterSaveInstanceHolder>)list))));
		if (val == null)
		{
			Log("FAIL no character called '" + (wantedId ?? wanted) + "'. There are: " + string.Join(", ", list.Select((CharacterSaveInstanceHolder s) => s.MostRecentInstance.CharSave.PSave.Name).ToArray()));
			yield break;
		}
		CharacterSelectionPanel val2 = (CharacterSelectionPanel)AccessTools.Field(typeof(MainScreen), "m_characterSelection").GetValue(menu);
		Log("Choosing " + val.MostRecentInstance.CharSave.PSave.Name + ".");
		val2.OnCharacterClicked(val);
		yield return WaitFor(delegate
		{
			//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)
			if ((Object)(object)Player() != (Object)null && Loaded())
			{
				Scene activeScene2 = SceneManager.GetActiveScene();
				return ((Scene)(ref activeScene2)).name != "LowMemory_TransitionScene";
			}
			return false;
		}, "the character is in the world", result);
		if (!ok)
		{
			yield break;
		}
		yield return PressAnyKey(result);
		if (!ok)
		{
			yield break;
		}
		string visit = (from l in request
			where l.StartsWith("visit ")
			select l.Substring("visit ".Length).Trim()).FirstOrDefault();
		if (visit != null)
		{
			Region visited = Region.All.FirstOrDefault((Region r) => r.Id == visit);
			if (visited == null || !visited.CanLoad)
			{
				KitPlugin.Log.LogError((object)("Couldn't go to '" + visit + "', because it isn't installed or can't load. The log above says why."));
				Log("FAIL couldn't visit '" + visit + "'.");
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(1f);
			yield return Travel(visited.SceneName, 0, result);
			if (ok)
			{
				Log("FINISHED, in " + visit + ", for a person to play.");
			}
			if (ok && UnityEngineExtensions.Contains<string>(request, "trydoor"))
			{
				yield return TryUsing();
			}
			yield break;
		}
		Player().Stats.RestoreAllVitals();
		yield return (object)new WaitForSecondsRealtime(3f);
		string text = (from l in request
			where l.StartsWith("startin ")
			select l.Substring(8).Trim()).FirstOrDefault();
		Scene activeScene;
		if (text != null)
		{
			activeScene = SceneManager.GetActiveScene();
			if (text != ((Scene)(ref activeScene)).name)
			{
				yield return Travel(text, 0, result);
				if (!ok)
				{
					yield break;
				}
				yield return (object)new WaitForSecondsRealtime(3f);
			}
		}
		activeScene = SceneManager.GetActiveScene();
		string home = ((Scene)(ref activeScene)).name;
		Log($"Started in {home}, at memory {SceneExtractor.PrivateMemory() / 1048576} MB.");
		CheckStanding();
		if (KitPlugin.Instance.UseCache.Value)
		{
			Shader val3 = AssetCache.LoadShader("Custom/Water/CustomWater");
			Log(((Object)(object)val3 != (Object)null && val3.isSupported) ? ("A shader from the cache works: " + ((Object)val3).name + ".") : "FAIL couldn't load Custom/Water/CustomWater from the cache.");
			AssetCache.ReleaseAll();
		}
		string[] array = regions;
		foreach (string id in array)
		{
			Region region = Region.All.FirstOrDefault((Region r) => r.Id == id);
			if (region == null)
			{
				Log("FAIL no region called '" + id + "'.");
				continue;
			}
			if (!region.CanLoad)
			{
				Log("'" + id + "' can't load, so it's left closed, and isn't visited.");
				continue;
			}
			yield return Travel(region.SceneName, 0, result);
			if (!ok)
			{
				yield break;
			}
			Log($"In {id}, at memory {SceneExtractor.PrivateMemory() / 1048576} MB.");
			Player().Invincible = true;
			yield return (object)new WaitForSecondsRealtime(12f);
			yield return Screenshot(id);
			if (UnityEngineExtensions.Contains<string>(request, "takeitems"))
			{
				yield return TakeItems();
			}
		}
		if (regions.Length != 0 && UnityEngineExtensions.Contains<string>(request, "dieinregion"))
		{
			activeScene = SceneManager.GetActiveScene();
			string died = ((Scene)(ref activeScene)).name;
			Log("Dying in " + died + ".");
			Player().Invincible = false;
			Player().Stats.ReceiveDamage(Player().Stats.MaxHealth * 10f);
			ProloguePanel defeatScreen = null;
			yield return WaitFor(() => (Object)(object)(defeatScreen = ((IEnumerable<ProloguePanel>)Resources.FindObjectsOfTypeAll<ProloguePanel>()).FirstOrDefault((Func<ProloguePanel, bool>)((ProloguePanel p) => ((UIElement)p).IsDisplayed))) != (Object)null, "the defeat screen is showing", result);
			if (!ok)
			{
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(2f);
			yield return Screenshot("defeat_screen");
			yield return (object)new WaitForSecondsRealtime(1f);
			defeatScreen.GoToNextPage();
			bool returned = false;
			yield return WaitFor(delegate
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				Scene activeScene2 = SceneManager.GetActiveScene();
				return ((Scene)(ref activeScene2)).name == home && (Object)(object)Player() != (Object)null && Loaded();
			}, "arriving back in " + home, delegate(bool r)
			{
				returned = r;
			});
			if (!returned)
			{
				yield break;
			}
			yield return PressAnyKey(result);
			if (!ok)
			{
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(3f);
			object[] obj = new object[4] { died, null, null, null };
			activeScene = SceneManager.GetActiveScene();
			obj[1] = ((Scene)(ref activeScene)).name;
			obj[2] = !Player().IsDead;
			obj[3] = Player().Stats.CurrentHealth;
			Log(string.Format("Died in {0} and came back in {1}, alive: {2}, health {3:0}.", obj));
			CheckStanding();
			Player().Stats.RestoreAllVitals();
		}
		if (regions.Length != 0 && !UnityEngineExtensions.Contains<string>(request, "endinregion"))
		{
			yield return Travel(home, 0, result);
			if (!ok)
			{
				yield break;
			}
			Log($"Back in {home}, so the game saved on the way, at memory {SceneExtractor.PrivateMemory() / 1048576} MB.");
			Player().Invincible = false;
			yield return (object)new WaitForSecondsRealtime(3f);
		}
		Log(quit ? "FINISHED, closing the game." : "FINISHED, staying open for a person to take over.");
		if (quit)
		{
			Application.Quit();
		}
	}

	private static IEnumerator TryUsing()
	{
		yield return (object)new WaitForSecondsRealtime(4f);
		Log((MenuManager.Instance.MasterCanvas.alpha == 1f && MenuManager.Instance.MasterCanvas.interactable && !Global.HideUI) ? "The HUD and menus are showing." : $"FAIL the HUD and menus are hidden: alpha {MenuManager.Instance.MasterCanvas.alpha}, interactable {MenuManager.Instance.MasterCanvas.interactable}, hidden {Global.HideUI}.");
		Scene activeScene = SceneManager.GetActiveScene();
		WaterRender val = ((Scene)(ref activeScene)).GetRootGameObjects().SelectMany((GameObject r) => r.GetComponentsInChildren<WaterRender>(true)).FirstOrDefault();
		if ((Object)(object)val != (Object)null)
		{
			Player().Teleport(((Component)val).transform.position + Vector3.up * 0.2f, ((Component)Player()).transform.rotation);
			yield return (object)new WaitForSecondsRealtime(3f);
			InteractionTriggerBase drink = Player().Interactable;
			Log(((Object)(object)drink != (Object)null && !string.IsNullOrEmpty(Player().PressText + Player().HoldText)) ? ("In the water, the prompt says '" + Player().PressText + "' '" + Player().HoldText + "'.") : "FAIL no prompt in the water.");
			yield return Screenshot("try_water");
			if ((Object)(object)drink != (Object)null)
			{
				drink.TryActivateBasicAction(Player());
			}
			yield return (object)new WaitForSecondsRealtime(3f);
		}
		GameObject val2 = GameObject.Find("OCK_ReturnDoor");
		if ((Object)(object)val2 == (Object)null)
		{
			Log("FAIL no return door to try.");
			yield break;
		}
		Player().Teleport(val2.transform.position + val2.transform.forward * 1.2f, Quaternion.LookRotation(-val2.transform.forward));
		yield return (object)new WaitForSecondsRealtime(3f);
		InteractionTriggerBase trigger = Player().Interactable;
		Log(((Object)(object)trigger != (Object)null) ? ("Beside the return door, the prompt says '" + Player().PressText + "'.") : "FAIL no prompt beside the return door.");
		yield return Screenshot("try_door");
		if ((Object)(object)trigger == (Object)null)
		{
			yield break;
		}
		activeScene = SceneManager.GetActiveScene();
		string region = ((Scene)(ref activeScene)).name;
		trigger.TryActivateBasicAction(Player());
		bool left = false;
		yield return WaitFor(delegate
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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)
			Scene activeScene2 = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene2)).name != region)
			{
				activeScene2 = SceneManager.GetActiveScene();
				if (((Scene)(ref activeScene2)).name != "LowMemory_TransitionScene" && (Object)(object)Player() != (Object)null)
				{
					return Loaded();
				}
			}
			return false;
		}, "the return door led out of the region", delegate(bool r)
		{
			left = r;
		});
		activeScene = SceneManager.GetActiveScene();
		Log("Now in " + ((Scene)(ref activeScene)).name + ".");
	}

	private static IEnumerator TakeItems()
	{
		List<Item> list = RegionItems.InWorld();
		Log(string.Format("{0} region items lying here: {1}.", list.Count, string.Join(", ", list.Select((Item i) => i.Name + " at " + ((object)((Component)i).transform.position/*cast due to .constrained prefix*/).ToString()).ToArray())));
		foreach (Item item in list)
		{
			int before = Player().Inventory.ItemCount(item.ItemID);
			Player().Inventory.TakeItem(item, false);
			yield return (object)new WaitForSecondsRealtime(2f);
			int num = Player().Inventory.ItemCount(item.ItemID);
			Log((num > before) ? $"Took {item.ItemID}: the bag holds {num}." : $"FAIL couldn't take {item.ItemID}: the bag holds {num}.");
		}
	}

	private static void CheckStanding()
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		Vector3 position = ((Component)Player()).transform.position;
		Log(Physics.Raycast(position + Vector3.up, Vector3.down, 6f, Global.FullEnvironmentMask, (QueryTriggerInteraction)1) ? $"Standing on the ground at {position}." : $"FAIL not standing on anything at {position}.");
	}

	private static Character Player()
	{
		if (!((Object)(object)CharacterManager.Instance != (Object)null))
		{
			return null;
		}
		return CharacterManager.Instance.GetFirstLocalCharacter();
	}

	private static bool Loaded()
	{
		if ((Object)(object)NetworkLevelLoader.Instance != (Object)null)
		{
			return NetworkLevelLoader.Instance.IsOverallLoadingDone;
		}
		return false;
	}

	private static IEnumerator PressAnyKey(Action<bool> result)
	{
		AccessTools.Method(typeof(NetworkLevelLoader), "SetContinueAfterLoading", (Type[])null, (Type[])null).Invoke(NetworkLevelLoader.Instance, null);
		yield return WaitFor(() => !NetworkLevelLoader.Instance.IsGameplayPaused, "gameplay has begun", result);
	}

	private static IEnumerator Travel(string sceneName, int spawnPoint, Action<bool> result)
	{
		Area areaFromSceneName = AreaManager.Instance.GetAreaFromSceneName(sceneName);
		if (areaFromSceneName == null)
		{
			Log("FAIL no area for scene " + sceneName + ".");
			result(obj: false);
			yield break;
		}
		Log("Travelling to " + sceneName + ".");
		CharacterManager.Instance.RequestAreaSwitch(Player(), areaFromSceneName, 0, spawnPoint, 1.5f, "");
		bool arrived = false;
		yield return WaitFor(delegate
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name == sceneName && (Object)(object)Player() != (Object)null && Loaded();
		}, "arrived in " + sceneName, delegate(bool r)
		{
			arrived = r;
		});
		if (!arrived)
		{
			result(obj: false);
		}
		else
		{
			yield return PressAnyKey(result);
		}
	}

	private static IEnumerator Screenshot(string name)
	{
		string text = Path.Combine(Paths.BepInExRootPath, "OCK_AutoTest");
		Directory.CreateDirectory(text);
		string file = Path.Combine(text, name + ".png");
		yield return (object)new WaitForEndOfFrame();
		ScreenCapture.CaptureScreenshot(file);
		Log("Screenshot " + file);
	}
}
internal static class PlayerNotice
{
	private static readonly List<string> s_pending = new List<string>();

	private static readonly HashSet<string> s_said = new HashSet<string>();

	public static void Add(string message)
	{
		if (s_said.Add(message))
		{
			KitPlugin.Log.LogWarning((object)("Notice: " + message));
			s_pending.Add(message);
		}
	}

	public static void ShowPending()
	{
		if (s_pending.Count != 0 && !((Object)(object)CharacterManager.Instance == (Object)null))
		{
			Character firstLocalCharacter = CharacterManager.Instance.GetFirstLocalCharacter();
			if (!((Object)(object)firstLocalCharacter == (Object)null) && !((Object)(object)firstLocalCharacter.CharacterUI == (Object)null))
			{
				firstLocalCharacter.CharacterUI.ShowInfoNotification("Construction Kit: " + string.Join(" ", s_pending.ToArray()) + " See BepInEx/LogOutput.log.");
				s_pending.Clear();
			}
		}
	}
}
internal static class RegionChecks
{
	private const float SETTLE_SECONDS = 8f;

	private const float GROUND_SEARCH_DISTANCE = 5f;

	private const int MAX_LISTED = 10;

	private const float PARKED_BELOW_HEIGHT = -1000f;

	public static IEnumerator Run(Region region, Scene scene, int propsPlaced)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		while ((Object)(object)NetworkLevelLoader.Instance == (Object)null || !NetworkLevelLoader.Instance.IsOverallLoadingDone)
		{
			yield return null;
		}
		yield return (object)new WaitForSeconds(8f);
		Character val = (((Object)(object)CharacterManager.Instance != (Object)null) ? CharacterManager.Instance.GetFirstLocalCharacter() : null);
		if (!((Scene)(ref scene)).isLoaded || ((Object)(object)val != (Object)null && ((Component)val).transform.position.y < -1000f))
		{
			KitPlugin.Log.LogMessage((object)$"[CHECK] {region.Id}: skipped, because the player left within {8f} seconds.");
			yield break;
		}
		int passed = 0;
		int failed = 0;
		Action<string, bool, string> action = delegate(string name, bool ok, string detail)
		{
			if (ok)
			{
				passed++;
			}
			else
			{
				failed++;
			}
			string text = "[CHECK] " + (ok ? "PASS" : "FAIL") + " " + region.Id + ": " + name + ". " + detail;
			if (ok)
			{
				KitPlugin.Log.LogMessage((object)text);
			}
			else
			{
				KitPlugin.Log.LogError((object)text);
			}
		};
		try
		{
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			CheckBasics(region, propsPlaced, action);
			CheckPlayerFooting(action);
			CheckEnemies(region, rootGameObjects, action);
			RegionItems.AddChecks(region, action);
			CheckGround(region, rootGameObjects, action);
			CheckWater(region, rootGameObjects, action);
			CheckReturnDoors(region, action);
			CheckShaders(rootGameObjects, action);
		}
		catch (Exception ex)
		{
			action("the checks themselves", arg2: false, ex.ToString());
		}
		KitPlugin.Log.LogMessage((object)$"[CHECK] {region.Id}: {passed} passed, {failed} failed.");
	}

	private static void CheckBasics(Region region, int propsPlaced, Action<string, bool, string> check)
	{
		SpawnPointManager instance = SpawnPointManager.Instance;
		int num = (((Object)(object)instance != (Object)null && instance.SpawnPoints != null) ? instance.SpawnPoints.Length : 0);
		check("has spawn points", num > 0, num + " found");
		check("has an environment", (Object)(object)EnvironmentConditions.Instance != (Object)null, "from " + region.Manifest.environmentDonor);
		check("has a main camera", (Object)(object)Global.MainCamera != (Object)null, "");
		check("placed every referenced prop", propsPlaced == region.Manifest.props.Count, $"{propsPlaced} of {region.Manifest.props.Count}");
	}

	private static void CheckPlayerFooting(Action<string, bool, string> check)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: 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)
		Character val = (((Object)(object)CharacterManager.Instance != (Object)null) ? CharacterManager.Instance.GetFirstLocalCharacter() : null);
		if (!((Object)(object)val == (Object)null))
		{
			bool arg = Physics.Raycast(((Component)val).transform.position + Vector3.up, Vector3.down, 5f, Global.FullEnvironmentMask, (QueryTriggerInteraction)1);
			check("player is standing on something", arg, "at " + ((object)((Component)val).transform.position/*cast due to .constrained prefix*/).ToString());
		}
	}

	private static void CheckEnemies(Region region, GameObject[] roots, Action<string, bool, string> check)
	{
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		if (region.Manifest.enemies.Count == 0)
		{
			return;
		}
		List<Character> list = (from c in roots.SelectMany((GameObject r) => r.GetComponentsInChildren<Character>(true))
			where (Object)(object)((Component)c).GetComponent<CharacterAI>() != (Object)null
			select c).ToList();
		check("placed every enemy", list.Count == region.Manifest.enemies.Count, $"{list.Count} of {region.Manifest.enemies.Count}");
		AISquadManager instance = AISquadManager.Instance;
		check("enemies have a wake distance", (Object)(object)instance != (Object)null && (instance.AIEnableDistances.x > 0f || instance.AIEnableDistances.y > 0f), ((Object)(object)instance != (Object)null) ? ((object)Unsafe.As<Vector2, Vector2>(ref instance.AIEnableDistances)/*cast due to .constrained prefix*/).ToString() : "no squad manager");
		int num = list.Count((Character e) => e.IsDead);
		if (num > 0)
		{
			KitPlugin.Log.LogMessage((object)$"[CHECK] {region.Id}: {num} enemies are already dead, so their movement can't be checked.");
		}
		foreach (Character item in list.Where((Character e) => !e.IsDead))
		{
			CharacterAI component = ((Component)item).GetComponent<CharacterAI>();
			NavMeshAgent component2 = ((Component)item).GetComponent<NavMeshAgent>();
			check("'" + ((Object)item).name + "' can move", !((CharacterControl)component).CloseToPlayer || ((Object)(object)component2 != (Object)null && ((Behaviour)component2).enabled && component2.isOnNavMesh), string.Format("close to player {0}, agent {1}, on NavMesh {2}, at {3}", ((CharacterControl)component).CloseToPlayer, ((Object)(object)component2 != (Object)null && ((Behaviour)component2).enabled) ? "on" : "off", (Object)(object)component2 != (Object)null && component2.isOnNavMesh, ((Component)item).transform.position));
		}
	}

	private static void CheckGround(Region region, GameObject[] roots, Action<string, bool, string> check)
	{
		if (region.Manifest.groundLayers.Count == 0)
		{
			return;
		}
		List<Terrain> list = roots.SelectMany((GameObject r) => r.GetComponentsInChildren<Terrain>(true)).ToList();
		check("has its terrain", list.Count > 0, list.Count + " found");
		int num = LayerMask.NameToLayer("LargeEnvironment");
		foreach (Terrain item in list)
		{
			string[] array = (from l in item.terrainData.terrainLayers
				where (Object)(object)l == (Object)null || (Object)(object)l.diffuseTexture == (Object)null
				select (!((Object)(object)l == (Object)null)) ? ((Object)l).name : "(missing)").ToArray();
			check("terrain '" + ((Object)item).name + "' has all its textures", array.Length == 0, (array.Length == 0) ? "" : ("blank: " + string.Join(", ", array)));
			TerrainCollider component = ((Component)item).GetComponent<TerrainCollider>();
			check("terrain '" + ((Object)item).name + "' can be walked on", (Object)(object)component != (Object)null && ((Collider)component).enabled && ((Component)component).gameObject.layer == num, ((Object)(object)component != (Object)null) ? ("layer " + LayerMask.LayerToName(((Component)component).gameObject.layer)) : "no collider");
		}
	}

	private static void CheckWater(Region region, GameObject[] roots, Action<string, bool, string> check)
	{
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		if (region.Manifest.water.Count == 0)
		{
			return;
		}
		List<WaterRender> list = roots.SelectMany((GameObject r) => r.GetComponentsInChildren<WaterRender>(true)).ToList();
		check("placed all its water", list.Count == region.Manifest.water.Count, $"{list.Count} of {region.Manifest.water.Count}");
		foreach (WaterRender item in list)
		{
			bool arg = ((Component)item).GetComponents<Collider>().Any((Collider c) => c.enabled) && (Global.WaterMask & (1 << ((Component)item).gameObject.layer)) != 0;
			check($"water at {((Component)item).transform.position} splashes underfoot", arg, "layer " + LayerMask.LayerToName(((Component)item).gameObject.layer));
		}
		int num = roots.SelectMany((GameObject r) => r.GetComponentsInChildren<WaterSource>(true)).Count();
		check("every water can be drunk from", num == region.Manifest.water.Count, $"{num} of {region.Manifest.water.Count}");
		foreach (RegionManifest.WaterReference asked in region.Manifest.water.Where((RegionManifest.WaterReference w) => !string.IsNullOrEmpty(w.waterType)))
		{
			string[] array = (from w in roots.SelectMany((GameObject r) => r.GetComponentsInChildren<IWaterSource>(true))
				select ((object)w.WaterType/*cast due to .constrained prefix*/).ToString()).Distinct().ToArray();
			check("water asking to be " + asked.waterType + " is", array.Any((string t) => t.Equals(asked.waterType, StringComparison.OrdinalIgnoreCase)), string.Join(", ", array));
		}
	}

	private static void CheckShaders(GameObject[] roots, Action<string, bool, string> check)
	{
		HashSet<string> hashSet = new HashSet<string>();
		foreach (Renderer item in roots.SelectMany((GameObject r) => r.GetComponentsInChildren<Renderer>(true)))
		{
			foreach (Material item2 in item.sharedMaterials.Where((Material m) => (Object)(object)m != (Object)null))
			{
				if ((Object)(object)item2.shader == (Object)null || !item2.shader.isSupported || ((Object)item2.shader).name == "Hidden/InternalErrorShader")
				{
					hashSet.Add(((Object)item).name + " (" + ((Object)item2).name + ": " + (((Object)(object)item2.shader != (Object)null) ? ((Object)item2.shader).name : "no shader") + ")");
				}
			}
		}
		check("every material has a working shader", hashSet.Count == 0, string.Join(", ", hashSet.Take(10).ToArray()));
	}

	private static void CheckReturnDoors(Region region, Action<string, bool, string> check)
	{
		//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)
		if (region.ReturnSpawnIndex.Value < 0)
		{
			check("has a way back", arg2: false, "its entrance door hasn't been placed");
			return;
		}
		int num = Mathf.Max(1, region.Manifest.returnDoors.Count);
		Scene activeScene = SceneManager.GetActiveScene();
		int num2 = ((Scene)(ref activeScene)).GetRootGameObjects().Count((GameObject r) => ((Object)r).name == "OCK_ReturnDoor");
		check("has a way back", num2 == num, $"{num2} of {num} return doors");
	}
}
internal static class SceneProbe
{
	private const int MAX_DEPTH = 2;

	private static readonly Type[] s_managers = new Type[12]
	{
		typeof(SpawnPointManager),
		typeof(SceneInteractionManager),
		typeof(DefeatScenariosManager),
		typeof(EnvironmentConditions),
		typeof(NetworkEnvironment),
		typeof(WeatherManager),
		typeof(QuestEventManager),
		typeof(AISceneManager),
		typeof(AISquadManager),
		typeof(SceneWind),
		typeof(TerrainManager),
		typeof(EnvironmentInteractionsManager)
	};

	private static readonly Type[] s_requiredInScene = new Type[4]
	{
		typeof(SpawnPointManager),
		typeof(EnvironmentConditions),
		typeof(AISquadManager),
		typeof(AISceneManager)
	};

	public static IEnumerable<string> MissingRequired()
	{
		return from t in s_requiredInScene
			where (Object)(object)GetInstance(t) == (Object)null
			select t.Name;
	}

	private static Component GetInstance(Type type)
	{
		FieldInfo field = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		if (!(field != null))
		{
			return null;
		}
		object? value = field.GetValue(null);
		return (Component)((value is Component) ? value : null);
	}

	public static IEnumerable<string> MissingManagers()
	{
		return from t in s_managers
			where (Object)(object)GetInstance(t) == (Object)null
			select t.Name;
	}

	public static void Run(string pluginDir)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_023e: Expected O, but got Unknown
		//IL_0245: Unknown result type (might be due to invalid IL or missing references)
		//IL_024a: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("Scene: " + ((Scene)(ref activeScene)).name + " (build index " + ((Scene)(ref activeScene)).buildIndex + ")");
		stringBuilder.AppendLine().AppendLine("== Managers ==");
		Type[] array = s_managers;
		Scene scene;
		foreach (Type type in array)
		{
			Component instance = GetInstance(type);
			string name = type.Name;
			object obj;
			if (!((Object)(object)instance == (Object)null))
			{
				scene = instance.gameObject.scene;
				obj = "in scene '" + ((Scene)(ref scene)).name + "' at " + PathOf(instance.transform);
			}
			else
			{
				obj = "MISSING";
			}
			stringBuilder.AppendLine(name + ": " + (string?)obj);
		}
		if ((Object)(object)SpawnPointManager.Instance != (Object)null && SpawnPointManager.Instance.SpawnPoints != null)
		{
			stringBuilder.AppendLine().AppendLine("Spawn points: " + SpawnPointManager.Instance.SpawnPoints.Length);
		}
		stringBuilder.AppendLine().AppendLine("== Areas ==");
		if ((Object)(object)AreaManager.Instance != (Object)null)
		{
			foreach (Area item in AreaManager.Instance.Areas.Where((Area a) => a != null))
			{
				stringBuilder.AppendLine(item.ID + " " + item.SceneName + " '" + item.DefaultName + "'");
			}
		}
		stringBuilder.AppendLine().AppendLine("== Scene objects ==");
		GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
		for (int i = 0; i < rootGameObjects.Length; i++)
		{
			Dump(rootGameObjects[i].transform, 0, stringBuilder);
		}
		stringBuilder.AppendLine().AppendLine("== DontDestroyOnLoad objects ==");
		GameObject val = new GameObject("OCK_Probe");
		Object.DontDestroyOnLoad((Object)(object)val);
		scene = val.scene;
		rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
		foreach (GameObject val2 in rootGameObjects)
		{
			if ((Object)(object)val2 != (Object)(object)val)
			{
				Dump(val2.transform, 2, stringBuilder);
			}
		}
		Object.Destroy((Object)(object)val);
		string text = Path.Combine(pluginDir, "probes");
		Directory.CreateDirectory(text);
		File.WriteAllText(Path.Combine(text, ((Scene)(ref activeScene)).name + ".txt"), stringBuilder.ToString());
		KitPlugin.Log.LogMessage((object)("Scene probe written for " + ((Scene)(ref activeScene)).name + ". Missing managers: " + string.Join(", ", MissingManagers().ToArray())));
	}

	private static void Dump(Transform t, int depth, StringBuilder text)
	{
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Expected O, but got Unknown
		string text2 = string.Join(", ", (from c in ((Component)t).GetComponents<Component>()
			where (Object)(object)c != (Object)null && !(c is Transform)
			select ((object)c).GetType().Name).ToArray());
		text.Append(new string(' ', depth * 2)).Append(((Object)t).name).Append(((Component)t).gameObject.activeSelf ? "" : " (off)");
		if (text2.Length > 0)
		{
			text.Append("  [").Append(text2).Append(']');
		}
		text.AppendLine();
		if (depth >= 2)
		{
			return;
		}
		foreach (Transform item in t)
		{
			Dump(item, depth + 1, text);
		}
	}

	private static string PathOf(Transform t)
	{
		if (!((Object)(object)t.parent == (Object)null))
		{
			return PathOf(t.parent) + "/" + ((Object)t).name;
		}
		return ((Object)t).name;
	}
}
internal static class EnemyDonor
{
	private const int VIEW_ID_BASE = 2110000000;

	private const int VIEW_IDS_PER_ENEMY = 50;

	private static readonly FieldInfo f_aiStates = AccessTools.Field(typeof(CharacterAI), "m_aiStates");

	private static readonly FieldInfo f_aiStatesRoot = AccessTools.Field(typeof(CharacterAI), "m_aiStatesRoot");

	private static readonly Dictionary<string, GameObject> s_templates = new Dictionary<string, GameObject>();

	private static GameObject s_holder;

	private static Vector2 s_enableDistances = new Vector2(-1f, -1f);

	private static readonly Vector2 s_usualEnableDistances = new Vector2(150f, 50f);

	internal static int ViewId(int enemyIndex, int slot)
	{
		return 2110000000 + enemyIndex * 50 + slot;
	}

	private static string KeyFor(RegionManifest.EnemyReference reference)
	{
		return reference.scene + "|" + reference.path;
	}

	public static void Harvest(Scene scene)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: 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_017b: 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_0115: Expected O, but got Unknown
		foreach (RegionManifest.EnemyReference item in from e in Region.All.SelectMany((Region r) => r.Manifest.enemies)
			where e.scene == ((Scene)(ref scene)).name
			select e)
		{
			if (s_templates.ContainsKey(KeyFor(item)))
			{
				continue;
			}
			Transform val = PropDonor.Find(scene, item.path);
			Character val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Character>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				KitLog("Enemy '" + item.path + "' not found in " + ((Scene)(ref scene)).name + ", so it's left out of the region. The game may have changed since this region was exported.", isError: true);
				continue;
			}
			if ((Object)(object)s_holder == (Object)null)
			{
				s_holder = new GameObject("OCK_EnemyDonor");
				s_holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)s_holder);
			}
			GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, s_holder.transform);
			((Object)val3).name = ((Object)val).name;
			val3.SetActive(true);
			RestoreAIStates(val2, val3);
			RemoveDonorTies(val3);
			s_templates[KeyFor(item)] = val3;
			ReadEnableDistances(scene);
			KitLog("Enemy '" + ((Object)val).name + "' cloned from " + ((Scene)(ref scene)).name + ", from " + PathOf(val) + ".", isError: false);
		}
	}

	private static void ReadEnableDistances(Scene scene)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		AISquadManager val = ((Scene)(ref scene)).GetRootGameObjects().SelectMany((GameObject r) => r.GetComponentsInChildren<AISquadManager>(true)).FirstOrDefault();
		if ((Object)(object)val != (Object)null)
		{
			s_enableDistances = Vector2.Max(s_enableDistances, val.AIEnableDistances);
		}
	}

	private static string PathOf(Transform t)
	{
		if (!((Object)(object)t.parent == (Object)null))
		{
			return PathOf(t.parent) + "/" + ((Object)t).name;
		}
		return ((Object)t).name;
	}

	public static void Place(Scene scene, Region region, Transform parent)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("OCK_EnemiesWaking");
		val.SetActive(false);
		SceneManager.MoveGameObjectToScene(val, scene);
		((Component)parent).GetComponent<AISquadManager>().AIEnableDistances = ((s_enableDistances.x > 0f || s_enableDistances.y > 0f) ? s_enableDistances : s_usualEnableDistances);
		if (region.Manifest.enemies.Count > 0)
		{
			KitLog($"Enemies wake within {((Component)parent).GetComponent<AISquadManager>().AIEnableDistances} of a player.", isError: false);
		}
		int num = 0;
		foreach (RegionManifest.EnemyReference enemy in region.Manifest.enemies)
		{
			num++;
			GameObject val2 = AssetCache.Load(enemy.scene, enemy.path);
			GameObject value = (((Object)(object)val2 != (Object)null) ? TemplateFromCache(val2) : null);
			if (!((Object)(object)value == (Object)null) || s_templates.TryGetValue(KeyFor(enemy), out value))
			{
				try
				{
					PlaceOne(value, enemy, region, num, val.transform, parent);
				}
				catch (Exception arg)
				{
					KitLog($"Couldn't place enemy '{((Object)value).name}': {arg}", isError: true);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
		}
		Object.Destroy((Object)(object)val);
	}

	private static GameObject TemplateFromCache(GameObject cached)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if ((Object)(object)s_holder == (Object)null)
		{
			s_holder = new GameObject("OCK_EnemyDonor");
			s_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)s_holder);
		}
		GameObject obj = Object.Instantiate<GameObject>(cached, s_holder.transform);
		((Object)obj).name = ((Object)cached).name;
		obj.SetActive(true);
		RemoveDonorTies(obj);
		return obj;
	}

	private static void PlaceOne(GameObject template, RegionManifest.EnemyReference reference, Region region, int index, Transform waiting, Transform parent)
	{
		//IL_0060: 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_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(template, waiting);
		((Object)val).name = ((Object)template).name + "_" + index;
		Character component = val.GetComponent<Character>();
		string text = "_ock_" + region.Id + "_" + index;
		component.SetUID(new UID(region.Id + "_" + ((Object)template).name + text));
		int num = 0;
		PhotonView[] componentsInChildren = val.GetComponentsInChildren<PhotonView>(true);
		foreach (PhotonView val2 in componentsInChildren)
		{
			if (val2.viewID != 0)
			{
				if (num >= 50)
				{
					throw new InvalidOperationException($"it has more than {50} network views");
				}
				val2.viewID = ViewId(index, num++);
				val2.ownerId = 0;
			}
		}
		MonoBehaviour[] componentsInChildren2 = val.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val3 in componentsInChildren2)
		{
			IUIDHolder val4 = (IUIDHolder)(object)((val3 is IUIDHolder) ? val3 : null);
			if (val4 != null && !(val3 is Character))
			{
				UID holderUID = val4.HolderUID;
				if (!((UID)(ref holderUID)).IsNull)
				{
					holderUID = val4.HolderUID;
					val4.SetHolderUID(new UID(((UID)(ref holderUID)).Value + text));
				}
			}
		}
		val.transform.SetParent(parent, false);
		val.transform.position = reference.position;
		val.transform.rotation = Quaternion.Euler(0f, reference.rotationY, 0f);
		NavMeshHit val5 = default(NavMeshHit);
		bool flag = NavMesh.SamplePosition(reference.position, ref val5, 3f, -1);
		if (flag)
		{
			val.transform.position = ((NavMeshHit)(ref val5)).position;
		}
		KitLog($"Enemy '{((Object)val).name}' placed at {val.transform.position}, on the NavMesh: {flag}.", isError: false);
	}

	private static void RestoreAIStates(Character original, GameObject clone)
	{
		CharacterAI component = ((Component)original).GetComponent<CharacterAI>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		object? value = f_aiStatesRoot.GetValue(component);
		AIRoot val = (AIRoot)((value is AIRoot) ? value : null);
		if ((Object)(object)val != (Object)null)
		{
			SetCounterpartActive(((Component)original).transform, ((Component)val).transform, clone.transform);
		}
		if (!(f_aiStates.GetValue(component) is AIState[] array))
		{
			return;
		}
		AIState[] array2 = array;
		foreach (AIState val2 in array2)
		{
			if ((Object)(object)val2 != (Object)null)
			{
				SetCounterpartActive(((Component)original).transform, ((Component)val2).transform, clone.transform);
			}
		}
	}

	private static void SetCounterpartActive(Transform originalRoot, Transform target, Transform cloneRoot)
	{
		List<int> list = new List<int>();
		Transform val = target;
		while ((Object)(object)val != (Object)(object)originalRoot)
		{
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			list.Add(val.GetSiblingIndex());
			val = val.parent;
		}
		Transform val2 = cloneRoot;
		for (int num = list.Count - 1; num >= 0; num--)
		{
			if (list[num] >= val2.childCount)
			{
				return;
			}
			val2 = val2.GetChild(list[num]);
		}
		((Component)val2).gameObject.SetActive(true);
	}

	private static void RemoveDonorTies(GameObject clone)
	{
		CharacterAI component = clone.GetComponent<CharacterAI>();
		if ((Object)(object)component != (Object)null && component.InstantiateCharAIDisable)
		{
			CharAIDisable[] components = clone.GetComponents<CharAIDisable>();
			for (int i = 0; i < components.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)components[i]);
			}
		}
		QuestEventOnDeath[] componentsInChildren = clone.GetComponentsInChildren<QuestEventOnDeath>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
		}
		AISquadMember[] componentsInChildren2 = clone.GetComponentsInChildren<AISquadMember>(true);
		for (int i = 0; i < componentsInChildren2.Length; i++)
		{
			Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
		}
	}

	private static void KitLog(string message, bool isError)
	{
		if (isError)
		{
			KitPlugin.Log.LogError((object)message);
		}
		else
		{
			KitPlugin.Detail(message);
		}
	}
}
internal static class EnvironmentDonor
{
	public const string ENVIRONMENT = "Environment";

	private const string MAIN_CAMERA = "Main Camera";

	public static readonly string[] KeepChildren = new string[4] { "WindZone", "WorldItems", "Sky Dome Custom", "WeatherEvents" };

	private static readonly Dictionary<string, List<GameObject>> s_templates = new Dictionary<string, List<GameObject>>();

	private static GameObject s_holder;

	private static string NameOf(string part)
	{
		if (!(part == "#environment"))
		{
			return part;
		}
		return "Environment";
	}

	private static bool AllCached(string donor)
	{
		return RegionManifest.EnvironmentParts.All((string part) => AssetCache.Has(donor, part));
	}

	public static bool IsReady(string donor)
	{
		if (donor == null)
		{
			return false;
		}
		if (!AllCached(donor))
		{
			if (s_templates.TryGetValue(donor, out var value))
			{
				return value.Count == RegionManifest.EnvironmentParts.Length;
			}
			return false;
		}
		return true;
	}

	private static GameObject Holder()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if ((Object)(object)s_holder == (Object)null)
		{
			s_holder = new GameObject("OCK_EnvironmentDonor");
			s_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)s_holder);
		}
		return s_holder;
	}

	public static void Harvest(Scene scene)
	{
		if (AllCached(((Scene)(ref scene)).name))
		{
			return;
		}
		List<GameObject> list = new List<GameObject>();
		s_templates[((Scene)(ref scene)).name] = list;
		string[] environmentParts = RegionManifest.EnvironmentParts;
		foreach (string part in environmentParts)
		{
			string name = NameOf(part);
			GameObject val = Array.Find(((Scene)(ref scene)).GetRootGameObjects(), (GameObject root) => ((Object)root).name == name);
			if ((Object)(object)val == (Object)null)
			{
				KitPlugin.Log.LogWarning((object)(((Scene)(ref scene)).name + " has no '" + name + "' to borrow."));
			}
			else
			{
				list.Add(MakeTemplate(val, name));
			}
		}
	}

	private static GameObject MakeTemplate(GameObject original, string name)
	{
		GameObject val = Object.Instantiate<GameObject>(original, Holder().transform);
		((Object)val).name = name;
		val.SetActive(true);
		if (name == "Environment")
		{
			StripEnvironment(val);
		}
		return val;
	}

	private static void StripEnvironment(GameObject environment)
	{
		EnvironmentConditions component = environment.GetComponent<EnvironmentConditions>();
		if (component.Seasons != null)
		{
			foreach (Season season in component.Seasons)
			{
				if ((Object)(object)season != (Object)null && (Object)(object)((Component)season).gameObject != (Object)(object)environment)
				{
					((Component)season).transform.SetParent(environment.transform, false);
				}
			}
		}
		for (int num = environment.transform.childCount - 1; num >= 0; num--)
		{
			Transform child = environment.transform.GetChild(num);
			if (Array.IndexOf(KeepChildren, ((Object)child).name) < 0 && (Object)(object)((Component)child).GetComponent<Season>() == (Object)null)
			{
				Object.DestroyImmediate((Object)(object)((Component)child).gameObject);
			}
		}
		LargeTerrainData component2 = environment.GetComponent<LargeTerrainData>();
		if ((Object)(object)component2 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component2);
		}
	}

	public static void Place(Scene scene, string donor)
	{
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		string[] environmentParts = RegionManifest.EnvironmentParts;
		foreach (string text in environmentParts)
		{
			string name = NameOf(text);
			GameObject val = AssetCache.Load(donor, text);
			List<GameObject> value;
			GameObject val2 = (GameObject)(((Object)(object)val != (Object)null) ? ((object)MakeTemplate(val, name)) : ((object)(s_templates.TryGetValue(donor, out value) ? value.Find((GameObject t) => ((Object)t).name == name) : null)));
			if (!((Object)(object)val2 == (Object)null))
			{
				GameObject val3 = Object.Instantiate<GameObject>(val2);
				((Object)val3).name = name;
				SceneManager.MoveGameObjectToScene(val3, scene);
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
				if (name == "Main Camera")
				{
					Global.MainCamera = val3.GetComponent<Camera>();
				}
			}
		}
	}
}
internal static class GroundDonor
{
	private static readonly Dictionary<string, Texture2D> s_textures = new Dictionary<string, Texture2D>();

	public static void Harvest(Scene scene)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		HashSet<string> hashSet = new HashSet<string>(from n in (from g in Region.All.SelectMany((Region r) => r.Manifest.groundLayers)
				where g.scene == ((Scene)(ref scene)).name
				select g).SelectMany((RegionManifest.GroundLayer g) => new string[2] { g.diffuse, g.normal })
			where !string.IsNullOrEmpty(n) && !s_textures.ContainsKey(n)
			select n);
		if (hashSet.Count == 0)
		{
			return;
		}
		Texture2D[] array = Resources.FindObjectsOfTypeAll<Texture2D>();
		foreach (Texture2D val in array)
		{
			if (hashSet.Contains(((Object)val).name))
			{
				s_textures[((Object)val).name] = val;
			}
		}
		foreach (string item in hashSet.Where((string n) => !s_textures.ContainsKey(n)))
		{
			KitPlugin.Log.LogError((object)("Ground texture '" + item + "' not found in " + ((Scene)(ref scene)).name + ", so that layer will be blank."));
		}
	}

	public static void Apply(Scene scene, Region region)
	{
		foreach (Terrain item in ((Scene)(ref scene)).GetRootGameObjects().SelectMany((GameObject r) => r.GetComponentsInChildren<Terrain>(true)))
		{
			TerrainLayer[] terrainLayers = item.terrainData.terrainLayers.Select((TerrainLayer l) => (!((Object)(object)l == (Object)null)) ? WithTextures(l, region) : null).ToArray();
			item.terrainData.terrainLayers = terrainLayers;
			item.terrainData.SetBaseMapDirty();
			item.Flush();
		}
	}

	private static TerrainLayer WithTextures(TerrainLayer layer, Region region)
	{
		RegionManifest.GroundLayer groundLayer = region.Manifest.groundLayers.FirstOrDefault((RegionManifest.GroundLayer g) => g.layer == ((Object)layer).name);
		if (groundLayer == null)
		{
			return layer;
		}
		TerrainLayer val = Object.Instantiate<TerrainLayer>(layer);
		((Object)val).name = ((Object)layer).name;
		Texture2D val2 = TextureFor(groundLayer.scene, groundLayer.diffuse);
		if ((Object)(object)val2 != (Object)null)
		{
			val.diffuseTexture = val2;
		}
		val2 = (string.IsNullOrEmpty(groundLayer.normal) ? null : TextureFor(groundLayer.scene, groundLayer.normal));
		if ((Object)(object)val2 != (Object)null)
		{
			val.normalMapTexture = val2;
		}
		return val;
	}

	private static Texture2D TextureFor(string scene, string name)
	{
		Texture2D value = AssetCache.LoadTexture(scene, name);
		if ((Object)(object)value == (Object)null)
		{
			s_textures.TryGetValue(name, out value);
		}
		return value;
	}
}
internal static class PropDonor
{
	private struct Template
	{
		public GameObject Object;

		public Vector3 SourcePosition;

		public Quaternion SourceRotation;
	}

	private static readonly Dictionary<string, Template> s_templates = new Dictionary<string, Template>();

	private static GameObject s_holder;

	private static string KeyFor(RegionManifest.PropReference reference)
	{
		return reference.scene + "|" + reference.path;
	}

	public static void Harvest(Scene scene)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: 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_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		foreach (RegionManifest.PropReference item in from p in Region.All.SelectMany((Region r) => r.Manifest.props)
			where p.scene == ((Scene)(ref scene)).name
			select p)
		{
			num++;
			if (s_templates.ContainsKey(KeyFor(item)))
			{
				continue;
			}
			Transform val = Find(scene, item.path);
			if ((Object)(object)val == (Object)null)
			{
				KitPlugin.Log.LogError((object)("Prop '" + item.path + "' not found in " + ((Scene)(ref scene)).name + ", so it's left out of the region. The game may have changed since this region was exported."));
				continue;
			}
			string text = DescribeForCheck(val);
			if (!string.IsNullOrEmpty(item.check) && item.check != text)
			{
				KitPlugin.Log.LogError((object)("'" + item.path + "' in " + ((Scene)(ref scene)).name + " isn't the expected prop (expected " + item.check + ", found " + text + "), so it's left out of the region."));
				continue;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, Holder().transform);
			((Object)val2).name = ((Object)val).name;
			val2.transform.localScale = val.lossyScale;
			val2.SetActive(true);
			foreach (MonoBehaviour item2 in val2.GetComponentsInChildren<MonoBehaviour>(true).Reverse())
			{
				Object.DestroyImmediate((Object)(object)item2);
			}
			s_templates[KeyFor(item)] = new Template
			{
				Object = val2,
				SourcePosition = val.position,
				SourceRotation = val.rotation
			};
		}
		if (num > 0)
		{
			KitPlugin.Detail($"{num} prop placements across all regions use {((Scene)(ref scene)).name}; {s_templates.Count} distinct props cloned so far.");
		}
	}

	private static string DescribeForCheck(Transform source)
	{
		List<MeshFilter> list = (from f in ((Component)source).GetComponentsInChildren<MeshFilter>(true)
			where (Object)(object)f.sharedMesh != (Object)null && (Object)(object)((Component)f).GetComponent<MeshRenderer>() != (Object)null
			select f).ToList();
		return ((list.Count > 0) ? ((Object)list[0]).name : "") + ":" + list.Count;
	}

	public static int Place(Scene scene, Region region)
	{
		//IL_006b: 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_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		foreach (RegionManifest.PropReference prop in region.Manifest.props)
		{
			GameObject val = AssetCache.Load(prop.scene, prop.path);
			Template value;
			if ((Object)(object)val != (Object)null)
			{
				value = TemplateFromCache(val, prop);
			}
			else if (!s_templates.TryGetValue(KeyFor(prop), out value))
			{
				continue;
			}
			if (!((Object)(object)value.Object == (Object)null))
			{
				try
				{
					PlaceCopy(scene, value.Object, value.SourcePosition, value.SourceRotation, prop.position, prop.rotation, prop.scale);
					num++;
				}
				catch (Exception arg)
				{
					KitPlugin.Log.LogError((object)$"Couldn't place '{((Object)value.Object).name}': {arg}");
				}
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)value.Object);
				}
			}
		}
		return num;
	}

	public static GameObject PlaceDoorModel(Scene scene, RegionManifest.PropReference model, Vector3 position, Quaternion rotation)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: 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_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_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: 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)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = AssetCache.Load(model.scene, model.path);
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		Template template = TemplateFromCache(val, model);
		try
		{
			Quaternion val2 = rotation * Quaternion.Euler(model.rotation) * Quaternion.Inverse(template.SourceRotation);
			return PlaceCopy(scene, template.Object, template.SourcePosition, template.SourceRotation, position + rotation * model.position, ((Quaternion)(ref val2)).eulerAngles, model.scale);
		}
		finally
		{
			Object.Destroy((Object)(object)template.Object);
		}
	}

	private static GameObject Holder()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if ((Object)(object)s_holder == (Object)null)
		{
			s_holder = new GameObject("OCK_PropDonor");
			s_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)s_holder);
		}
		return s_holder;
	}

	private static Template TemplateFromCache(GameObject cached, RegionManifest.PropReference reference)
	{
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		string text = DescribeForCheck(cached.transform);
		if (!string.IsNullOrEmpty(reference.check) && reference.check != text)
		{
			KitPlugin.Log.LogError((object)("'" + reference.path + "' in " + reference.scene + " isn't the expected prop (expected " + reference.check + ", found " + text + "), so it's left out of the region."));
			return default(Template);
		}
		GameObject val = Object.Instantiate<GameObject>(cached, Holder().transform);
		((Object)val).name = ((Object)cached).name;
		val.SetActive(true);
		foreach (MonoBehaviour item in val.GetComponentsInChildren<MonoBehaviour>(true).Reverse())
		{
			Object.DestroyImmediate((Object)(object)item);
		}
		return new Template
		{
			Object = val,
			SourcePosition = cached.transform.position,
			SourceRotation = cached.transform.rotation
		};
	}

	internal static GameObject PlaceCopy(Scene scene, GameObject source, Vector3 sourcePosition, Quaternion sourceRotation, Vector3 position, Vector3 rotation, float scale = 1f)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: 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)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: 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_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: 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_00d7: 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_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(source);
		((Object)val).name = ((Object)source).name;
		SceneManager.MoveGameObjectToScene(val, scene);
		Quaternion val2 = Quaternion.Euler(rotation);
		val.transform.position = position;
		val.transform.rotation = val2 * sourceRotation;
		Transform transform = val.transform;
		transform.localScale *= scale;
		Transform val3 = null;
		int num = 0;
		Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
		Renderer[] array = componentsInChildren;
		foreach (Renderer val4 in array)
		{
			val4.lightmapIndex = -1;
			if (val4.isPartOfStaticBatch)
			{
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = new GameObject(((Object)val).name + "_BatchRoot").transform;
					SceneManager.MoveGameObjectToScene(((Component)val3).gameObject, scene);
					val3.rotation = val2;
					val3.localScale = Vector3.one * scale;
					val3.position = position - val2 * (sourcePosition * scale);
				}
				AccessTools.Property(typeof(Renderer), "staticBatchRootTransform").SetValue(val4, val3, null);
				val4.materials = val4.materials;
				num++;
			}
		}
		KitPlugin.Detail($"Prop '{((Object)val).name}' placed at {val.transform.position}, turned {rotation}, scale {scale}:{componentsInChildren.Length} renderers ({num} batched), {val.GetComponentsInChildren<Collider>(true).Length} colliders, LOD group {(Object)(object)val.GetComponent<LODGroup>() != (Object)null}.");
		return val;
	}

	internal static Transform Find(Scene scene, string path)
	{
		string[] parts = path.Split(new char[1] { '/' }, 2);
		GameObject val = Array.Find(((Scene)(ref scene)).GetRootGameObjects(), (GameObject r) => ((Object)r).name == parts[0]);
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		if (parts.Length != 1)
		{
			return val.transform.Find(parts[1]);
		}
		return val.transform;
	}
}
internal static class SceneExtractor
{
	[HarmonyPatch(typeof(NetworkLevelLoader), "StartLoadLevel")]
	private static class StartLoadLevelPatch
	{
		private static bool Prefix(NetworkLevelLoader __instance, bool ___m_transitionSceneLoaded)
		{
			if (s_done || Region.All.Count == 0)
			{
				return true;
			}
			if (IsExtracting)
			{
				return false;
			}
			if (__instance.LowMemoryLoading && !___m_transitionSceneLoaded)
			{
				return true;
			}
			IsExtracting = true;
			((MonoBehaviour)KitPlugin.Instance).StartCoroutine(Run(__instance));
			return false;
		}
	}

	private struct ProcessMemoryCounters
	{
		public uint Size;

		public uint PageFaultCount;

		public UIntPtr PeakWorkingSetSize;

		public UIntPtr WorkingSetSize;

		public UIntPtr QuotaPeakPagedPoolUsage;

		public UIntPtr QuotaPagedPoolUsage;

		public UIntPtr QuotaPeakNonPagedPoolUsage;

		public UIntPtr QuotaNonPagedPoolUsage;

		public UIntPtr PagefileUsage;

		public UIntPtr PeakPagefileUsage;

		public UIntPtr PrivateUsage;
	}

	private struct StaticSnapshot
	{
		private FieldInfo m_field;

		private object m_value;

		public static List<StaticSnapshot> TakeAll()
		{
			List<StaticSnapshot> list = new List<StaticSnapshot>();
			foreach (Assembly item in new Assembly[2]
			{
				typeof(NetworkLevelLoader).Assembly,
				typeof(TOD_Sky).Assembly
			}.Distinct())
			{
				Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(item);
				foreach (Type type in typesFromAssembly)
				{
					if (type.ContainsGenericParameters)
					{
						continue;
					}
					FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						if (!fieldInfo.IsLiteral && !fieldInfo.IsInitOnly && typeof(Object).IsAssignableFrom(fieldInfo.FieldType))
						{
							try
							{
								list.Add(new StaticSnapshot
								{
									m_field = fieldInfo,
									m_value = fieldInfo.GetValue(null)
								});
							}
							catch (Exception)
							{
							}
						}
					}
				}
			}
			return list;
		}

		public static void RestoreAll(List<StaticSnapshot> snapshots)
		{
			List<string> list = new List<string>();
			foreach (StaticSnapshot snapshot in snapshots)
			{
				if (snapshot.m_field.GetValue(null) != snapshot.m_value)
				{
					snapshot.m_field.SetValue(null, snapshot.m_value);
					list.Add(snapshot.m_field.DeclaringType.Name + "." + snapshot.m_field.Name);
				}
			}
			KitPlugin.Detail(string.Format("Restored {0} statics overwritten by donors: {1}", list.Count, string.Join(", ", list.ToArray())));
		}
	}

	private const float LOAD_TIMEOUT_SECONDS = 180f;

	private static bool s_done;

	private static List<string> s_donors;

	public static bool IsExtracting { get; private set; }

	public static void Patch(Harmony harmony)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		harmony.PatchAll(typeof(StartLoadLevelPatch));
		HarmonyMethod val = new HarmonyMethod(typeof(SceneExtractor), "SkipWhileExtracting", (Type[])null);
		Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(NetworkLevelLoader).Assembly);
		foreach (Type type in typesFromAssembly)
		{
			if (!type.ContainsGenericParameters)
			{
				MethodInfo method = type.GetMethod("OnLevelWasLoaded", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method != null && !method.IsAbstract)
				{
					harmony.Patch((MethodBase)method, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}
	}

	private static bool SkipWhileExtracting()
	{
		return !IsExtracting;
	}

	private static IEnumerator Run(NetworkLevelLoader loader)
	{
		Stopwatch total = Stopwatch.StartNew();
		long memoryBefore = PrivateMemory();
		List<StaticSnapshot> statics = StaticSnapshot.TakeAll();
		AssetCensus census = (KitPlugin.Instance.MemoryReport.Value ? AssetCensus.Take() : null);
		s_donors = Region.AllDonorScenes().ToList();
		SceneManager.sceneLoaded += OnDonorLoaded;
		try
		{
			foreach (string donor in s_donors)
			{
				Stopwatch timer = Stopwatch.StartNew();
				long memoryStart = PrivateMemory();
				AsyncOperation load = SceneManager.LoadSceneAsync(donor, (LoadSceneMode)1);
				if (load == null)
				{
					KitPlugin.Log.LogError((object)("Donor scene '" + donor + "' does not exist."));
					continue;
				}
				float waited = 0f;
				while (!load.isDone && waited < 180f)
				{
					waited += Time.unscaledDeltaTime;
					yield return null;
				}
				long loadedMs = timer.ElapsedMilliseconds;
				long memoryLoaded = PrivateMemory();
				Scene sceneByName = SceneManager.GetSceneByName(donor);
				if (((Scene)(ref sceneByName)).IsValid())
				{
					AsyncOperation val = SceneManager.UnloadSceneAsync(sceneByName);
					if (val != null)
					{
						yield return val;
					}
				}
				yield return Resources.UnloadUnusedAssets();
				GC.Collect();
				KitPlugin.Log.LogMessage((object)$"Donor {donor}: loaded in {loadedMs} ms, unloaded by {timer.ElapsedMilliseconds} ms. Memory: {Mb(memoryLoaded - memoryStart)} MB while loaded, {Mb(PrivateMemory() - memoryStart)} MB kept.");
			}
		}
		finally
		{
			SceneManager.sceneLoaded -= OnDonorLoaded;
			StaticSnapshot.RestoreAll(statics);
			try
			{
				census?.LogReport();
			}
			catch (Exception ex)
			{
				KitPlugin.Log.LogError((object)("Asset census failed: " + ex));
			}
			s_done = true;
			IsExtracting = false;
			KitPlugin.Log.LogMessage((object)$"Extraction finished in {total.ElapsedMilliseconds} ms for {Region.All.Count} regions from {s_donors.Count} donor scenes, {Mb(PrivateMemory() - memoryBefore)} MB kept.");
			AccessTools.Method(typeof(NetworkLevelLoader), "StartLoadLevel", (Type[])null, (Type[])null).Invoke(loader, null);
		}
	}

	private static void OnDonorLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Invalid comparison between Unknown and I4
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due

OutwardConstructionKit.Extractor.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using AssetsTools.NET;
using AssetsTools.NET.Extra;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("OCK.Runtime.Tests")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("OutwardConstructionKit.Extractor")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+7cca316ce4f1390ad2ee819e9e8737b08b7c4e4b")]
[assembly: AssemblyProduct("OutwardConstructionKit.Extractor")]
[assembly: AssemblyTitle("OutwardConstructionKit.Extractor")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace OutwardConstructionKit.Extractor;

public class BundleBuilder
{
	private class LevelIndex
	{
		public AssetsFile File;

		public Dictionary<long, AssetFileInfo> ById;

		public Dictionary<long, string> Names = new Dictionary<long, string>();

		public Dictionary<long, long> GameObjectOf = new Dictionary<long, long>();

		public Dictionary<long, long> FatherOf = new Dictionary<long, long>();

		public Dictionary<long, List<long>> ChildrenOf = new Dictionary<long, List<long>>();

		public List<long> RootTransforms = new List<long>();

		public Dictionary<ushort, string> ScriptClasses = new Dictionary<ushort, string>();
	}

	private const string TEMPLATE_RESOURCE = "ock_template";

	public const string PREFAB_PATH = "assets/ock/extracted.prefab";

	public const string POINTER_PATH = "assets/ock/extracted.pointer";

	private const int GAME_OBJECT = 1;

	private const int TRANSFORM = 4;

	private const int TEXTURE = 28;

	private const int SHADER = 48;

	private const int WIND_ZONE = 182;

	private const int MESH = 43;

	private const int SCRIPT = 114;

	private const int MESH_FILTER = 33;

	private const int ASSET_BUNDLE = 142;

	private const int CHARACTER_CONTROLLER = 143;

	private const int LOD_GROUP = 205;

	private const long BUNDLE_RECORD_ID = 1L;

	private readonly string m_gameData;

	private readonly AssetsManager m_manager = new AssetsManager();

	private readonly byte[] m_template;

	private readonly Dictionary<int, TypeTreeType> m_types;

	private readonly ScriptDescriber m_describer;

	private readonly MonoCecilTempGenerator m_scriptReader;

	private readonly Dictionary<string, LevelIndex> m_levels = new Dictionary<string, LevelIndex>();

	private readonly Dictionary<string, AssetsFile> m_scriptFiles = new Dictionary<string, AssetsFile>();

	private readonly Dictionary<string, AssetTypeTemplateField> m_scriptFields = new Dictionary<string, AssetTypeTemplateField>();

	private HashSet<long> m_onlyChildren;

	public BundleBuilder(string gameData)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Expected O, but got Unknown
		m_gameData = gameData;
		using (Stream stream = typeof(BundleBuilder).Assembly.GetManifestResourceStream("ock_template"))
		{
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			m_template = memoryStream.ToArray();
		}
		BundleFileInstance bundle;
		AssetBundleDirectoryInfo entry;
		AssetsFile val = OpenTemplate(out bundle, out entry);
		m_types = (from t in val.Metadata.TypeTreeTypes
			group t by t.TypeId).ToDictionary((IGrouping<int, TypeTreeType> g) => g.Key, (IGrouping<int, TypeTreeType> g) => g.First());
		m_describer = new ScriptDescriber(m_types.Values);
		m_scriptReader = new MonoCecilTempGenerator(Path.Combine(gameData, "Managed"));
		DescribeWindZone();
	}

	private void DescribeWindZone()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: 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_00f7: Expected O, but got Unknown
		AssetTypeTemplateField val = new AssetTypeTemplateField();
		val.FromTypeTree(m_types[114]);
		val.Type = "WindZone";
		val.Children = val.Children.Where((AssetTypeTemplateField c) => c.Name == "m_GameObject" || c.Name == "m_Enabled").ToList();
		val.Children.Add(SimpleField("m_Mode", "int", (AssetValueType)6));
		string[] array = new string[5] { "m_Radius", "m_WindMain", "m_WindTurbulence", "m_WindPulseMagnitude", "m_WindPulseFrequency" };
		foreach (string name in array)
		{
			val.Children.Add(SimpleField(name, "float", (AssetValueType)10));
		}
		TypeTreeType val2 = new TypeTreeType
		{
			TypeId = 182,
			ScriptTypeIndex = ushort.MaxValue,
			TypeDependencies = new int[0]
		};
		m_describer.Describe(val, val2);
		m_types[182] = val2;
	}

	private static AssetTypeTemplateField SimpleField(string name, string type, AssetValueType valueType)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: 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_0013: 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_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected O, but got Unknown
		return new AssetTypeTemplateField
		{
			Name = name,
			Type = type,
			ValueType = valueType,
			HasValue = true,
			Children = new List<AssetTypeTemplateField>()
		};
	}

	private AssetsFile OpenTemplate(out BundleFileInstance bundle, out AssetBundleDirectoryInfo entry)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		AssetsManager val = new AssetsManager();
		bundle = val.LoadBundleFile((Stream)new MemoryStream(m_template), "ock_template", true);
		entry = bundle.file.BlockAndDirInfo.DirectoryInfos.First((AssetBundleDirectoryInfo d) => !d.Name.EndsWith(".resS") && !d.Name.EndsWith(".resource"));
		return val.LoadAssetsFileFromBundle(bundle, entry.Name, false).file;
	}

	private AssetTypeValueField Read(AssetFileInfo info, AssetsFile file)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		AssetTypeTemplateField val = new AssetTypeTemplateField();
		val.FromTypeTree(m_types[info.TypeId]);
		return val.MakeValue(file.Reader, info.GetAbsoluteByteOffset(file), (RefTypeManager)null);
	}

	private LevelIndex LevelFor(string levelFile)
	{
		if (m_levels.TryGetValue(levelFile, out var value))
		{
			return value;
		}
		AssetsFile file = m_manager.LoadAssetsFile(Path.Combine(m_gameData, levelFile), false).file;
		value = new LevelIndex
		{
			File = file,
			ById = file.AssetInfos.ToDictionary((AssetFileInfo i) => i.PathId)
		};
		foreach (AssetFileInfo item in file.AssetInfos.Where((AssetFileInfo i) => i.TypeId == 1))
		{
			value.Names[item.PathId] = Read(item, file)["m_Name"].AsString;
		}
		foreach (AssetFileInfo item2 in file.AssetInfos.Where((AssetFileInfo i) => i.TypeId == 4))
		{
			AssetTypeValueField val = Read(item2, file);
			long asLong = val["m_Father.m_PathID"].AsLong;
			value.GameObjectOf[item2.PathId] = val["m_GameObject.m_PathID"].AsLong;
			value.FatherOf[item2.PathId] = asLong;
			value.ChildrenOf[item2.PathId] = val["m_Children.Array"].Children.Select((AssetTypeValueField c) => c["m_PathID"].AsLong).ToList();
			if (asLong == 0L)
			{
				value.RootTransforms.Add(item2.PathId);
			}
		}
		m_levels[levelFile] = value;
		return value;
	}

	private static long FindTransform(LevelIndex level, string path)
	{
		string[] parts = path.Split(new char[1] { '/' });
		long num = level.RootTransforms.FirstOrDefault((long t) => NameOf(level, t) == parts[0]);
		int i;
		for (i = 1; i < parts.Length; i++)
		{
			if (num == 0L)
			{
				break;
			}
			num = level.ChildrenOf[num].FirstOrDefault((long c) => NameOf(level, c) == parts[i]);
		}
		return num;
	}

	private static string NameOf(LevelIndex level, long transform)
	{
		if (!level.Names.TryGetValue(level.GameObjectOf[transform], out var value))
		{
			return "";
		}
		return value;
	}

	public BuildReport Build(string levelFile, string hierarchyPath, string outputFile)
	{
		LevelIndex level = LevelFor(levelFile);
		long num = FindTransform(level, hierarchyPath);
		if (num == 0L)
		{
			throw new InvalidDataException("'" + hierarchyPath + "' isn't in " + levelFile + ". The game may have changed.");
		}
		return BuildFrom(level, num, hierarchyPath, outputFile);
	}

	public BuildReport BuildScriptHolder(string levelFile, string scriptClass, bool largest, string outputFile)
	{
		LevelIndex level = LevelFor(levelFile);
		List<long> list = (from i in level.File.AssetInfos
			where i.TypeId == 114 && ClassOf(level, i) == scriptClass
			select TransformOfScript(level, i) into t
			where t != 0
			select t).ToList();
		if (list.Count == 0)
		{
			throw new InvalidDataException(levelFile + " has nothing holding a " + scriptClass + ".");
		}
		long root = (largest ? list.OrderByDescending(ScaleOf(level)).First() : FirstInSceneOrder(level, list));
		return BuildFrom(level, root, scriptClass, outputFile);
	}

	private static long FirstInSceneOrder(LevelIndex level, List<long> candidates)
	{
		HashSet<long> wanted = new HashSet<long>(candidates);
		Func<long, long> search = null;
		search = delegate(long t)
		{
			if (wanted.Contains(t))
			{
				return t;
			}
			foreach (long item in level.ChildrenOf[t])
			{
				long num = search(item);
				if (num != 0L)
				{
					return num;
				}
			}
			return 0L;
		};
		return level.RootTransforms.Select(search).FirstOrDefault((long t) => t != 0);
	}

	private Func<long, float> ScaleOf(LevelIndex level)
	{
		return delegate(long t)
		{
			AssetTypeValueField val = Read(level.ById[t], level.File);
			return (!Read(level.ById[level.GameObjectOf[t]], level.File)["m_Component.Array"].Children.Any((AssetTypeValueField c) => level.ById[c["component.m_PathID"].AsLong].TypeId == 33)) ? 0f : val["m_LocalScale.x"].AsFloat;
		};
	}

	private long TransformOfScript(LevelIndex level, AssetFileInfo script)
	{
		long asLong = Read(script, level.File)["m_GameObject.m_PathID"].AsLong;
		foreach (KeyValuePair<long, long> item in level.GameObjectOf)
		{
			if (item.Value == asLong)
			{
				return item.Key;
			}
		}
		return 0L;
	}

	private string ClassOf(LevelIndex level, AssetFileInfo script)
	{
		TypeTreeType val = level.File.Metadata.TypeTreeTypes[script.TypeIdOrIndex];
		if (level.ScriptClasses.TryGetValue(val.ScriptTypeIndex, out var value))
		{
			return value;
		}
		AssetPPtr pointer = level.File.Metadata.ScriptTypes[val.ScriptTypeIndex];
		string pathName = level.File.Metadata.Externals[pointer.FileId - 1].PathName;
		AssetsFile val2 = ScriptFileFor(pathName);
		value = Read(val2.AssetInfos.First((AssetFileInfo i) => i.PathId == pointer.PathId), val2)["m_ClassName"].AsString;
		level.ScriptClasses[val.ScriptTypeIndex] = value;
		return value;
	}

	private AssetsFile ScriptFileFor(string fileName)
	{
		if (!m_scriptFiles.TryGetValue(fileName, out var value))
		{
			value = (m_scriptFiles[fileName] = m_manager.LoadAssetsFile(Path.Combine(m_gameData, fileName), false).file);
		}
		return value;
	}

	public BuildReport BuildTexturePointer(string levelFile, string textureName, string outputFile)
	{
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Expected O, but got Unknown
		List<AssetsFileExternal> list = LevelFor(levelFile).File.Metadata.Externals.Where((AssetsFileExternal e) => e.PathName.EndsWith(".assets")).ToList();
		foreach (string path in from p in Directory.GetFiles(m_gameData, "*.assets")
			orderby p
			select p)
		{
			if (!list.Any((AssetsFileExternal c) => c.PathName == Path.GetFileName(path)))
			{
				list.Add(new AssetsFileExternal
				{
					PathName = Path.GetFileName(path),
					OriginalPathName = Path.GetFileName(path),
					VirtualAssetPathName = "",
					Type = (AssetsFileExternalType)0
				});
			}
		}
		AssetsFileExternal val = null;
		long pathId = 0L;
		foreach (AssetsFileExternal item in list)
		{
			if (item.PathName == "globalgamemanagers.assets" || !File.Exists(Path.Combine(m_gameData, item.PathName)))
			{
				continue;
			}
			AssetsFile val2 = ScriptFileFor(item.PathName);
			foreach (AssetFileInfo item2 in val2.AssetInfos.Where((AssetFileInfo i) => i.TypeId == 28))
			{
				val2.Reader.Position = item2.GetAbsoluteByteOffset(val2);
				int num = ((BinaryReader)(object)val2.Reader).ReadInt32();
				if (num == textureName.Length && Encoding.UTF8.GetString(((BinaryReader)(object)val2.Reader).ReadBytes(num)) == textureName)
				{
					val = item;
					pathId = item2.PathId;
					break;
				}
			}
			if (val != null)
			{
				break;
			}
		}
		if (val == null)
		{
			throw new InvalidDataException("No texture called " + textureName + " in the game's files.");
		}
		return BuildPointer(val, pathId, outputFile);
	}

	public BuildReport BuildShaderPointer(string shaderName, string outputFile)
	{
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Expected O, but got Unknown
		foreach (string item in from p in Directory.GetFiles(m_gameData, "*.assets")
			orderby p
			select p)
		{
			string fileName = Path.GetFileName(item);
			AssetsFile val = ScriptFileFor(fileName);
			foreach (AssetFileInfo item2 in val.AssetInfos.Where((AssetFileInfo i) => i.TypeId == 48))
			{
				if (!(Read(item2, val)["m_ParsedForm.m_Name"].AsString != shaderName))
				{
					AssetsFileExternal external = new AssetsFileExternal
					{
						PathName = fileName,
						OriginalPathName = fileName,
						VirtualAssetPathName = "",
						Type = (AssetsFileExternalType)0
					};
					return BuildPointer(external, item2.PathId, outputFile);
				}
			}
		}
		throw new InvalidDataException("No shader called " + shaderName + " in the game's files.");
	}

	private BuildReport BuildPointer(AssetsFileExternal external, long pathId, string outputFile)
	{
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_0216: Expected O, but got Unknown
		BundleFileInstance bundle;
		AssetBundleDirectoryInfo entry;
		AssetsFile val = OpenTemplate(out bundle, out entry);
		AssetFileInfo info = val.AssetInfos.First((AssetFileInfo i) => i.TypeId == 142);
		AssetTypeValueField obj = Read(info, val);
		string fileName = Path.GetFileName(outputFile);
		obj["m_Name"].AsString = fileName;
		obj["m_AssetBundleName"].AsString = fileName;
		AssetTypeValueField obj2 = obj["m_PreloadTable.Array"];
		obj2.Children.Clear();
		AssetTypeValueField val2 = ValueBuilder.DefaultValueFieldFromArrayTemplate(obj2);
		val2["m_FileID"].AsInt = 1;
		val2["m_PathID"].AsLong = pathId;
		obj2.Children.Add(val2);
		AssetTypeValueField obj3 = obj["m_Container.Array"];
		AssetTypeValueField val3 = obj3.Children[0];
		obj3.Children.Clear();
		val3["first"].AsString = "assets/ock/extracted.pointer";
		val3["second.preloadIndex"].AsInt = 0;
		val3["second.preloadSize"].AsInt = 1;
		val3["second.asset.m_FileID"].AsInt = 1;
		val3["second.asset.m_PathID"].AsLong = pathId;
		obj3.Children.Add(val3);
		byte[] newData = obj.WriteToByteArray(false);
		foreach (AssetFileInfo item in val.AssetInfos.ToList())
		{
			val.Metadata.RemoveAssetInfo(item);
		}
		val.Metadata.Externals = new List<AssetsFileExternal> { external };
		val.Metadata.ScriptTypes = new List<AssetPPtr>();
		val.Metadata.TypeTreeTypes = new List<TypeTreeType> { m_types[142] };
		AssetFileInfo val4 = new AssetFileInfo
		{
			PathId = 1L,
			TypeIdOrIndex = 0,
			OldTypeId = 142,
			ScriptTypeIndex = ushort.MaxValue,
			TypeId = 142
		};
		val4.SetNewData(newData);
		val.Metadata.AddAssetInfo(val4);
		return Write(bundle, entry, val, outputFile, new BuildReport
		{
			Objects = 1
		});
	}

	private static BuildReport Write(BundleFileInstance bundle, AssetBundleDirectoryInfo entry, AssetsFile output, string outputFile, BuildReport report)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		entry.Name = "CAB-ock-" + Path.GetFileName(outputFile);
		entry.SetNewData(output);
		string text = outputFile + ".tmp";
		Directory.CreateDirectory(Path.GetDirectoryName(outputFile));
		AssetsFileWriter val = new AssetsFileWriter(text);
		try
		{
			bundle.file.Write(val, 0L);
		}
		finally
		{
			((IDisposable)val)?.Dispose();
		}
		if (File.Exists(outputFile))
		{
			File.Delete(outputFile);
		}
		File.Move(text, outputFile);
		report.Bytes = new FileInfo(outputFile).Length;
		return report;
	}

	public BuildReport BuildPruned(string levelFile, string rootName, string[] keepChildren, string keepHolding, string outputFile)
	{
		LevelIndex level = LevelFor(levelFile);
		long num = FindTransform(level, rootName);
		if (num == 0L)
		{
			throw new InvalidDataException("'" + rootName + "' isn't in " + levelFile + ". The game may have changed.");
		}
		HashSet<long> hashSet = new HashSet<long>(level.ChildrenOf[num].Where((long c) => keepChildren.Contains(NameOf(level, c))));
		foreach (AssetFileInfo item in level.File.AssetInfos.Where((AssetFileInfo i) => i.TypeId == 114 && ClassOf(level, i) == keepHolding))
		{
			long num2 = TransformOfScript(level, item);
			bool flag = num2 == num;
			long num3 = num2;
			while (num3 != 0L && num3 != num && !flag)
			{
				flag = hashSet.Contains(num3);
				num3 = level.FatherOf[num3];
			}
			if (num2 != 0L && !flag)
			{
				hashSet.Add(num2);
			}
		}
		return BuildFrom(level, num, rootName, outputFile, hashSet);
	}

	private BuildReport BuildFrom(LevelIndex level, long root, string hierarchyPath, string outputFile, HashSet<long> onlyChildren = null)
	{
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: 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_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: 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_027b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_0295: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: Expected O, but got Unknown
		//IL_0328: Unknown result type (might be due to invalid IL or missing references)
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0335: Unknown result type (might be due to invalid IL or missing references)
		//IL_0344: Unknown result type (might be due to invalid IL or missing references)
		//IL_034f: Unknown result type (might be due to invalid IL or missing references)
		//IL_035a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0367: Expected O, but got Unknown
		//IL_03da: Unknown result type (might be due to invalid IL or missing references)
		//IL_03df: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e7: 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_0408: Unknown result type (might be due to invalid IL or missing references)
		//IL_0415: Unknown result type (might be due to invalid IL or missing references)
		//IL_0422: Unknown result type (might be due to invalid IL or missing references)
		//IL_0431: Expected O, but got Unknown
		m_onlyChildren = onlyChildren;
		HashSet<long> hashSet = Gather(level, root);
		string text = string.Join(", ", from t in hashSet.Select((long k) => level.ById[k].TypeId).Distinct()
			where !m_types.ContainsKey(t)
			orderby t
			select t);
		if (text.Length > 0)
		{
			throw new NotSupportedException("'" + hierarchyPath + "' uses classes the template can't describe yet: " + text + ".");
		}
		BundleFileInstance bundle;
		AssetBundleDirectoryInfo entry;
		AssetsFile val = OpenTemplate(out bundle, out entry);
		byte[] newData = MakeBundleRecord(val, hashSet, level.GameObjectOf[root], Path.GetFileName(outputFile));
		foreach (AssetFileInfo item in val.AssetInfos.ToList())
		{
			val.Metadata.RemoveAssetInfo(item);
		}
		AssetsFileMetadata metadata = val.Metadata;
		metadata.Externals = level.File.Metadata.Externals;
		metadata.ScriptTypes = level.File.Metadata.ScriptTypes;
		metadata.TypeTreeEnabled = true;
		List<TypeTreeType> list = new List<TypeTreeType>();
		Dictionary<int, int> dictionary = new Dictionary<int, int>();
		BuildReport buildReport = new BuildReport();
		foreach (int item2 in from i in hashSet.Select((long k) => level.ById[k].TypeIdOrIndex).Distinct()
			orderby i
			select i)
		{
			TypeTreeType val2 = level.File.Metadata.TypeTreeTypes[item2];
			TypeTreeType val3 = m_types[val2.TypeId];
			dictionary[item2] = list.Count;
			TypeTreeType val4 = new TypeTreeType
			{
				TypeId = val2.TypeId,
				IsStrippedType = val2.IsStrippedType,
				ScriptTypeIndex = val2.ScriptTypeIndex,
				ScriptIdHash = val2.ScriptIdHash,
				TypeHash = val2.TypeHash,
				StringBufferBytes = val3.StringBufferBytes,
				Nodes = val3.Nodes,
				TypeDependencies = new int[0]
			};
			list.Add(val4);
			if (val2.TypeId == 114)
			{
				CheckAndDescribeScript(level, hashSet, item2, val2, val4, buildReport);
			}
		}
		list.Add(m_types[142]);
		metadata.TypeTreeTypes = list;
		if (hashSet.Contains(1L))
		{
			throw new NotSupportedException($"'{hierarchyPath}' holds object {1L}, which a bundle needs for itself.");
		}
		AssetFileInfo val5 = new AssetFileInfo
		{
			PathId = 1L,
			TypeIdOrIndex = list.Count - 1,
			OldTypeId = 142,
			ScriptTypeIndex = ushort.MaxValue,
			TypeId = 142
		};
		val5.SetNewData(newData);
		metadata.AddAssetInfo(val5);
		foreach (long item3 in hashSet.OrderBy((long i) => i))
		{
			AssetFileInfo val6 = level.ById[item3];
			byte[] newData2 = BytesFor(level, val6, root, buildReport);
			AssetFileInfo val7 = new AssetFileInfo
			{
				PathId = item3,
				TypeIdOrIndex = dictionary[val6.TypeIdOrIndex],
				OldTypeId = val6.OldTypeId,
				ScriptTypeIndex = val6.ScriptTypeIndex,
				Stripped = val6.Stripped,
				TypeId = val6.TypeId
			};
			val7.SetNewData(newData2);
			metadata.AddAssetInfo(val7);
			buildReport.Objects++;
		}
		return Write(bundle, entry, val, outputFile, buildReport);
	}

	public string[] MissingClasses(string levelFile, string hierarchyPath)
	{
		LevelIndex level = LevelFor(levelFile);
		long num = FindTransform(level, hierarchyPath);
		if (num == 0L)
		{
			return new string[1] { "not found" };
		}
		m_onlyChildren = null;
		return (from t in (from k in Gather(level, num)
				select level.ById[k].TypeId).Distinct()
			where !m_types.ContainsKey(t)
			select "class " + t).ToArray();
	}

	private HashSet<long> Gather(LevelIndex level, long root)
	{
		HashSet<long> keep = new HashSet<long>();
		Queue<long> queue = new Queue<long>();
		Action<long> enqueue = delegate(long id)
		{
			if (id != 0L && keep.Add(id))
			{
				queue.Enqueue(id);
			}
		};
		Action<long> addHierarchy = null;
		addHierarchy = delegate(long t)
		{
			enqueue(t);
			long num = level.GameObjectOf[t];
			enqueue(num);
			foreach (AssetTypeValueField child in Read(level.ById[num], level.File)["m_Component.Array"].Children)
			{
				enqueue(child["component.m_PathID"].AsLong);
			}
			IEnumerable<long> enumerable2;
			if (t != root || m_onlyChildren == null)
			{
				IEnumerable<long> enumerable = level.ChildrenOf[t];
				enumerable2 = enumerable;
			}
			else
			{
				IEnumerable<long> enumerable = m_onlyChildren;
				enumerable2 = enumerable;
			}
			foreach (long item in enumerable2)
			{
				addHierarchy(item);
			}
		};
		addHierarchy(root);
		while (queue.Count > 0)
		{
			AssetFileInfo val = level.ById[queue.Dequeue()];
			if (val.TypeId == 114 || val.TypeId == 43 || !m_types.ContainsKey(val.TypeId))
			{
				continue;
			}
			VisitPointers(Read(val, level.File), delegate(AssetTypeValueField pointer)
			{
				if (pointer["m_FileID"].AsInt == 0 && level.ById.TryGetValue(pointer["m_PathID"].AsLong, out var value) && value.TypeId != 1 && value.TypeId != 4 && value.TypeId != 114)
				{
					enqueue(value.PathId);
				}
			});
		}
		return keep;
	}

	private static void VisitPointers(AssetTypeValueField field, Action<AssetTypeValueField> onPointer)
	{
		if (field.TemplateField.Type.StartsWith("PPtr<"))
		{
			onPointer(field);
		}
		else
		{
			if (field.Children == null)
			{
				return;
			}
			foreach (AssetTypeValueField child in field.Children)
			{
				VisitPointers(child, onPointer);
			}
		}
	}

	private byte[] MakeBundleRecord(AssetsFile template, HashSet<long> keep, long mainObject, string name)
	{
		AssetFileInfo info = template.AssetInfos.First((AssetFileInfo i) => i.TypeId == 142);
		AssetTypeValueField val = Read(info, template);
		val["m_Name"].AsString = name;
		val["m_AssetBundleName"].AsString = name;
		AssetTypeValueField val2 = val["m_PreloadTable.Array"];
		val2.Children.Clear();
		foreach (long item in keep.OrderBy((long i) => i))
		{
			AssetTypeValueField val3 = ValueBuilder.DefaultValueFieldFromArrayTemplate(val2);
			val3["m_FileID"].AsInt = 0;
			val3["m_PathID"].AsLong = item;
			val2.Children.Add(val3);
		}
		AssetTypeValueField obj = val["m_Container.Array"];
		AssetTypeValueField val4 = obj.Children[0];
		obj.Children.Clear();
		val4["first"].AsString = "assets/ock/extracted.prefab";
		val4["second.preloadIndex"].AsInt = 0;
		val4["second.preloadSize"].AsInt = keep.Count;
		val4["second.asset.m_FileID"].AsInt = 0;
		val4["second.asset.m_PathID"].AsLong = mainObject;
		obj.Children.Add(val4);
		return val.WriteToByteArray(false);
	}

	private void CheckAndDescribeScript(LevelIndex level, HashSet<long> keep, int oldIndex, TypeTreeType source, TypeTreeType type, BuildReport report)
	{
		AssetTypeTemplateField val = ScriptFields(level, source);
		foreach (AssetFileInfo item in from k in keep
			select level.ById[k] into i
			where i.TypeIdOrIndex == oldIndex
			select i)
		{
			int num = val.MakeValue(level.File.Reader, item.GetAbsoluteByteOffset(level.File), (RefTypeManager)null).WriteToByteArray(false).Length;
			if (num != (int)item.ByteSize)
			{
				throw new NotSupportedException($"A script's description gives {num} bytes where the game has {item.ByteSize}, so its data can't be trusted.");
			}
			report.Scripts++;
		}
		m_describer.Describe(val, type);
	}

	private AssetTypeTemplateField ScriptFields(LevelIndex level, TypeTreeType source)
	{
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Expected O, but got Unknown
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Expected O, but got Unknown
		AssetPPtr pointer = level.File.Metadata.ScriptTypes[source.ScriptTypeIndex];
		string pathName = level.File.Metadata.Externals[pointer.FileId - 1].PathName;
		AssetsFile val = ScriptFileFor(pathName);
		AssetFileInfo info = val.AssetInfos.First((AssetFileInfo i) => i.PathId == pointer.PathId);
		AssetTypeValueField val2 = Read(info, val);
		string asString = val2["m_Namespace"].AsString;
		string asString2 = val2["m_ClassName"].AsString;
		string text = asString + "." + asString2;
		if (m_scriptFields.TryGetValue(text, out var value))
		{
			return value;
		}
		string text2 = val2["m_AssemblyName"].AsString;
		if (!text2.EndsWith(".dll"))
		{
			text2 += ".dll";
		}
		AssetTypeTemplateField val3 = new AssetTypeTemplateField();
		val3.FromTypeTree(m_types[114]);
		value = m_scriptReader.GetTemplateField(val3, text2, asString, asString2, new UnityVersion(level.File.Metadata.UnityVersion));
		if (value == null)
		{
			throw new NotSupportedException("No description for script " + text);
		}
		m_scriptFields[text] = value;
		return value;
	}

	private byte[] BytesFor(LevelIndex level, AssetFileInfo info, long root, BuildReport report)
	{
		AssetsFile file = level.File;
		if (info.PathId == root)
		{
			return RootTransformBytes(level, info);
		}
		if (info.TypeId == 4 && m_onlyChildren != null && m_onlyChildren.Contains(info.PathId) && level.FatherOf[info.PathId] != root)
		{
			AssetTypeValueField obj = Read(info, file);
			obj["m_Father.m_PathID"].AsLong = root;
			return obj.WriteToByteArray(false);
		}
		if (info.TypeId == 43)
		{
			AssetTypeValueField val = Read(info, file);
			string asString = val["m_StreamData.path"].AsString;
			if (!string.IsNullOrEmpty(asString))
			{
				byte[] array = new byte[val["m_StreamData.size"].AsUInt];
				using (FileStream fileStream = File.OpenRead(Path.Combine(m_gameData, Path.GetFileName(asString))))
				{
					fileStream.Position = (long)val["m_StreamData.offset"].AsULong;
					for (int i = 0; i < array.Length; i += fileStream.Read(array, i, array.Length - i))
					{
					}
				}
				val["m_VertexData.m_DataSize"].AsByteArray = array;
				val["m_StreamData.path"].AsString = "";
				val["m_StreamData.offset"].AsULong = 0uL;
				val["m_StreamData.size"].AsUInt = 0u;
				report.MeshBytes += array.Length;
				return val.WriteToByteArray(false);
			}
		}
		file.Reader.Position = info.GetAbsoluteByteOffset(file);
		return ((BinaryReader)(object)file.Reader).ReadBytes((int)info.ByteSize);
	}

	private byte[] RootTransformBytes(LevelIndex level, AssetFileInfo info)
	{
		Placement placement = Placement.Identity;
		List<long> list = new List<long>();
		for (long num = info.PathId; num != 0L; num = level.FatherOf[num])
		{
			list.Insert(0, num);
		}
		foreach (long item in list)
		{
			AssetTypeValueField val = Read(level.ById[item], level.File);
			placement = placement.Then(new Placement
			{
				PX = val["m_LocalPosition.x"].AsFloat,
				PY = val["m_LocalPosition.y"].AsFloat,
				PZ = val["m_LocalPosition.z"].AsFloat,
				RX = val["m_LocalRotation.x"].AsFloat,
				RY = val["m_LocalRotation.y"].AsFloat,
				RZ = val["m_LocalRotation.z"].AsFloat,
				RW = val["m_LocalRotation.w"].AsFloat,
				SX = val["m_LocalScale.x"].AsFloat,
				SY = val["m_LocalScale.y"].AsFloat,
				SZ = val["m_LocalScale.z"].AsFloat
			});
		}
		AssetTypeValueField val2 = Read(info, level.File);
		val2["m_Father.m_FileID"].AsInt = 0;
		val2["m_Father.m_PathID"].AsLong = 0L;
		val2["m_LocalPosition.x"].AsFloat = placement.PX;
		val2["m_LocalPosition.y"].AsFloat = placement.PY;
		val2["m_LocalPosition.z"].AsFloat = placement.PZ;
		val2["m_LocalRotation.x"].AsFloat = placement.RX;
		val2["m_LocalRotation.y"].AsFloat = placement.RY;
		val2["m_LocalRotation.z"].AsFloat = placement.RZ;
		val2["m_LocalRotation.w"].AsFloat = placement.RW;
		val2["m_LocalScale.x"].AsFloat = placement.SX;
		val2["m_LocalScale.y"].AsFloat = placement.SY;
		val2["m_LocalScale.z"].AsFloat = placement.SZ;
		if (m_onlyChildren != null)
		{
			AssetTypeValueField val3 = val2["m_Children.Array"];
			val3.Children.Clear();
			foreach (long onlyChild in m_onlyChildren)
			{
				AssetTypeValueField val4 = ValueBuilder.DefaultValueFieldFromArrayTemplate(val3);
				val4["m_FileID"].AsInt = 0;
				val4["m_PathID"].AsLong = onlyChild;
				val3.Children.Add(val4);
			}
		}
		return val2.WriteToByteArray(false);
	}

	public List<string> CandidatePaths(string levelFile)
	{
		LevelIndex level = LevelFor(levelFile);
		List<string> found = new List<string>();
		Action<long, string> walk = null;
		walk = delegate(long t, string parent)
		{
			string text = ((parent.Length == 0) ? NameOf(level, t) : (parent + "/" + NameOf(level, t)));
			HashSet<int> hashSet = new HashSet<int>(Read(level.ById[level.GameObjectOf[t]], level.File)["m_Component.Array"].Children.Select((AssetTypeValueField c) => level.ById[c["component.m_PathID"].AsLong].TypeId));
			if (parent.Length > 0 && (hashSet.Contains(205) || hashSet.Contains(33) || hashSet.Contains(143)))
			{
				found.Add(text);
				return;
			}
			foreach (long item in level.ChildrenOf[t])
			{
				walk(item, text);
			}
		};
		foreach (long rootTransform in level.RootTransforms)
		{
			walk(rootTransform, "");
		}
		return found;
	}
}
internal struct Placement
{
	public float PX;

	public float PY;

	public float PZ;

	public float RX;

	public float RY;

	public float RZ;

	public float RW;

	public float SX;

	public float SY;

	public float SZ;

	public static Placement Identity => new Placement
	{
		RW = 1f,
		SX = 1f,
		SY = 1f,
		SZ = 1f
	};

	public Placement Then(Placement child)
	{
		float num = child.PX * SX;
		float num2 = child.PY * SY;
		float num3 = child.PZ * SZ;
		float num4 = RY * num3 - RZ * num2;
		float num5 = RZ * num - RX * num3;
		float num6 = RX * num2 - RY * num;
		float num7 = RY * num6 - RZ * num5;
		float num8 = RZ * num4 - RX * num6;
		float num9 = RX * num5 - RY * num4;
		return new Placement
		{
			PX = PX + num + 2f * (RW * num4 + num7),
			PY = PY + num2 + 2f * (RW * num5 + num8),
			PZ = PZ + num3 + 2f * (RW * num6 + num9),
			RX = RW * child.RX + RX * child.RW + RY * child.RZ - RZ * child.RY,
			RY = RW * child.RY - RX * child.RZ + RY * child.RW + RZ * child.RX,
			RZ = RW * child.RZ + RX * child.RY - RY * child.RX + RZ * child.RW,
			RW = RW * child.RW - RX * child.RX - RY * child.RY - RZ * child.RZ,
			SX = SX * child.SX,
			SY = SY * child.SY,
			SZ = SZ * child.SZ
		};
	}
}
public class BuildReport
{
	public int Objects;

	public int Scripts;

	public long MeshBytes;

	public long Bytes;
}
internal class ScriptDescriber
{
	private struct BuiltInType
	{
		public string Name;

		public ushort Version;

		public BuiltInType(string name, ushort version)
		{
			Name = name;
			Version = version;
		}
	}

	private const uint ALIGN_FLAG = 16384u;

	private const uint ROOT_FLAG = 32768u;

	private const uint COMMON_STRING = 2147483648u;

	private static readonly Dictionary<string, BuiltInType> s_builtIn = new Dictionary<string, BuiltInType>
	{
		{
			"Vector2",
			new BuiltInType("Vector2f", 1)
		},
		{
			"Vector3",
			new BuiltInType("Vector3f", 1)
		},
		{
			"Vector4",
			new BuiltInType("Vector4f", 1)
		},
		{
			"Quaternion",
			new BuiltInType("Quaternionf", 1)
		},
		{
			"Color",
			new BuiltInType("ColorRGBA", 1)
		},
		{
			"Color32",
			new BuiltInType("ColorRGBA", 2)
		},
		{
			"Rect",
			new BuiltInType("Rectf", 2)
		},
		{
			"Bounds",
			new BuiltInType("AABB", 1)
		},
		{
			"LayerMask",
			new BuiltInType("BitField", 2)
		},
		{
			"AnimationCurve",
			new BuiltInType("AnimationCurve", 2)
		},
		{
			"Keyframe",
			new BuiltInType("Keyframe", 3)
		},
		{
			"Gradient",
			new BuiltInType("Gradient", 2)
		}
	};

	private readonly Dictionary<string, uint> m_commonStrings = new Dictionary<string, uint>();

	public ScriptDescriber(IEnumerable<TypeTreeType> knownTypes)
	{
		foreach (TypeTreeType knownType in knownTypes)
		{
			foreach (TypeTreeNode node in knownType.Nodes)
			{
				if ((node.TypeStrOffset & 0x80000000u) != 0)
				{
					m_commonStrings[node.GetTypeString(knownType.StringBufferBytes, (byte[])null)] = node.TypeStrOffset;
				}
				if ((node.NameStrOffset & 0x80000000u) != 0)
				{
					m_commonStrings[node.GetNameString(knownType.StringBufferBytes, (byte[])null)] = node.NameStrOffset;
				}
			}
		}
	}

	public void Describe(AssetTypeTemplateField fields, TypeTreeType type)
	{
		List<TypeTreeNode> nodes = new List<TypeTreeNode>();
		MemoryStream memoryStream = new MemoryStream();
		Dictionary<string, uint> local = new Dictionary<string, uint>();
		Flatten(fields, 0, nodes, memoryStream, local);
		type.StringBufferBytes = memoryStream.ToArray();
		type.Nodes = nodes;
	}

	private int Flatten(AssetTypeTemplateField field, byte level, List<TypeTreeNode> nodes, MemoryStream strings, Dictionary<string, uint> local)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Expected O, but got Unknown
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		BuiltInType value;
		string text = (s_builtIn.TryGetValue(field.Type, out value) ? value.Name : field.Type);
		TypeTreeNode val = new TypeTreeNode
		{
			Version = (ushort)((!s_builtIn.ContainsKey(field.Type)) ? 1 : value.Version),
			Level = level,
			TypeFlags = (TypeTreeNodeFlags)field.IsArray,
			TypeStrOffset = AddString(text, strings, local),
			NameStrOffset = AddString(field.Name, strings, local),
			Index = (uint)nodes.Count,
			MetaFlags = (uint)((IsAligned(field) ? 16384 : 0) | ((level == 0) ? 32768 : 0))
		};
		nodes.Add(val);
		int num = SizeOf(field.ValueType);
		bool flag = num < 0 && !field.IsArray && field.Type != "string" && field.Children.Count > 0;
		if (flag)
		{
			num = 0;
		}
		foreach (AssetTypeTemplateField child in field.Children)
		{
			int num2 = Flatten(child, (byte)(level + 1), nodes, strings, local);
			if (flag)
			{
				num = ((num < 0 || num2 < 0) ? (-1) : (num + num2));
			}
		}
		val.ByteSize = ((field.IsArray || field.Type == "string") ? (-1) : num);
		return val.ByteSize;
	}

	private uint AddString(string text, MemoryStream strings, Dictionary<string, uint> local)
	{
		if (m_commonStrings.TryGetValue(text, out var value) || local.TryGetValue(text, out value))
		{
			return value;
		}
		value = (local[text] = (uint)strings.Position);
		byte[] bytes = Encoding.UTF8.GetBytes(text);
		strings.Write(bytes, 0, bytes.Length);
		strings.WriteByte(0);
		return value;
	}

	private static int SizeOf(AssetValueType type)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected I4, but got Unknown
		switch (type - 1)
		{
		case 0:
		case 1:
		case 2:
			return 1;
		case 3:
		case 4:
			return 2;
		case 5:
		case 6:
		case 9:
			return 4;
		case 7:
		case 8:
		case 10:
			return 8;
		default:
			return -1;
		}
	}

	private static bool IsAligned(AssetTypeTemplateField field)
	{
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Invalid comparison between Unknown and I4
		if (!field.IsArray)
		{
			if (field.Type == "vector" && field.Children.Count == 1 && field.Children[0].Children.Count == 2)
			{
				string type = field.Children[0].Children[1].Type;
				switch (type)
				{
				default:
					return type == "bool";
				case "UInt8":
				case "SInt8":
				case "char":
					return true;
				}
			}
			return field.IsAligned;
		}
		AssetTypeTemplateField val = field.Children[1];
		if (!(val.Type == "string") && !(val.Type == "Keyframe"))
		{
			return (int)val.ValueType > 0;
		}
		return true;
	}
}