Decompiled source of Outward Construction Kit v0.3.1
AssetsTools.NET.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
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 agousing 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
The result has been truncated due to the large size, download it to view full contents!
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 agousing 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; } }