using System; using System.Buffers; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using AssetHelperLib.BundleTools; using AssetHelperLib.Extensions; using AssetHelperLib.IO; using AssetHelperLib.PreloadTable; using AssetHelperLib.Repacking; using AssetHelperLib.Util; using AssetsTools.NET; using AssetsTools.NET.Extra; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AssetHelperLib")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Scene Asset repacking library built upon AssetsTools.NET.")] [assembly: AssemblyFileVersion("0.12.1.0")] [assembly: AssemblyInformationalVersion("0.12.1+5c3795e0bfb720babc088918564f2ffc0ca06000")] [assembly: AssemblyProduct("AssetHelperLib")] [assembly: AssemblyTitle("AssetHelperLib")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/flibber-hk/AssetHelperLib")] [assembly: AssemblyVersion("0.12.1.0")] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator { object IEnumerator.Current => _item; T IEnumerator.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.Count => 1; T IReadOnlyList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection.Count => 1; bool ICollection.IsReadOnly => true; T IList.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.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { if (!EqualityComparer.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 IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return EqualityComparer.Default.Equals(_item, item); } void ICollection.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { if (!EqualityComparer.Default.Equals(_item, item)) { return -1; } return 0; } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace AssetHelperLib { public static class Logging { public static event Action? OnLog; public static event Action? OnLogWarning; public static event Action? OnLogError; public static event Action? OnLogDebug; internal static void LogInfo(string message) { Logging.OnLog?.Invoke(message); } internal static void LogWarning(string message) { Logging.OnLogWarning?.Invoke(message); } internal static void LogError(string message) { Logging.OnLogError?.Invoke(message); } internal static void LogDebug(string message) { Logging.OnLogDebug?.Invoke(message); } } } namespace AssetHelperLib.Util { public static class ObjPathUtil { public static bool HasPrefix(this string self, string? maybePrefix) { if (maybePrefix == null) { return false; } if (!self.StartsWith(maybePrefix)) { return false; } if (self == maybePrefix) { return true; } if (self[maybePrefix.Length] == '/') { return true; } return false; } public static List GetHighestNodes(this ICollection objPaths) { List list = new List(); 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(1) { ancestor }, descendant, out ancestorPath, out relativePath); } public static bool TryFindAncestor(List? paths, string objName, [MaybeNullWhen(false)] out string ancestorPath, out string? relativePath) { foreach (string item in paths ?? Enumerable.Empty()) { 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? GameObjectAssets { get; set; } public List? 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 ObjectNames { get; set; } public required string ContainerPrefix { get; set; } public required string OutBundlePath { get; set; } public Action? LateCallback { get; set; } [CompilerGenerated] [SetsRequiredMembers] protected RepackingParams(RepackingParams original) { SceneBundlePath = original.SceneBundlePath; ObjectNames = original.ObjectNames; ContainerPrefix = original.ContainerPrefix; OutBundlePath = original.OutBundlePath; LateCallback = original.LateCallback; } public RepackingParams() { } } public abstract class SceneRepacker { protected virtual string RepackStrategy => GetType().Name; protected static void GetDefaultBundleNames(RepackingParams repackingParams, out string cabName, out string bundleName) { using SHA256 sHA = SHA256.Create(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("AssetHelperSalt\n"); stringBuilder.AppendLine(repackingParams.SceneBundlePath ?? string.Empty); foreach (string objectName in repackingParams.ObjectNames) { stringBuilder.AppendLine("\n" + objectName); } stringBuilder.AppendLine(repackingParams.OutBundlePath); string s = stringBuilder.ToString(); byte[] bytes = Encoding.UTF8.GetBytes(s); byte[] array = sHA.ComputeHash(bytes); StringBuilder stringBuilder2 = new StringBuilder(64); byte[] array2 = array; foreach (byte b in array2) { stringBuilder2.Append(b.ToString("x2")); } string text = stringBuilder2.ToString(); cabName = "CAB-" + text.Substring(0, 32); bundleName = text.Substring(32, 32) + ".bundle"; } public RepackedBundleData Repack(RepackingParams repackingParams) { RepackedBundleData outData = new RepackedBundleData(); Repack(repackingParams, ref outData); return outData; } public void Repack(RepackingParams repackingParams, ref RepackedBundleData outData) { outData.RepackStrategy = RepackStrategy; GetDefaultBundleNames(repackingParams, out string cabName, out string bundleName); RepackedBundleData repackedBundleData = outData; if (repackedBundleData.CabName == null) { string text2 = (repackedBundleData.CabName = cabName); } repackedBundleData = outData; if (repackedBundleData.BundleName == null) { string text2 = (repackedBundleData.BundleName = bundleName); } AssetsManager val = BundleUtils.CreateDefaultManager(); using RentedFileArray rentedFileArray = new RentedFileArray(repackingParams.SceneBundlePath); BundleFileInstance val2 = val.LoadBundleFile((Stream)rentedFileArray.Stream, repackingParams.SceneBundlePath, true); if (!val.TryFindAssetsFiles(val2, out BundleUtils.SceneBundleInfo info)) { throw new NotSupportedException("Could not find assets files for " + repackingParams.SceneBundlePath); } AssetsFileInstance mainAssetsFileInstance = val.LoadAssetsFileFromBundle(val2, info.mainAfileInstIndex, false); AssetsFileInstance sharedAssetsFileInstance = val.LoadAssetsFileFromBundle(val2, info.sharedAssetsAfileIndex, false); RepackingContext repackingContext = new RepackingContext { SceneAssetsManager = val, SceneBundleFileInstance = val2, MainAssetsFileInstance = mainAssetsFileInstance, SharedAssetsFileInstance = sharedAssetsFileInstance, SceneBundleInfo = info }; Run(repackingContext, repackingParams, outData); repackingParams.LateCallback?.Invoke(repackingContext, outData); val.UnloadAll(false); } protected abstract void Run(RepackingContext ctx, RepackingParams repackingParams, RepackedBundleData outData); } public class StrippedSceneRepacker : SceneRepacker { private BasePreloadTableResolver _preloadResolver; public StrippedSceneRepacker() : this(new DefaultPreloadTableResolver()) { } public StrippedSceneRepacker(BasePreloadTableResolver preloadResolver) { _preloadResolver = preloadResolver; } protected override void Run(RepackingContext ctx, RepackingParams repackingParams, RepackedBundleData outData) { List highestNodes = repackingParams.ObjectNames.GetHighestNodes(); ctx.GameObjLookup = GameObjectLookup.CreateFromFile(ctx.SceneAssetsManager, ctx.MainAssetsFileInstance); HashSet hashSet = new HashSet(); foreach (string item2 in highestNodes) { if (ctx.GameObjLookup.TryLookupName(item2, out List info)) { Logging.LogInfo($"Found {info.Count} assets for {item2} in {repackingParams.SceneBundlePath}"); foreach (GameObjectLookup.GameObjectInfo item3 in info) { hashSet.Add(item3.GameObjectPathId); hashSet.UnionWith(ctx.AssetDeps.FindBundleDeps(item3.GameObjectPathId).InternalPaths); } } else { Logging.LogError("Couldn't find game object " + item2); } } List list = new List(); foreach (long item4 in hashSet) { if (ctx.GameObjLookup.TryLookupGameObject(item4, out GameObjectLookup.GameObjectInfo info2)) { list.Add(info2.GameObjectName); } } List highestNodes2 = list.GetHighestNodes(); HashSet hashSet2 = new HashSet(); List list2 = new List(); foreach (string item5 in highestNodes) { if (ObjPathUtil.TryFindAncestor(highestNodes2, item5, out string ancestorPath, out string _)) { hashSet2.Add(ancestorPath); continue; } Logging.LogWarning("Did not find " + item5 + " in bundle"); list2.Add(item5); } outData.NonRepackedAssets = list2; foreach (AssetFileInfo item6 in ctx.MainAssetsFileInstance.file.AssetInfos.ToList()) { if (!hashSet.Contains(item6.PathId)) { ctx.MainAssetsFileInstance.file.Metadata.RemoveAssetInfo(item6); } } long newOneAssetPathId = 1L; if (hashSet.Contains(1L)) { for (newOneAssetPathId = -1L; hashSet.Contains(newOneAssetPathId); newOneAssetPathId--) { } } foreach (GameObjectLookup.GameObjectInfo item7 in ctx.GameObjLookup) { if (hashSet.Contains(item7.TransformPathId) && item7.GameObjectName.TryGetParent(out string parent)) { if (!ctx.GameObjLookup.TryLookupTransfrom(item7.ParentPathId, out GameObjectLookup.GameObjectInfo info3)) { Logging.LogWarning("Unexpectedly failed to find " + parent + " from " + item7.GameObjectName); } else if (!hashSet.Contains(info3.TransformPathId)) { AssetFileInfo assetInfo = ctx.MainAssetsFileInstance.file.GetAssetInfo(item7.TransformPathId); AssetTypeValueField baseField = ctx.SceneAssetsManager.GetBaseField(ctx.MainAssetsFileInstance, assetInfo, (AssetReadFlags)0); baseField["m_Father.m_PathID"].AsLong = 0L; assetInfo.SetNewData(baseField); } } } AssetFileInfo val = ctx.SharedAssetsFileInstance.file.GetAssetsOfType((AssetClassID)142).First(); AssetTypeValueField baseField2 = ctx.SceneAssetsManager.GetBaseField(ctx.SharedAssetsFileInstance, val, (AssetReadFlags)0); baseField2["m_Name"].AsString = outData.BundleName; baseField2["m_AssetBundleName"].AsString = outData.BundleName; baseField2["m_IsStreamedSceneAssetBundle"].AsBool = false; baseField2["m_SceneHashes.Array"].Children.Clear(); List list3 = new List(); List list4 = new List(); Dictionary dictionary = new Dictionary(); foreach (string item8 in hashSet2) { foreach (GameObjectLookup.GameObjectInfo item9 in ctx.GameObjLookup.LookupName(item8)) { long gameObjectPathId = item9.GameObjectPathId; HashSet<(int, long)> tableInfos = new HashSet<(int, long)>(); _preloadResolver.BuildPreloadTable(gameObjectPathId, ctx, ref tableInfos); int count = list3.Count; foreach (var item10 in tableInfos) { AssetTypeValueField val2 = ValueBuilder.DefaultValueFieldFromArrayTemplate(baseField2["m_PreloadTable.Array"]); val2["m_FileID"].AsInt = item10.Item1; val2["m_PathID"].AsLong = item10.Item2; list3.Add(val2); } int asInt = list3.Count - count; string text = $"{repackingParams.ContainerPrefix}/{item9.TransformPathId}/{item8}.prefab"; dictionary[text] = item8; AssetTypeValueField val3 = ValueBuilder.DefaultValueFieldFromArrayTemplate(baseField2["m_Container.Array"]); val3["first"].AsString = text; val3["second.preloadIndex"].AsInt = count; val3["second.preloadSize"].AsInt = asInt; val3["second.asset.m_FileID"].AsInt = 0; val3["second.asset.m_PathID"].AsLong = updatedPathId(item9.GameObjectPathId); list4.Add(val3); } } baseField2["m_PreloadTable.Array"].Children.Clear(); baseField2["m_PreloadTable.Array"].Children.AddRange(list3); baseField2["m_Container.Array"].Children.Clear(); baseField2["m_Container.Array"].Children.AddRange(list4); outData.GameObjectAssets = dictionary; if (newOneAssetPathId != 1) { int num = 0; AssetFileInfo assetInfo2 = ctx.MainAssetsFileInstance.file.GetAssetInfo(1L); ctx.MainAssetsFileInstance.file.Metadata.RemoveAssetInfo(assetInfo2); assetInfo2.PathId = newOneAssetPathId; ctx.MainAssetsFileInstance.file.Metadata.AddAssetInfo(assetInfo2); foreach (long item11 in hashSet) { if (item11 != 1 && ctx.AssetDeps.FindImmediateDeps(item11).InternalPaths.Contains(1L)) { num += ctx.SceneAssetsManager.Redirect(ctx.MainAssetsFileInstance, ctx.MainAssetsFileInstance.file.GetAssetInfo(item11), 1L, newOneAssetPathId); } } int num2 = ctx.SceneAssetsManager.Redirect(ctx.MainAssetsFileInstance, assetInfo2, 1L, newOneAssetPathId); Logging.LogDebug($"Redirected {num} references plus {num2} self-references"); } if (!ctx.MainAssetsFileInstance.file.Metadata.TypeTreeTypes.Any((TypeTreeType x) => x.TypeId == 142)) { TypeTreeType item = ctx.SharedAssetsFileInstance.file.Metadata.TypeTreeTypes.First((TypeTreeType x) => x.TypeId == 142); ctx.MainAssetsFileInstance.file.Metadata.TypeTreeTypes.Add(item); } AssetFileInfo val4 = AssetFileInfo.Create(ctx.MainAssetsFileInstance.file, (long)ctx.SceneBundleInfo.mainAfileInstIndex, 142, (ClassDatabaseFile)null, false); val4.SetNewData(baseField2); ctx.MainAssetsFileInstance.file.Metadata.AddAssetInfo(val4); ctx.SceneBundleFileInstance.file.BlockAndDirInfo.DirectoryInfos[ctx.SceneBundleInfo.mainAfileInstIndex].SetNewData(ctx.MainAssetsFileInstance.file); ctx.SceneBundleFileInstance.file.BlockAndDirInfo.DirectoryInfos[ctx.SceneBundleInfo.mainAfileInstIndex].Name = outData.CabName; int count2 = ctx.SceneBundleFileInstance.file.BlockAndDirInfo.DirectoryInfos.Count; for (int i = 0; i < count2; i++) { if (i != ctx.SceneBundleInfo.mainAfileInstIndex) { ctx.SceneBundleFileInstance.file.BlockAndDirInfo.DirectoryInfos[i].SetRemoved(); } } ctx.SceneBundleFileInstance.file.WriteBundleToFile(repackingParams.OutBundlePath); long updatedPathId(long orig) { if (orig != 1) { return orig; } return newOneAssetPathId; } } } } namespace AssetHelperLib.PreloadTable { public abstract class BasePreloadTableResolver { public abstract void BuildPreloadTable(long assetPathId, RepackingContext ctx, ref HashSet<(int fileId, long pathId)> tableInfos); } public sealed class ContainerPointerPreloadsBundleData { public required List ContainerPaths { get; set; } public Dictionary> ContainerInternalDeps { get; set; } = new Dictionary>(); public static ContainerPointerPreloadsBundleData FromFile(string bundlePath) { AssetsManager val = BundleUtils.CreateDefaultManager(); using RentedFileArray rentedFileArray = new RentedFileArray(bundlePath); BundleFileInstance val2 = val.LoadBundleFile((Stream)rentedFileArray.Stream, bundlePath, true); AssetsFileInstance val3 = val.LoadAssetsFileFromBundle(val2, 0, false); List list = val.GetBaseField(val3, 1L, (AssetReadFlags)0)["m_Container.Array"].Children.Select((AssetTypeValueField x) => x["second.asset.m_PathID"].AsLong).ToList(); ContainerPointerPreloadsBundleData containerPointerPreloadsBundleData = new ContainerPointerPreloadsBundleData { ContainerPaths = list }; AssetDependencies assetDependencies = new AssetDependencies(val, val3); foreach (long item in list) { containerPointerPreloadsBundleData.ContainerInternalDeps[item] = assetDependencies.FindBundleDeps(item).InternalPaths; } val.UnloadAll(false); return containerPointerPreloadsBundleData; } } public class ContainerPointerPreloads : BasePreloadTableResolver { public delegate bool CabResolver(string cabName, out string? bundlePath); private readonly CabResolver _cabResolver; public Dictionary Cache { get; init; } public ContainerPointerPreloads(CabResolver cabResolver) { _cabResolver = cabResolver; Cache = new Dictionary(); base..ctor(); } public override void BuildPreloadTable(long assetPathId, RepackingContext ctx, ref HashSet<(int fileId, long pathId)> tableInfos) { foreach (var item4 in (from item in tableInfos group item by item.fileId into @group select (@group.Key, new HashSet(@group.Select(((int fileId, long pathId) g) => g.pathId)))).ToList()) { int item2 = item4.Item1; HashSet item3 = item4.Item2; string text = ctx.MainAssetsFileInstance.file.Metadata.Externals[item2 - 1].OriginalPathName.Split("/").Last().ToLowerInvariant(); if (!_cabResolver(text, out var bundlePath)) { Logging.LogWarning("Unexpectedly failed to resolve cab name " + text + " for ContainerPointerPreloads while running for " + ctx.MainAssetsFileInstance.name); } else { if (bundlePath == null) { continue; } if (!Cache.TryGetValue(text, out ContainerPointerPreloadsBundleData value)) { Logging.LogInfo("Building cache for " + text); value = ContainerPointerPreloadsBundleData.FromFile(bundlePath); Cache[text] = value; } foreach (long item5 in item3) { if (value.ContainerPaths.Contains(item5)) { continue; } bool flag = false; foreach (var (num2, hashSet2) in value.ContainerInternalDeps) { if (hashSet2.Contains(item5)) { flag = true; if (tableInfos.Add((item2, num2))) { Logging.LogDebug($"Added new {num2} for {item5} within {text}, for {ctx.MainAssetsFileInstance.name} :: {assetPathId}"); } break; } } if (!flag) { Logging.LogWarning($"Failed to find container asset for cab {text}, path {item5} while running for {ctx.MainAssetsFileInstance.name}"); } } } } } } public sealed class DefaultPreloadTableResolver : BasePreloadTableResolver { public override void BuildPreloadTable(long assetPathId, RepackingContext ctx, ref HashSet<(int fileId, long pathId)> tableInfos) { HashSet 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 _resolvers; public PreloadTableResolver(List resolvers) { _resolvers = resolvers; base..ctor(); } public override void BuildPreloadTable(long assetPathId, RepackingContext ctx, ref HashSet<(int fileId, long pathId)> tableInfos) { foreach (BasePreloadTableResolver resolver in _resolvers) { resolver.BuildPreloadTable(assetPathId, ctx, ref tableInfos); } } } } namespace AssetHelperLib.IO { internal static class Extensions { public static int ReadExact(this FileStream fs, byte[] array, int offset, int count) { int i; int num; for (i = 0; i < count; i += num) { num = fs.Read(array, offset + i, count - i); if (num == 0) { return i; } } return i; } } public class RentedFileArray : IDisposable { private static ArrayPool _pool = ArrayPool.Shared; private int _length; private ArrayPool _owner; private byte[] _buffer; private bool _isDisposed; public static ArrayPool Pool { get { return _pool; } [param: AllowNull] set { _pool = value ?? ArrayPool.Shared; } } public MemoryStream Stream { get; private init; } public RentedFileArray(string filepath) { _length = (int)new FileInfo(filepath).Length; _owner = Pool; _buffer = Pool.Rent(_length); try { using FileStream fs = File.OpenRead(filepath); fs.ReadExact(_buffer, 0, _length); } catch { _owner.Return(_buffer); throw; } Stream = new MemoryStream(_buffer, 0, _length); } protected virtual void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { Stream.Dispose(); _owner.Return(_buffer); _owner = null; _buffer = null; } _isDisposed = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } } namespace AssetHelperLib.Extensions { internal static class CollectionExtensions { public static void AddEntry(this Dictionary> self, TKey key, TValue value) { if (self.TryGetValue(key, out List value2)) { value2.Add(value); return; } self[key] = new List(1) { value }; } } } namespace AssetHelperLib.BundleTools { public class AssetDependencies { public class Config { public bool FollowTransformParent { get; set; } } public record PPtrData(int FileId, long PathId, string TypeName); public record ChildPPtrs(HashSet InternalPaths, HashSet ExternalPaths) { public static ChildPPtrs CreateNew() { return new ChildPPtrs(new HashSet(), new HashSet()); } 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 _immediateDeps; private readonly Dictionary _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(); _bundleDeps = new Dictionary(); 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"); foreach (AssetTypeValueField child in baseField["m_Children.Array"].Children) { childPPtrs.Add(child, "PPtr"); } 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 hashSet = new HashSet(new <>z__ReadOnlySingleElementList(assetPathId)); HashSet hashSet2 = new HashSet(); Queue queue = new Queue(); 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 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.Enumerator <>7__wrap1; (string, int) IEnumerator<(string, int)>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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.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.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() { d__16 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__16(0); } d__.mgr = <>3__mgr; d__.afi = <>3__afi; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<(string, int)>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__5 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private AssetFileInfo <>2__current; private int <>l__initialThreadId; private AssetsFile afile; public AssetsFile <>3__afile; private List.Enumerator <>7__wrap1; private List.Enumerator <>7__wrap2; AssetFileInfo IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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.Enumerator); <>7__wrap2 = default(List.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.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.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 IEnumerable.GetEnumerator() { d__5 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__5(0); } d__.afile = <>3__afile; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__6 : IEnumerable, IEnumerable, IEnumerator, 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 <>7__wrap1; AssetData IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 IEnumerable.GetEnumerator() { d__6 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__6(0); } d__.mgr = <>3__mgr; d__.afileInst = <>3__afileInst; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static List TransformClassIds { get; } = new List(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(d__5))] public static IEnumerable GetAllTransforms(this AssetsFile afile) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__5(-2) { <>3__afile = afile }; } [IteratorStateMachine(typeof(d__6))] public static IEnumerable GetRootTransforms(this AssetsManager mgr, AssetsFileInstance afileInst) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__6(-2) { <>3__mgr = mgr, <>3__afileInst = afileInst }; } public static Dictionary FindRootGameObjects(this AssetsManager mgr, AssetsFileInstance afileInst, List objectNames, out List missingObjects) { Dictionary gameObjects = new Dictionary(); 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 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(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 d__16(-2) { <>3__mgr = mgr, <>3__afi = afi }; } } public class GameObjectLookup : IEnumerable, IEnumerable { public record GameObjectInfo(long GameObjectPathId, long TransformPathId, string GameObjectName, long ParentPathId); private readonly Dictionary> _fromName; private readonly Dictionary _fromGameObject; private readonly Dictionary _fromTransform; private GameObjectLookup(Dictionary> fromName, Dictionary fromGameObject, Dictionary fromTransform) { _fromName = fromName; _fromGameObject = fromGameObject; _fromTransform = fromTransform; } public static GameObjectLookup CreateFromInfos(IEnumerable infos) { Dictionary> dictionary = new Dictionary>(); Dictionary dictionary2 = new Dictionary(); Dictionary dictionary3 = new Dictionary(); foreach (GameObjectInfo info in infos) { dictionary.AddEntry(info.GameObjectName, info); dictionary2[info.GameObjectPathId] = info; dictionary3[info.TransformPathId] = info; } return new GameObjectLookup(dictionary, dictionary2, dictionary3); } public static GameObjectLookup CreateFromFile(AssetsManager mgr, AssetsFileInstance afileInst) { Dictionary go2name = new Dictionary(); Dictionary tf2parent = new Dictionary(); Dictionary tf2go = new Dictionary(); 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 fromTransformLookup = new Dictionary(); foreach (long key in tf2parent.Keys) { DoAdd(key); } return CreateFromInfos(fromTransformLookup.Values); GameObjectInfo DoAdd(long tPathId) { if (fromTransformLookup.TryGetValue(tPathId, out GameObjectInfo value)) { return value; } long num = tf2parent[tPathId]; long num2 = tf2go[tPathId]; string text = go2name[num2]; if (num == 0L) { GameObjectInfo gameObjectInfo = new GameObjectInfo(num2, tPathId, text, 0L); fromTransformLookup[tPathId] = gameObjectInfo; return gameObjectInfo; } string gameObjectName = DoAdd(num).GameObjectName; GameObjectInfo gameObjectInfo2 = new GameObjectInfo(num2, tPathId, gameObjectName + "/" + text, num); fromTransformLookup[tPathId] = gameObjectInfo2; return gameObjectInfo2; } } private bool TryGet(TKey key, Dictionary lookupDict, [MaybeNullWhen(false)] out TValue info) { return lookupDict.TryGetValue(key, out info); } public GameObjectInfo LookupTransform(long pathId) { if (!TryGet(pathId, _fromTransform, out var info)) { throw new KeyNotFoundException($"Did not find transform key {pathId}"); } return info; } public GameObjectInfo LookupGameObject(long pathId) { if (!TryGet(pathId, _fromGameObject, out var info)) { throw new KeyNotFoundException($"Did not find game object key {pathId}"); } return info; } public List LookupName(string name) { if (!TryGet>(name, _fromName, out var info)) { throw new KeyNotFoundException("Did not find name " + name); } return info; } public bool TryLookupTransfrom(long pathId, [MaybeNullWhen(false)] out GameObjectInfo info) { return TryGet(pathId, _fromTransform, out info); } public bool TryLookupGameObject(long pathId, [MaybeNullWhen(false)] out GameObjectInfo info) { return TryGet(pathId, _fromGameObject, out info); } public bool TryLookupName(string name, [MaybeNullWhen(false)] out List info) { return TryGet(name, _fromName, out info); } public IEnumerator GetEnumerator() { return _fromGameObject.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public static class GameObjectLookupExtensions { [CompilerGenerated] private sealed class <>c__DisplayClass0_0 { public Dictionary> children; } public static IEnumerable TraverseOrdered(this GameObjectLookup self) { <>c__DisplayClass0_0 CS$<>8__locals0 = new <>c__DisplayClass0_0(); CS$<>8__locals0.children = new Dictionary>(); foreach (GameObjectLookup.GameObjectInfo item in self) { if (!CS$<>8__locals0.children.TryGetValue(item.ParentPathId, out List value)) { value = new List(); CS$<>8__locals0.children[item.ParentPathId] = value; } value.Add(item); } return InnerTraverse(0L); [IteratorStateMachine(typeof(<>c__DisplayClass0_0.<g__InnerTraverse|0>d))] IEnumerable InnerTraverse(long pathId) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass0_0.<g__InnerTraverse|0>d(-2) { <>4__this = CS$<>8__locals0, <>3__pathId = pathId }; } } } }