Decompiled source of AssetHelper v1.0.2
plugins/AssetHelperLib.dll
Decompiled 19 hours agousing System; 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.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.10.0.0")] [assembly: AssemblyInformationalVersion("0.10.0+1cf7c9c01a64364be35f3b4ad53d0fae43901194")] [assembly: AssemblyProduct("AssetHelperLib")] [assembly: AssemblyTitle("AssetHelperLib")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/flibber-hk/AssetHelperLib")] [assembly: AssemblyVersion("0.10.0.0")] [module: RefSafetyRules(11)] 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; 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); } } } 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; } [CompilerGenerated] [SetsRequiredMembers] protected RepackingParams(RepackingParams original) { SceneBundlePath = original.SceneBundlePath; ObjectNames = original.ObjectNames; ContainerPrefix = original.ContainerPrefix; OutBundlePath = original.OutBundlePath; } 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 MemoryStream memoryStream = new MemoryStream(File.ReadAllBytes(repackingParams.SceneBundlePath)); BundleFileInstance val2 = val.LoadBundleFile((Stream)memoryStream, 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 ctx = new RepackingContext { SceneAssetsManager = val, SceneBundleFileInstance = val2, MainAssetsFileInstance = mainAssetsFileInstance, SharedAssetsFileInstance = sharedAssetsFileInstance, SceneBundleInfo = info }; Run(ctx, repackingParams, 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 GameObjectLookup.GameObjectInfo info)) { hashSet.Add(info.GameObjectPathId); hashSet.UnionWith(ctx.AssetDeps.FindBundleDeps(info.GameObjectPathId).InternalPaths); } else { Logging.LogError("Couldn't find game object " + item2); } } List<string> list = new List<string>(); foreach (long item3 in hashSet) { if (ctx.GameObjLookup.TryLookupGameObject(item3, 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 item4 in highestNodes) { if (ObjPathUtil.TryFindAncestor(highestNodes2, item4, out string ancestorPath, out string _)) { hashSet2.Add(ancestorPath); continue; } Logging.LogWarning("Did not find " + item4 + " in bundle"); list2.Add(item4); } outData.NonRepackedAssets = list2; foreach (AssetFileInfo item5 in ctx.MainAssetsFileInstance.file.AssetInfos.ToList()) { if (!hashSet.Contains(item5.PathId)) { ctx.MainAssetsFileInstance.file.Metadata.RemoveAssetInfo(item5); } } long newOneAssetPathId = 1L; if (hashSet.Contains(1L)) { for (newOneAssetPathId = -1L; hashSet.Contains(newOneAssetPathId); newOneAssetPathId--) { } } foreach (GameObjectLookup.GameObjectInfo item6 in ctx.GameObjLookup) { if (hashSet.Contains(item6.TransformPathId) && item6.GameObjectName.TryGetParent(out string parent)) { if (!ctx.GameObjLookup.TryLookupName(parent, out GameObjectLookup.GameObjectInfo info3)) { Logging.LogWarning("Unexpectedly failed to find " + parent + " from " + item6.GameObjectName); } else if (!hashSet.Contains(info3.TransformPathId)) { AssetFileInfo assetInfo = ctx.MainAssetsFileInstance.file.GetAssetInfo(item6.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 item7 in hashSet2) { GameObjectLookup.GameObjectInfo gameObjectInfo = ctx.GameObjLookup.LookupName(item7); long gameObjectPathId = gameObjectInfo.GameObjectPathId; HashSet<(int, long)> tableInfos = new HashSet<(int, long)>(); _preloadResolver.BuildPreloadTable(gameObjectPathId, ctx, ref tableInfos); int count = list3.Count; foreach (var item8 in tableInfos) { AssetTypeValueField val2 = ValueBuilder.DefaultValueFieldFromArrayTemplate(baseField2["m_PreloadTable.Array"]); val2["m_FileID"].AsInt = item8.Item1; val2["m_PathID"].AsLong = item8.Item2; list3.Add(val2); } int asInt = list3.Count - count; string text = repackingParams.ContainerPrefix + "/" + item7 + ".prefab"; dictionary[text] = item7; 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(gameObjectInfo.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 item9 in hashSet) { if (item9 != 1 && ctx.AssetDeps.FindImmediateDeps(item9).InternalPaths.Contains(1L)) { num += ctx.SceneAssetsManager.Redirect(ctx.MainAssetsFileInstance, ctx.MainAssetsFileInstance.file.GetAssetInfo(item9), 1L, newOneAssetPathId); } } int num2 = ctx.SceneAssetsManager.Redirect(ctx.MainAssetsFileInstance, assetInfo2, 1L, newOneAssetPathId); Logging.LogInfo($"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 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.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, GameObjectInfo> _fromName; private readonly Dictionary<long, GameObjectInfo> _fromGameObject; private readonly Dictionary<long, GameObjectInfo> _fromTransform; private GameObjectLookup(Dictionary<string, 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, GameObjectInfo> dictionary = new Dictionary<string, GameObjectInfo>(); Dictionary<long, GameObjectInfo> dictionary2 = new Dictionary<long, GameObjectInfo>(); Dictionary<long, GameObjectInfo> dictionary3 = new Dictionary<long, GameObjectInfo>(); foreach (GameObjectInfo info in infos) { dictionary[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<T>(T key, Dictionary<T, GameObjectInfo> lookupDict, [MaybeNullWhen(false)] out GameObjectInfo info) { return lookupDict.TryGetValue(key, out info); } public GameObjectInfo LookupTransform(long pathId) { if (!TryGet(pathId, _fromTransform, out GameObjectInfo info)) { throw new KeyNotFoundException($"Did not find transform key {pathId}"); } return info; } public GameObjectInfo LookupGameObject(long pathId) { if (!TryGet(pathId, _fromGameObject, out GameObjectInfo info)) { throw new KeyNotFoundException($"Did not find game object key {pathId}"); } return info; } public GameObjectInfo LookupName(string name) { if (!TryGet(name, _fromName, out GameObjectInfo 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 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 }; } } } } [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(); } }
plugins/AssetHelper.dll
Decompiled 19 hours 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.Repacking; using AssetHelperLib.Util; using AssetsTools.NET; using AssetsTools.NET.Extra; using BepInEx; using BepInEx.Logging; using DataDrivenConstants.Marker; using Md.StartManager; using Microsoft.CodeAnalysis; using Mono.Cecil.Cil; using MonoDetour; using MonoDetour.Cil; using MonoDetour.DetourTypes; using MonoDetour.HookGen; using MonoDetour.Reflection.Unspeakable; using MonoMod.Cil; 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.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: 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.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+f17467b4df559b03b1fb649efa5f577839c76333")] [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.0.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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; } } } internal class LoadingBar : MonoBehaviour { private RectTransform _fillImageRect; private GameObject _canvasObject; private CanvasGroup _canvasGroup; private Text _statusText; public static LoadingBar Create() { //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 LoadingBar"); LoadingBar result = val.AddComponent<LoadingBar>(); val.SetActive(true); return result; } 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) _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, 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; } private void OnDestroy() { if ((Object)(object)_canvasObject != (Object)null) { Object.Destroy((Object)(object)_canvasObject); } } } namespace Md.StartManager { 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()); } } 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"); } } } } 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.Class, Inherited = false, AllowMultiple = false)] 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 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.0.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.RequestApiAvailable = false; <>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.0.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 { [CompilerGenerated] private static class <>O { public static Manipulator <0>__PatchATVI; public static Action<Action<Stream, Stream, long, int>, Stream, Stream, long, int> <1>__PatchC2C; } private static ILHook? _atIteratorHook; 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 //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown MethodInfo? method = typeof(AssetTypeValueIterator).GetMethod("ReadNext"); object obj = <>O.<0>__PatchATVI; if (obj == null) { Manipulator val = PatchATVI; <>O.<0>__PatchATVI = val; obj = (object)val; } _atIteratorHook = new ILHook((MethodBase)method, (Manipulator)obj); _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); } private static void PatchATVI(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); int num3 = default(int); int num2 = default(int); int num = default(int); ILLabel[] array2 = default(ILLabel[]); if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[6] { (Instruction i) => ILPatternMatchingExt.MatchCallvirt<AssetTypeTemplateField>(i, "get_ValueType"), (Instruction i) => ILPatternMatchingExt.MatchStloc(i, ref num3), (Instruction i) => ILPatternMatchingExt.MatchLdloc(i, ref num2), (Instruction i) => ILPatternMatchingExt.MatchLdcI4(i, ref num), (Instruction i) => ILPatternMatchingExt.MatchSub(i), (Instruction i) => ILPatternMatchingExt.MatchSwitch(i, ref array2) })) { ILLabel[] array = (ILLabel[])val.Prev.Operand; array[10] = array[7]; } } } } namespace Silksong.AssetHelper.Plugin { public static class AssetRequestAPI { internal static DelayedAction AfterBundleCreationComplete = new DelayedAction(); internal static bool RequestApiAvailable { get; set; } = true; internal static bool AnyRequestMade { get { if (RequestedNonSceneAssets.Count <= 0) { return SceneAssetRequest.Count > 0; } return true; } } internal static Dictionary<string, HashSet<string>> SceneAssetRequest { get; } = new Dictionary<string, HashSet<string>>(); public static IResourceLocator? SceneAssetLocator { get; internal set; } public static IResourceLocator? NonSceneAssetLocator { get; internal set; } internal static Dictionary<(string bundleName, string assetName), Type> RequestedNonSceneAssets { get; } = new Dictionary<(string, string), Type>(); 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 = (SceneAssetRequest.TryGetValue(sceneName, out value) ? value : new HashSet<string>()); hashSet.UnionWith(assetPaths); SceneAssetRequest[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 (RequestedNonSceneAssets.TryGetValue((bundleName, assetName), out Type value) && value != assetType) { AssetHelperPlugin.InstanceLogger.LogError((object)("Asset " + bundleName + " - " + assetName + " requested with both " + value.Name + " and " + assetType.Name)); } RequestedNonSceneAssets[(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 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 class CatalogMetadata { public string SilksongVersion { get; set; } = VersionData.SilksongVersion; public string PluginVersion { get; set; } = AssetHelperPlugin.Version; } 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 { 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, 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, string bundlePath) { string text = _primaryKeyPrefix + "/SceneBundles/" + sceneName; ContentCatalogDataEntry item = CatalogEntryUtils.CreateBundleEntry(text, bundlePath, data.BundleName, new List<string>()); _addedEntries.Add(item); List<string> list = new List<string>(1) { text }; foreach (string item3 in BundleMetadata.DetermineCatalogDeps("scenes_scenes_scenes/" + sceneName + ".bundle")) { if (!TryDeclareBundleDep(item3, out string primaryKey)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Error adding asset from scene " + sceneName + " with alien dep " + item3)); } else { list.Add(primaryKey); } } foreach (KeyValuePair<string, string> item4 in data.GameObjectAssets ?? new Dictionary<string, string>()) { item4.Deconstruct(out var key, out var value); string internalId = key; string text2 = value; ContentCatalogDataEntry item2 = CatalogEntryUtils.CreateAssetEntry(internalId, typeof(GameObject), list, _primaryKeyPrefix + "/Assets/" + sceneName + "/" + text2); _addedEntries.Add(item2); } } 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, _primaryKeyPrefix + "/" + item); _addedEntries.Add(item3); } } public void AddCatalogEntry(ContentCatalogDataEntry entry) { _addedEntries.Add(entry); } public string Build(string? catalogId = null) { if (catalogId == null) { catalogId = _primaryKeyPrefix; } List<ContentCatalogDataEntry> list = new List<ContentCatalogDataEntry>(); list.AddRange(_includedBaseBundles.Select((string x) => _baseBundleEntries[x])); list.AddRange(_addedEntries); return CatalogUtils.WriteCatalog(list, catalogId); } } public sealed class RepackedSceneBundleData { public string SilksongVersion { get; init; } = VersionData.SilksongVersion; public string PluginVersion { get; init; } = AssetHelperPlugin.Version; public required string SceneName { get; init; } public string? BundleHash { get; init; } public RepackedBundleData? Data { get; set; } } [MonoDetourTargets(typeof(StartManager))] 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 LoadingBar <bar>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(); } } <bar>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; <bar>5__2 = LoadingBar.Create(); <failed>5__3 = false; <>7__wrap3 = _tasks.GetEnumerator(); <>1__state = -3; goto IL_0151; case 2: <>1__state = -3; goto IL_00c6; case 3: <>1__state = -1; <>2__current = original; <>1__state = 4; return true; case 4: { <>1__state = -1; return false; } IL_0151: if (<>7__wrap3.MoveNext()) { <task>5__5 = <>7__wrap3.Current; <enumerator>5__6 = <task>5__5.Run(<bar>5__2); goto IL_00c6; } goto IL_0161; IL_00c6: 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_013b; } if (flag) { <>2__current = <enumerator>5__6.Current; <>1__state = 2; return true; } goto IL_013b; IL_0161: <>m__Finally1(); <>7__wrap3 = default(List<BaseStartupTask>.Enumerator); if (!<failed>5__3) { AssetHelperPlugin.InstanceLogger.LogInfo((object)"AssetHelper prep complete!"); AssetRequestAPI.AfterBundleCreationComplete.Activate(); _startupRun = true; <bar>5__2.SetProgress(1f); } else { AssetHelperPlugin.InstanceLogger.LogWarning((object)"An error occurred during startup, and AssetHelper did not finish."); } Object.Destroy((Object)(object)<bar>5__2); <>2__current = null; <>1__state = 3; return true; IL_013b: if (!<failed>5__3) { <enumerator>5__6 = null; <task>5__5 = null; goto IL_0151; } goto IL_0161; } } 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) { 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 abstract class BaseStartupTask { public abstract IEnumerator Run(LoadingBar loadingBar); } internal class BundleDepsPrecompute : BaseStartupTask { [CompilerGenerated] private sealed class <Run>d__0 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public LoadingBar loadingBar; 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.RequestedNonSceneAssets.Count == 0) { return false; } loadingBar.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(); loadingBar.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++; loadingBar.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(LoadingBar loadingBar) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Run>d__0(0) { loadingBar = loadingBar }; } } 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 LoadingBar 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; NonSceneCatalog nonSceneCatalog = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <nonSceneCatalogCreate>5__2 = nonSceneCatalog.CreateNonSceneAssetCatalog(); bar.SetText("BUILDING_NON_SCENE".GetLocalized()); <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; goto IL_008a; case 2: <>1__state = -1; goto IL_008a; case 3: <>1__state = -1; if (File.Exists(NonSceneCatalogPath) && AssetRequestAPI.RequestedNonSceneAssets.Count > 0) { bar.SetText("LOADING_NON_SCENE".GetLocalized()); <>2__current = null; <>1__state = 4; return true; } goto IL_0156; 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_0156; case 6: { <>1__state = -1; return false; } IL_0156: <>2__current = null; <>1__state = 6; return true; IL_008a: 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; private string <catalogMetadataPath>5__2; private NonSceneCatalogMetadata <metadata>5__3; private CustomCatalogBuilder <cbr>5__4; 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() { <catalogMetadataPath>5__2 = null; <metadata>5__3 = null; <cbr>5__4 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; 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.SilksongVersion == VersionData.SilksongVersion && VersionData.EarliestAcceptableNonSceneCatalogVersion.AllowCachedData(obj.PluginVersion)) { dictionary = obj.CatalogAssets; } (string, string) key; Type value; foreach (KeyValuePair<(string, string), Type> requestedNonSceneAsset in AssetRequestAPI.RequestedNonSceneAssets) { requestedNonSceneAsset.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"); return false; } <metadata>5__3 = new NonSceneCatalogMetadata(); <cbr>5__4 = new CustomCatalogBuilder(CatalogKeys.NonSceneCatalogId); foreach (KeyValuePair<(string, string), Type> requestedNonSceneAsset2 in AssetRequestAPI.RequestedNonSceneAssets) { requestedNonSceneAsset2.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; return true; } case 1: <>1__state = -1; AssetHelperPlugin.InstanceLogger.LogInfo((object)"Writing catalog"); <cbr>5__4.Build(); <metadata>5__3.SerializeToFile(<catalogMetadataPath>5__2); 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(); } } private static string NonSceneCatalogPath => Path.Combine(AssetPaths.CatalogFolder, CatalogKeys.NonSceneCatalogId + ".bin"); public override IEnumerator Run(LoadingBar loadingBar) { return CreateAndLoadCatalog(loadingBar); } [IteratorStateMachine(typeof(<CreateAndLoadCatalog>d__3))] private IEnumerator CreateAndLoadCatalog(LoadingBar 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() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CreateNonSceneAssetCatalog>d__4(0); } } internal class SceneRepacking : BaseStartupTask { [CompilerGenerated] private sealed class <CreateSceneAssetCatalog>d__13 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SceneRepacking <>4__this; public Dictionary<string, RepackedSceneBundleData> data; private string <catalogMetadataPath>5__2; private CustomCatalogBuilder <cbr>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CreateSceneAssetCatalog>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <catalogMetadataPath>5__2 = null; <cbr>5__3 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; SceneRepacking sceneRepacking = <>4__this; switch (num) { default: return false; case 0: { <>1__state = -1; <catalogMetadataPath>5__2 = Path.ChangeExtension(SceneCatalogPath, ".json"); if (!sceneRepacking._didRepack && JsonExtensions.TryLoadFromFile<SceneCatalogMetadata>(<catalogMetadataPath>5__2, out SceneCatalogMetadata obj) && obj.SilksongVersion == VersionData.SilksongVersion && VersionData.EarliestAcceptableSceneRepackVersion.AllowCachedData(obj.PluginVersion)) { return false; } AssetHelperPlugin.InstanceLogger.LogInfo((object)"Creating catalog"); Stopwatch stopwatch = Stopwatch.StartNew(); <cbr>5__3 = new CustomCatalogBuilder(CatalogKeys.SceneCatalogId); string objPath = default(string); string text3 = default(string); foreach (var (text2, repackedSceneBundleData2) in data) { if (repackedSceneBundleData2.Data == null) { continue; } string bundlePathForScene = GetBundlePathForScene(text2); <cbr>5__3.AddRepackedSceneData(text2, repackedSceneBundleData2.Data, bundlePathForScene); if (!AssetRequestAPI.SceneAssetRequest.TryGetValue(text2, out HashSet<string> value)) { continue; } foreach (string item in value) { if (!ObjPathUtil.TryFindAncestor(repackedSceneBundleData2.Data.GameObjectAssets?.Values.ToList(), item, ref objPath, ref text3)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Failed to find " + item + " in bundle for " + text2 + " as loadable")); } else if (!string.IsNullOrEmpty(text3)) { ContentCatalogDataEntry entry = CatalogEntryUtils.CreateChildGameObjectEntry(CatalogKeys.GetKeyForSceneAsset(text2, objPath), primaryKey: CatalogKeys.GetKeyForSceneAsset(text2, item), relativePath: text3); <cbr>5__3.AddCatalogEntry(entry); } } } stopwatch.Stop(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Prepared catalog in {stopwatch.ElapsedMilliseconds} ms"); <>2__current = null; <>1__state = 1; return true; } case 1: { <>1__state = -1; Stopwatch stopwatch = Stopwatch.StartNew(); <cbr>5__3.Build(); stopwatch.Stop(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Finished writing catalog in {stopwatch.ElapsedMilliseconds} ms"); new SceneCatalogMetadata().SerializeToFile(<catalogMetadataPath>5__2); <>2__current = null; <>1__state = 2; return true; } case 2: <>1__state = -1; 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(); } } [CompilerGenerated] private sealed class <RepackAndCatalogScenes>d__7 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SceneRepacking <>4__this; public LoadingBar bar; private IEnumerator <repack>5__2; private IEnumerator <catalogCreate>5__3; private AsyncOperationHandle<IResourceLocator> <catalogLoadOp>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RepackAndCatalogScenes>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) <repack>5__2 = null; <catalogCreate>5__3 = null; <catalogLoadOp>5__4 = default(AsyncOperationHandle<IResourceLocator>); <>1__state = -2; } private bool MoveNext() { //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; SceneRepacking sceneRepacking = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <repack>5__2 = sceneRepacking.PrepareAndRun(bar); bar.SetText("REPACKING_SCENE".GetLocalized()); <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; goto IL_0098; case 2: <>1__state = -1; goto IL_0098; case 3: <>1__state = -1; <catalogCreate>5__3 = sceneRepacking.CreateSceneAssetCatalog(sceneRepacking._repackData); goto IL_010c; case 4: <>1__state = -1; goto IL_010c; case 5: <>1__state = -1; if (sceneRepacking._repackData.Count > 0) { bar.SetText("LOADING_SCENE".GetLocalized()); <>2__current = null; <>1__state = 6; return true; } goto IL_01ca; case 6: <>1__state = -1; AssetHelperPlugin.InstanceLogger.LogInfo((object)"Loading scene catalog"); <catalogLoadOp>5__4 = Addressables.LoadContentCatalogAsync(SceneCatalogPath, (string)null); <>2__current = <catalogLoadOp>5__4; <>1__state = 7; return true; case 7: <>1__state = -1; AssetRequestAPI.SceneAssetLocator = <catalogLoadOp>5__4.Result; <catalogLoadOp>5__4 = default(AsyncOperationHandle<IResourceLocator>); goto IL_01ca; case 8: { <>1__state = -1; return false; } IL_0098: if (<repack>5__2.MoveNext()) { <>2__current = null; <>1__state = 2; return true; } bar.SetProgress(1f); bar.SetText("BULDING_SCENE".GetLocalized()); <>2__current = null; <>1__state = 3; return true; IL_01ca: <>2__current = null; <>1__state = 8; return true; IL_010c: if (<catalogCreate>5__3.MoveNext()) { <>2__current = null; <>1__state = 4; return true; } <>2__current = null; <>1__state = 5; 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 <RunRepacking>d__12 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SceneRepacking <>4__this; public LoadingBar bar; private SceneRepacker <repacker>5__2; private int <total>5__3; private int <count>5__4; private Dictionary<string, HashSet<string>>.Enumerator <>7__wrap4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RunRepacking>d__12(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(); } } <repacker>5__2 = null; <>7__wrap4 = default(Dictionary<string, HashSet<string>>.Enumerator); <>1__state = -2; } private bool MoveNext() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown try { int num = <>1__state; SceneRepacking sceneRepacking = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <repacker>5__2 = (SceneRepacker)new StrippedSceneRepacker(); <total>5__3 = sceneRepacking._toRepack.Count; <count>5__4 = 0; AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Repacking {sceneRepacking._toRepack.Count} scenes"); <>7__wrap4 = sceneRepacking._toRepack.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } if (<>7__wrap4.MoveNext()) { <>7__wrap4.Current.Deconstruct(out string key, out HashSet<string> value); string text = key; HashSet<string> hashSet = value; Stopwatch stopwatch = Stopwatch.StartNew(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Repacking {hashSet.Count} objects in scene {text}"); RepackingParams val = new RepackingParams { SceneBundlePath = AssetPaths.GetScenePath(text), ObjectNames = hashSet.ToList(), ContainerPrefix = "AssetHelper/" + text, OutBundlePath = GetBundlePathForScene(text) }; RepackedBundleData data = <repacker>5__2.Repack(val); string bundleHash = null; if (AddressablesData.TryGetLocationForScene(text, out IResourceLocation location)) { object data2 = location.Data; AssetBundleRequestOptions val2 = (AssetBundleRequestOptions)((data2 is AssetBundleRequestOptions) ? data2 : null); if (val2 != null) { bundleHash = val2.Hash; } } RepackedSceneBundleData value2 = new RepackedSceneBundleData { SceneName = text, BundleHash = bundleHash, Data = data }; sceneRepacking._repackData[text] = value2; sceneRepacking._repackData.SerializeToFile(_repackDataPath); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Repacked {text} in {stopwatch.ElapsedMilliseconds} ms"); <count>5__4++; bar.SetProgress((float)<count>5__4 / (float)<total>5__3); <>2__current = null; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap4 = default(Dictionary<string, HashSet<string>>.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__wrap4).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static string _repackDataPath = Path.Combine(AssetPaths.RepackedSceneBundleDir, "repack_data.json"); private Dictionary<string, HashSet<string>> _toRepack = new Dictionary<string, HashSet<string>>(); private Dictionary<string, RepackedSceneBundleData> _repackData = new Dictionary<string, RepackedSceneBundleData>(); private bool _didRepack; private static string SceneCatalogPath => Path.Combine(AssetPaths.CatalogFolder, CatalogKeys.SceneCatalogId + ".bin"); public override IEnumerator Run(LoadingBar loadingBar) { return RepackAndCatalogScenes(loadingBar); } [IteratorStateMachine(typeof(<RepackAndCatalogScenes>d__7))] private IEnumerator RepackAndCatalogScenes(LoadingBar bar) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RepackAndCatalogScenes>d__7(0) { <>4__this = this, bar = bar }; } private IEnumerator PrepareAndRun(LoadingBar bar) { Prepare(); if (_toRepack.Count > 0) { _didRepack = true; return RunRepacking(bar); } return Enumerable.Empty<object>().GetEnumerator(); } private void Prepare() { if (JsonExtensions.TryLoadFromFile<Dictionary<string, RepackedSceneBundleData>>(_repackDataPath, out Dictionary<string, RepackedSceneBundleData> obj)) { _repackData = obj; } else { _repackData = new Dictionary<string, RepackedSceneBundleData>(); } _repackData = _repackData.Where<KeyValuePair<string, RepackedSceneBundleData>>((KeyValuePair<string, RepackedSceneBundleData> kvp) => !MetadataMismatch(kvp.Key, kvp.Value) && File.Exists(GetBundlePathForScene(kvp.Key))).ToDictionary((KeyValuePair<string, RepackedSceneBundleData> kvp) => kvp.Key, (KeyValuePair<string, RepackedSceneBundleData> kvp) => kvp.Value); _toRepack = new Dictionary<string, HashSet<string>>(); foreach (KeyValuePair<string, HashSet<string>> item in AssetRequestAPI.SceneAssetRequest) { item.Deconstruct(out var key, out var value); string key2 = key; HashSet<string> hashSet = value; if (!_repackData.TryGetValue(key2, out RepackedSceneBundleData existingBundleData)) { _toRepack[key2] = hashSet; } else if (existingBundleData.Data == null) { _toRepack[key2] = hashSet; } else if (!hashSet.All((string x) => RepackedBundleDataExtensions.TriedToRepack(existingBundleData.Data, x))) { Dictionary<string, HashSet<string>> toRepack = _toRepack; IEnumerable<string> enumerable = existingBundleData.Data.GameObjectAssets?.Values; toRepack[key2] = new HashSet<string>(hashSet.Union(enumerable ?? Enumerable.Empty<string>())); } } } private static string GetBundlePathForScene(string sceneName) { return Path.Combine(AssetPaths.RepackedSceneBundleDir, "repacked_" + sceneName + ".bundle"); } private static bool MetadataMismatch(string scene, RepackedSceneBundleData existingData) { if (!VersionData.EarliestAcceptableSceneRepackVersion.AllowCachedData(existingData.PluginVersion)) { return true; } if (existingData.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; } [IteratorStateMachine(typeof(<RunRepacking>d__12))] private IEnumerator RunRepacking(LoadingBar bar) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RunRepacking>d__12(0) { <>4__this = this, bar = bar }; } [IteratorStateMachine(typeof(<CreateSceneAssetCatalog>d__13))] private IEnumerator CreateSceneAssetCatalog(Dictionary<string, RepackedSceneBundleData> data) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CreateSceneAssetCatalog>d__13(0) { <>4__this = this, data = data }; } } } namespace Silksong.AssetHelper.ManagedAssets { public interface IManagedAsset { object? Load(); void Unload(); } public class ManagedAsset<T> : IManagedAsset { private AsyncOperationHandle<T>? _handle; public string Key { get; } public AsyncOperationHandle<T> 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 key " + Key + " 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 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!"); } if (AssetRequestAPI.RequestApiAvailable) { AssetRequestAPI.RequestSceneAsset(sceneName, objPath); } 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); } return new ManagedAsset<T>(CatalogKeys.GetKeyForNonSceneAsset(assetName)); } 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>((object)Key); } 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; } } } 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 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 class ManagedAssetGroup<T> : IManagedAsset { public record SceneAssetInfo(string SceneName, string ObjPath); public record NonSceneAssetInfo(string BundleName, string AssetName); private 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) { if (!AssetRequestAPI.RequestApiAvailable) { throw new InvalidOperationException("Asset requests should be made during or before a plugin's Awake method!"); } 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; AssetRequestAPI.RequestSceneAsset(sceneAssetInfo.SceneName, sceneAssetInfo.ObjPath); 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 value2); string key3 = key; NonSceneAssetInfo nonSceneAssetInfo = value2; AssetRequestAPI.RequestNonSceneAsset<T>(nonSceneAssetInfo.BundleName, nonSceneAssetInfo.AssetName); 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 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 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 CachedObject<T> where T : class { [JsonProperty] public required string SilksongVersion { get; init; } [JsonProperty] public required string PluginVersion { get; init; } [JsonProperty] public required T Value { get; set; } private CachedObject() { } private bool IsValid() { if (SilksongVersion == null || PluginVersion == null) { return false; } if (VersionData.SilksongVersion != SilksongVersion) { return false; } if (!VersionData.EarliestAcceptableGeneralVersion.AllowCachedData(PluginVersion)) { return false; } return true; } public static CachedObject<T> CreateSynced(string filename, Func<T> createDefault, bool mutable = true) { string filePath = Path.Combine(AssetPaths.CacheDirectory, filename); if (JsonExtensions.TryLoadFromFile<CachedObject<T>>(filePath, out CachedObject<T> fromCache) && fromCache.Value != null && fromCache.IsValid()) { AssetHelperPlugin.OnQuitApplication += delegate { fromCache.SerializeToFile(filePath); }; return fromCache; } CachedObject<T> created = new CachedObject<T> { SilksongVersion = VersionData.SilksongVersion, PluginVersion = AssetHelperPlugin.Version, Value = createDefault() }; created.SerializeToFile(filePath); if (mutable) { AssetHelperPlugin.OnQuitApplication += delegate { created.SerializeToFile(filePath); }; } return created; } } 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 JsonExtensions { public static void SerializeToFile<T>(this T self, string filePath) { string contents = JsonConvert.SerializeObject((object)self, (Formatting)1); File.WriteAllText(filePath, contents); } public static void SerializeToFileInBackground<T>(this T self, string filePath) { T self2 = self; string filePath2 = filePath; Task.Run(delegate { self2.SerializeToFile(filePath2); }); } public static bool TryLoadFromFile<T>(string filePath, [NotNullWhen(true)] out T? obj) { obj = default(T); if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) { return false; } try { string text = File.ReadAllText(filePath); obj = JsonConvert.DeserializeObject<T>(text); return obj != null; } catch (Exception) { return false; } } } [JsonData("$.*~", new string[] { "**/languages/en.json" })] internal static class LanguageKeys { public const string BUILDING_NON_SCENE = "BUILDING_NON_SCENE"; public const string BULDING_SCENE = "BULDING_SCENE"; public const string COMPUTING_BUNDLE_DEPS = "COMPUTING_BUNDLE_DEPS"; public const string LOADING_NON_SCENE = "LOADING_NON_SCENE"; public const string LOADING_SCENE = "LOADING_SCENE"; public const string REPACKING_SCENE = "REPACKING_SCENE"; public static string GetLocalized(this string key) { return Language.Get(key, "Mods.org.silksong-modding.assethelper"); } } internal static class VersionData { private static string? _silksongVersion; public static string SilksongVersion { get { if (_silksongVersion == null) { _silksongVersion = GetSilksongVersion(); } return _silksongVersion; } } internal static Version EarliestAcceptableGeneralVersion { get; } = Version.Parse("0.1.0"); internal static Version EarliestAcceptableSceneRepackVersion { get; } = Version.Parse("1.0.1"); internal static Version EarliestAcceptableNonSceneCatalogVersion { get; } = Version.Parse("1.0.1"); private static string GetSilksongVersion() { return (typeof(Constants).GetField("GAME_VERSION", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetRawConstantValue() as string) ?? "UNKNOWN"; } internal static bool AllowCachedData(this Version earliest, string cachedPluginVersion) { if (!Version.TryParse(cachedPluginVersion, out Version result)) { return false; } if (result > Version.Parse(AssetHelperPlugin.Version)) { return false; } if (result < earliest) { return false; } return true; } } } namespace Silksong.AssetHelper.Dev { public static class DebugTools { private class LocatorInfo { public string? LocatorID { get; init; } public Dictionary<string, List<AddressablesAssetInfo>> Infos { get; init; } = new Dictionary<string, List<AddressablesAssetInfo>>(); } private class AddressablesAssetInfo { public string? InternalId { get; init; } public string? ProviderId { get; init; } public int DependencyCount { get; init; } public List<string>? Dependencies { get; init; } public string? PrimaryKey { get; init; } public Type? ResourceType { get; init; } public Type? AuxDataType { get; init; } public static AddressablesAssetInfo FromLocation(IResourceLocation loc, bool includeDependencyNames) { List<string> dependencies = ((!includeDependencyNames) ? null : (loc.Dependencies?.Select((IResourceLocation x) => "[" + ((x != null) ? x.PrimaryKey : null) + " | " + ((x != null) ? x.InternalId : null) + "]").ToList() ?? new List<string>())); return new AddressablesAssetInfo { InternalId = loc.InternalId, ProviderId = loc.ProviderId, DependencyCount = (loc.Dependencies?.Count ?? 0), Dependencies = dependencies, PrimaryKey = loc.PrimaryKey, ResourceType = loc.ResourceType, AuxDataType = loc.Data?.GetType() }; } } public class LoadedBundleNames { public List<string> VanillaBundleNames; public List<string> Unknown; public LoadedBundleNames(List<string> names, List<string> unknown) { VanillaBundleNames = names; Unknown = unknown; base..ctor(); } } private static readonly ManualLogSource Log = Logger.CreateLogSource("AssetHelper.DebugTools"); private static string _debugDataDir = Path.Combine(AssetPaths.AssemblyFolder, "DebugData"); private static Dictionary<string, string>? _bundleNameLookup; public static string DebugDataDir { get { if (!Directory.Exists(_debugDataDir)) { Directory.CreateDirectory(_debugDataDir); } return _debugDataDir; } } public static void DumpAddressablesKeys() { string dumpFile = Path.Combine(DebugDataDir, "bundle_keys.json"); AddressablesData.InvokeAfterAddressablesLoaded(delegate { AddressablesData.BundleKeys.SerializeToFileInBackground(dumpFile); }); } public static void DumpAllAssetNames() { AddressablesData.InvokeAfterAddressablesLoaded(DumpAllAssetNamesInternal); } private static void DumpAllAssetNamesInternal() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) string filePath = Path.Combine(DebugDataDir, "asset_names.json"); Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(); Dictionary<string, List<string>> dictionary2 = new Dictionary<string, List<string>>(); Stopwatch stopwatch = Stopwatch.StartNew(); foreach (KeyValuePair<string, string> bundleKey in AddressablesData.BundleKeys) { bundleKey.Deconstruct(out var key, out var value); string key2 = key; AsyncOperationHandle<IAssetBundleResource> val = Addressables.LoadAssetAsync<IAssetBundleResource>((object)value); AssetBundle assetBundle = val.WaitForCompletion().GetAssetBundle(); string[] allScenePaths = assetBundle.GetAllScenePaths(); if (allScenePaths.Length != 0) { dictionary2[key2] = allScenePaths.ToList(); } string[] allAssetNames = assetBundle.GetAllAssetNames(); if (allAssetNames.Length != 0) { dictionary[key2] = allAssetNames.ToList(); } Addressables.Release<IAssetBundleResource>(val); } stopwatch.Stop(); Log.LogInfo((object)$"Determined asset names in {stopwatch.ElapsedMilliseconds} ms"); new Dictionary<string, Dictionary<string, List<string>>> { ["assets"] = dictionary, ["scenes"] = dictionary2 }.SerializeToFileInBackground(filePath); } public static void DumpAllAddressableAssets() { AddressablesData.InvokeAfterAddressablesLoaded(DumpAllAddressableAssetsInternal); } private static void DumpAllAddressableAssetsInternal() { if (AddressablesData.MainLocator != null) { DumpAllAddressableAssets(AddressablesData.MainLocator, "addressables_main.json"); } } public static void DumpAllAddressableAssets(IResourceLocator locator, string fileName, bool includeDependencyNames = false) { Dictionary<string, List<AddressablesAssetInfo>> dictionary = new Dictionary<string, List<AddressablesAssetInfo>>(); IList<IResourceLocation> source = default(IList<IResourceLocation>); foreach (string item in locator.Keys.OfType<string>()) { if (locator.Locate((object)item, (Type)null, ref source)) { dictionary[item] = source.Select((IResourceLocation x) => AddressablesAssetInfo.FromLocation(x, includeDependencyNames)).ToList(); } } new LocatorInfo { LocatorID = locator.LocatorId, Infos = dictionary }.SerializeToFileInBackground(Path.Combine(DebugDataDir, fileName)); } private static Dictionary<string, string> GenerateBundleNameLookup() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (KeyValuePair<string, string> bundleKey in AddressablesData.BundleKeys) { bundleKey.Deconstruct(out var key, out var value); string value2 = key; AsyncOperationHandle<IAssetBundleResource> val = Addressables.LoadAssetAsync<IAssetBundleResource>((object)value); val.WaitForCompletion(); dictionary[((Object)val.Result.GetAssetBundle()).name] = value2; Addressables.Release<IAssetBundleResource>(val); } return dictionary; } public static LoadedBundleNames GetLoadedBundleNames() { if (!AddressablesData.IsAddressablesLoaded) { throw new InvalidOperationException("GetLoadedBundleNames cannot be called until Addressables is loaded!"); } if (_bundleNameLookup == null) { _bundleNameLookup = CachedObject<Dictionary<string, string>>.CreateSynced("bundle_name_lookup.json", GenerateBundleNameLookup, mutable: false).Value; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); foreach (string item in from b in AssetBundle.GetAllLoadedAssetBundles() select ((Object)b).name) { if (_bundleNameLookup.TryGetValue(item, out string value)) { list.Add(value); } else { list2.Add(item); } } return new LoadedBundleNames(list, list2); } public static void DumpGameObjectPaths(string sceneName, bool compressed) { string path = "paths_" + sceneName + (compressed ? "_compressed.json" : ".json"); string filePath = Path.Combine(DebugDataDir, path); AssetsManager val = BundleUtils.CreateDefaultManager(); BundleFileInstance val2 = val.LoadBundleFile(AssetPaths.GetScenePath(sceneName), true); SceneBundleInfo val3 = default(SceneBundleInfo); if (!BundleUtils.TryFindAssetsFiles(val, val2, ref val3)) { return; } AssetsFileInstance val4 = val.LoadAssetsFileFromBundle(val2, val3.mainAfileInstIndex, false); List<GameObjectInfo> list = GameObjectLookupExtensions.TraverseOrdered(GameObjectLookup.CreateFromFile(val, val4)).ToList(); if (!compressed) { list.SerializeToFile(filePath); return; } list.Select((GameObjectInfo x) => $"{x.GameObjectName} [{x.GameObjectPathId}, {x.TransformPathId}]").ToList().SerializeToFile(filePath); val.UnloadAll(false); } } } namespace Silksong.AssetHelper.Core { public static class AddressablesData { private static readonly ManualLogSource Log = Logger.CreateLogSource("AssetHelper.AddressablesData"); private static Dictionary<string, string>? _bundleKeys; private static DelayedAction _afterAddressablesLoaded = new DelayedAction(); private static readonly string BundleSuffix = "_[0-9a-fA-F]{32}\\.bundle+$"; private static readonly Regex BundleSuffixRegex = new Regex(BundleSuffix, RegexOptions.Compiled); public static IResourceLocator? MainLocator { get; private set; } public static IReadOnlyDictionary<string, string>? BundleKeys { get { if (_bundleKeys != null) { return new ReadOnlyDictionary<string, string>(_bundleKeys); } return null; } } public static bool IsAddressablesLoaded => _bundleKeys != null; public static bool TryGetLocation(string bundleName, [NotNullWhen(true)] out IResourceLocation? location) { string text = ToBundleKey(bundleName); IList<IResourceLocation> source = Array.Empty<IResourceLocation>(); IResourceLocator? mainLocator = MainLocator; if (mainLocator != null && !mainLocator.Locate((object)text, typeof(IAssetBundleResource), ref source)) { location = null; return false; } location = source.FirstOrDefault(); return location != null; } public static bool TryGetLocationForScene(string sceneName, [NotNullWhen(true)] out IResourceLocation? location) { return TryGetLocation("scenes_scenes_scenes/" + sceneName.ToLowerInvariant(), out location); } public static void InvokeAfterAddressablesLoaded(Action a) { _afterAddressablesLoaded.Subscribe(a); } internal static bool TryStrip(string key, [MaybeNullWhen(false)] out string stripped) { if (BundleSuffixRegex.IsMatch(key)) { stripped = BundleSuffixRegex.Replace(key, ""); return true; } stripped = key; return false; } internal static bool TryLoadBundleKeys() { Dictionary<string, string> dictionary = new Dictionary<string, string>(); Stopwatch stopwatch = Stopwatch.StartNew(); MainLocator = Addressables.ResourceLocators.FirstOrDefault((Func<IResourceLocator, bool>)((IResourceLocator x) => x.Keys.Any())); if (MainLocator == null) { Log.LogWarning((object)"Addressables not loaded yet"); return false; } foreach (string item in MainLocator.Keys.OfType<string>()) { if (TryStrip(item, out string stripped)) { dictionary[stripped] = item; } } stopwatch.Stop(); Log.LogInfo((object)$"Loaded {dictionary.Count} bundle locations in {stopwatch.ElapsedMilliseconds} ms"); if (dictionary.Count == 0) { return false; } _bundleKeys = dictionary; _afterAddressablesLoaded.Activate(); return true; } public static string ToBundleKey(string name) { if (_bundleKeys == null) { Log.LogWarning((object)"ToBundleKey called before addressables loaded"); return name; } if (TryStrip(name, out string stripped)) { name = stripped; } else if (name.EndsWith(".bundle")) { string text = name; name = text.Substring(0, text.Length - 7); } if (_bundleKeys.TryGetValue(name, out string value)) { return value; } throw new Exception("Bundle " + name + " not found in lookup."); } } public static class AssetPaths { public static string OSFolderName { get { //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_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 RuntimePlatform platform = Application.platform; if ((int)platform != 1) { if ((int)platform != 2) { if ((int)platform == 13) { return "StandaloneLinux64"; } return ""; } return "StandaloneWindows64"; } return "StandaloneOSX"; } } public static string BundleFolder => Path.Combine(Application.streamingAssetsPath, "aa", OSFolderName); private static string CacheSubfolder => "AssetHelper"; internal static string CacheDirectory => Path.Combine(Paths.CachePath, CacheSubfolder).CreateIfNeeded(); internal static string RepackedSceneBundleDir => Path.Combine(CacheDirectory, "repacked_scenes").CreateIfNeeded(); internal static string CatalogFolder => Path.Combine(CacheDirectory, "Catalogs").CreateIfNeeded(); internal static string AssemblyFolder => Directory.GetParent(typeof(AssetPaths).Assembly.Location).FullName; private static string CreateIfNeeded(this string path) { Directory.CreateDirectory(path); return path; } public static string GetScenePath(string sceneName) { return Path.Combine(BundleFolder, "scenes_scenes_scenes", sceneName.ToLowerInvariant() + ".bundle"); } } public static class BundleMetadata { public static IReadOnlyDictionary<string, string> CabLookup { get; private set; } private static CachedObject<Dictionary<string, List<string>>> DirectDependencyLookup { get; set; } internal static void Setup() { CabLookup = CachedObject<IReadOnlyDictionary<string, string>>.CreateSynced("cabs.json", GenerateCabLookup, mutable: false).Value; DirectDependencyLookup = CachedObject<Dictionary<string, List<string>>>.CreateSynced("direct_deps.json", () => new Dictionary<string, List<string>>()); } private static Dictionary<string, string> GenerateCabLookup() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown Stopwatch stopwatch = Stopwatch.StartNew(); AssetsManager val = new AssetsManager(); string bundleFolder = AssetPaths.BundleFolder; Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string key in AddressablesData.BundleKeys.Keys) { string text = key.Replace("\\", "/"); if (!text.EndsWith(".bundle")) { text += ".bundle"; } string text2 = Path.Combine(bundleFolder, text); string text3 = val.LoadBundleFile(text2, true).file.GetFileName(0).Split(".")[0].ToLowerInvariant(); if (dictionary.ContainsKey(text3)) { AssetHelperPlugin.InstanceLogger.LogWarning((object)("Duplicate cab detected! " + text3 + ": " + dictionary[text3] + " -> " + text)); } else { dictionary[text3] = text; } val.UnloadAll(false); } stopwatch.Stop(); AssetHelperPlugin.InstanceLogger.LogInfo((object)$"Generated CAB lookup in {stopwatch.ElapsedMilliseconds} ms"); return dictionary; } public static List<string> DetermineDirectDeps(string bundleName) { bool cacheHit; return DetermineDirectDepsInternal(bundleName, out cacheHit); } internal static List<string> DetermineDirectDepsInternal(string bundleName, out bool cacheHit) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown string text = bundleName; if (!text.EndsWith(".bundle")) { text += ".bundle"; } if (DirectDependencyLookup.Value.TryGetValue(text, out List<string> value)) { cacheHit = true; return value.ToList(); } cacheHit = false; AssetsManager val = new AssetsManager(); string text2 = Path.Combine(AssetPaths.BundleFolder, text); using MemoryStream memoryStream = new MemoryStream(File.ReadAllBytes(text2)); BundleFileInstance val2 = val.LoadBundleFile((Stream)memoryStream, text2, true); AssetsFile file = val.LoadAssetsFileFromBundle(val2, 0, false).file; List<string> list = new List<string>(); foreach (AssetsFileExternal external in file.Metadata.Externals) { string key = external.OriginalPathName.Split('/')[^1].Split(".")[0].ToLowerInvariant(); if (CabLookup.TryGetValue(key, out string value2)) { list.Add(value2); } } DirectDependencyLookup.Value[text] = list.ToList(); val.UnloadAll(false); return list; } public static List<string> DetermineTransitiveDeps(string bundleName) { string text = bundleName; if (!text.EndsWith(".bundle")) { text += ".bundle"; } HashSet<string> hashSet = new HashSet<string> { text }; Queue<string> queue = new Queue<string>(); queue.Enqueue(text); string result; while (queue.TryDequeue(out result)) { foreach (string item in DetermineDirectDeps(result)) { if (hashSet.Add(item)) { queue.Enqueue(item); } } } hashSet.Remove(text); return hashSet.ToList(); } public static List<string> DetermineCatalogDeps(string sceneBundle) { sceneBundle = sceneBundle.Replace(".bundle", ""); if (!sceneBundle.StartsWith("scenes_scenes_scenes/")) { sceneBundle = "scenes_scenes_scenes/" + sceneBundle; } string sceneName = sceneBundle.Substring("scenes_scenes_scenes/".Length); if (AddressablesData.MainLocator == null) { throw new InvalidOperationException("Cannot inspect catalog until after Addressables has loaded"); } string text = (from s in AddressablesData.MainLocator.Keys.OfType<string>() where s.StartsWith("Scenes/") && s.Substring(7).Equals(sceneName, StringComparison.InvariantCultureIgnoreCase) select s).First(); IList<IResourceLocation> source = default(IList<IResourceLocation>); AddressablesData.MainLocator.Locate((object)text, typeof(SceneInstance), ref source); IResourceLocation obj = source.First(); List<string> list = new List<string>(); foreach (IResourceLocation dependency in obj.Dependencies) { AddressablesData.TryStrip(dependency.PrimaryKey, out string stripped); if (!(stripped == sceneBundle)) { list.Add(stripped + ".bundle"); } } return list; } } } namespace Silksong.AssetHelper.CatalogTools { internal static class CatalogEntryUtils { public static ContentCatalogDataEntry CreateBundleEntry(string primaryKey, string bundlePath, string internalBundleName, List<string> dependencyKeys) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown AssetBundleRequestOptions val = new AssetBundleRequestOptions(); val.AssetLoadMode = (AssetLoadMode)0; val.BundleName = internalBundleName; val.ChunkedTransfer = false; val.RetryCount = 0; val.RedirectLimit = 32; val.Timeout = 0; val.BundleSize = 0L; val.ClearOtherCachedVersionsWhenLoaded = false; val.Crc = 0u; val.UseCrcForCachedBundle = true; val.BundleSize = new FileInfo(bundlePath).Length; return new ContentCatalogDataEntry(typeof(IAssetBundleResource), bundlePath, "UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider", (IEnumerable<object>)new object[1] { primaryKey }, (IEnumerable<object>)dependencyKeys, (object)val); } public static ContentCatalogDataEntry CreateAssetEntry(string internalId, Type assetType, List<string> dependencyKeys, out string primaryKey) { primaryKey = internalId; return CreateAssetEntry(internalId, assetType, dependencyKeys, primaryKey); } public static ContentCatalogDataEntry CreateAssetEntry(string internalId, Type assetType, List<string> dependencyKeys, string primaryKey) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown object[] array = dependencyKeys.Cast<object>().ToArray(); return new ContentCatalogDataEntry(assetType, internalId, "UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider", (IEnumerable<object>)new object[1] { primaryKey }, (IEnumerable<object>)array, (object)null); } public static ContentCatalogDataEntry CreateChildGameObjectEntry(string parentPrimaryKey, string relativePath, out string primaryKey) { int num = parentPrimaryKey.LastIndexOf('.'); int num2 = parentPrimaryKey.LastIndexOf('/'); if (num != -1 && num > num2) { string text = parentPrimaryKey.Substring(0, num); string text2 = parentPrimaryKey.Substring(num); primaryKey = text + "/" + relativePath + text2; } else if (parentPrimaryKey.EndsWith('/')) { primaryKey = parentPrimaryKey + relativePath; } else { primaryKey = parentPrimaryKey + "/" + relativePath; } return CreateChildGameObjectEntry(parentPrimaryKey, relativePath, primaryKey); } public static ContentCatalogDataEntry CreateChildGameObjectEntry(string parentPrimaryKey, string relativePath, string primaryKey) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown object[] array = new object[1] { parentPrimaryKey }; return new ContentCatalogDataEntry(typeof(GameObject), relativePath + "/" + ChildGameObjectProvider.InternalIdSeparator + "/" + parentPrimaryKey, ChildGameObjectProvider.ClassProviderId, (IEnumerable<object>)new object[1] { primaryKey }, (IEnumerable<object>)array, (object)null); } public static ContentCatalogDataEntry CreateEntryFromLocation(IResourceLocation location, out string primaryKey) { primaryKey = "AssetHelper:" + location.PrimaryKey; return CreateEntryFromLocation(location, primaryKey); } public static ContentCatalogDataEntry CreateEntryFromLocation(IResourceLocation location, string primaryKey) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown return new ContentCatalogDataEntry(location.ResourceType, location.InternalId, location.ProviderId, (IEnumerable<object>)new object[1] { primaryKey }, (IEnumerable<object>)null, locati
plugins/AssetsTools.NET.dll
Decompiled 19 hours 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