Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AssetHelper v1.3.2
plugins/AssetsTools.NET.dll
Decompiled a month 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(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyVersion("3.0.0.0")] namespace SevenZip { internal class CRC { public static readonly uint[] Table; private uint _value = uint.MaxValue; static CRC() { Table = new uint[256]; for (uint num = 0u; num < 256; num++) { uint num2 = num; for (int i = 0; i < 8; i++) { num2 = (((num2 & 1) == 0) ? (num2 >> 1) : ((num2 >> 1) ^ 0xEDB88320u)); } Table[num] = num2; } } public void Init() { _value = uint.MaxValue; } public void UpdateByte(byte b) { _value = Table[(byte)_value ^ b] ^ (_value >> 8); } public void Update(byte[] data, uint offset, uint size) { for (uint num = 0u; num < size; num++) { _value = Table[(byte)_value ^ data[offset + num]] ^ (_value >> 8); } } public uint GetDigest() { return _value ^ 0xFFFFFFFFu; } private static uint CalculateDigest(byte[] data, uint offset, uint size) { CRC cRC = new CRC(); cRC.Update(data, offset, size); return cRC.GetDigest(); } private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size) { return CalculateDigest(data, offset, size) == digest; } } internal class DataErrorException : ApplicationException { public DataErrorException() : base("Data Error") { } } internal class InvalidParamException : ApplicationException { public InvalidParamException() : base("Invalid Parameter") { } } public interface ICodeProgress { void SetProgress(long inSize, long outSize); } public interface ICoder { void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress); } public enum CoderPropID { DefaultProp, DictionarySize, UsedMemorySize, Order, BlockSize, PosStateBits, LitContextBits, LitPosBits, NumFastBytes, MatchFinder, MatchFinderCycles, NumPasses, Algorithm, NumThreads, EndMarker } public interface ISetCoderProperties { void SetCoderProperties(CoderPropID[] propIDs, object[] properties); } public interface IWriteCoderProperties { void WriteCoderProperties(Stream outStream); } public interface ISetDecoderProperties { void SetDecoderProperties(byte[] properties); } } namespace SevenZip.Compression.RangeCoder { internal class Encoder { public const uint kTopValue = 16777216u; private Stream Stream; public ulong Low; public uint Range; private uint _cacheSize; private byte _cache; private long StartPosition; public void SetStream(Stream stream) { Stream = stream; } public void ReleaseStream() { Stream = null; } public void Init() { StartPosition = Stream.Position; Low = 0uL; Range = uint.MaxValue; _cacheSize = 1u; _cache = 0; } public void FlushData() { for (int i = 0; i < 5; i++) { ShiftLow(); } } public void FlushStream() { Stream.Flush(); } public void CloseStream() { Stream.Close(); } public void Encode(uint start, uint size, uint total) { Low += start * (Range /= total); Range *= size; while (Range < 16777216) { Range <<= 8; ShiftLow(); } } public void ShiftLow() { if ((uint)Low < 4278190080u || (int)(Low >> 32) == 1) { byte b = _cache; do { Stream.WriteByte((byte)(b + (Low >> 32))); b = byte.MaxValue; } while (--_cacheSize != 0); _cache = (byte)((uint)Low >> 24); } _cacheSize++; Low = (uint)((int)Low << 8); } public void EncodeDirectBits(uint v, int numTotalBits) { for (int num = numTotalBits - 1; num >= 0; num--) { Range >>= 1; if (((v >> num) & 1) == 1) { Low += Range; } if (Range < 16777216) { Range <<= 8; ShiftLow(); } } } public void EncodeBit(uint size0, int numTotalBits, uint symbol) { uint num = (Range >> numTotalBits) * size0; if (symbol == 0) { Range = num; } else { Low += num; Range -= num; } while (Range < 16777216) { Range <<= 8; ShiftLow(); } } public long GetProcessedSizeAdd() { return _cacheSize + Stream.Position - StartPosition + 4; } } internal class Decoder { public const uint kTopValue = 16777216u; public uint Range; public uint Code; public Stream Stream; public void Init(Stream stream) { Stream = stream; Code = 0u; Range = uint.MaxValue; for (int i = 0; i < 5; i++) { Code = (Code << 8) | (byte)Stream.ReadByte(); } } public void ReleaseStream() { Stream = null; } public void CloseStream() { Stream.Close(); } public void Normalize() { while (Range < 16777216) { Code = (Code << 8) | (byte)Stream.ReadByte(); Range <<= 8; } } public void Normalize2() { if (Range < 16777216) { Code = (Code << 8) | (byte)Stream.ReadByte(); Range <<= 8; } } public uint GetThreshold(uint total) { return Code / (Range /= total); } public void Decode(uint start, uint size, uint total) { Code -= start * Range; Range *= size; Normalize(); } public uint DecodeDirectBits(int numTotalBits) { uint num = Range; uint num2 = Code; uint num3 = 0u; for (int num4 = numTotalBits; num4 > 0; num4--) { num >>= 1; uint num5 = num2 - num >> 31; num2 -= num & (num5 - 1); num3 = (num3 << 1) | (1 - num5); if (num < 16777216) { num2 = (num2 << 8) | (byte)Stream.ReadByte(); num <<= 8; } } Range = num; Code = num2; return num3; } public uint DecodeBit(uint size0, int numTotalBits) { uint num = (Range >> numTotalBits) * size0; uint result; if (Code < num) { result = 0u; Range = num; } else { result = 1u; Code -= num; Range -= num; } Normalize(); return result; } } internal struct BitEncoder { public const int kNumBitModelTotalBits = 11; public const uint kBitModelTotal = 2048u; private const int kNumMoveBits = 5; private const int kNumMoveReducingBits = 2; public const int kNumBitPriceShiftBits = 6; private uint Prob; private static uint[] ProbPrices; public void Init() { Prob = 1024u; } public void UpdateModel(uint symbol) { if (symbol == 0) { Prob += 2048 - Prob >> 5; } else { Prob -= Prob >> 5; } } public void Encode(Encoder encoder, uint symbol) { uint num = (encoder.Range >> 11) * Prob; if (symbol == 0) { encoder.Range = num; Prob += 2048 - Prob >> 5; } else { encoder.Low += num; encoder.Range -= num; Prob -= Prob >> 5; } if (encoder.Range < 16777216) { encoder.Range <<= 8; encoder.ShiftLow(); } } static BitEncoder() { ProbPrices = new uint[512]; for (int num = 8; num >= 0; num--) { int num2 = 1 << 9 - num - 1; uint num3 = (uint)(1 << 9 - num); for (uint num4 = (uint)num2; num4 < num3; num4++) { ProbPrices[num4] = (uint)(num << 6) + (num3 - num4 << 6 >> 9 - num - 1); } } } public uint GetPrice(uint symbol) { return ProbPrices[(((Prob - symbol) ^ (int)(0 - symbol)) & 0x7FF) >> 2]; } public uint GetPrice0() { return ProbPrices[Prob >> 2]; } public uint GetPrice1() { return ProbPrices[2048 - Prob >> 2]; } } internal struct BitDecoder { public const int kNumBitModelTotalBits = 11; public const uint kBitModelTotal = 2048u; private const int kNumMoveBits = 5; private uint Prob; public void UpdateModel(int numMoveBits, uint symbol) { if (symbol == 0) { Prob += 2048 - Prob >> numMoveBits; } else { Prob -= Prob >> numMoveBits; } } public void Init() { Prob = 1024u; } public uint Decode(Decoder rangeDecoder) { uint num = (rangeDecoder.Range >> 11) * Prob; if (rangeDecoder.Code < num) { rangeDecoder.Range = num; Prob += 2048 - Prob >> 5; if (rangeDecoder.Range < 16777216) { rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); rangeDecoder.Range <<= 8; } return 0u; } rangeDecoder.Range -= num; rangeDecoder.Code -= num; Prob -= Prob >> 5; if (rangeDecoder.Range < 16777216) { rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); rangeDecoder.Range <<= 8; } return 1u; } } internal struct BitTreeEncoder { private BitEncoder[] Models; private int NumBitLevels; public BitTreeEncoder(int numBitLevels) { NumBitLevels = numBitLevels; Models = new BitEncoder[1 << numBitLevels]; } public void Init() { for (uint num = 1u; num < 1 << NumBitLevels; num++) { Models[num].Init(); } } public void Encode(Encoder rangeEncoder, uint symbol) { uint num = 1u; int num2 = NumBitLevels; while (num2 > 0) { num2--; uint num3 = (symbol >> num2) & 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
plugins/AssetHelper.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using System.Threading.Tasks; using AssetHelperLib; using AssetHelperLib.BundleTools; using AssetHelperLib.IO; using AssetHelperLib.PreloadTable; using AssetHelperLib.Repacking; using AssetsTools.NET; using AssetsTools.NET.Extra; using BepInEx; using BepInEx.Logging; using DataDrivenConstants.Marker; using HarmonyLib; using Md.StartManager; using Microsoft.CodeAnalysis; using MonoDetour; using MonoDetour.Cil; using MonoDetour.DetourTypes; using MonoDetour.HookGen; using MonoDetour.Reflection.Unspeakable; using MonoMod.RuntimeDetour; using MonoMod.Utils; using Newtonsoft.Json; using Silksong.AssetHelper.CatalogTools; using Silksong.AssetHelper.Core; using Silksong.AssetHelper.Internal; using Silksong.AssetHelper.Plugin; using Silksong.AssetHelper.Plugin.LoadingPage; using Silksong.AssetHelper.Plugin.Tasks; using TeamCherry.Localization; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets.ResourceLocators; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.ResourceManagement.ResourceLocations; using UnityEngine.ResourceManagement.ResourceProviders; using UnityEngine.ResourceManagement.Util; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MonoDetourTargets(typeof(StartManager))] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AssetHelper")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Library for helping with loading vanilla Silksong assets.")] [assembly: AssemblyFileVersion("1.3.2.0")] [assembly: AssemblyInformationalVersion("1.3.2+cdd9cae110fc2313b117652474be58605ce40dba")] [assembly: AssemblyProduct("AssetHelper")] [assembly: AssemblyTitle("AssetHelper")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/silksong-modding/Silksong.AssetHelper")] [assembly: NeutralResourcesLanguage("EN")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.3.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlyList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int ICollection.Count => _items.Count; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => _items.Count; T IReadOnlyList<T>.this[int index] => _items[index]; int ICollection<T>.Count => _items.Count; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyList(List<T> items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return _items.Contains(item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return _items.IndexOf(item); } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } } [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T> { object IEnumerator.Current => _item; T IEnumerator<T>.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { if (!_moveNextCalled) { return _moveNextCalled = true; } return false; } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => 1; T IReadOnlyList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection<T>.Count => 1; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return EqualityComparer<T>.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { if (!EqualityComparer<T>.Default.Equals(_item, (T)value)) { return -1; } return 0; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new Enumerator(_item); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return EqualityComparer<T>.Default.Equals(_item, item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { if (!EqualityComparer<T>.Default.Equals(_item, item)) { return -1; } return 0; } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Md.StartManager { internal static class _Start_d__8 { internal static class MoveNext { public delegate void PrefixSignature(object self); public delegate void PostfixSignature(object self, ref bool returnValue); public static MonoDetourHook Prefix(PrefixSignature hook, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).Hook<PrefixDetour>(Target(), (Delegate)hook, config, applyByDefault); } public static MonoDetourHook Postfix(PostfixSignature hook, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).Hook<PostfixDetour>(Target(), (Delegate)hook, config, applyByDefault); } public static MonoDetourHook ILHook(Manipulator manipulator, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).ILHook(Target(), manipulator, config, applyByDefault); } public static MethodBase Target() { return (Type.GetType("StartManager+<Start>d__8, Assembly-CSharp") ?? throw new Exception("Missing Type: 'StartManager+<Start>d__8'")).GetMethod("MoveNext", (BindingFlags)(-1), null, Array.Empty<Type>(), null) ?? throw new MissingMethodException("StartManager+<Start>d__8", "MoveNext"); } } } internal static class Start { public delegate void PrefixSignature(StartManager self); public delegate void PostfixSignature(StartManager self, ref IEnumerator returnValue); public delegate void PrefixMoveNextSignature(SpeakableEnumerator<object, StartManager> self); public delegate void PostfixMoveNextSignature(SpeakableEnumerator<object, StartManager> self, ref bool continueEnumeration); public static MonoDetourHook Prefix(PrefixSignature hook, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).Hook<PrefixDetour>(Target(), (Delegate)hook, config, applyByDefault); } public static MonoDetourHook Postfix(PostfixSignature hook, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).Hook<PostfixDetour>(Target(), (Delegate)hook, config, applyByDefault); } public static MonoDetourHook ILHook(Manipulator manipulator, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).ILHook(Target(), manipulator, config, applyByDefault); } public static MonoDetourHook PrefixMoveNext(PrefixMoveNextSignature hook, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).Hook<PrefixDetour>((MethodBase)StateMachineTarget(), (Delegate)hook, config, applyByDefault); } public static MonoDetourHook PostfixMoveNext(PostfixMoveNextSignature hook, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).Hook<PostfixDetour>((MethodBase)StateMachineTarget(), (Delegate)hook, config, applyByDefault); } public static MonoDetourHook ILHookMoveNext(Manipulator manipulator, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null) { return (manager ?? DefaultMonoDetourManager.Instance).ILHook((MethodBase)StateMachineTarget(), manipulator, config, applyByDefault); } public static MethodBase Target() { return typeof(StartManager).GetMethod("Start", (BindingFlags)(-1), null, Array.Empty<Type>(), null) ?? throw new MissingMethodException("StartManager", "Start"); } public static MethodInfo StateMachineTarget() { return Extensions.GetStateMachineTarget((MethodInfo)Target()); } } } namespace MonoDetour.HookGen { internal static class DefaultMonoDetourManager { internal static MonoDetourManager Instance { get; } = New(); internal static MonoDetourManager New() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown return new MonoDetourManager(typeof(DefaultMonoDetourManager).Assembly.GetName().Name); } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true, Inherited = false)] internal class MonoDetourTargetsAttribute : Attribute, IMonoDetourTargets { public Type? TargetType { get; } public bool IncludeNestedTypes { get; set; } public string[]? Members { get; set; } public string[]? MemberNamePrefixes { get; set; } public string[]? MemberNameSuffixes { get; set; } public bool GenerateControlFlowVariants { get; set; } public MonoDetourTargetsAttribute(Type? targetType = null) { TargetType = targetType; IncludeNestedTypes = true; base..ctor(); } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Microsoft.CodeAnalysis.Embedded] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Microsoft.CodeAnalysis.Embedded] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Microsoft.CodeAnalysis { [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace DataDrivenConstants.Marker { [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)] internal sealed class DataInjectAttribute : Attribute { public string Prefix { get; set; } = "Get"; } [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] internal sealed class JsonDataAttribute : Attribute { public string ValuePath { get; } public string[] FileGlobs { get; } public JsonDataAttribute(string valuePath, params string[] fileGlobs) { ValuePath = valuePath; FileGlobs = (string[])fileGlobs.Clone(); } } internal enum NameStyle { PascalCase, CamelCase, SnakeCase, UpperSnakeCase } [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] internal sealed class NameGenerationStyleAttribute : Attribute { public NameStyle NameStyle { get; } public NameGenerationStyleAttribute(NameStyle nameStyle) { NameStyle = nameStyle; } } internal enum ReplacementKind { Normal, Regex } [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] internal sealed class ReplacementRuleAttribute : Attribute { public string OldString { get; } public string NewString { get; } public ReplacementKind ReplacementKind { get; } public ReplacementRuleAttribute(string oldString, string newString, ReplacementKind replacementKind = ReplacementKind.Normal) { OldString = oldString; NewString = newString; ReplacementKind = replacementKind; } } } namespace Silksong.AssetHelper { [AttributeUsage(AttributeTargets.Class)] internal class ModMenuIgnoreAttribute : Attribute { } [BepInDependency(/*Could not decode attribute arguments.*/)] [ModMenuIgnore] [BepInPlugin("org.silksong-modding.assethelper", "AssetHelper", "1.3.2")] public class AssetHelperPlugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <Start>d__13 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Start>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; AssetRequestAPI.CloseRequestAPI(); <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; } if (!AddressablesData.TryLoadBundleKeys()) { <>2__current = null; <>1__state = 2; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const string Id = "org.silksong-modding.assethelper"; public static AssetHelperPlugin Instance { get; private set; } internal static ManualLogSource InstanceLogger { get; private set; } public static string Name => "AssetHelper"; public static string Version => "1.3.2"; public static event Action? OnQuitApplication; private void Awake() { Instance = this; InstanceLogger = ((BaseUnityPlugin)this).Logger; InitLibLogging(); AssetsToolsPatch.Init(); AddressablesData.InvokeAfterAddressablesLoaded(BundleMetadata.Setup); StartupOverrideManager.Hook(); Addressables.ResourceManager.ResourceProviders.Add((IResourceProvider)(object)new ChildGameObjectProvider()); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Silksong version: " + VersionData.SilksongVersion + " // OS String: " + AssetPaths.OSFolderName)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin " + Name + " (org.silksong-modding.assethelper) has loaded!")); } private static void InitLibLogging() { ManualLogSource @object = Logger.CreateLogSource("AssetHelper.Lib"); Logging.OnLog += @object.LogInfo; Logging.OnLogWarning += @object.LogWarning; Logging.OnLogError += @object.LogError; } [IteratorStateMachine(typeof(<Start>d__13))] private IEnumerator Start() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Start>d__13(0); } private void OnApplicationQuit() { Delegate[] array = AssetHelperPlugin.OnQuitApplication?.GetInvocationList() ?? Array.Empty<Action>(); for (int i = 0; i < array.Length; i++) { ActionUtil.SafeInvoke((Action)array[i]); } } } internal static class AssetsToolsPatch { private static Hook? _atCopyHook; public static void Init() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown _atCopyHook = new Hook((MethodBase)typeof(Net35Polyfill).GetMethod("CopyToCompat"), (Delegate)new Action<Action<Stream, Stream, long, int>, Stream, Stream, long, int>(PatchC2C)); } private static void PatchC2C(Action<Stream, Stream, long, int> orig, Stream input, Stream output, long bytes, int bufferSize) { byte[] array = ArrayPool<byte>.Shared.Rent(bufferSize); if (bytes == -1) { bytes = long.MaxValue; } int num; while (bytes > 0 && (num = input.Read(array, 0, (int)Math.Min(array.Length, bytes))) > 0) { output.Write(array, 0, num); bytes -= num; } ArrayPool<byte>.Shared.Return(array); } } } namespace Silksong.AssetHelper.Plugin { internal class AssetRequest { public Dictionary<string, HashSet<string>> SceneAssets { get; set; } = new Dictionary<string, HashSet<string>>(); [JsonConverter(typeof(DictListConverter<ValueTuple<string, string>, Type>))] public Dictionary<(string bundleName, string assetName), Type> NonSceneAssets { get; set; } = new Dictionary<(string, string), Type>(); [JsonIgnore] public bool AnyRequestMade { get { if (SceneAssets.Count <= 0) { return NonSceneAssets.Count > 0; } return true; } } } public static class AssetRequestAPI { internal static DelayedAction AfterBundleCreationComplete; internal static AssetRequest Request { get; private set; } private static string SerializedRequestPath => Path.Combine(AssetPaths.CacheDirectory, "accumulated_request.json"); internal static bool RequestApiAvailable { get; private set; } public static IResourceLocator? SceneAssetLocator { get; internal set; } public static IResourceLocator? NonSceneAssetLocator { get; internal set; } static AssetRequestAPI() { RequestApiAvailable = true; AfterBundleCreationComplete = new DelayedAction(); if (JsonExtensions.TryLoadFromFile<AssetRequest>(SerializedRequestPath, out AssetRequest obj)) { Request = obj; } else { Request = new AssetRequest(); } } internal static void CloseRequestAPI() { RequestApiAvailable = false; Request.SerializeToFile(SerializedRequestPath); } private static void VerifyRequest([CallerMemberName] string? caller = null) { if (!RequestApiAvailable) { throw new InvalidOperationException("Requests made through " + caller + " should be made during a plugin's Awake method!"); } } public static void InvokeAfterBundleCreation(Action a) { AfterBundleCreationComplete.Subscribe(a); } public static void RequestSceneAssets(string sceneName, IEnumerable<string> assetPaths) { VerifyRequest("RequestSceneAssets"); sceneName = sceneName.ToLowerInvariant(); HashSet<string> value; HashSet<string> hashSet = (Request.SceneAssets.TryGetValue(sceneName, out value) ? value : new HashSet<string>()); hashSet.UnionWith(assetPaths); Request.SceneAssets[sceneName] = hashSet; } public static void RequestSceneAsset(string sceneName, string assetPath) { RequestSceneAssets(sceneName, new <>z__ReadOnlySingleElementList<string>(assetPath)); } public static void RequestSceneAssets(Dictionary<string, List<string>> assetData) { foreach (var (sceneName, assetPaths) in assetData) { RequestSceneAssets(sceneName, assetPaths); } } public static void RequestNonSceneAsset<T>(string bundleName, string assetName) { RequestNonSceneAsset(bundleName, assetName, typeof(T)); } public static void RequestNonSceneAsset(string bundleName, string assetName, Type assetType) { VerifyRequest("RequestNonSceneAsset"); bundleName = bundleName.ToLowerInvariant(); if (bundleName.EndsWith(".bundle")) { string text = bundleName; bundleName = text.Substring(0, text.Length - 7); } if (Request.NonSceneAssets.TryGetValue((bundleName, assetName), out Type value) && value != assetType) { AssetHelperPlugin.InstanceLogger.LogError((object)("Asset " + bundleName + " - " + assetName + " requested with both " + value.Name + " and " + assetType.Name)); } Request.NonSceneAssets[(bundleName, assetName)] = assetType; } public static void RequestNonSceneAssets<T>(string bundleName, IEnumerable<string> assetNames) where T : Object { foreach (string assetName in assetNames) { RequestNonSceneAsset<T>(bundleName, assetName); } } } public abstract class BaseStartupTask { public abstract IEnumerator Run(ILoadingScreen loadingScreen); } public static class CatalogKeys { public static string SceneCatalogId => "AssetHelper-RepackedScenes"; public static string NonSceneCatalogId => "AssetHelper-BundleAssets"; public static string GetKeyForSceneAsset(string sceneName, string objPath) { return SceneCatalogId + "/Assets/" + sceneName.ToLowerInvariant() + "/" + objPath; } public static string GetKeyForNonSceneAsset(string assetName) { return NonSceneCatalogId + "/" + assetName; } internal static string GetKeyForAssetAtTransform(string sceneName, long tPathId) { return $"{SceneCatalogId}/RepackedTransforms/{sceneName}/t{tPathId}.prefab"; } } internal class CatalogMetadata { [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(null)] public CachedFileMetadata Metadata { get; set; } = CachedFileMetadata.CreateNew(); } internal class SceneCatalogMetadata : CatalogMetadata { } internal class NonSceneCatalogMetadata : CatalogMetadata { [JsonConverter(typeof(DictListConverter<ValueTuple<string, string>, Type>))] public Dictionary<(string bundleName, string assetName), Type> CatalogAssets { get; set; } = new Dictionary<(string, string), Type>(); } internal class CustomCatalogBuilder { [CompilerGenerated] private sealed class <BuildRoutine>d__10 : IEnumerator<float>, IEnumerator, IDisposable { private int <>1__state; private float <>2__current; public string catalogId; public CustomCatalogBuilder <>4__this; private List<ContentCatalogDataEntry> <allEntries>5__2; private IEnumerator<int> <serializationRoutine>5__3; float IEnumerator<float>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <BuildRoutine>d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <allEntries>5__2 = null; <serializationRoutine>5__3 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { int num = <>1__state; CustomCatalogBuilder CS$<>8__locals0 = <>4__this; switch (num) { default: result = false; goto end_IL_0000; case 0: { <>1__state = -1; if (catalogId == null) { catalogId = CS$<>8__locals0._primaryKeyPrefix; } List<ContentCatalogDataEntry> list = new List<ContentCatalogDataEntry>(); list.AddRange(CS$<>8__locals0._includedBaseBundles.Select((string x) => CS$<>8__locals0._baseBundleEntries[x])); list.AddRange(CS$<>8__locals0._addedEntries); <allEntries>5__2 = list; <serializationRoutine>5__3 = CatalogUtils.WriteCatalogRoutine(<allEntries>5__2, catalogId); <>1__state = -3; break; } case 1: <>1__state = -3; break; } if (<serializationRoutine>5__3.MoveNext()) { <>2__current = (float)<serializationRoutine>5__3.Current / (float)<allEntries>5__2.Count; <>1__state = 1; result = true; } else { result = false; <>m__Finally1(); } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<serializationRoutine>5__3 != null) { <serializationRoutine>5__3.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private readonly string _primaryKeyPrefix; private readonly Dictionary<string, ContentCatalogDataEntry> _baseBundleEntries; private readonly HashSet<string> _includedBaseBundles = new HashSet<string>(); private readonly Dictionary<string, string> _basePrimaryKeys = new Dictionary<string, string>(); private readonly List<ContentCatalogDataEntry> _addedEntries = new List<ContentCatalogDataEntry>(); public CustomCatalogBuilder(string primaryKeyPrefix = "AssetHelper") { _primaryKeyPrefix = primaryKeyPrefix; _baseBundleEntries = new Dictionary<string, ContentCatalogDataEntry>(); foreach (string key in AddressablesData.BundleKeys.Keys) { if (AddressablesData.TryGetLocation(key, out IResourceLocation location) && !(location.ResourceType != typeof(IAssetBundleResource)) && !location.PrimaryKey.StartsWith("scenes_scenes_scenes") && AddressablesData.TryStrip(location.PrimaryKey, out string stripped)) { string text = _primaryKeyPrefix + "/DependencyBundles/" + stripped; ContentCatalogDataEntry value = CatalogEntryUtils.CreateEntryFromLocation(location, new List<string>(1) { text }); _baseBundleEntries.Add(stripped, value); _basePrimaryKeys.Add(stripped, text); } } } public bool TryDeclareBundleDep(string bundleName, [NotNullWhen(true)] out string? primaryKey) { string text = bundleName.ToLowerInvariant().Replace(".bundle", ""); if (!_basePrimaryKeys.TryGetValue(text, out primaryKey)) { return false; } _includedBaseBundles.Add(text); return true; } public void AddRepackedSceneData(string sceneName, RepackedBundleData data, SceneCatalogInfo info, string bundlePath, string? serializedBundlePath = null) { string text = _primaryKeyPrefix + "/SceneBundles/" + sceneName; ContentCatalogDataEntry item = CatalogEntryUtils.CreateBundleEntry(text, bundlePath, data.BundleName, new List<string>(), serializedBundlePath); _addedEntries.Add(item); List<string> list = new List<string>(1) { text }; foreach (string item4 in BundleMetadata.DetermineCatalogDeps("scenes_scenes_scenes/" + sceneName + ".bundle")) { if (!TryDeclareBundleDep(item4, out string primaryKey)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Error adding asset from scene " + sceneName + " with alien dep " + item4)); } else { list.Add(primaryKey); } } foreach (SceneCatalogInfo.GameObjectInfo rootGameObject in info.RootGameObjects) { ContentCatalogDataEntry item2 = CatalogEntryUtils.CreateAssetEntry(rootGameObject.ContainerPath, typeof(GameObject), list, new List<string>(2) { _primaryKeyPrefix + "/Assets/" + sceneName + "/" + rootGameObject.ObjPath, CatalogKeys.GetKeyForAssetAtTransform(sceneName, rootGameObject.TransformPathId) }); _addedEntries.Add(item2); } foreach (SceneCatalogInfo.ChildGameObjectInfo childGameObject in info.ChildGameObjects) { ContentCatalogDataEntry item3 = CatalogEntryUtils.CreateChildGameObjectEntry(CatalogKeys.GetKeyForAssetAtTransform(sceneName, childGameObject.AncestorTransformPathId), childGameObject.RelativePath, new List<string>(2) { _primaryKeyPrefix + "/Assets/" + sceneName + "/" + childGameObject.ObjPath, CatalogKeys.GetKeyForAssetAtTransform(sceneName, childGameObject.TransformPathId) }); _addedEntries.Add(item3); } } public void AddAssets(string bundle, List<(string asset, Type assetType)> data) { if (!TryDeclareBundleDep(bundle, out string primaryKey)) { throw new ArgumentException("Error adding assets from bundle " + bundle + ": bundle not recognized"); } List<string> list = new List<string>(1) { primaryKey }; foreach (string item4 in BundleMetadata.DetermineTransitiveDeps(bundle)) { if (!TryDeclareBundleDep(item4, out string primaryKey2)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Error adding asset from " + bundle + ": unrecognized T-dep " + item4)); } else { list.Add(primaryKey2); } } foreach (var datum in data) { string item = datum.asset; Type item2 = datum.assetType; ContentCatalogDataEntry item3 = CatalogEntryUtils.CreateAssetEntry(item, item2, list, new List<string>(1) { _primaryKeyPrefix + "/" + item }); _addedEntries.Add(item3); } } public void AddCatalogEntry(ContentCatalogDataEntry entry) { _addedEntries.Add(entry); } [IteratorStateMachine(typeof(<BuildRoutine>d__10))] public IEnumerator<float> BuildRoutine(string? catalogId = null) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <BuildRoutine>d__10(0) { <>4__this = this, catalogId = catalogId }; } } internal sealed class RepackedSceneBundleData { [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(null)] public CachedFileMetadata Metadata { get; init; } = CachedFileMetadata.CreateNew(); public required string SceneName { get; init; } public string? BundleHash { get; init; } public RepackedBundleData? Data { get; set; } public SceneCatalogInfo? CatalogInfo { get; set; } } internal static class StartupOverrideManager { [CompilerGenerated] private sealed class <WrapStartManagerStart>d__4 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public IEnumerator original; private LoadingScreen <screen>5__2; private bool <failed>5__3; private List<BaseStartupTask>.Enumerator <>7__wrap3; private BaseStartupTask <task>5__5; private IEnumerator <enumerator>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WrapStartManagerStart>d__4(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 2) { try { } finally { <>m__Finally1(); } } <screen>5__2 = null; <>7__wrap3 = default(List<BaseStartupTask>.Enumerator); <task>5__5 = null; <enumerator>5__6 = null; <>1__state = -2; } private bool MoveNext() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown try { bool flag; switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitUntil((Func<bool>)(() => AddressablesData.IsAddressablesLoaded)); <>1__state = 1; return true; case 1: <>1__state = -1; RentedFileArray.Pool = ArrayPool<byte>.Create(262144000, 5); <screen>5__2 = LoadingScreenExtensions.Create<LoadingScreen>(); <failed>5__3 = false; <>7__wrap3 = _tasks.GetEnumerator(); <>1__state = -3; goto IL_0161; case 2: <>1__state = -3; goto IL_00d6; case 3: <>1__state = -1; <>2__current = original; <>1__state = 4; return true; case 4: { <>1__state = -1; return false; } IL_0161: if (<>7__wrap3.MoveNext()) { <task>5__5 = <>7__wrap3.Current; <enumerator>5__6 = <task>5__5.Run(<screen>5__2); goto IL_00d6; } goto IL_0171; IL_00d6: try { flag = <enumerator>5__6.MoveNext(); } catch (Exception ex) { AssetHelperPlugin.InstanceLogger.LogError((object)($"Error during startup task of type {<task>5__5.GetType()}\n" + ex)); <failed>5__3 = true; goto IL_014b; } if (flag) { <>2__current = <enumerator>5__6.Current; <>1__state = 2; return true; } goto IL_014b; IL_0171: <>m__Finally1(); <>7__wrap3 = default(List<BaseStartupTask>.Enumerator); if (!<failed>5__3) { AssetHelperPlugin.InstanceLogger.LogInfo((object)"AssetHelper prep complete!"); AssetRequestAPI.AfterBundleCreationComplete.Activate(); _startupRun = true; <screen>5__2.SetProgress(1f); } else { AssetHelperPlugin.InstanceLogger.LogWarning((object)"An error occurred during startup, and AssetHelper did not finish."); } Object.Destroy((Object)(object)<screen>5__2); RentedFileArray.Pool = null; <>2__current = null; <>1__state = 3; return true; IL_014b: if (!<failed>5__3) { <enumerator>5__6 = null; <task>5__5 = null; goto IL_0161; } goto IL_0171; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap3).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static bool _startupRun = false; private static List<BaseStartupTask> _tasks = new List<BaseStartupTask>(3) { new BundleDepsPrecompute(), new SceneRepacking(), new NonSceneCatalog() }; internal static void Hook() { Start.Postfix(PrependStartManagerStart); } private static void PrependStartManagerStart(StartManager self, ref IEnumerator returnValue) { if (!_startupRun && AssetRequestAPI.Request.AnyRequestMade) { returnValue = WrapStartManagerStart(self, returnValue); } } [IteratorStateMachine(typeof(<WrapStartManagerStart>d__4))] private static IEnumerator WrapStartManagerStart(StartManager self, IEnumerator original) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WrapStartManagerStart>d__4(0) { original = original }; } } } namespace Silksong.AssetHelper.Plugin.Tasks { internal class BundleDepsPrecompute : BaseStartupTask { [CompilerGenerated] private sealed class <Run>d__0 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ILoadingScreen loadingScreen; private Stopwatch <sw>5__2; private List<string> <bundles>5__3; private int <ct>5__4; private int <misses>5__5; private List<string>.Enumerator <>7__wrap5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Run>d__0(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 2) { try { } finally { <>m__Finally1(); } } <sw>5__2 = null; <bundles>5__3 = null; <>7__wrap5 = default(List<string>.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (AssetRequestAPI.Request.NonSceneAssets.Count == 0) { return false; } loadingScreen.SetText("COMPUTING_BUNDLE_DEPS".GetLocalized()); <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; AssetHelperPlugin.InstanceLogger.LogInfo((object)"Computing bundle deps"); <sw>5__2 = Stopwatch.StartNew(); <bundles>5__3 = AddressablesData.BundleKeys.Keys.Where((string x) => !x.Contains("scenes_scenes_scenes")).ToList(); loadingScreen.SetProgress(0f); <ct>5__4 = 0; <misses>5__5 = 0; <>7__wrap5 = <bundles>5__3.GetEnumerator(); <>1__state = -3; break; case 2: <>1__state = -3; break; } while (<>7__wrap5.MoveNext()) { BundleMetadata.DetermineDirectDepsInternal(<>7__wrap5.Current, out var cacheHit); <ct>5__4++; loadingScreen.SetProgress((float)<ct>5__4 / (float)<bundles>5__3.Count); if (!cacheHit) { <misses>5__5++; if (<misses>5__5 % 5 == 0) { <>2__current = null; <>1__state = 2; return true; } } } <>m__Finally1(); <>7__wrap5 = default(List<string>.Enumerator); <sw>5__2.Stop(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Computed bundle deps in {<sw>5__2.ElapsedMilliseconds} ms."); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap5).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [IteratorStateMachine(typeof(<Run>d__0))] public override IEnumerator Run(ILoadingScreen loadingScreen) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Run>d__0(0) { loadingScreen = loadingScreen }; } } internal class NonSceneCatalog : BaseStartupTask { [CompilerGenerated] private sealed class <CreateAndLoadCatalog>d__3 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public NonSceneCatalog <>4__this; public ILoadingScreen bar; private IEnumerator <nonSceneCatalogCreate>5__2; private AsyncOperationHandle<IResourceLocator> <catalogLoadOp>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CreateAndLoadCatalog>d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) <nonSceneCatalogCreate>5__2 = null; <catalogLoadOp>5__3 = default(AsyncOperationHandle<IResourceLocator>); <>1__state = -2; } private bool MoveNext() { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; NonSceneCatalog nonSceneCatalog = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <nonSceneCatalogCreate>5__2 = nonSceneCatalog.CreateNonSceneAssetCatalog(bar); bar.SetText("BUILDING_NON_SCENE".GetLocalized()); <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; goto IL_0090; case 2: <>1__state = -1; goto IL_0090; case 3: <>1__state = -1; if (File.Exists(NonSceneCatalogPath) && AssetRequestAPI.Request.NonSceneAssets.Count > 0) { bar.SetText("LOADING_NON_SCENE".GetLocalized()); <>2__current = null; <>1__state = 4; return true; } goto IL_0161; case 4: <>1__state = -1; AssetHelperPlugin.InstanceLogger.LogInfo((object)"Loading non-scene catalog"); <catalogLoadOp>5__3 = Addressables.LoadContentCatalogAsync(NonSceneCatalogPath, (string)null); <>2__current = <catalogLoadOp>5__3; <>1__state = 5; return true; case 5: <>1__state = -1; AssetRequestAPI.NonSceneAssetLocator = <catalogLoadOp>5__3.Result; <catalogLoadOp>5__3 = default(AsyncOperationHandle<IResourceLocator>); goto IL_0161; case 6: { <>1__state = -1; return false; } IL_0161: <>2__current = null; <>1__state = 6; return true; IL_0090: if (<nonSceneCatalogCreate>5__2.MoveNext()) { <>2__current = null; <>1__state = 2; return true; } <>2__current = null; <>1__state = 3; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CreateNonSceneAssetCatalog>d__4 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ILoadingScreen screen; private string <catalogMetadataPath>5__2; private NonSceneCatalogMetadata <metadata>5__3; private CustomCatalogBuilder <cbr>5__4; private int <count>5__5; private IEnumerator<float> <serializationRoutine>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CreateNonSceneAssetCatalog>d__4(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 2) { try { } finally { <>m__Finally1(); } } <catalogMetadataPath>5__2 = null; <metadata>5__3 = null; <cbr>5__4 = null; <serializationRoutine>5__6 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: { <>1__state = -1; <catalogMetadataPath>5__2 = Path.ChangeExtension(NonSceneCatalogPath, ".json"); AssetHelperPlugin.InstanceLogger.LogInfo((object)"Creating NS catalog"); Dictionary<(string, string), Type> dictionary = new Dictionary<(string, string), Type>(); bool flag = false; if (JsonExtensions.TryLoadFromFile<NonSceneCatalogMetadata>(<catalogMetadataPath>5__2, out NonSceneCatalogMetadata obj) && obj.Metadata != null && obj.Metadata.SilksongVersion == VersionData.SilksongVersion && VersionData.EarliestAcceptableNonSceneCatalogVersion.AllowCachedData(obj.Metadata.PluginVersion) && obj.Metadata.OSFolderName == AssetPaths.OSFolderName) { dictionary = obj.CatalogAssets; } (string, string) key; Type value; foreach (KeyValuePair<(string, string), Type> nonSceneAsset in AssetRequestAPI.Request.NonSceneAssets) { nonSceneAsset.Deconstruct(out key, out value); (string, string) tuple = key; Type type = value; if (!dictionary.ContainsKey(tuple)) { dictionary.Add(tuple, type); flag = true; } else if (dictionary[tuple] != type) { AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Replacing {tuple} :: {dictionary[tuple]} -> {type}"); dictionary[tuple] = type; flag = true; } } if (!flag) { AssetHelperPlugin.InstanceLogger.LogInfo((object)"Not writing non-scene catalog: no new assets added"); result = false; } else { <metadata>5__3 = new NonSceneCatalogMetadata(); <cbr>5__4 = new CustomCatalogBuilder(CatalogKeys.NonSceneCatalogId); foreach (KeyValuePair<(string, string), Type> nonSceneAsset2 in AssetRequestAPI.Request.NonSceneAssets) { nonSceneAsset2.Deconstruct(out key, out value); (string, string) tuple2 = key; string item = tuple2.Item1; string item2 = tuple2.Item2; Type type2 = value; <cbr>5__4.AddAssets(item, new List<(string, Type)>(1) { (item2, type2) }); <metadata>5__3.CatalogAssets.Add((item, item2), type2); } <>2__current = null; <>1__state = 1; result = true; } goto end_IL_0000; } case 1: <>1__state = -1; AssetHelperPlugin.InstanceLogger.LogInfo((object)"Writing catalog"); <count>5__5 = 0; <serializationRoutine>5__6 = <cbr>5__4.BuildRoutine(); <>1__state = -3; break; case 2: <>1__state = -3; break; } while (true) { if (<serializationRoutine>5__6.MoveNext()) { float current = <serializationRoutine>5__6.Current; <count>5__5++; if (<count>5__5 % 10 == 0) { screen.SetProgress(current); <>2__current = null; <>1__state = 2; result = true; break; } continue; } <metadata>5__3.SerializeToFile(<catalogMetadataPath>5__2); result = false; <>m__Finally1(); break; } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<serializationRoutine>5__6 != null) { <serializationRoutine>5__6.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static string NonSceneCatalogPath => Path.Combine(AssetPaths.CatalogFolder, CatalogKeys.NonSceneCatalogId + ".bin"); public override IEnumerator Run(ILoadingScreen loadingScreen) { return CreateAndLoadCatalog(loadingScreen); } [IteratorStateMachine(typeof(<CreateAndLoadCatalog>d__3))] private IEnumerator CreateAndLoadCatalog(ILoadingScreen bar) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CreateAndLoadCatalog>d__3(0) { <>4__this = this, bar = bar }; } [IteratorStateMachine(typeof(<CreateNonSceneAssetCatalog>d__4))] private IEnumerator CreateNonSceneAssetCatalog(ILoadingScreen screen) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CreateNonSceneAssetCatalog>d__4(0) { screen = screen }; } } internal class SceneCatalogInfo { public record GameObjectInfo(string ObjPath, string ContainerPath, long TransformPathId); public record ChildGameObjectInfo(string ObjPath, long TransformPathId, string AncestorObjPath, string RelativePath, long AncestorTransformPathId); public List<GameObjectInfo> RootGameObjects { get; init; } = new List<GameObjectInfo>(); public List<ChildGameObjectInfo> ChildGameObjects { get; init; } = new List<ChildGameObjectInfo>(); public IEnumerable<string> LoadableAssets { get { List<string> list = new List<string>(); list.AddRange(RootGameObjects.Select((GameObjectInfo x) => x.ObjPath)); list.AddRange(ChildGameObjects.Select((ChildGameObjectInfo x) => x.ObjPath)); return new <>z__ReadOnlyList<string>(list); } } } internal class SceneRepacking : BaseStartupTask { [CompilerGenerated] private static class <>O { public static CabResolver <0>__ResolveCab; } [CompilerGenerated] private sealed class <Run>d__5 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SceneRepacking <>4__this; public ILoadingScreen loadingScreen; private List<string> <scenesToRepack>5__2; private AsyncOperationHandle<IResourceLocator> <catalogLoadOp>5__3; private IDisposable <cppSyncHandle>5__4; private SceneRepacker <repacker>5__5; private Stopwatch <mainSw>5__6; private int <total>5__7; private int <count>5__8; private List<string>.Enumerator <>7__wrap8; private CustomCatalogBuilder <cbr>5__10; private IEnumerator<float> <serializationRoutine>5__11; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Run>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { case -3: case 2: try { } finally { <>m__Finally1(); } break; case -4: case 6: try { } finally { <>m__Finally2(); } break; } <scenesToRepack>5__2 = null; <catalogLoadOp>5__3 = default(AsyncOperationHandle<IResourceLocator>); <cppSyncHandle>5__4 = null; <repacker>5__5 = null; <mainSw>5__6 = null; <>7__wrap8 = default(List<string>.Enumerator); <cbr>5__10 = null; <serializationRoutine>5__11 = null; <>1__state = -2; } private bool MoveNext() { //IL_072c: Unknown result type (might be due to invalid IL or missing references) //IL_0731: Unknown result type (might be due to invalid IL or missing references) //IL_0738: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Expected O, but got Unknown //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Expected O, but got Unknown //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Expected O, but got Unknown try { int num = <>1__state; SceneRepacking CS$<>8__locals0 = <>4__this; switch (num) { default: return false; case 0: { <>1__state = -1; if (AssetRequestAPI.Request.SceneAssets.Count == 0) { AssetHelperPlugin.InstanceLogger.LogInfo((object)"Not running scene repack operation: no scenes in request"); } if (JsonExtensions.TryLoadFromFile<Dictionary<string, RepackedSceneBundleData>>(AssetPaths.RepackedSceneBundleMetadataPath, out Dictionary<string, RepackedSceneBundleData> obj2)) { CS$<>8__locals0._repackData = obj2; } else { CS$<>8__locals0._repackData = new Dictionary<string, RepackedSceneBundleData>(); } CS$<>8__locals0._repackData = (from kvp in CS$<>8__locals0._repackData where kvp.Value.CatalogInfo != null && kvp.Value.Data != null where !MetadataMismatch(kvp.Key, kvp.Value) where File.Exists(GetBundlePathForScene(kvp.Key)) where CS$<>8__locals0.CanLoadAll(kvp.Value.CatalogInfo, kvp.Key) select kvp).ToDictionary((KeyValuePair<string, RepackedSceneBundleData> kvp) => kvp.Key, (KeyValuePair<string, RepackedSceneBundleData> kvp) => kvp.Value); loadingScreen.Reset(); loadingScreen.SetText("REPACKING_SCENE".GetLocalized()); <>2__current = null; <>1__state = 1; return true; } case 1: { <>1__state = -1; CachedObject<Dictionary<string, ContainerPointerPreloadsBundleData>> cachedObject = CachedObject<Dictionary<string, ContainerPointerPreloadsBundleData>>.CreateSynced("container_pointer_preloads_cache.json", () => new Dictionary<string, ContainerPointerPreloadsBundleData>(), mutable: true, out <cppSyncHandle>5__4); object obj = <>O.<0>__ResolveCab; if (obj == null) { CabResolver val = ResolveCab; <>O.<0>__ResolveCab = val; obj = (object)val; } ContainerPointerPreloads val2 = new ContainerPointerPreloads((CabResolver)obj); val2.set_Cache(cachedObject.Value); ContainerPointerPreloads item = val2; PreloadTableResolver val3 = new PreloadTableResolver(new List<BasePreloadTableResolver>(2) { (BasePreloadTableResolver)new DefaultPreloadTableResolver(), (BasePreloadTableResolver)(object)item }); <repacker>5__5 = (SceneRepacker)new StrippedSceneRepacker((BasePreloadTableResolver)(object)val3); <scenesToRepack>5__2 = AssetRequestAPI.Request.SceneAssets.Keys.Where((string x) => !CS$<>8__locals0._repackData.ContainsKey(x)).ToList(); <mainSw>5__6 = Stopwatch.StartNew(); <total>5__7 = <scenesToRepack>5__2.Count; <count>5__8 = 0; AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Repacking {<total>5__7} scenes"); <>7__wrap8 = <scenesToRepack>5__2.GetEnumerator(); <>1__state = -3; goto IL_03a6; } case 2: <>1__state = -3; goto IL_03a6; case 3: <>1__state = -1; <cppSyncHandle>5__4 = null; <repacker>5__5 = null; <mainSw>5__6 = null; if (<scenesToRepack>5__2.Count > 0 || CS$<>8__locals0.MustWriteCatalog()) { loadingScreen.Reset(); loadingScreen.SetText("BULDING_SCENE".GetLocalized()); <>2__current = null; <>1__state = 4; return true; } AssetHelperPlugin.InstanceLogger.LogInfo((object)"Not creating catalog"); goto IL_06c9; case 4: <>1__state = -1; AssetHelperPlugin.InstanceLogger.LogInfo((object)"Creating catalog"); <mainSw>5__6 = Stopwatch.StartNew(); <cbr>5__10 = new CustomCatalogBuilder(CatalogKeys.SceneCatalogId); foreach (var (sceneName, repackedSceneBundleData2) in CS$<>8__locals0._repackData) { if (repackedSceneBundleData2.Data != null && repackedSceneBundleData2.CatalogInfo != null) { string bundlePathForScene = GetBundlePathForScene(sceneName); string fileName = Path.GetFileName(bundlePathForScene); string serializedBundlePath = GetSerializedBundleDirPrefix() + "/" + fileName; <cbr>5__10.AddRepackedSceneData(sceneName, repackedSceneBundleData2.Data, repackedSceneBundleData2.CatalogInfo, bundlePathForScene, serializedBundlePath); } } <mainSw>5__6.Stop(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Prepared catalog in {<mainSw>5__6.ElapsedMilliseconds} ms"); loadingScreen.SetText("WRITING_SCENE".GetLocalized()); loadingScreen.SetProgress(0f); <>2__current = null; <>1__state = 5; return true; case 5: <>1__state = -1; <mainSw>5__6 = Stopwatch.StartNew(); <count>5__8 = 0; <serializationRoutine>5__11 = <cbr>5__10.BuildRoutine(); <>1__state = -4; goto IL_0652; case 6: <>1__state = -4; goto IL_0652; case 7: <>1__state = -1; loadingScreen.SetText("LOADING_SCENE".GetLocalized()); <>2__current = null; <>1__state = 8; return true; case 8: <>1__state = -1; AssetHelperPlugin.InstanceLogger.LogInfo((object)"Loading scene catalog"); <catalogLoadOp>5__3 = Addressables.LoadContentCatalogAsync(SceneCatalogPath, (string)null); <>2__current = <catalogLoadOp>5__3; <>1__state = 9; return true; case 9: <>1__state = -1; AssetRequestAPI.SceneAssetLocator = <catalogLoadOp>5__3.Result; <>2__current = null; <>1__state = 10; return true; case 10: { <>1__state = -1; return false; } IL_0652: while (<serializationRoutine>5__11.MoveNext()) { float current = <serializationRoutine>5__11.Current; <count>5__8++; if (<count>5__8 % 10 == 0) { loadingScreen.SetProgress(current); <>2__current = null; <>1__state = 6; return true; } } <mainSw>5__6.Stop(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Finished writing catalog in {<mainSw>5__6.ElapsedMilliseconds} ms"); new SceneCatalogMetadata().SerializeToFile(CatalogMetadataPath); <>m__Finally2(); <mainSw>5__6 = null; <cbr>5__10 = null; <serializationRoutine>5__11 = null; goto IL_06c9; IL_06c9: <>2__current = null; <>1__state = 7; return true; IL_03a6: if (<>7__wrap8.MoveNext()) { string current2 = <>7__wrap8.Current; HashSet<string> hashSet = AssetRequestAPI.Request.SceneAssets[current2]; Stopwatch stopwatch = Stopwatch.StartNew(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Repacking {hashSet.Count} objects in scene {current2}"); loadingScreen.SetSubtext(current2); RepackedSceneBundleData value = CS$<>8__locals0.DoRepack(current2, hashSet, <repacker>5__5); stopwatch.Stop(); CS$<>8__locals0._repackData[current2] = value; CS$<>8__locals0._repackData.SerializeToFile(AssetPaths.RepackedSceneBundleMetadataPath); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Repacked {current2} in {stopwatch.ElapsedMilliseconds} ms"); <count>5__8++; loadingScreen.SetProgress((float)<count>5__8 / (float)<total>5__7); <>2__current = null; <>1__state = 2; return true; } <>m__Finally1(); <>7__wrap8 = default(List<string>.Enumerator); <mainSw>5__6.Stop(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Finished scene repacking after {<mainSw>5__6.ElapsedMilliseconds} ms"); loadingScreen.Reset(); <cppSyncHandle>5__4?.Dispose(); <>2__current = null; <>1__state = 3; return true; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap8).Dispose(); } private void <>m__Finally2() { <>1__state = -1; if (<serializationRoutine>5__11 != null) { <serializationRoutine>5__11.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private Dictionary<string, RepackedSceneBundleData> _repackData = new Dictionary<string, RepackedSceneBundleData>(); private static string SceneCatalogPath => Path.Combine(AssetPaths.CatalogFolder, CatalogKeys.SceneCatalogId + ".bin"); private static string CatalogMetadataPath => Path.ChangeExtension(SceneCatalogPath, ".json"); [IteratorStateMachine(typeof(<Run>d__5))] public override IEnumerator Run(ILoadingScreen loadingScreen) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Run>d__5(0) { <>4__this = this, loadingScreen = loadingScreen }; } private RepackedSceneBundleData DoRepack(string scene, HashSet<string> request, SceneRepacker repacker) { //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_0038: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown HashSet<string> request2 = request; Dictionary<string, List<List<long>>> transformSeqs = null; string containerPrefix = "AssetHelper/" + scene; RepackingParams val = new RepackingParams { SceneBundlePath = AssetPaths.GetScenePath(scene), ObjectNames = request2.ToList(), ContainerPrefix = containerPrefix, OutBundlePath = GetBundlePathForScene(scene), LateCallback = delegate(RepackingContext ctx, RepackedBundleData data) { transformSeqs = BuildTransformSequences(ctx, data, request2); } }; RepackedBundleData val2 = repacker.Repack(val); string bundleHash = null; if (AddressablesData.TryGetLocationForScene(scene, out IResourceLocation location)) { object data2 = location.Data; AssetBundleRequestOptions val3 = (AssetBundleRequestOptions)((data2 is AssetBundleRequestOptions) ? data2 : null); if (val3 != null) { bundleHash = val3.Hash; } } SceneCatalogInfo catalogInfo = BuildSceneCatalogInfo(val2, transformSeqs, containerPrefix); return new RepackedSceneBundleData { SceneName = scene, BundleHash = bundleHash, Data = val2, CatalogInfo = catalogInfo }; } private SceneCatalogInfo BuildSceneCatalogInfo(RepackedBundleData repackData, Dictionary<string, List<List<long>>> transformSeqs, string containerPrefix) { string containerPrefix2 = containerPrefix; SceneCatalogInfo sceneCatalogInfo = new SceneCatalogInfo(); HashSet<string> hashSet = repackData.GameObjectAssets?.Values.Distinct().ToHashSet() ?? new HashSet<string>(); Dictionary<long, string> rootTransformPathIds = new Dictionary<long, string>(); foreach (string rootGo in hashSet) { foreach (List<long> transformSeq in transformSeqs[rootGo]) { string key = repackData.GameObjectAssets.First((KeyValuePair<string, string> kvp) => kvp.Key.StartsWith($"{containerPrefix2}/{transformSeq[0]}") && kvp.Value == rootGo).Key; sceneCatalogInfo.RootGameObjects.Add(new SceneCatalogInfo.GameObjectInfo(rootGo, key, transformSeq[0])); rootTransformPathIds.Add(transformSeq[0], rootGo); } } foreach (string key2 in transformSeqs.Keys) { if (hashSet.Contains(key2)) { continue; } foreach (List<long> item in transformSeqs[key2]) { long num = item.FirstOrDefault((long x) => rootTransformPathIds.ContainsKey(x)); if (num == 0L) { throw new Exception($"Unexpectedly failed to find ancestor for {key2} [{item[0]}]"); } string text = rootTransformPathIds[num]; if (!key2.StartsWith(text + "/")) { throw new Exception("Object " + key2 + " unexpectedly matched ancestor " + text); } string relativePath = key2.Substring(text.Length + 1); sceneCatalogInfo.ChildGameObjects.Add(new SceneCatalogInfo.ChildGameObjectInfo(key2, item[0], text, relativePath, num)); } } return sceneCatalogInfo; } private Dictionary<string, List<List<long>>> BuildTransformSequences(RepackingContext ctx, RepackedBundleData data, HashSet<string> request) { GameObjectLookup val = ctx.GameObjLookup ?? GameObjectLookup.CreateFromFile(ctx.SceneAssetsManager, ctx.MainAssetsFileInstance); Dictionary<string, List<List<long>>> dictionary = new Dictionary<string, List<List<long>>>(); HashSet<string> hashSet = new HashSet<string>(); foreach (string item in request) { hashSet.Add(item); } IEnumerable<string> enumerable = data.GameObjectAssets?.Values; foreach (string item2 in enumerable ?? Enumerable.Empty<string>()) { hashSet.Add(item2); } List<GameObjectInfo> list2 = default(List<GameObjectInfo>); foreach (string item3 in hashSet) { List<List<long>> list = new List<List<long>>(); if (!val.TryLookupName(item3, ref list2)) { throw new Exception("Failed to find " + item3 + " in bundle"); } foreach (GameObjectInfo item4 in list2) { GameObjectInfo val2 = item4; List<long> list3 = new List<long>(); long transformPathId = val2.TransformPathId; list3.Add(transformPathId); while (val2.ParentPathId != 0L) { val2 = val.LookupTransform(val2.ParentPathId); list3.Add(val2.TransformPathId); } list.Add(list3); } dictionary[item3] = list; } return dictionary; } private bool MustWriteCatalog() { if (!JsonExtensions.TryLoadFromFile<SceneCatalogMetadata>(CatalogMetadataPath, out SceneCatalogMetadata obj) || obj.Metadata == null || obj.Metadata.SilksongVersion != VersionData.SilksongVersion || !VersionData.EarliestAcceptableSceneRepackVersion.AllowCachedData(obj.Metadata.PluginVersion) || obj.Metadata.OSFolderName != AssetPaths.OSFolderName) { return true; } if (!File.Exists(SceneCatalogPath)) { return true; } return false; } private static bool MetadataMismatch(string scene, RepackedSceneBundleData existingData) { if (existingData.Metadata == null) { return true; } if (!VersionData.EarliestAcceptableSceneRepackVersion.AllowCachedData(existingData.Metadata.PluginVersion)) { return true; } if (existingData.Metadata.OSFolderName != AssetPaths.OSFolderName) { return true; } if (existingData.Metadata.SilksongVersion == VersionData.SilksongVersion) { return false; } if (AddressablesData.TryGetLocationForScene(scene, out IResourceLocation location)) { object data = location.Data; AssetBundleRequestOptions val = (AssetBundleRequestOptions)((data is AssetBundleRequestOptions) ? data : null); if (val != null && !string.IsNullOrEmpty(val.Hash) && !string.IsNullOrEmpty(existingData.BundleHash) && val.Hash == existingData.BundleHash) { return false; } } return true; } private bool CanLoadAll(SceneCatalogInfo catalogInfo, string sceneName) { HashSet<string> other = new HashSet<string>(catalogInfo.LoadableAssets); if (!AssetRequestAPI.Request.SceneAssets.TryGetValue(sceneName, out HashSet<string> value)) { return true; } return value.IsSubsetOf(other); } private static string GetSerializedBundleDirPrefix() { return "{Silksong.AssetHelper.Core.AssetPaths.RepackedSceneBundleDir}"; } private static string GetBundlePathForScene(string sceneName) { return Path.Combine(AssetPaths.RepackedSceneBundleDir, "repacked_" + sceneName + ".bundle"); } private static bool ResolveCab(string cabName, out string? bundlePath) { bundlePath = null; if (cabName.Contains("unity")) { return true; } if (!BundleMetadata.CabLookup.TryGetValue(cabName.ToLowerInvariant(), out string value)) { return false; } if (value.Contains("monoscripts") || value.Contains("builtinassets")) { return true; } bundlePath = Path.Combine(AssetPaths.BundleFolder, value); return true; } } } namespace Silksong.AssetHelper.Plugin.LoadingPage { public interface ILoadingScreen { void SetText(string text); void SetSubtext(string text); void SetProgress(float progress); void SetVisible(bool visible); } internal static class LoadingScreenExtensions { public static T Create<T>() where T : MonoBehaviour, ILoadingScreen { //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) GameObject val = new GameObject("AssetHelper LoadingScreen"); T result = val.AddComponent<T>(); val.SetActive(true); return result; } public static void Reset(this ILoadingScreen self) { self.SetText(string.Empty); self.SetSubtext(string.Empty); self.SetProgress(0f); self.SetVisible(visible: true); } } internal class LoadingScreen : MonoBehaviour, ILoadingScreen { private RectTransform _fillImageRect; private GameObject _canvasObject; private CanvasGroup _canvasGroup; private Text _statusText; private Text _subText; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_00f5: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0211: 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_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Expected O, but got Unknown //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Expected O, but got Unknown //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) _canvasObject = new GameObject("LoadingCanvas"); Canvas obj = _canvasObject.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 999; _canvasObject.AddComponent<CanvasScaler>(); _canvasObject.AddComponent<GraphicRaycaster>(); _canvasGroup = _canvasObject.AddComponent<CanvasGroup>(); _canvasGroup.interactable = false; _canvasGroup.blocksRaycasts = true; GameObject val = new GameObject("Background"); val.transform.SetParent(_canvasObject.transform); Image obj2 = val.AddComponent<Image>(); ((Graphic)obj2).color = Color.black; RectTransform rectTransform = ((Graphic)obj2).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.sizeDelta = Vector2.zero; rectTransform.anchoredPosition = Vector2.zero; GameObject val2 = new GameObject("Outline"); val2.transform.SetParent(_canvasObject.transform); Image obj3 = val2.AddComponent<Image>(); ((Graphic)obj3).color = Color.white; RectTransform rectTransform2 = ((Graphic)obj3).rectTransform; rectTransform2.anchorMin = new Vector2(0.5f, 0.5f); rectTransform2.anchorMax = new Vector2(0.5f, 0.5f); rectTransform2.pivot = new Vector2(0.5f, 0.5f); rectTransform2.sizeDelta = new Vector2(500f, 66f); rectTransform2.anchoredPosition = Vector2.zero; GameObject val3 = new GameObject("InnerBG"); val3.transform.SetParent(val2.transform); Image obj4 = val3.AddComponent<Image>(); ((Graphic)obj4).color = Color.black; RectTransform rectTransform3 = ((Graphic)obj4).rectTransform; rectTransform3.anchorMin = Vector2.zero; rectTransform3.anchorMax = Vector2.one; rectTransform3.sizeDelta = new Vector2(-4f, -4f); rectTransform3.anchoredPosition = Vector2.zero; GameObject val4 = new GameObject("Fill"); val4.transform.SetParent(val3.transform); Image val5 = val4.AddComponent<Image>(); ((Graphic)val5).color = Color.white; _fillImageRect = ((Graphic)val5).rectTransform; _fillImageRect.anchorMin = new Vector2(0f, 0f); _fillImageRect.anchorMax = new Vector2(0f, 1f); _fillImageRect.pivot = new Vector2(0f, 0.5f); _fillImageRect.sizeDelta = Vector2.zero; _fillImageRect.anchoredPosition = Vector2.zero; GameObject val6 = new GameObject("StatusText"); val6.transform.SetParent(_canvasObject.transform); _statusText = val6.AddComponent<Text>(); _statusText.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); _statusText.text = string.Empty; _statusText.fontSize = 30; _statusText.alignment = (TextAnchor)4; ((Graphic)_statusText).color = Color.white; RectTransform rectTransform4 = ((Graphic)_statusText).rectTransform; rectTransform4.anchorMin = new Vector2(0.5f, 0.5f); rectTransform4.anchorMax = new Vector2(0.5f, 0.5f); rectTransform4.pivot = new Vector2(0.5f, 0f); rectTransform4.sizeDelta = new Vector2(800f, 50f); rectTransform4.anchoredPosition = new Vector2(0f, 60f); GameObject val7 = new GameObject("SubText"); val7.transform.SetParent(_canvasObject.transform); _subText = val7.AddComponent<Text>(); _subText.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); _subText.text = string.Empty; _subText.fontSize = 20; _subText.alignment = (TextAnchor)4; ((Graphic)_subText).color = Color.white; RectTransform rectTransform5 = ((Graphic)_subText).rectTransform; rectTransform5.anchorMin = new Vector2(0.5f, 0.5f); rectTransform5.anchorMax = new Vector2(0.5f, 0.5f); rectTransform5.pivot = new Vector2(0.5f, 1f); rectTransform5.sizeDelta = new Vector2(800f, 50f); rectTransform5.anchoredPosition = new Vector2(0f, -45f); _statusText.text = "Loading..."; } public void SetProgress(float progress) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) progress = Mathf.Clamp01(progress); _fillImageRect.anchorMax = new Vector2(progress, 1f); } public void SetVisible(bool visible) { _canvasGroup.alpha = (visible ? 1f : 0f); } public void SetText(string text) { _statusText.text = text; } public void SetSubtext(string text) { _subText.text = text; } private void OnDestroy() { if ((Object)(object)_canvasObject != (Object)null) { Object.Destroy((Object)(object)_canvasObject); } } } [RequireComponent(typeof(Text))] internal class MemoryWatcher : MonoBehaviour { private long maxSoFar; private Text _text; private void Awake() { _text = ((Component)this).GetComponent<Text>(); } private void Update() { long totalMemory = GC.GetTotalMemory(forceFullCollection: false); maxSoFar = ((totalMemory > maxSoFar) ? totalMemory : maxSoFar); _text.text = $"Memory: {totalMemory:E}\nMax {maxSoFar:E}"; } } } namespace Silksong.AssetHelper.ManagedAssets { public interface IManagedAsset { object? Load(); void Unload(); } public class ManagedAsset<T> : ManagedAssetBase<T> { public string Key { get; } protected internal override string Identifier => Key; public ManagedAsset(string key) { Key = key; base..ctor(); } public static ManagedAsset<T> FromSceneAsset(string sceneName, string objPath) { if (typeof(T) != typeof(GameObject)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)"ManagedAsset instances for scene assets should have GameObject as the type argument!"); } HashSet<string> value; if (AssetRequestAPI.RequestApiAvailable) { AssetRequestAPI.RequestSceneAsset(sceneName, objPath); } else if (!AssetRequestAPI.Request.SceneAssets.TryGetValue(sceneName.ToLowerInvariant(), out value) || !value.Contains(objPath)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Constructing managed asset from scene " + sceneName + ", " + objPath + " after Awake may not work unless the asset has been requested first!")); } return new ManagedAsset<T>(CatalogKeys.GetKeyForSceneAsset(sceneName, objPath)); } public static ManagedAsset<T> FromNonSceneAsset(string assetName, string? bundleName = null) { if (AssetRequestAPI.RequestApiAvailable && !string.IsNullOrEmpty(bundleName)) { AssetRequestAPI.RequestNonSceneAsset<T>(bundleName, assetName); } else if (!string.IsNullOrEmpty(bundleName) && !AssetRequestAPI.Request.NonSceneAssets.ContainsKey((bundleName, assetName))) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Constructing managed asset " + assetName + " from non-scene bundle " + bundleName + " after Awake may not work unless the asset has been requested first!")); } return new ManagedAsset<T>(CatalogKeys.GetKeyForNonSceneAsset(assetName)); } protected override AsyncOperationHandle<T> DoLoad() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Addressables.LoadAssetAsync<T>((object)Key); } public ManagedAsset<T> Clone() { return new ManagedAsset<T>(Key); } } public abstract class ManagedAssetBase<THandleResult> : IManagedAsset { private AsyncOperationHandle<THandleResult>? _handle; protected internal abstract string Identifier { get; } public AsyncOperationHandle<THandleResult> Handle { get { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (!_handle.HasValue) { throw new InvalidOperationException("Addressable asset with identifier " + Identifier + " must be loaded before accessing the handle!"); } return _handle.Value; } } public bool IsLoaded { get { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (HasBeenLoaded) { return Handle.IsDone; } return false; } } public bool HasBeenLoaded => _handle.HasValue; public AsyncOperationHandle<THandleResult> Load() { //IL_001f: 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) if (!_handle.HasValue) { _handle = DoLoad(); } return Handle; } protected abstract AsyncOperationHandle<THandleResult> DoLoad(); object? IManagedAsset.Load() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Load(); } public void Unload() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (_handle.HasValue) { Addressables.Release<THandleResult>(_handle.Value); _handle = null; } } } public class ManagedAssetBundle : ManagedAssetBase<IAssetBundleResource> { public string BundleName { get; } protected internal override string Identifier => BundleName; public ManagedAssetBundle(string bundleName) { BundleName = bundleName; base..ctor(); } protected override AsyncOperationHandle<IAssetBundleResource> DoLoad() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return Addressables.LoadAssetAsync<IAssetBundleResource>((object)AddressablesData.ToBundleKey(BundleName)); } public ManagedAssetBundle Clone() { return new ManagedAssetBundle(BundleName); } } public static class ManagedAssetExtensions { public static T InstantiateAsset<T>(this ManagedAsset<T> asset) where T : Object { //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 (!asset.IsLoaded) { throw new InvalidOperationException("The asset has not finished loading!"); } return Object.Instantiate<T>(asset.Handle.Result); } public static void EnsureLoaded<T>(this ManagedAssetBase<T> asset) { //IL_0028: 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_004b: 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_006b: 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) if (!asset.HasBeenLoaded) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("EnsureLoaded has been called on " + asset.Identifier + " before loading the asset!")); asset.Load(); } if (!asset.IsLoaded) { asset.Handle.WaitForCompletion(); } if (asset.Handle.OperationException != null) { AssetHelperPlugin.InstanceLogger.LogError((object)("Operation exception when loading asset " + asset.Identifier + "\n" + asset.Handle.OperationException)); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void EnsureLoaded<T>(this ManagedAsset<T> asset) { ((ManagedAssetBase<T>)asset).EnsureLoaded(); } public static T InstantiateAsset<T>(this ManagedAssetGroup<T> group, string key) where T : Object { //IL_0015: 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) if (!group.IsLoaded) { throw new InvalidOperationException("The group has not finished loading!"); } return Object.Instantiate<T>(group[key].Result); } public static T InstantiateAsset<T>(this ManagedAssetList<T> asset, Func<T, bool> predicate) where T : Object { //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 (!asset.IsLoaded) { throw new InvalidOperationException("The asset has not finished loading!"); } foreach (T item in asset.Handle.Result) { if (predicate(item)) { return Object.Instantiate<T>(item); } } throw new ArgumentException("No matching asset for managed asset list with key " + asset.Key + " was found!"); } } public class ManagedAssetGroup<T> : IManagedAsset { public record SceneAssetInfo(string SceneName, string ObjPath); public record NonSceneAssetInfo(string BundleName, string AssetName); private readonly Dictionary<string, string> _keyLookup; private Dictionary<string, AsyncOperationHandle<T>>? _handles; public AsyncOperationHandle<T> this[string name] { get { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (_handles == null) { throw new InvalidOperationException("Handles can not be accessed until this instance has started loading"); } return _handles[name]; } } public bool IsLoaded { get { if (HasBeenLoaded) { return _handles.Values.All((AsyncOperationHandle<T> x) => x.IsDone); } return false; } } public bool HasBeenLoaded => _handles != null; public ManagedAssetGroup(Dictionary<string, string> keyLookup) { _keyLookup = keyLookup; } public static ManagedAssetGroup<T> RequestAndCreate(Dictionary<string, SceneAssetInfo>? sceneAssets = null, Dictionary<string, NonSceneAssetInfo>? nonSceneAssets = null) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); string key; if (sceneAssets != null) { if (typeof(T) != typeof(GameObject)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)"ManagedAssetGroup instances for scene assets should have GameObject as the type argument!"); } foreach (KeyValuePair<string, SceneAssetInfo> sceneAsset in sceneAssets) { sceneAsset.Deconstruct(out key, out var value); string key2 = key; SceneAssetInfo sceneAssetInfo = value; HashSet<string> value2; if (AssetRequestAPI.RequestApiAvailable) { AssetRequestAPI.RequestSceneAsset(sceneAssetInfo.SceneName, sceneAssetInfo.ObjPath); } else if (!AssetRequestAPI.Request.SceneAssets.TryGetValue(sceneAssetInfo.SceneName.ToLowerInvariant(), out value2) || !value2.Contains(sceneAssetInfo.ObjPath)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Constructing managed asset from scene " + sceneAssetInfo.SceneName + ", " + sceneAssetInfo.ObjPath + " after Awake may not work unless the asset has been requested first!")); } dictionary.Add(key2, CatalogKeys.GetKeyForSceneAsset(sceneAssetInfo.SceneName, sceneAssetInfo.ObjPath)); } } if (nonSceneAssets != null) { foreach (KeyValuePair<string, NonSceneAssetInfo> nonSceneAsset in nonSceneAssets) { nonSceneAsset.Deconstruct(out key, out var value3); string key3 = key; NonSceneAssetInfo nonSceneAssetInfo = value3; if (AssetRequestAPI.RequestApiAvailable) { AssetRequestAPI.RequestNonSceneAsset<T>(nonSceneAssetInfo.BundleName, nonSceneAssetInfo.AssetName); } else if (!AssetRequestAPI.Request.NonSceneAssets.ContainsKey((nonSceneAssetInfo.BundleName, nonSceneAssetInfo.AssetName))) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Constructing managed asset " + nonSceneAssetInfo.AssetName + " from non-scene bundle " + nonSceneAssetInfo.BundleName + " after Awake may not work unless the asset has been requested first!")); } dictionary.Add(key3, CatalogKeys.GetKeyForNonSceneAsset(nonSceneAssetInfo.AssetName)); } } return new ManagedAssetGroup<T>(dictionary); } public CustomYieldInstruction GetYieldInstruction() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (_handles == null) { throw new InvalidOperationException("This ManagedAssetGroup must be loaded before awaiting!"); } return (CustomYieldInstruction)new WaitUntil((Func<bool>)(() => IsLoaded)); } public CustomYieldInstruction Load() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (_handles != null) { return GetYieldInstruction(); } _handles = new Dictionary<string, AsyncOperationHandle<T>>(); foreach (var (key, text3) in _keyLookup) { _handles[key] = Addressables.LoadAssetAsync<T>((object)text3); } return GetYieldInstruction(); } object? IManagedAsset.Load() { return Load(); } public Task GetTask() { if (_handles == null) { throw new InvalidOperationException("This ManagedAssetGroup must be loaded before awaiting!"); } return Task.WhenAll(_handles.Values.Select((AsyncOperationHandle<T> x) => x.Task)); } public ManagedAsset<T> GetIndividualAsset(string name) { return new ManagedAsset<T>(_keyLookup[name]); } public void Unload() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (_handles == null) { return; } foreach (AsyncOperationHandle<T> value in _handles.Values) { Addressables.Release<T>(value); } _handles = null; } } public class ManagedAssetList<T> : ManagedAssetBase<IList<T>> { public string Key { get; } protected internal override string Identifier => Key; public ManagedAssetList(string key) { Key = key; base..ctor(); } protected override AsyncOperationHandle<IList<T>> DoLoad() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Addressables.LoadAssetsAsync<T>(Key, (Action<T>)null); } public ManagedAssetList<T> Clone() { return new ManagedAssetList<T>(Key); } public static ManagedAssetList<T> FromSceneAsset(string sceneName, string objPath) { if (typeof(T) != typeof(GameObject)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)"ManagedAssetList instances for scene assets should have GameObject as the type argument!"); } HashSet<string> value; if (AssetRequestAPI.RequestApiAvailable) { AssetRequestAPI.RequestSceneAsset(sceneName, objPath); } else if (!AssetRequestAPI.Request.SceneAssets.TryGetValue(sceneName.ToLowerInvariant(), out value) || !value.Contains(objPath)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Constructing managed asset list from scene " + sceneName + ", " + objPath + " after Awake may not work unless the asset has been requested first!")); } return new ManagedAssetList<T>(CatalogKeys.GetKeyForSceneAsset(sceneName, objPath)); } } public class ManagedResourceLocation<T> : IManagedAsset { private AsyncOperationHandle<T>? _handle; public IResourceLocation Location { get; } public AsyncOperationHandle<T> Handle { get { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!_handle.HasValue) { throw new InvalidOperationException("Addressable asset with location " + Location.InternalId + " must be loaded before accessing the handle!"); } return _handle.Value; } } public bool IsLoaded { get { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (HasBeenLoaded) { return Handle.IsDone; } return false; } } public bool HasBeenLoaded => _handle.HasValue; public ManagedResourceLocation(IResourceLocation location) { Location = location; base..ctor(); } public AsyncOperationHandle<T> Load() { //IL_0024: 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) if (!_handle.HasValue) { _handle = Addressables.LoadAssetAsync<T>(Location); } return Handle; } object? IManagedAsset.Load() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Load(); } public void Unload() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (_handle.HasValue) { Addressables.Release<T>(_handle.Value); _handle = null; } } } } namespace Silksong.AssetHelper.Internal { internal static class ActionUtil { private static readonly ManualLogSource Log = Logger.CreateLogSource("AssetHelper.ActionUtil"); public static void SafeInvoke(Action? a) { if (a == null) { return; } try { a(); } catch (Exception ex) { Log.LogError((object)("Error invoking action " + a.Method.Name + "\n" + ex)); } } public static void SafeInvoke<T>(Action<T>? a, T arg) { if (a == null) { return; } try { a(arg); } catch (Exception ex) { Log.LogError((object)("Error invoking action " + a.Method.Name + "\n" + ex)); } } } internal class CachedFileMetadata { public required string SilksongVersion { get; init; } public required string PluginVersion { get; init; } public required string OSFolderName { get; init; } public static CachedFileMetadata CreateNew() { return new CachedFileMetadata { SilksongVersion = VersionData.SilksongVersion, PluginVersion = AssetHelperPlugin.Version, OSFolderName = AssetPaths.OSFolderName }; } } internal class CachedObject<T> where T : class { [JsonProperty(/*Could not decode attribute arguments.*/)] [DefaultValue(null)] public required CachedFileMetadata Metadata { get; init; } [JsonProperty] public required T Value { get; set; } private CachedObject() { } private bool IsValid() { if (Metadata == null || Metadata.SilksongVersion == null || Metadata.PluginVersion == null) { return false; } if (Metadata.OSFolderName != AssetPaths.OSFolderName) { return false; } if (VersionData.SilksongVersion != Metadata.SilksongVersion) { return false; } if (!VersionData.EarliestAcceptableGeneralVersion.AllowCachedData(Metadata.PluginVersion)) { return false; } return true; } public static CachedObject<T> CreateSynced(string filename, Func<T> createDefault, bool mutable, out IDisposable? syncHandle) { syncHandle = null; string text = Path.Combine(AssetPaths.CacheDirectory, filename); if (JsonExtensions.TryLoadFromFile<CachedObject<T>>(text, out CachedObject<T> obj) && obj.Value != null && obj.IsValid()) { if (mutable) { syncHandle = new <CachedObject>F2DD635EBDE083CBD17FC2C9D7D25FDDFBD73B1716C77C87C4A78F37A6C77FBC9__CachedObjectSyncHandle<T>(obj, text); } return obj; } CachedObject<T> cachedObject = new CachedObject<T> { Metadata = CachedFileMetadata.CreateNew(), Value = createDefault() }; cachedObject.SerializeToFile(text); if (mutable) { syncHandle = new <CachedObject>F2DD635EBDE083CBD17FC2C9D7D25FDDFBD73B1716C77C87C4A78F37A6C77FBC9__CachedObjectSyncHandle<T>(cachedObject, text); } return cachedObject; } } internal class <CachedObject>F2DD635EBDE083CBD17FC2C9D7D25FDDFBD73B1716C77C87C4A78F37A6C77FBC9__CachedObjectSyncHandle<T> : IDisposable where T : class { private CachedObject<T> _obj; private string _filepath; public <CachedObject>F2DD635EBDE083CBD17FC2C9D7D25FDDFBD73B1716C77C87C4A78F37A6C77FBC9__CachedObjectSyncHandle(CachedObject<T> obj, string filepath) { _obj = obj; _filepath = filepath; AssetHelperPlugin.OnQuitApplication += SyncObj; } private void SyncObj() { _obj.SerializeToFile(_filepath); } public void Dispose() { SyncObj(); AssetHelperPlugin.OnQuitApplication -= SyncObj; } } internal class DelayedAction { private List<Action> _subscribers = new List<Action>(); public bool Activated { get; private set; } public void Activate() { if (Activated) { return; } Activated = true; foreach (Action subscriber in _subscribers) { ActionUtil.SafeInvoke(subscriber); } _subscribers.Clear(); } public void Subscribe(Action toInvoke) { if (Activated) { ActionUtil.SafeInvoke(toInvoke); } else { _subscribers.Add(toInvoke); } } } internal class DictListConverter<T, U> : JsonConverter<Dictionary<T, U>> { public override Dictionary<T, U>? ReadJson(JsonReader reader, Type objectType, Dictionary<T, U>? existingValue, bool hasExistingValue, JsonSerializer serializer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)reader.TokenType == 11) { return null; } return serializer.Deserialize<List<(T, U)>>(reader)?.ToDictionary(((T, U) x) => x.Item1, ((T, U) x) => x.Item2); } public override void WriteJson(JsonWriter writer, Dictionary<T, U>? value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); return; } List<(T, U)> list = value.Select<KeyValuePair<T, U>, (T, U)>((KeyValuePair<T, U> kvp) => (kvp.Key, kvp.Value)).ToList(); serializer.Serialize(writer, (object)list); } public DictListConverter() { ((JsonConverter<Dictionary<Dictionary<T, U>, ?>>)(object)this)..ctor(); } } internal static class EnumeratorExtensions { public static void Consume(this IEnumerator self) { while (self.MoveNext()) { } } } internal static class JsonExtensions { public static void SerializeToFile<T>(this T self, s
plugins/AssetHelperLib.dll
Decompiled a month agousing System; using System.Buffers; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using AssetHelperLib.BundleTools; using AssetHelperLib.Extensions; using AssetHelperLib.IO; using AssetHelperLib.PreloadTable; using AssetHelperLib.Repacking; using AssetHelperLib.Util; using AssetsTools.NET; using AssetsTools.NET.Extra; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AssetHelperLib")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Scene Asset repacking library built upon AssetsTools.NET.")] [assembly: AssemblyFileVersion("0.12.1.0")] [assembly: AssemblyInformationalVersion("0.12.1+5c3795e0bfb720babc088918564f2ffc0ca06000")] [assembly: AssemblyProduct("AssetHelperLib")] [assembly: AssemblyTitle("AssetHelperLib")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/flibber-hk/AssetHelperLib")] [assembly: AssemblyVersion("0.12.1.0")] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T> { object IEnumerator.Current => _item; T IEnumerator<T>.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { if (!_moveNextCalled) { return _moveNextCalled = true; } return false; } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => 1; T IReadOnlyList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection<T>.Count => 1; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return EqualityComparer<T>.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { if (!EqualityComparer<T>.Default.Equals(_item, (T)value)) { return -1; } return 0; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new Enumerator(_item); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return EqualityComparer<T>.Default.Equals(_item, item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { if (!EqualityComparer<T>.Default.Equals(_item, item)) { return -1; } return 0; } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace AssetHelperLib { public static class Logging { public static event Action<string>? OnLog; public static event Action<string>? OnLogWarning; public static event Action<string>? OnLogError; public static event Action<string>? OnLogDebug; internal static void LogInfo(string message) { Logging.OnLog?.Invoke(message); } internal static void LogWarning(string message) { Logging.OnLogWarning?.Invoke(message); } internal static void LogError(string message) { Logging.OnLogError?.Invoke(message); } internal static void LogDebug(string message) { Logging.OnLogDebug?.Invoke(message); } } } namespace AssetHelperLib.Util { public static class ObjPathUtil { public static bool HasPrefix(this string self, string? maybePrefix) { if (maybePrefix == null) { return false; } if (!self.StartsWith(maybePrefix)) { return false; } if (self == maybePrefix) { return true; } if (self[maybePrefix.Length] == '/') { return true; } return false; } public static List<string> GetHighestNodes(this ICollection<string> objPaths) { List<string> list = new List<string>(); string maybePrefix = null; foreach (string item in objPaths.OrderBy((string x) => x)) { if (!item.HasPrefix(maybePrefix)) { maybePrefix = item; list.Add(item); } } return list; } public static bool TryFindRelativePath(string ancestor, string descendant, out string? relativePath) { string ancestorPath; return TryFindAncestor(new List<string>(1) { ancestor }, descendant, out ancestorPath, out relativePath); } public static bool TryFindAncestor(List<string>? paths, string objName, [MaybeNullWhen(false)] out string ancestorPath, out string? relativePath) { foreach (string item in paths ?? Enumerable.Empty<string>()) { if (objName == item) { ancestorPath = objName; relativePath = null; return true; } if (objName.HasPrefix(item)) { ancestorPath = item; int num = 1 + item.Length; relativePath = objName.Substring(num, objName.Length - num); return true; } } ancestorPath = null; relativePath = null; return false; } public static bool TryGetParent(this string objName, out string parent) { int num = objName.LastIndexOf('/'); if (num == -1) { parent = string.Empty; return false; } parent = objName.Substring(0, num); return true; } } } namespace AssetHelperLib.Repacking { public class RepackedBundleData { public string? RepackStrategy { get; set; } public string? BundleName { get; set; } public string? CabName { get; set; } public Dictionary<string, string>? GameObjectAssets { get; set; } public List<string>? NonRepackedAssets { get; set; } } public static class RepackedBundleDataExtensions { public static bool CanLoad(this RepackedBundleData data, string objName, [MaybeNullWhen(false)] out string assetPath, out string? relativePath) { if (data.GameObjectAssets == null) { assetPath = null; relativePath = null; return false; } foreach (var (text3, ancestor) in data.GameObjectAssets) { if (ObjPathUtil.TryFindRelativePath(ancestor, objName, out relativePath)) { assetPath = text3; return true; } } assetPath = null; relativePath = null; return false; } public static bool TriedToRepack(this RepackedBundleData data, string objName) { if (data.NonRepackedAssets != null && ObjPathUtil.TryFindAncestor(data.NonRepackedAssets, objName, out string relativePath, out string assetPath)) { return true; } return data.CanLoad(objName, out assetPath, out relativePath); } } public class RepackingContext { private AssetDependencies? _assetDeps; public required AssetsManager SceneAssetsManager { get; init; } public required BundleFileInstance SceneBundleFileInstance { get; init; } public required AssetsFileInstance SharedAssetsFileInstance { get; init; } public required AssetsFileInstance MainAssetsFileInstance { get; init; } public required BundleUtils.SceneBundleInfo SceneBundleInfo { get; init; } public GameObjectLookup? GameObjLookup { get; set; } public AssetDependencies AssetDeps { get { if (_assetDeps == null) { _assetDeps = new AssetDependencies(SceneAssetsManager, MainAssetsFileInstance); } return _assetDeps; } } } public record RepackingParams { public required string SceneBundlePath { get; set; } public required List<string> ObjectNames { get; set; } public required string ContainerPrefix { get; set; } public required string OutBundlePath { get; set; } public Action<RepackingContext, RepackedBundleData>? LateCallback { get; set; } [CompilerGenerated] [SetsRequiredMembers] protected RepackingParams(RepackingParams original) { SceneBundlePath = original.SceneBundlePath; ObjectNames = original.ObjectNames; ContainerPrefix = original.ContainerPrefix; OutBundlePath = original.OutBundlePath; LateCallback = original.LateCallback; } public RepackingParams() { } } public abstract class SceneRepacker { protected virtual string RepackStrategy => GetType().Name; protected static void GetDefaultBundleNames(RepackingParams repackingParams, out string cabName, out string bundleName) { using SHA256 sHA = SHA256.Create(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("AssetHelperSalt\n"); stringBuilder.AppendLine(repackingParams.SceneBundlePath ?? string.Empty); foreach (string objectName in repackingParams.ObjectNames) { stringBuilder.AppendLine("\n" + objectName); } stringBuilder.AppendLine(repackingParams.OutBundlePath); string s = stringBuilder.ToString(); byte[] bytes = Encoding.UTF8.GetBytes(s); byte[] array = sHA.ComputeHash(bytes); StringBuilder stringBuilder2 = new StringBuilder(64); byte[] array2 = array; foreach (byte b in array2) { stringBuilder2.Append(b.ToString("x2")); } string text = stringBuilder2.ToString(); cabName = "CAB-" + text.Substring(0, 32); bundleName = text.Substring(32, 32) + ".bundle"; } public RepackedBundleData Repack(RepackingParams repackingParams) { RepackedBundleData outData = new RepackedBundleData(); Repack(repackingParams, ref outData); return outData; } public void Repack(RepackingParams repackingParams, ref RepackedBundleData outData) { outData.RepackStrategy = RepackStrategy; GetDefaultBundleNames(repackingParams, out string cabName, out string bundleName); RepackedBundleData repackedBundleData = outData; if (repackedBundleData.CabName == null) { string text2 = (repackedBundleData.CabName = cabName); } repackedBundleData = outData; if (repackedBundleData.BundleName == null) { string text2 = (repackedBundleData.BundleName = bundleName); } AssetsManager val = BundleUtils.CreateDefaultManager(); using RentedFileArray rentedFileArray = new RentedFileArray(repackingParams.SceneBundlePath); BundleFileInstance val2 = val.LoadBundleFile((Stream)rentedFileArray.Stream, repackingParams.SceneBundlePath, true); if (!val.TryFindAssetsFiles(val2, out BundleUtils.SceneBundleInfo info)) { throw new NotSupportedException("Could not find assets files for " + repackingParams.SceneBundlePath); } AssetsFileInstance mainAssetsFileInstance = val.LoadAssetsFileFromBundle(val2, info.mainAfileInstIndex, false); AssetsFileInstance sharedAssetsFileInstance = val.LoadAssetsFileFromBundle(val2, info.sharedAssetsAfileIndex, false); RepackingContext repackingContext = new RepackingContext { SceneAssetsManager = val, SceneBundleFileInstance = val2, MainAssetsFileInstance = mainAssetsFileInstance, SharedAssetsFileInstance = sharedAssetsFileInstance, SceneBundleInfo = info }; Run(repackingContext, repackingParams, outData); repackingParams.LateCallback?.Invoke(repackingContext, outData); val.UnloadAll(false); } protected abstract void Run(RepackingContext ctx, RepackingParams repackingParams, RepackedBundleData outData); } public class StrippedSceneRepacker : SceneRepacker { private BasePreloadTableResolver _preloadResolver; public StrippedSceneRepacker() : this(new DefaultPreloadTableResolver()) { } public StrippedSceneRepacker(BasePreloadTableResolver preloadResolver) { _preloadResolver = preloadResolver; } protected override void Run(RepackingContext ctx, RepackingParams repackingParams, RepackedBundleData outData) { List<string> highestNodes = repackingParams.ObjectNames.GetHighestNodes(); ctx.GameObjLookup = GameObjectLookup.CreateFromFile(ctx.SceneAssetsManager, ctx.MainAssetsFileInstance); HashSet<long> hashSet = new HashSet<long>(); foreach (string item2 in highestNodes) { if (ctx.GameObjLookup.TryLookupName(item2, out List<GameObjectLookup.GameObjectInfo> info)) { Logging.LogInfo($"Found {info.Count} assets for {item2} in {repackingParams.SceneBundlePath}"); foreach (GameObjectLookup.GameObjectInfo item3 in info) { hashSet.Add(item3.GameObjectPathId); hashSet.UnionWith(ctx.AssetDeps.FindBundleDeps(item3.GameObjectPathId).InternalPaths); } } else { Logging.LogError("Couldn't find game object " + item2); } } List<string> list = new List<string>(); foreach (long item4 in hashSet) { if (ctx.GameObjLookup.TryLookupGameObject(item4, out GameObjectLookup.GameObjectInfo info2)) { list.Add(info2.GameObjectName); } } List<string> highestNodes2 = list.GetHighestNodes(); HashSet<string> hashSet2 = new HashSet<string>(); List<string> list2 = new List<string>(); foreach (string item5 in highestNodes) { if (ObjPathUtil.TryFindAncestor(highestNodes2, item5, out string ancestorPath, out string _)) { hashSet2.Add(ancestorPath); continue; } Logging.LogWarning("Did not find " + item5 + " in bundle"); list2.Add(item5); } outData.NonRepackedAssets = list2; foreach (AssetFileInfo item6 in ctx.MainAssetsFileInstance.file.AssetInfos.ToList()) { if (!hashSet.Contains(item6.PathId)) { ctx.MainAssetsFileInstance.file.Metadata.RemoveAssetInfo(item6); } } long newOneAssetPathId = 1L; if (hashSet.Contains(1L)) { for (newOneAssetPathId = -1L; hashSet.Contains(newOneAssetPathId); newOneAssetPathId--) { } } foreach (GameObjectLookup.GameObjectInfo item7 in ctx.GameObjLookup) { if (hashSet.Contains(item7.TransformPathId) && item7.GameObjectName.TryGetParent(out string parent)) { if (!ctx.GameObjLookup.TryLookupTransfrom(item7.ParentPathId, out GameObjectLookup.GameObjectInfo info3)) { Logging.LogWarning("Unexpectedly failed to find " + parent + " from " + item7.GameObjectName); } else if (!hashSet.Contains(info3.TransformPathId)) { AssetFileInfo assetInfo = ctx.MainAssetsFileInstance.file.GetAssetInfo(item7.TransformPathId); AssetTypeValueField baseField = ctx.SceneAssetsManager.GetBaseField(ctx.MainAssetsFileInstance, assetInfo, (AssetReadFlags)0); baseField["m_Father.m_PathID"].AsLong = 0L; assetInfo.SetNewData(baseField); } } } AssetFileInfo val = ctx.SharedAssetsFileInstance.file.GetAssetsOfType((AssetClassID)142).First(); AssetTypeValueField baseField2 = ctx.SceneAssetsManager.GetBaseField(ctx.SharedAssetsFileInstance, val, (AssetReadFlags)0); baseField2["m_Name"].AsString = outData.BundleName; baseField2["m_AssetBundleName"].AsString = outData.BundleName; baseField2["m_IsStreamedSceneAssetBundle"].AsBool = false; baseField2["m_SceneHashes.Array"].Children.Clear(); List<AssetTypeValueField> list3 = new List<AssetTypeValueField>(); List<AssetTypeValueField> list4 = new List<AssetTypeValueField>(); Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string item8 in hashSet2) { foreach (GameObjectLookup.GameObjectInfo item9 in ctx.GameObjLookup.LookupName(item8)) { long gameObjectPathId = item9.GameObjectPathId; HashSet<(int, long)> tableInfos = new HashSet<(int, long)>(); _preloadResolver.BuildPreloadTable(gameObjectPathId, ctx, ref tableInfos); int count = list3.Count; foreach (var item10 in tableInfos) { AssetTypeValueField val2 = ValueBuilder.DefaultValueFieldFromArrayTemplate(baseField2["m_PreloadTable.Array"]); val2["m_FileID"].AsInt = item10.Item1; val2["m_PathID"].AsLong = item10.Item2; list3.Add(val2); } int asInt = list3.Count - count; string text = $"{repackingParams.ContainerPrefix}/{item9.TransformPathId}/{item8}.prefab"; dictionary[text] = item8; AssetTypeValueField val3 = ValueBuilder.DefaultValueFieldFromArrayTemplate(baseField2["m_Container.Array"]); val3["first"].AsString = text; val3["second.preloadIndex"].AsInt = count; val3["second.preloadSize"].AsInt = asInt; val3["second.asset.m_FileID"].AsInt = 0; val3["second.asset.m_PathID"].AsLong = updatedPathId(item9.GameObjectPathId); list4.Add(val3); } } baseField2["m_PreloadTable.Array"].Children.Clear(); baseField2["m_PreloadTable.Array"].Children.AddRange(list3); baseField2["m_Container.Array"].Children.Clear(); baseField2["m_Container.Array"].Children.AddRange(list4); outData.GameObjectAssets = dictionary; if (newOneAssetPathId != 1) { int num = 0; AssetFileInfo assetInfo2 = ctx.MainAssetsFileInstance.file.GetAssetInfo(1L); ctx.MainAssetsFileInstance.file.Metadata.RemoveAssetInfo(assetInfo2); assetInfo2.PathId = newOneAssetPathId; ctx.MainAssetsFileInstance.file.Metadata.AddAssetInfo(assetInfo2); foreach (long item11 in hashSet) { if (item11 != 1 && ctx.AssetDeps.FindImmediateDeps(item11).InternalPaths.Contains(1L)) { num += ctx.SceneAssetsManager.Redirect(ctx.MainAssetsFileInstance, ctx.MainAssetsFileInstance.file.GetAssetInfo(item11), 1L, newOneAssetPathId); } } int num2 = ctx.SceneAssetsManager.Redirect(ctx.MainAssetsFileInstance, assetInfo2, 1L, newOneAssetPathId); Logging.LogDebug($"Redirected {num} references plus {num2} self-references"); } if (!ctx.MainAssetsFileInstance.file.Metadata.TypeTreeTypes.Any((TypeTreeType x) => x.TypeId == 142)) { TypeTreeType item = ctx.SharedAssetsFileInstance.file.Metadata.TypeTreeTypes.First((TypeTreeType x) => x.TypeId == 142); ctx.MainAssetsFileInstance.file.Metadata.TypeTreeTypes.Add(item); } AssetFileInfo val4 = AssetFileInfo.Create(ctx.MainAssetsFileInstance.file, (long)ctx.SceneBundleInfo.mainAfileInstIndex, 142, (ClassDatabaseFile)null, false); val4.SetNewData(baseField2); ctx.MainAssetsFileInstance.file.Metadata.AddAssetInfo(val4); ctx.SceneBundleFileInstance.file.BlockAndDirInfo.DirectoryInfos[ctx.SceneBundleInfo.mainAfileInstIndex].SetNewData(ctx.MainAssetsFileInstance.file); ctx.SceneBundleFileInstance.file.BlockAndDirInfo.DirectoryInfos[ctx.SceneBundleInfo.mainAfileInstIndex].Name = outData.CabName; int count2 = ctx.SceneBundleFileInstance.file.BlockAndDirInfo.DirectoryInfos.Count; for (int i = 0; i < count2; i++) { if (i != ctx.SceneBundleInfo.mainAfileInstIndex) { ctx.SceneBundleFileInstance.file.BlockAndDirInfo.DirectoryInfos[i].SetRemoved(); } } ctx.SceneBundleFileInstance.file.WriteBundleToFile(repackingParams.OutBundlePath); long updatedPathId(long orig) { if (orig != 1) { return orig; } return newOneAssetPathId; } } } } namespace AssetHelperLib.PreloadTable { public abstract class BasePreloadTableResolver { public abstract void BuildPreloadTable(long assetPathId, RepackingContext ctx, ref HashSet<(int fileId, long pathId)> tableInfos); } public sealed class ContainerPointerPreloadsBundleData { public required List<long> ContainerPaths { get; set; } public Dictionary<long, HashSet<long>> ContainerInternalDeps { get; set; } = new Dictionary<long, HashSet<long>>(); public static ContainerPointerPreloadsBundleData FromFile(string bundlePath) { AssetsManager val = BundleUtils.CreateDefaultManager(); using RentedFileArray rentedFileArray = new RentedFileArray(bundlePath); BundleFileInstance val2 = val.LoadBundleFile((Stream)rentedFileArray.Stream, bundlePath, true); AssetsFileInstance val3 = val.LoadAssetsFileFromBundle(val2, 0, false); List<long> list = val.GetBaseField(val3, 1L, (AssetReadFlags)0)["m_Container.Array"].Children.Select((AssetTypeValueField x) => x["second.asset.m_PathID"].AsLong).ToList(); ContainerPointerPreloadsBundleData containerPointerPreloadsBundleData = new ContainerPointerPreloadsBundleData { ContainerPaths = list }; AssetDependencies assetDependencies = new AssetDependencies(val, val3); foreach (long item in list) { containerPointerPreloadsBundleData.ContainerInternalDeps[item] = assetDependencies.FindBundleDeps(item).InternalPaths; } val.UnloadAll(false); return containerPointerPreloadsBundleData; } } public class ContainerPointerPreloads : BasePreloadTableResolver { public delegate bool CabResolver(string cabName, out string? bundlePath); private readonly CabResolver _cabResolver; public Dictionary<string, ContainerPointerPreloadsBundleData> Cache { get; init; } public ContainerPointerPreloads(CabResolver cabResolver) { _cabResolver = cabResolver; Cache = new Dictionary<string, ContainerPointerPreloadsBundleData>(); base..ctor(); } public override void BuildPreloadTable(long assetPathId, RepackingContext ctx, ref HashSet<(int fileId, long pathId)> tableInfos) { foreach (var item4 in (from item in tableInfos group item by item.fileId into @group select (@group.Key, new HashSet<long>(@group.Select(((int fileId, long pathId) g) => g.pathId)))).ToList()) { int item2 = item4.Item1; HashSet<long> item3 = item4.Item2; string text = ctx.MainAssetsFileInstance.file.Metadata.Externals[item2 - 1].OriginalPathName.Split("/").Last().ToLowerInvariant(); if (!_cabResolver(text, out var bundlePath)) { Logging.LogWarning("Unexpectedly failed to resolve cab name " + text + " for ContainerPointerPreloads while running for " + ctx.MainAssetsFileInstance.name); } else { if (bundlePath == null) { continue; } if (!Cache.TryGetValue(text, out ContainerPointerPreloadsBundleData value)) { Logging.LogInfo("Building cache for " + text); value = ContainerPointerPreloadsBundleData.FromFile(bundlePath); Cache[text] = value; } foreach (long item5 in item3) { if (value.ContainerPaths.Contains(item5)) { continue; } bool flag = false; foreach (var (num2, hashSet2) in value.ContainerInternalDeps) { if (hashSet2.Contains(item5)) { flag = true; if (tableInfos.Add((item2, num2))) { Logging.LogDebug($"Added new {num2} for {item5} within {text}, for {ctx.MainAssetsFileInstance.name} :: {assetPathId}"); } break; } } if (!flag) { Logging.LogWarning($"Failed to find container asset for cab {text}, path {item5} while running for {ctx.MainAssetsFileInstance.name}"); } } } } } } public sealed class DefaultPreloadTableResolver : BasePreloadTableResolver { public override void BuildPreloadTable(long assetPathId, RepackingContext ctx, ref HashSet<(int fileId, long pathId)> tableInfos) { HashSet<AssetDependencies.PPtrData> externalPaths = ctx.AssetDeps.FindBundleDeps(assetPathId).ExternalPaths; tableInfos.UnionWith(externalPaths.Select((AssetDependencies.PPtrData dep) => (dep.FileId, dep.PathId))); } } public sealed class PreloadTableResolver : BasePreloadTableResolver { private readonly List<BasePreloadTableResolver> _resolvers; public PreloadTableResolver(List<BasePreloadTableResolver> resolvers) { _resolvers = resolvers; base..ctor(); } public override void BuildPreloadTable(long assetPathId, RepackingContext ctx, ref HashSet<(int fileId, long pathId)> tableInfos) { foreach (BasePreloadTableResolver resolver in _resolvers) { resolver.BuildPreloadTable(assetPathId, ctx, ref tableInfos); } } } } namespace AssetHelperLib.IO { internal static class Extensions { public static int ReadExact(this FileStream fs, byte[] array, int offset, int count) { int i; int num; for (i = 0; i < count; i += num) { num = fs.Read(array, offset + i, count - i); if (num == 0) { return i; } } return i; } } public class RentedFileArray : IDisposable { private static ArrayPool<byte> _pool = ArrayPool<byte>.Shared; private int _length; private ArrayPool<byte> _owner; private byte[] _buffer; private bool _isDisposed; public static ArrayPool<byte> Pool { get { return _pool; } [param: AllowNull] set { _pool = value ?? ArrayPool<byte>.Shared; } } public MemoryStream Stream { get; private init; } public RentedFileArray(string filepath) { _length = (int)new FileInfo(filepath).Length; _owner = Pool; _buffer = Pool.Rent(_length); try { using FileStream fs = File.OpenRead(filepath); fs.ReadExact(_buffer, 0, _length); } catch { _owner.Return(_buffer); throw; } Stream = new MemoryStream(_buffer, 0, _length); } protected virtual void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { Stream.Dispose(); _owner.Return(_buffer); _owner = null; _buffer = null; } _isDisposed = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } } namespace AssetHelperLib.Extensions { internal static class CollectionExtensions { public static void AddEntry<TKey, TValue>(this Dictionary<TKey, List<TValue>> self, TKey key, TValue value) { if (self.TryGetValue(key, out List<TValue> value2)) { value2.Add(value); return; } self[key] = new List<TValue>(1) { value }; } } } namespace AssetHelperLib.BundleTools { public class AssetDependencies { public class Config { public bool FollowTransformParent { get; set; } } public record PPtrData(int FileId, long PathId, string TypeName); public record ChildPPtrs(HashSet<long> InternalPaths, HashSet<PPtrData> ExternalPaths) { public static ChildPPtrs CreateNew() { return new ChildPPtrs(new HashSet<long>(), new HashSet<PPtrData>()); } public bool Add(int fileId, long pathId, string typeName) { if (pathId == 0L) { return false; } if (fileId == 0) { return InternalPaths.Add(pathId); } return ExternalPaths.Add(new PPtrData(fileId, pathId, typeName)); } public bool Add(AssetTypeValueField valueField, string typeName) { return Add(valueField["m_FileID"].AsInt, valueField["m_PathID"].AsLong, typeName); } } private readonly AssetsManager _mgr; private readonly AssetsFileInstance _afileInst; private readonly Dictionary<long, ChildPPtrs> _immediateDeps; private readonly Dictionary<long, ChildPPtrs> _bundleDeps; public Config Settings { get; init; } public int Hits { get; private set; } public int Misses { get; private set; } public AssetDependencies(AssetsManager mgr, AssetsFileInstance afileInst, Config? settings = null) { _mgr = mgr; _afileInst = afileInst; Settings = settings ?? new Config(); _immediateDeps = new Dictionary<long, ChildPPtrs>(); _bundleDeps = new Dictionary<long, ChildPPtrs>(); base..ctor(); } public ChildPPtrs FindImmediateDeps(long assetPathId) { if (_immediateDeps.TryGetValue(assetPathId, out ChildPPtrs value)) { Hits++; return value; } Misses++; AssetFileInfo assetInfo = _afileInst.file.GetAssetInfo(assetPathId); ChildPPtrs childPPtrs = ChildPPtrs.CreateNew(); if (!Settings.FollowTransformParent && (assetInfo.TypeId == 4 || assetInfo.TypeId == 224)) { AssetTypeValueField baseField = _mgr.GetBaseField(_afileInst, assetInfo, (AssetReadFlags)0); childPPtrs.Add(baseField["m_GameObject"], "PPtr<GameObject>"); foreach (AssetTypeValueField child in baseField["m_Children.Array"].Children) { childPPtrs.Add(child, "PPtr<Transform>"); } return _immediateDeps[assetPathId] = childPPtrs; } AssetTypeValueIterator val = _mgr.CreateIterator(_afileInst, assetInfo); while (val.ReadNext()) { string type = val.TempField.Type; if (type.StartsWith("PPtr<")) { AssetTypeValueField valueField = val.ReadValueField(); childPPtrs.Add(valueField, type); } } return _immediateDeps[assetPathId] = childPPtrs; } public ChildPPtrs FindBundleDeps(long assetPathId) { if (_bundleDeps.TryGetValue(assetPathId, out ChildPPtrs value)) { return value; } HashSet<long> hashSet = new HashSet<long>(new <>z__ReadOnlySingleElementList<long>(assetPathId)); HashSet<PPtrData> hashSet2 = new HashSet<PPtrData>(); Queue<long> queue = new Queue<long>(); queue.Enqueue(assetPathId); lock (_afileInst.LockReader) { long result; while (queue.TryDequeue(out result)) { ChildPPtrs childPPtrs = FindImmediateDeps(result); hashSet2.UnionWith(childPPtrs.ExternalPaths); foreach (long internalPath in childPPtrs.InternalPaths) { if (hashSet.Add(internalPath)) { queue.Enqueue(internalPath); } } } } hashSet.Remove(assetPathId); return _bundleDeps[assetPathId] = new ChildPPtrs(hashSet, hashSet2); } } public static class BundleUtils { public record AssetData(AssetFileInfo Info, AssetTypeValueField ValueField); public record SceneBundleInfo(int mainAfileInstIndex, int sharedAssetsAfileIndex); [CompilerGenerated] private sealed class <EnumerateContainer>d__16 : IEnumerable<(string name, int assetTypeId)>, IEnumerable, IEnumerator<(string name, int assetTypeId)>, IEnumerator, IDisposable { private int <>1__state; private (string name, int assetTypeId) <>2__current; private int <>l__initialThreadId; private AssetsManager mgr; public AssetsManager <>3__mgr; private AssetsFileInstance afi; public AssetsFileInstance <>3__afi; private List<AssetTypeValueField>.Enumerator <>7__wrap1; (string, int) IEnumerator<(string, int)>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnumerateContainer>d__16(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(List<AssetTypeValueField>.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; AssetTypeValueField baseField = mgr.GetBaseField(afi, 1L, (AssetReadFlags)0); <>7__wrap1 = baseField["m_Container.Array"].Children.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { AssetTypeValueField current = <>7__wrap1.Current; string asString = current["first"].AsString; long asLong = current["second.asset.m_PathID"].AsLong; int typeId = afi.file.GetAssetInfo(asLong).TypeId; <>2__current = (asString, typeId); <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(List<AssetTypeValueField>.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<(string name, int assetTypeId)> IEnumerable<(string, int)>.GetEnumerator() { <EnumerateContainer>d__16 <EnumerateContainer>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <EnumerateContainer>d__ = this; } else { <EnumerateContainer>d__ = new <EnumerateContainer>d__16(0); } <EnumerateContainer>d__.mgr = <>3__mgr; <EnumerateContainer>d__.afi = <>3__afi; return <EnumerateContainer>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<(string, int)>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <GetAllTransforms>d__5 : IEnumerable<AssetFileInfo>, IEnumerable, IEnumerator<AssetFileInfo>, IEnumerator, IDisposable { private int <>1__state; private AssetFileInfo <>2__current; private int <>l__initialThreadId; private AssetsFile afile; public AssetsFile <>3__afile; private List<AssetClassID>.Enumerator <>7__wrap1; private List<AssetFileInfo>.Enumerator <>7__wrap2; AssetFileInfo IEnumerator<AssetFileInfo>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetAllTransforms>d__5(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -4) <= 1u || num == 1) { try { if (num == -4 || num == 1) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <>7__wrap1 = default(List<AssetClassID>.Enumerator); <>7__wrap2 = default(List<AssetFileInfo>.Enumerator); <>1__state = -2; } private bool MoveNext() { //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_0049: Unknown result type (might be due to invalid IL or missing references) try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -4; goto IL_0089; } <>1__state = -1; <>7__wrap1 = TransformClassIds.GetEnumerator(); <>1__state = -3; goto IL_00a8; IL_0089: if (<>7__wrap2.MoveNext()) { AssetFileInfo current = <>7__wrap2.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally2(); <>7__wrap2 = default(List<AssetFileInfo>.Enumerator); goto IL_00a8; IL_00a8: if (<>7__wrap1.MoveNext()) { AssetClassID current2 = <>7__wrap1.Current; <>7__wrap2 = afile.GetAssetsOfType(current2).GetEnumerator(); <>1__state = -4; goto IL_0089; } <>m__Finally1(); <>7__wrap1 = default(List<AssetClassID>.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<AssetFileInfo> IEnumerable<AssetFileInfo>.GetEnumerator() { <GetAllTransforms>d__5 <GetAllTransforms>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetAllTransforms>d__ = this; } else { <GetAllTransforms>d__ = new <GetAllTransforms>d__5(0); } <GetAllTransforms>d__.afile = <>3__afile; return <GetAllTransforms>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<AssetFileInfo>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <GetRootTransforms>d__6 : IEnumerable<AssetData>, IEnumerable, IEnumerator<AssetData>, IEnumerator, IDisposable { private int <>1__state; private AssetData <>2__current; private int <>l__initialThreadId; private AssetsFileInstance afileInst; public AssetsFileInstance <>3__afileInst; private AssetsManager mgr; public AssetsManager <>3__mgr; private IEnumerator<AssetFileInfo> <>7__wrap1; AssetData IEnumerator<AssetData>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetRootTransforms>d__6(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = afileInst.file.GetAllTransforms().GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { AssetFileInfo current = <>7__wrap1.Current; AssetTypeValueField baseField = mgr.GetBaseField(afileInst, current, (AssetReadFlags)0); if (baseField["m_Father"]["m_PathID"].AsLong == 0L) { <>2__current = new AssetData(current, baseField); <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<AssetData> IEnumerable<AssetData>.GetEnumerator() { <GetRootTransforms>d__6 <GetRootTransforms>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetRootTransforms>d__ = this; } else { <GetRootTransforms>d__ = new <GetRootTransforms>d__6(0); } <GetRootTransforms>d__.mgr = <>3__mgr; <GetRootTransforms>d__.afileInst = <>3__afileInst; return <GetRootTransforms>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<AssetData>)this).GetEnumerator(); } } public static List<AssetClassID> TransformClassIds { get; } = new List<AssetClassID>(2) { (AssetClassID)4, (AssetClassID)224 }; public static AssetsManager CreateDefaultManager() { //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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown return new AssetsManager { UseQuickLookup = true, UseMonoTemplateFieldCache = true, UseRefTypeManagerCache = true, UseTemplateFieldCache = true }; } [IteratorStateMachine(typeof(<GetAllTransforms>d__5))] public static IEnumerable<AssetFileInfo> GetAllTransforms(this AssetsFile afile) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetAllTransforms>d__5(-2) { <>3__afile = afile }; } [IteratorStateMachine(typeof(<GetRootTransforms>d__6))] public static IEnumerable<AssetData> GetRootTransforms(this AssetsManager mgr, AssetsFileInstance afileInst) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetRootTransforms>d__6(-2) { <>3__mgr = mgr, <>3__afileInst = afileInst }; } public static Dictionary<string, AssetData> FindRootGameObjects(this AssetsManager mgr, AssetsFileInstance afileInst, List<string> objectNames, out List<string> missingObjects) { Dictionary<string, AssetData> gameObjects = new Dictionary<string, AssetData>(); foreach (AssetData rootTransform in mgr.GetRootTransforms(afileInst)) { AssetFileInfo assetInfo = afileInst.file.GetAssetInfo(rootTransform.ValueField["m_GameObject.m_PathID"].AsLong); AssetTypeValueField baseField = mgr.GetBaseField(afileInst, assetInfo, (AssetReadFlags)0); string asString = baseField["m_Name"].AsString; if (objectNames.Contains(asString)) { gameObjects[asString] = new AssetData(assetInfo, baseField); } } missingObjects = objectNames.Where((string x) => !gameObjects.ContainsKey(x)).ToList(); return gameObjects; } public static string GetTransformName(this AssetsManager mgr, AssetsFileInstance afileInst, AssetFileInfo info) { AssetTypeValueField baseField = mgr.GetBaseField(afileInst, info, (AssetReadFlags)0); return mgr.GetTransformName(afileInst, baseField); } public static string GetTransformName(this AssetsManager mgr, AssetsFileInstance afileInst, AssetTypeValueField transform) { long asLong = transform["m_GameObject.m_PathID"].AsLong; return mgr.GetBaseField(afileInst, asLong, (AssetReadFlags)0)["m_Name"].AsString; } public static AssetData FindTransform(this AssetsManager mgr, AssetsFileInstance afileInst, string name) { string[] array = name.Split('/'); string text = array[0]; string[] subArray = array[1..]; AssetData assetData = null; foreach (AssetData rootTransform in mgr.GetRootTransforms(afileInst)) { if (mgr.GetTransformName(afileInst, rootTransform.ValueField) == text) { assetData = rootTransform; break; } } if (assetData == null) { throw new Exception("Did not find root game object " + text); } AssetData assetData2 = assetData; string[] array2 = subArray; foreach (string text2 in array2) { bool flag = false; foreach (AssetTypeValueField child in assetData2.ValueField["m_Children.Array"].Children) { long asLong = child["m_PathID"].AsLong; AssetFileInfo assetInfo = afileInst.file.GetAssetInfo(asLong); AssetTypeValueField baseField = mgr.GetBaseField(afileInst, assetInfo, (AssetReadFlags)0); if (mgr.GetTransformName(afileInst, baseField) == text2) { flag = true; assetData2 = new AssetData(assetInfo, baseField); break; } } if (!flag) { throw new Exception("Did not find part " + text2); } } return assetData2; } public static bool TryFindAssetsFiles(this AssetsManager mgr, BundleFileInstance sceneBun, out SceneBundleInfo info) { int num = -1; int num2 = -1; List<string> allFileNames = sceneBun.file.GetAllFileNames(); for (int i = 0; i < allFileNames.Count; i++) { if (!allFileNames[i].Contains('.')) { num = i; } else if (allFileNames[i].EndsWith(".sharedAssets")) { num2 = i; } } info = new SceneBundleInfo(num, num2); if (num == -1 || num2 == -1) { return false; } return true; } public static AssetTypeValueIterator CreateIterator(this AssetsManager mgr, AssetsFileInstance afileinst, AssetFileInfo info) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown AssetTypeTemplateField templateBaseField = mgr.GetTemplateBaseField(afileinst, info, (AssetReadFlags)0); RefTypeManager refTypeManager = mgr.GetRefTypeManager(afileinst); long absoluteByteOffset = info.GetAbsoluteByteOffset(afileinst.file); return new AssetTypeValueIterator(templateBaseField, afileinst.file.Reader, absoluteByteOffset, refTypeManager); } public static int Redirect(this AssetsManager mgr, AssetsFileInstance afileinst, AssetFileInfo info, long source, long target) { int num = 0; lock (afileinst.LockReader) { byte[] array = mgr.GetBaseField(afileinst, info, (AssetReadFlags)0).WriteToByteArray(false); AssetTypeValueIterator val = mgr.CreateIterator(afileinst, info); while (val.ReadNext()) { if (val.TempField.Type.StartsWith("PPtr<")) { AssetTypeValueField val2 = val.ReadValueField(); if (val2["m_PathID"].AsLong == source && val2["m_FileID"].AsInt == 0) { val2["m_PathID"].AsLong = target; byte[] array2 = val2.WriteToByteArray(false); int destinationIndex = val.ReadPosition - array2.Length; Array.Copy(array2, 0, array, destinationIndex, array2.Length); num++; } } } info.SetNewData(array); return num; } } public static void WriteBundleToFile(this AssetBundleFile bunFile, string outBundlePath) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown using MemoryStream memoryStream = new MemoryStream(); AssetsFileWriter val = new AssetsFileWriter(memoryStream); try { bunFile.Write(val, 0L); using FileStream fileStream = new FileStream(outBundlePath, FileMode.Create, FileAccess.Write); byte[] buffer = memoryStream.GetBuffer(); fileStream.Write(buffer, 0, (int)memoryStream.Length); } finally { ((IDisposable)val)?.Dispose(); } } [IteratorStateMachine(typeof(<EnumerateContainer>d__16))] public static IEnumerable<(string name, int assetTypeId)> EnumerateContainer(this AssetsManager mgr, AssetsFileInstance afi) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnumerateContainer>d__16(-2) { <>3__mgr = mgr, <>3__afi = afi }; } } public class GameObjectLookup : IEnumerable<GameObjectLookup.GameObjectInfo>, IEnumerable { public record GameObjectInfo(long GameObjectPathId, long TransformPathId, string GameObjectName, long ParentPathId); private readonly Dictionary<string, List<GameObjectInfo>> _fromName; private readonly Dictionary<long, GameObjectInfo> _fromGameObject; private readonly Dictionary<long, GameObjectInfo> _fromTransform; private GameObjectLookup(Dictionary<string, List<GameObjectInfo>> fromName, Dictionary<long, GameObjectInfo> fromGameObject, Dictionary<long, GameObjectInfo> fromTransform) { _fromName = fromName; _fromGameObject = fromGameObject; _fromTransform = fromTransform; } public static GameObjectLookup CreateFromInfos(IEnumerable<GameObjectInfo> infos) { Dictionary<string, List<GameObjectInfo>> dictionary = new Dictionary<string, List<GameObjectInfo>>(); Dictionary<long, GameObjectInfo> dictionary2 = new Dictionary<long, GameObjectInfo>(); Dictionary<long, GameObjectInfo> dictionary3 = new Dictionary<long, GameObjectInfo>(); foreach (GameObjectInfo info in infos) { dictionary.AddEntry(info.GameObjectName, info); dictionary2[info.GameObjectPathId] = info; dictionary3[info.TransformPathId] = info; } return new GameObjectLookup(dictionary, dictionary2, dictionary3); } public static GameObjectLookup CreateFromFile(AssetsManager mgr, AssetsFileInstance afileInst) { Dictionary<long, string> go2name = new Dictionary<long, string>(); Dictionary<long, long> tf2parent = new Dictionary<long, long>(); Dictionary<long, long> tf2go = new Dictionary<long, long>(); foreach (AssetFileInfo assetInfo in afileInst.file.AssetInfos) { if (assetInfo.TypeId == 1) { AssetTypeValueField baseField = mgr.GetBaseField(afileInst, assetInfo, (AssetReadFlags)0); go2name[assetInfo.PathId] = baseField["m_Name"].AsString; } else if (assetInfo.TypeId == 4 || assetInfo.TypeId == 224) { AssetTypeValueField baseField2 = mgr.GetBaseField(afileInst, assetInfo, (AssetReadFlags)0); tf2parent[assetInfo.PathId] = baseField2["m_Father.m_PathID"].AsLong; tf2go[assetInfo.PathId] = baseField2["m_GameObject.m_PathID"].AsLong; } } Dictionary<long, GameObjectInfo> fromTransformLookup = new Dictionary<long, GameObjectInfo>(); foreach (long key in tf2parent.Keys) { DoAdd(key); } return CreateFromInfos(fromTransformLookup.Values); GameObjectInfo DoAdd(long tPathId) { if (fromTransformLookup.TryGetValue(tPathId, out GameObjectInfo value)) { return value; } long num = tf2parent[tPathId]; long num2 = tf2go[tPathId]; string text = go2name[num2]; if (num == 0L) { GameObjectInfo gameObjectInfo = new GameObjectInfo(num2, tPathId, text, 0L); fromTransformLookup[tPathId] = gameObjectInfo; return gameObjectInfo; } string gameObjectName = DoAdd(num).GameObjectName; GameObjectInfo gameObjectInfo2 = new GameObjectInfo(num2, tPathId, gameObjectName + "/" + text, num); fromTransformLookup[tPathId] = gameObjectInfo2; return gameObjectInfo2; } } private bool TryGet<TKey, TValue>(TKey key, Dictionary<TKey, TValue> lookupDict, [MaybeNullWhen(false)] out TValue info) { return lookupDict.TryGetValue(key, out info); } public GameObjectInfo LookupTransform(long pathId) { if (!TryGet(pathId, _fromTransform, out var info)) { throw new KeyNotFoundException($"Did not find transform key {pathId}"); } return info; } public GameObjectInfo LookupGameObject(long pathId) { if (!TryGet(pathId, _fromGameObject, out var info)) { throw new KeyNotFoundException($"Did not find game object key {pathId}"); } return info; } public List<GameObjectInfo> LookupName(string name) { if (!TryGet<string, List<GameObjectInfo>>(name, _fromName, out var info)) { throw new KeyNotFoundException("Did not find name " + name); } return info; } public bool TryLookupTransfrom(long pathId, [MaybeNullWhen(false)] out GameObjectInfo info) { return TryGet(pathId, _fromTransform, out info); } public bool TryLookupGameObject(long pathId, [MaybeNullWhen(false)] out GameObjectInfo info) { return TryGet(pathId, _fromGameObject, out info); } public bool TryLookupName(string name, [MaybeNullWhen(false)] out List<GameObjectInfo> info) { return TryGet(name, _fromName, out info); } public IEnumerator<GameObjectInfo> GetEnumerator() { return _fromGameObject.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public static class GameObjectLookupExtensions { [CompilerGenerated] private sealed class <>c__DisplayClass0_0 { public Dictionary<long, List<GameObjectLookup.GameObjectInfo>> children; } public static IEnumerable<GameObjectLookup.GameObjectInfo> TraverseOrdered(this GameObjectLookup self) { <>c__DisplayClass0_0 CS$<>8__locals0 = new <>c__DisplayClass0_0(); CS$<>8__locals0.children = new Dictionary<long, List<GameObjectLookup.GameObjectInfo>>(); foreach (GameObjectLookup.GameObjectInfo item in self) { if (!CS$<>8__locals0.children.TryGetValue(item.ParentPathId, out List<GameObjectLookup.GameObjectInfo> value)) { value = new List<GameObjectLookup.GameObjectInfo>(); CS$<>8__locals0.children[item.ParentPathId] = value; } value.Add(item); } return InnerTraverse(0L); [IteratorStateMachine(typeof(<>c__DisplayClass0_0.<<TraverseOrdered>g__InnerTraverse|0>d))] IEnumerable<GameObjectLookup.GameObjectInfo> InnerTraverse(long pathId) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass0_0.<<TraverseOrdered>g__InnerTraverse|0>d(-2) { <>4__this = CS$<>8__locals0, <>3__pathId = pathId }; } } } }