using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis; using UnityEngine; using XUnity.Common.Constants; using XUnity.Common.Extensions; using XUnity.Common.Harmony; using XUnity.Common.Logging; using XUnity.Common.MonoMod; using XUnity.Common.Utilities; using XUnity.ResourceRedirector.Constants; using XUnity.ResourceRedirector.Hooks; using XUnity.ResourceRedirector.Properties; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("gravydevsupreme")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2018 / MIT License")] [assembly: AssemblyDescription("Main development dependency for XUnity Resource Redirector.")] [assembly: AssemblyFileVersion("2.1.0.0")] [assembly: AssemblyInformationalVersion("2.1.0+7f1f3b9e8fc7d93a97734773804ba9c8fdf57714")] [assembly: AssemblyProduct("XUnity.ResourceRedirector")] [assembly: AssemblyTitle("XUnity.ResourceRedirector")] [assembly: AssemblyVersion("2.1.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace XUnity.ResourceRedirector { internal class AssetBundleExtensionData { private string _normalizedPath; private string _path; public string NormalizedPath { get { if (Path != null && _normalizedPath == null) { _normalizedPath = StringExtensions.MakeRelativePath(Path.ToLowerInvariant(), EnvironmentEx.LoweredCurrentDirectory); } return _normalizedPath; } } public string Path { get { return _path; } set { if (_path != value) { _path = value; _normalizedPath = null; } } } } public static class AssetBundleHelper { internal static string PathForLoadedInMemoryBundle; public static AssetBundle CreateEmptyAssetBundle() { byte[] empty = Resources.empty; CabHelper.RandomizeCab(empty); return AssetBundle.LoadFromMemory(empty); } public static AssetBundleCreateRequest CreateEmptyAssetBundleRequest() { byte[] empty = Resources.empty; CabHelper.RandomizeCab(empty); return AssetBundle.LoadFromMemoryAsync(empty); } public static AssetBundle LoadFromMemory(string path, byte[] binary, uint crc) { try { PathForLoadedInMemoryBundle = path; return AssetBundle.LoadFromMemory(binary, crc); } finally { PathForLoadedInMemoryBundle = null; } } public static AssetBundleCreateRequest LoadFromMemoryAsync(string path, byte[] binary, uint crc) { try { PathForLoadedInMemoryBundle = path; return AssetBundle.LoadFromMemoryAsync(binary, crc); } finally { PathForLoadedInMemoryBundle = null; } } public static AssetBundle LoadFromFileWithRandomizedCabIfRequired(string path, uint crc, ulong offset) { return LoadFromFileWithRandomizedCabIfRequired(path, crc, offset, confirmFileExists: true); } internal static AssetBundle LoadFromFileWithRandomizedCabIfRequired(string path, uint crc, ulong offset, bool confirmFileExists) { AssetBundle val = AssetBundle.LoadFromFile(path, crc, offset); if ((Object)(object)val == (Object)null && (!confirmFileExists || File.Exists(path))) { byte[] array; using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) { long num = fileStream.Length - (long)offset; fileStream.Seek((long)offset, SeekOrigin.Begin); array = StreamExtensions.ReadFully((Stream)fileStream, (int)num); } CabHelper.RandomizeCabWithAnyLength(array); XuaLogger.ResourceRedirector.Warn("Randomized CAB for '" + path + "' in order to load it because another asset bundle already uses its CAB-string. You can ignore the previous error message, but this is likely caused by two mods incorrectly using the same CAB-string."); return AssetBundle.LoadFromMemory(array); } return val; } } public class AssetBundleLoadedContext { private string _normalizedPath; public AssetBundleLoadingParameters Parameters { get; } public AssetBundle Bundle { get; set; } internal bool SkipRemainingPostfixes { get; private set; } internal AssetBundleLoadedContext(AssetBundleLoadingParameters parameters, AssetBundle bundle) { Parameters = parameters; Bundle = bundle; } public string GetNormalizedPath() { if (_normalizedPath == null && Parameters.Path != null) { _normalizedPath = StringExtensions.MakeRelativePath(StringExtensions.UseCorrectDirectorySeparators(Parameters.Path.ToLowerInvariant()), EnvironmentEx.LoweredCurrentDirectory); } return _normalizedPath; } public void Complete(bool skipRemainingPostfixes = true) { SkipRemainingPostfixes = skipRemainingPostfixes; } public void DisableRecursion() { ResourceRedirection.RecursionEnabled = false; } } public class AssetBundleLoadingContext : IAssetBundleLoadingContext { private string _normalizedPath; public AssetBundleLoadingParameters Parameters { get; } public AssetBundle Bundle { get; set; } internal bool SkipRemainingPrefixes { get; private set; } internal bool SkipOriginalCall { get; private set; } internal bool SkipAllPostfixes { get; private set; } internal AssetBundleLoadingContext(AssetBundleLoadingParameters parameters) { Parameters = parameters; } public string GetNormalizedPath() { if (_normalizedPath == null && Parameters.Path != null) { _normalizedPath = StringExtensions.MakeRelativePath(StringExtensions.UseCorrectDirectorySeparators(Parameters.Path.ToLowerInvariant()), EnvironmentEx.LoweredCurrentDirectory); } return _normalizedPath; } public void Complete() { Complete(skipRemainingPrefixes: true, true, true); } public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true) { Complete(skipRemainingPrefixes, skipOriginalCall, true); } public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true) { SkipRemainingPrefixes = skipRemainingPrefixes; if (skipOriginalCall.HasValue) { SkipOriginalCall = skipOriginalCall.Value; } if (skipAllPostfixes.HasValue) { SkipAllPostfixes = skipAllPostfixes.Value; } } public void DisableRecursion() { ResourceRedirection.RecursionEnabled = false; } } public class AssetBundleLoadingParameters { public string Path { get; set; } public uint Crc { get; set; } public ulong Offset { get; set; } public Stream Stream { get; set; } public uint ManagedReadBufferSize { get; } public byte[] Binary { get; set; } public AssetBundleLoadType LoadType { get; } internal AssetBundleLoadingParameters(byte[] data, string path, uint crc, ulong offset, Stream stream, uint managedReadBufferSize, AssetBundleLoadType loadType) { Binary = data; Path = path; Crc = crc; Offset = offset; Stream = stream; ManagedReadBufferSize = managedReadBufferSize; LoadType = loadType; } } public enum AssetBundleLoadType { LoadFromFile = 1, LoadFromMemory, LoadFromStream } public class AssetLoadedContext : IAssetOrResourceLoadedContext { private AssetBundleExtensionData _ext; private bool _lookedForExt; private BackingFieldOrArray _backingField; public AssetLoadedParameters Parameters { get; } public AssetBundle Bundle { get; } public Object[] Assets { get { return _backingField.Array; } set { _backingField.Array = value; } } public Object Asset { get { return _backingField.Field; } set { _backingField.Field = value; } } internal bool SkipRemainingPostfixes { get; private set; } internal AssetLoadedContext(AssetLoadedParameters parameters, AssetBundle bundle, Object[] assets) { Parameters = parameters; Bundle = bundle; _backingField = new BackingFieldOrArray(assets); } internal AssetLoadedContext(AssetLoadedParameters parameters, AssetBundle bundle, Object asset) { Parameters = parameters; Bundle = bundle; _backingField = new BackingFieldOrArray(asset); } public bool HasReferenceBeenRedirectedBefore(Object asset) { return ExtensionDataHelper.GetExtensionData((object)asset)?.HasBeenRedirected ?? false; } public string GetUniqueFileSystemAssetPath(Object asset) { ResourceExtensionData orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData((object)asset); if (orCreateExtensionData.FullFileSystemAssetPath == null) { string text = ExtensionDataHelper.GetExtensionData((object)Bundle)?.NormalizedPath; string path = (string.IsNullOrEmpty(text) ? "unnamed_assetbundle" : text.ToLowerInvariant()); string name = asset.name; if (!string.IsNullOrEmpty(name)) { path = Path.Combine(path, name.ToLowerInvariant()); } else { string text2 = null; if (Assets.Length > 1) { int num = Array.IndexOf(Assets, asset); text2 = ((num != -1) ? ("_" + num.ToString(CultureInfo.InvariantCulture)) : "_with_unknown_index"); } path = Path.Combine(path, (Parameters.LoadType == AssetLoadType.LoadMainAsset) ? "main_asset" : ("unnamed_asset" + text2)); } path = StringExtensions.UseCorrectDirectorySeparators(path); orCreateExtensionData.FullFileSystemAssetPath = path; } return orCreateExtensionData.FullFileSystemAssetPath; } public string GetAssetBundlePath() { if (!_lookedForExt) { _lookedForExt = true; _ext = ExtensionDataHelper.GetExtensionData((object)Bundle); } return _ext?.Path; } public string GetNormalizedAssetBundlePath() { if (!_lookedForExt) { _lookedForExt = true; _ext = ExtensionDataHelper.GetExtensionData((object)Bundle); } return _ext?.NormalizedPath; } public void Complete(bool skipRemainingPostfixes = true) { SkipRemainingPostfixes = skipRemainingPostfixes; } public void DisableRecursion() { ResourceRedirection.RecursionEnabled = false; } } public class AssetLoadedParameters { public string Name { get; } public Type Type { get; } public AssetLoadType LoadType { get; } internal AssetLoadedParameters(string name, Type type, AssetLoadType loadType) { Name = name; Type = type; LoadType = loadType; } } public class AssetLoadingContext : IAssetLoadingContext { private AssetBundleExtensionData _ext; private bool _lookedForExt; private BackingFieldOrArray _backingField; public AssetLoadingParameters Parameters { get; } public AssetBundle Bundle { get; } public Object[] Assets { get { return _backingField.Array; } set { _backingField.Array = value; } } public Object Asset { get { return _backingField.Field; } set { _backingField.Field = value; } } internal bool SkipRemainingPrefixes { get; private set; } internal bool SkipOriginalCall { get; private set; } internal bool SkipAllPostfixes { get; private set; } internal AssetLoadingContext(AssetLoadingParameters parameters, AssetBundle bundle) { Parameters = parameters; Bundle = bundle; } public string GetAssetBundlePath() { if (!_lookedForExt) { _lookedForExt = true; _ext = ExtensionDataHelper.GetExtensionData((object)Bundle); } return _ext?.Path; } public string GetNormalizedAssetBundlePath() { if (!_lookedForExt) { _lookedForExt = true; _ext = ExtensionDataHelper.GetExtensionData((object)Bundle); } return _ext?.NormalizedPath; } public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true) { SkipRemainingPrefixes = skipRemainingPrefixes; if (skipOriginalCall.HasValue) { SkipOriginalCall = skipOriginalCall.Value; } if (skipAllPostfixes.HasValue) { SkipAllPostfixes = skipAllPostfixes.Value; } } public void DisableRecursion() { ResourceRedirection.RecursionEnabled = false; } } public class AssetLoadingParameters { public string Name { get; set; } public Type Type { get; set; } public AssetLoadType LoadType { get; } internal AssetLoadingParameters(string name, Type type, AssetLoadType loadType) { Name = name; Type = type; LoadType = loadType; } internal AssetLoadedParameters ToAssetLoadedParameters() { return new AssetLoadedParameters(Name, Type, LoadType); } } public enum AssetLoadType { LoadMainAsset = 1, LoadByType, LoadNamed, LoadNamedWithSubAssets } internal class AsyncAssetBundleLoadInfo { public AssetBundleLoadingParameters Parameters { get; } public AssetBundle Bundle { get; } public bool SkipAllPostfixes { get; } public AsyncAssetBundleLoadingResolve ResolveType { get; } public AsyncAssetBundleLoadInfo(AssetBundleLoadingParameters parameters, AssetBundle bundle, bool skipAllPostfixes, AsyncAssetBundleLoadingResolve resolveType) { Parameters = parameters; Bundle = bundle; SkipAllPostfixes = skipAllPostfixes; ResolveType = resolveType; } } public class AsyncAssetBundleLoadingContext : IAssetBundleLoadingContext { private string _normalizedPath; private AssetBundle _bundle; private AssetBundleCreateRequest _request; public AssetBundleLoadingParameters Parameters { get; } public AssetBundleCreateRequest Request { get { return _request; } set { _request = value; ResolveType = AsyncAssetBundleLoadingResolve.ThroughRequest; } } public AssetBundle Bundle { get { return _bundle; } set { if (!ResourceRedirection.SyncOverAsyncEnabled) { throw new InvalidOperationException("Trying to set the Bundle property in async load operation while 'SyncOverAsyncAssetLoads' is disabled is not allowed. Consider settting the Request property instead if possible or enabling 'SyncOverAsyncAssetLoads' through the method 'ResourceRedirection.EnableSyncOverAsyncAssetLoads()'."); } _bundle = value; ResolveType = AsyncAssetBundleLoadingResolve.ThroughBundle; } } public AsyncAssetBundleLoadingResolve ResolveType { get; set; } internal bool SkipRemainingPrefixes { get; private set; } internal bool SkipOriginalCall { get; set; } internal bool SkipAllPostfixes { get; private set; } internal AsyncAssetBundleLoadingContext(AssetBundleLoadingParameters parameters) { Parameters = parameters; } public string GetNormalizedPath() { if (_normalizedPath == null && Parameters.Path != null) { _normalizedPath = StringExtensions.MakeRelativePath(StringExtensions.UseCorrectDirectorySeparators(Parameters.Path.ToLowerInvariant()), EnvironmentEx.LoweredCurrentDirectory); } return _normalizedPath; } public void Complete() { Complete(skipRemainingPrefixes: true, true, true); } public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true) { Complete(skipRemainingPrefixes, skipOriginalCall, true); } public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true) { SkipRemainingPrefixes = skipRemainingPrefixes; if (skipOriginalCall.HasValue) { SkipOriginalCall = skipOriginalCall.Value; } if (skipAllPostfixes.HasValue) { SkipAllPostfixes = skipAllPostfixes.Value; } } public void DisableRecursion() { ResourceRedirection.RecursionEnabled = false; } } public enum AsyncAssetBundleLoadingResolve { ThroughRequest, ThroughBundle } internal class AsyncAssetLoadInfo { public AssetLoadingParameters Parameters { get; } public AssetBundle Bundle { get; } public bool SkipAllPostfixes { get; } public AsyncAssetLoadingResolve ResolveType { get; } public Object[] Assets { get; } public AsyncAssetLoadInfo(AssetLoadingParameters parameters, AssetBundle bundle, bool skipAllPostfixes, AsyncAssetLoadingResolve resolveType, Object[] assets) { Parameters = parameters; Bundle = bundle; SkipAllPostfixes = skipAllPostfixes; ResolveType = resolveType; Assets = assets; } } public class AsyncAssetLoadingContext : IAssetLoadingContext { private AssetBundleExtensionData _ext; private bool _lookedForExt; private Object[] _assets; private AssetBundleRequest _request; private BackingFieldOrArray _backingField; public AssetLoadingParameters Parameters { get; } public AssetBundle Bundle { get; } public AssetBundleRequest Request { get { return _request; } set { _request = value; ResolveType = AsyncAssetLoadingResolve.ThroughRequest; } } public Object[] Assets { get { return _backingField.Array; } set { if (!ResourceRedirection.SyncOverAsyncEnabled) { throw new InvalidOperationException("Trying to set the Assets/Asset property in async load operation while 'SyncOverAsyncAssetLoads' is disabled is not allowed. Consider settting the Request property instead if possible or enabling 'SyncOverAsyncAssetLoads' through the method 'ResourceRedirection.EnableSyncOverAsyncAssetLoads()'."); } _backingField.Array = value; ResolveType = AsyncAssetLoadingResolve.ThroughAssets; } } public Object Asset { get { return _backingField.Field; } set { if (!ResourceRedirection.SyncOverAsyncEnabled) { throw new InvalidOperationException("Trying to set the Assets/Asset property in async load operation while 'SyncOverAsyncAssetLoads' is disabled is not allowed. Consider settting the Request property instead if possible or enabling 'SyncOverAsyncAssetLoads' through the method 'ResourceRedirection.EnableSyncOverAsyncAssetLoads()'."); } _backingField.Field = value; ResolveType = AsyncAssetLoadingResolve.ThroughAssets; } } public AsyncAssetLoadingResolve ResolveType { get; set; } internal bool SkipRemainingPrefixes { get; private set; } internal bool SkipOriginalCall { get; set; } internal bool SkipAllPostfixes { get; private set; } internal AsyncAssetLoadingContext(AssetLoadingParameters parameters, AssetBundle bundle) { Parameters = parameters; Bundle = bundle; } public string GetAssetBundlePath() { if (!_lookedForExt) { _lookedForExt = true; _ext = ExtensionDataHelper.GetExtensionData((object)Bundle); } return _ext?.Path; } public string GetNormalizedAssetBundlePath() { if (!_lookedForExt) { _lookedForExt = true; _ext = ExtensionDataHelper.GetExtensionData((object)Bundle); } return _ext?.NormalizedPath; } public void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true) { SkipRemainingPrefixes = skipRemainingPrefixes; if (skipOriginalCall.HasValue) { SkipOriginalCall = skipOriginalCall.Value; } if (skipAllPostfixes.HasValue) { SkipAllPostfixes = skipAllPostfixes.Value; } } public void DisableRecursion() { ResourceRedirection.RecursionEnabled = false; } } public enum AsyncAssetLoadingResolve { ThroughRequest, ThroughAssets } internal struct BackingFieldOrArray { [CompilerGenerated] private sealed class d__11 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private Object <>2__current; private int <>l__initialThreadId; public BackingFieldOrArray <>4__this; public BackingFieldOrArray <>3__<>4__this; private Object[] <>7__wrap1; private int <>7__wrap2; Object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__11(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (<>4__this._array != null) { <>7__wrap1 = <>4__this._array; <>7__wrap2 = 0; goto IL_007c; } if (<>4__this._field != (Object)null) { <>2__current = <>4__this._field; <>1__state = 2; return true; } break; case 1: <>1__state = -1; <>7__wrap2++; goto IL_007c; case 2: { <>1__state = -1; break; } IL_007c: if (<>7__wrap2 < <>7__wrap1.Length) { Object val = <>7__wrap1[<>7__wrap2]; <>2__current = val; <>1__state = 1; return true; } <>7__wrap1 = null; break; } 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(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__11 d__; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__11(0); } d__.<>4__this = <>3__<>4__this; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private Object _field; private Object[] _array; private BackingSource _source; public Object Field { get { if (_source == BackingSource.None) { return null; } if (_source == BackingSource.SingleField) { return _field; } if (_array == null || _array.Length == 0) { return null; } return _array[0]; } set { _field = value; _array = null; _source = BackingSource.SingleField; } } public Object[] Array { get { if (_source == BackingSource.Array) { return _array; } if (_field == (Object)null) { Array = (Object[])(object)new Object[0]; } else { Array = (Object[])(object)new Object[1] { _field }; } return _array; } set { _field = null; _array = value; _source = BackingSource.Array; } } public BackingFieldOrArray(Object field) { _field = field; _array = null; _source = BackingSource.SingleField; } public BackingFieldOrArray(Object[] array) { _field = null; _array = array; _source = BackingSource.Array; } public IEnumerable IterateObjects() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__11(-2) { <>3__<>4__this = this }; } } internal enum BackingSource : byte { None, SingleField, Array } public static class CallbackPriority { public const int Default = 0; } public enum HookBehaviour { OneCallbackPerLoadCall = 1, OneCallbackPerResourceLoaded } public interface IAssetBundleLoadingContext { AssetBundleLoadingParameters Parameters { get; } AssetBundle Bundle { get; set; } string GetNormalizedPath(); void Complete(); void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true); void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true); void DisableRecursion(); } public interface IAssetLoadingContext { AssetLoadingParameters Parameters { get; } AssetBundle Bundle { get; } Object[] Assets { get; set; } Object Asset { get; set; } string GetAssetBundlePath(); string GetNormalizedAssetBundlePath(); void Complete(bool skipRemainingPrefixes = true, bool? skipOriginalCall = true, bool? skipAllPostfixes = true); void DisableRecursion(); } public interface IAssetOrResourceLoadedContext { Object[] Assets { get; set; } Object Asset { get; set; } bool HasReferenceBeenRedirectedBefore(Object asset); string GetUniqueFileSystemAssetPath(Object asset); void Complete(bool skipRemainingPostfixes = true); void DisableRecursion(); } internal class PrioritizedCallback { public static PrioritizedCallback Create(TCallback item, int priority) where TCallback : Delegate { return new PrioritizedCallback(item, priority); } } internal class PrioritizedCallback : PrioritizedCallback, IComparable>, IEquatable> where TCallback : Delegate { public TCallback Callback { get; } public int Priority { get; } public Type TargetType { get; set; } public bool IsBeingCalled { get; set; } public PrioritizedCallback(TCallback callback, int priority) { Callback = callback; Priority = priority; TargetType = callback.Target?.GetType(); } public int CompareTo(PrioritizedCallback other) { return other.Priority.CompareTo(Priority); } public override bool Equals(object obj) { return Equals(obj as PrioritizedCallback); } public bool Equals(PrioritizedCallback other) { return EqualityComparer.Default.Equals(Callback, other.Callback); } public override int GetHashCode() { return -1406788065 * -1521134295 + EqualityComparer.Default.GetHashCode(Callback); } public override string ToString() { return "[" + Priority + "] " + (TargetType?.Name ?? Callback.Method.DeclaringType?.Name) + "." + Callback.Method?.Name; } } internal class ResourceExtensionData { public bool HasBeenRedirected { get; set; } public string FullFileSystemAssetPath { get; set; } } public class ResourceLoadedContext : IAssetOrResourceLoadedContext { private BackingFieldOrArray _backingField; public ResourceLoadedParameters Parameters { get; } public Object[] Assets { get { return _backingField.Array; } set { _backingField.Array = value; } } public Object Asset { get { return _backingField.Field; } set { _backingField.Field = value; } } internal bool SkipRemainingPostfixes { get; set; } internal ResourceLoadedContext(ResourceLoadedParameters parameters, Object[] assets) { Parameters = parameters; _backingField = new BackingFieldOrArray(assets); } internal ResourceLoadedContext(ResourceLoadedParameters parameters, Object asset) { Parameters = parameters; _backingField = new BackingFieldOrArray(asset); } public bool HasReferenceBeenRedirectedBefore(Object asset) { return ExtensionDataHelper.GetExtensionData((object)asset)?.HasBeenRedirected ?? false; } public string GetUniqueFileSystemAssetPath(Object asset) { ResourceExtensionData orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData((object)asset); if (orCreateExtensionData.FullFileSystemAssetPath == null) { string text = string.Empty; if (!string.IsNullOrEmpty(Parameters.Path)) { text = Parameters.Path.ToLowerInvariant(); } if (Parameters.LoadType == ResourceLoadType.LoadByType) { string name = asset.name; if (!string.IsNullOrEmpty(name)) { text = Path.Combine(text, name.ToLowerInvariant()); } else { string text2 = null; if (Assets.Length > 1) { int num = Array.IndexOf(Assets, asset); text2 = ((num != -1) ? ("_" + num.ToString(CultureInfo.InvariantCulture)) : "_with_unknown_index"); } text = Path.Combine(text, "unnamed_asset" + text2); } } text = StringExtensions.UseCorrectDirectorySeparators(text); orCreateExtensionData.FullFileSystemAssetPath = text; } return orCreateExtensionData.FullFileSystemAssetPath; } public void Complete(bool skipRemainingPostfixes = true) { SkipRemainingPostfixes = skipRemainingPostfixes; } public void DisableRecursion() { ResourceRedirection.RecursionEnabled = false; } } public class ResourceLoadedParameters { public string Path { get; set; } public Type Type { get; set; } public ResourceLoadType LoadType { get; } internal ResourceLoadedParameters(string path, Type type, ResourceLoadType loadType) { Path = path; Type = type; LoadType = loadType; } } public enum ResourceLoadType { LoadByType = 1, LoadNamed, LoadNamedBuiltIn } public static class ResourceRedirection { private static readonly List>> PostfixRedirectionsForAssetsPerCall = new List>>(); private static readonly List>> PostfixRedirectionsForAssetsPerResource = new List>>(); private static readonly List>> PostfixRedirectionsForResourcesPerCall = new List>>(); private static readonly List>> PostfixRedirectionsForResourcesPerResource = new List>>(); private static readonly List> PrefixRedirectionsForAssetsPerCall = new List>(); private static readonly List> PrefixRedirectionsForAsyncAssetsPerCall = new List>(); private static readonly List> PrefixRedirectionsForAssetBundles = new List>(); private static readonly List> PrefixRedirectionsForAsyncAssetBundles = new List>(); private static readonly List>> PostfixRedirectionsForAssetBundles = new List>>(); private static Action _emulateAssetBundles; private static Action _emulateAssetBundlesAsync; private static Action _redirectionMissingAssetBundlesToEmpty; private static Action _redirectionMissingAssetBundlesToEmptyAsync; private static bool _enabledRandomizeCabIfConflict = false; private static Action _enableCabRandomizationPrefix; private static Action _enableCabRandomizationPrefixAsync; private static Action _enableCabRandomizationPostfix; private static bool _initialized = false; private static bool _initializedSyncOverAsyncEnabled = false; private static bool _logAllLoadedResources = false; private static bool _isFiringAssetBundle; private static bool _isFiringResource; private static bool _isFiringAsset; private static bool _isRecursionDisabledPermanently; internal static bool RecursionEnabled = true; internal static bool SyncOverAsyncEnabled = false; public static bool LogAllLoadedResources { get { return _logAllLoadedResources; } set { if (value) { Initialize(); } _logAllLoadedResources = value; } } public static bool LogCallbackOrder { get; set; } public static void Initialize() { if (!_initialized) { _initialized = true; HookingHelper.PatchAll((IEnumerable)ResourceAndAssetHooks.GeneralHooks, false); } } public static void EnableSyncOverAsyncAssetLoads() { Initialize(); if (!_initializedSyncOverAsyncEnabled) { _initializedSyncOverAsyncEnabled = true; SyncOverAsyncEnabled = true; HookingHelper.PatchAll((IEnumerable)ResourceAndAssetHooks.SyncOverAsyncHooks, false); } } public static void DisableRecursionPermanently() { _isRecursionDisabledPermanently = true; } public static void EnableEmulateAssetBundles(int priority, string emulationDirectory) { if (_emulateAssetBundles == null && _emulateAssetBundlesAsync == null) { _emulateAssetBundles = delegate(AssetBundleLoadingContext ctx) { HandleAssetBundleEmulation(ctx, SetBundle); }; _emulateAssetBundlesAsync = delegate(AsyncAssetBundleLoadingContext ctx) { HandleAssetBundleEmulation(ctx, SetRequest); }; RegisterAssetBundleLoadingHook(priority, _emulateAssetBundles); RegisterAsyncAssetBundleLoadingHook(priority, _emulateAssetBundlesAsync); } void HandleAssetBundleEmulation(T context, Action changeBundle) where T : IAssetBundleLoadingContext { if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromFile) { string normalizedPath = context.GetNormalizedPath(); string text = Path.Combine(emulationDirectory, normalizedPath); if (File.Exists(text)) { changeBundle(context, text); ref T reference = ref context; T val = default(T); if (val == null) { val = reference; reference = ref val; } reference.Complete(skipRemainingPrefixes: true, true); XuaLogger.ResourceRedirector.Debug("Redirected asset bundle: '" + context.Parameters.Path + "' => '" + text + "'"); } } } static void SetBundle(AssetBundleLoadingContext context, string path) { context.Bundle = AssetBundle.LoadFromFile(path, context.Parameters.Crc, context.Parameters.Offset); } static void SetRequest(AsyncAssetBundleLoadingContext context, string path) { context.Request = AssetBundle.LoadFromFileAsync(path, context.Parameters.Crc, context.Parameters.Offset); } } public static void DisableEmulateAssetBundles() { if (_emulateAssetBundles != null && _emulateAssetBundlesAsync != null) { UnregisterAssetBundleLoadingHook(_emulateAssetBundles); UnregisterAsyncAssetBundleLoadingHook(_emulateAssetBundlesAsync); _emulateAssetBundles = null; _emulateAssetBundlesAsync = null; } } public static void EnableRedirectMissingAssetBundlesToEmptyAssetBundle(int priority) { if (_redirectionMissingAssetBundlesToEmpty == null && _redirectionMissingAssetBundlesToEmptyAsync == null) { _redirectionMissingAssetBundlesToEmpty = delegate(AssetBundleLoadingContext ctx) { HandleMissingBundle(ctx, SetBundle); }; _redirectionMissingAssetBundlesToEmptyAsync = delegate(AsyncAssetBundleLoadingContext ctx) { HandleMissingBundle(ctx, SetRequest); }; RegisterAssetBundleLoadingHook(priority, _redirectionMissingAssetBundlesToEmpty); RegisterAsyncAssetBundleLoadingHook(priority, _redirectionMissingAssetBundlesToEmptyAsync); } static void HandleMissingBundle(TContext context, Action changeBundle) where TContext : IAssetBundleLoadingContext { if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromFile && !File.Exists(context.Parameters.Path)) { byte[] empty = Resources.empty; CabHelper.RandomizeCab(empty); changeBundle(context, empty); ref TContext reference = ref context; TContext val = default(TContext); if (val == null) { val = reference; reference = ref val; } reference.Complete(skipRemainingPrefixes: true, true); XuaLogger.ResourceRedirector.Warn("Tried to load non-existing asset bundle: " + context.Parameters.Path); } } static void SetBundle(AssetBundleLoadingContext context, byte[] assetBundleData) { AssetBundle bundle = AssetBundle.LoadFromMemory(assetBundleData); context.Bundle = bundle; } static void SetRequest(AsyncAssetBundleLoadingContext context, byte[] assetBundleData) { AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(assetBundleData); context.Request = request; } } public static void EnableRandomizeCabIfConflict(int priority, bool forceRandomizeWhenInMemory) { if (_enabledRandomizeCabIfConflict) { return; } _enabledRandomizeCabIfConflict = true; if (forceRandomizeWhenInMemory) { _enableCabRandomizationPrefix = delegate(AssetBundleLoadingContext ctx) { HandleCabRandomizePrefix(ctx); }; _enableCabRandomizationPrefixAsync = delegate(AsyncAssetBundleLoadingContext ctx) { HandleCabRandomizePrefix(ctx); }; RegisterAssetBundleLoadingHook(priority, _enableCabRandomizationPrefix); RegisterAsyncAssetBundleLoadingHook(priority, _enableCabRandomizationPrefixAsync); } _enableCabRandomizationPostfix = delegate(AssetBundleLoadedContext ctx) { HandleCabRandomizePostfix(ctx); }; RegisterAssetBundleLoadedHook(priority, _enableCabRandomizationPostfix); void HandleCabRandomizePostfix(AssetBundleLoadedContext context) { if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromFile) { if ((Object)(object)context.Bundle == (Object)null && File.Exists(context.Parameters.Path)) { XuaLogger.ResourceRedirector.Warn("The asset bundle '" + context.Parameters.Path + "' could not be loaded likely due to conflicting CAB-string. Retrying in-memory with randomized CAB-string."); byte[] array; using (FileStream fileStream = new FileStream(context.Parameters.Path, FileMode.Open, FileAccess.Read)) { long length = fileStream.Length; long offset = (long)context.Parameters.Offset; long num = length - offset; fileStream.Seek(offset, SeekOrigin.Begin); array = StreamExtensions.ReadFully((Stream)fileStream, (int)num); } if (!forceRandomizeWhenInMemory) { CabHelper.RandomizeCabWithAnyLength(array); } AssetBundle val = AssetBundle.LoadFromMemory(array, 0u); if ((Object)(object)val != (Object)null) { context.Bundle = val; context.Complete(); } } } else if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromMemory) { if ((Object)(object)context.Bundle == (Object)null && !forceRandomizeWhenInMemory) { string text = AssetBundleHelper.PathForLoadedInMemoryBundle ?? "Unnamed"; XuaLogger.ResourceRedirector.Warn("Could not load an in-memory asset bundle (" + text + ") likely due to conflicting CAB-string. Retrying with randomized CAB-string."); CabHelper.RandomizeCabWithAnyLength(context.Parameters.Binary); AssetBundle val2 = AssetBundle.LoadFromMemory(context.Parameters.Binary, 0u); if ((Object)(object)val2 != (Object)null) { context.Bundle = val2; context.Complete(); } } } else if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromStream && (Object)(object)context.Bundle == (Object)null) { string text2 = AssetBundleHelper.PathForLoadedInMemoryBundle ?? "Unnamed"; XuaLogger.ResourceRedirector.Warn("Could not load a stream asset bundle (" + text2 + ") likely due to conflicting CAB-string. Retrying with randomized CAB-string."); byte[] array2 = StreamExtensions.ReadFully(context.Parameters.Stream, 0); if (!forceRandomizeWhenInMemory) { CabHelper.RandomizeCabWithAnyLength(array2); } AssetBundle val3 = AssetBundle.LoadFromMemory(array2, 0u); if ((Object)(object)val3 != (Object)null) { context.Bundle = val3; context.Complete(); } } } static void HandleCabRandomizePrefix(IAssetBundleLoadingContext context) { if (context.Parameters.LoadType == AssetBundleLoadType.LoadFromMemory) { CabHelper.RandomizeCabWithAnyLength(context.Parameters.Binary); } } } public static void DisableRandomizeCabIfConflict() { if (_enabledRandomizeCabIfConflict) { _enabledRandomizeCabIfConflict = false; if (_enableCabRandomizationPrefix != null) { UnregisterAssetBundleLoadingHook(_enableCabRandomizationPrefix); _enableCabRandomizationPrefix = null; } if (_enableCabRandomizationPrefixAsync != null) { UnregisterAsyncAssetBundleLoadingHook(_enableCabRandomizationPrefixAsync); _enableCabRandomizationPrefixAsync = null; } if (_enableCabRandomizationPostfix != null) { UnregisterAssetBundleLoadedHook(_enableCabRandomizationPostfix); _enableCabRandomizationPostfix = null; } } } public static void DisableRedirectMissingAssetBundlesToEmptyAssetBundle() { if (_redirectionMissingAssetBundlesToEmpty != null && _redirectionMissingAssetBundlesToEmptyAsync != null) { UnregisterAssetBundleLoadingHook(_redirectionMissingAssetBundlesToEmpty); UnregisterAsyncAssetBundleLoadingHook(_redirectionMissingAssetBundlesToEmptyAsync); _redirectionMissingAssetBundlesToEmpty = null; _redirectionMissingAssetBundlesToEmptyAsync = null; } } internal static bool TryGetAssetBundleLoadInfo(AssetBundleRequest request, out AsyncAssetLoadInfo result) { result = ExtensionDataHelper.GetExtensionData((object)request); return result != null; } internal static bool TryGetAssetBundle(AssetBundleCreateRequest request, out AsyncAssetBundleLoadInfo result) { result = ExtensionDataHelper.GetExtensionData((object)request); return result != null; } internal static bool ShouldBlockAsyncOperationMethods(AssetBundleRequest operation) { if (TryGetAssetBundleLoadInfo(operation, out var result)) { return result.ResolveType == AsyncAssetLoadingResolve.ThroughAssets; } return false; } internal static bool ShouldBlockAsyncOperationMethods(AssetBundleCreateRequest operation) { if (TryGetAssetBundle(operation, out var result)) { return result.ResolveType == AsyncAssetBundleLoadingResolve.ThroughBundle; } return false; } internal static bool ShouldBlockAsyncOperationMethods(AsyncOperation operation) { if (SyncOverAsyncEnabled) { AssetBundleRequest operation2 = default(AssetBundleRequest); if (!ObjectExtensions.TryCastTo((object)operation, ref operation2) || !ShouldBlockAsyncOperationMethods(operation2)) { AssetBundleCreateRequest operation3 = default(AssetBundleCreateRequest); if (ObjectExtensions.TryCastTo((object)operation, ref operation3)) { return ShouldBlockAsyncOperationMethods(operation3); } return false; } return true; } return false; } internal static AssetBundleLoadingContext Hook_AssetBundleLoading_Prefix(AssetBundleLoadingParameters parameters, out AssetBundle bundle) { AssetBundleLoadingContext assetBundleLoadingContext = new AssetBundleLoadingContext(parameters); if (_isFiringAssetBundle && (_isRecursionDisabledPermanently || !RecursionEnabled)) { bundle = null; return assetBundleLoadingContext; } try { _isFiringAssetBundle = true; if (_logAllLoadedResources) { XuaLogger.ResourceRedirector.Debug("Loading Asset Bundle: (" + assetBundleLoadingContext.GetNormalizedPath() + ")."); } List> prefixRedirectionsForAssetBundles = PrefixRedirectionsForAssetBundles; int count = prefixRedirectionsForAssetBundles.Count; for (int i = 0; i < count; i++) { PrioritizedCallback prioritizedCallback = prefixRedirectionsForAssetBundles[i]; if (prioritizedCallback.IsBeingCalled) { continue; } try { prioritizedCallback.IsBeingCalled = true; if (prioritizedCallback.Callback is Action action) { action(assetBundleLoadingContext); } else if (prioritizedCallback.Callback is Action action2) { action2(assetBundleLoadingContext); } if (assetBundleLoadingContext.SkipRemainingPrefixes) { break; } } catch (Exception ex) { XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetBundleLoading event."); } finally { RecursionEnabled = true; prioritizedCallback.IsBeingCalled = false; } } } catch (Exception ex2) { XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AssetBundleLoading event."); } finally { _isFiringAssetBundle = false; } bundle = assetBundleLoadingContext.Bundle; return assetBundleLoadingContext; } internal static AssetBundleLoadedContext Hook_AssetBundleLoaded_Postfix(AssetBundleLoadingParameters parameters, ref AssetBundle bundle) { AssetBundleLoadedContext assetBundleLoadedContext = new AssetBundleLoadedContext(parameters, bundle); if (_isFiringAssetBundle && (_isRecursionDisabledPermanently || !RecursionEnabled)) { bundle = null; return assetBundleLoadedContext; } try { _isFiringAssetBundle = true; List>> postfixRedirectionsForAssetBundles = PostfixRedirectionsForAssetBundles; int count = postfixRedirectionsForAssetBundles.Count; for (int i = 0; i < count; i++) { PrioritizedCallback> prioritizedCallback = postfixRedirectionsForAssetBundles[i]; if (prioritizedCallback.IsBeingCalled) { continue; } try { prioritizedCallback.IsBeingCalled = true; prioritizedCallback.Callback(assetBundleLoadedContext); if (assetBundleLoadedContext.SkipRemainingPostfixes) { break; } } catch (Exception ex) { XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetBundleLoaded event."); } finally { RecursionEnabled = true; prioritizedCallback.IsBeingCalled = false; } } } catch (Exception ex2) { XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AssetBundleLoaded event."); } finally { _isFiringAssetBundle = false; } bundle = assetBundleLoadedContext.Bundle; return assetBundleLoadedContext; } internal static AsyncAssetBundleLoadingContext Hook_AssetBundleLoading_Prefix(AssetBundleLoadingParameters parameters, out AssetBundleCreateRequest request) { //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown AsyncAssetBundleLoadingContext asyncAssetBundleLoadingContext = new AsyncAssetBundleLoadingContext(parameters); if (_isFiringAssetBundle && (_isRecursionDisabledPermanently || !RecursionEnabled)) { request = null; return asyncAssetBundleLoadingContext; } try { _isFiringAssetBundle = true; if (_logAllLoadedResources) { XuaLogger.ResourceRedirector.Debug("Loading Asset Bundle (async): (" + asyncAssetBundleLoadingContext.GetNormalizedPath() + ")."); } List> prefixRedirectionsForAsyncAssetBundles = PrefixRedirectionsForAsyncAssetBundles; int count = prefixRedirectionsForAsyncAssetBundles.Count; for (int i = 0; i < count; i++) { PrioritizedCallback prioritizedCallback = prefixRedirectionsForAsyncAssetBundles[i]; if (prioritizedCallback.IsBeingCalled) { continue; } try { prioritizedCallback.IsBeingCalled = true; if (prioritizedCallback.Callback is Action action) { action(asyncAssetBundleLoadingContext); } else if (prioritizedCallback.Callback is Action action2) { action2(asyncAssetBundleLoadingContext); } if (asyncAssetBundleLoadingContext.SkipRemainingPrefixes) { break; } } catch (Exception ex) { XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetBundleLoading event."); } finally { RecursionEnabled = true; prioritizedCallback.IsBeingCalled = false; } } } catch (Exception ex2) { XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AsyncAssetBundleLoading event."); } finally { _isFiringAssetBundle = false; } if (asyncAssetBundleLoadingContext.ResolveType == AsyncAssetBundleLoadingResolve.ThroughRequest) { request = asyncAssetBundleLoadingContext.Request; } else { if (asyncAssetBundleLoadingContext.ResolveType != AsyncAssetBundleLoadingResolve.ThroughBundle) { throw new InvalidOperationException("Found invalid ResolveType on context: " + asyncAssetBundleLoadingContext.ResolveType); } request = new AssetBundleCreateRequest(); if (!asyncAssetBundleLoadingContext.SkipOriginalCall) { XuaLogger.ResourceRedirector.Warn("Resolving sync over async asset load, but 'SkipOriginalCall' was not set to true. Forcing it to true."); asyncAssetBundleLoadingContext.SkipOriginalCall = true; } } return asyncAssetBundleLoadingContext; } internal static void Hook_AssetBundleLoading_Postfix(AsyncAssetBundleLoadingContext context, AssetBundleCreateRequest request) { if (request != null) { ExtensionDataHelper.SetExtensionData((object)request, new AsyncAssetBundleLoadInfo(context.Parameters, context.Bundle, context.SkipAllPostfixes, context.ResolveType)); } } internal static void Hook_AssetLoading_Postfix(AsyncAssetLoadingContext context, AssetBundleRequest request) { if (request != null) { ExtensionDataHelper.SetExtensionData((object)request, new AsyncAssetLoadInfo(context.Parameters, context.Bundle, context.SkipAllPostfixes, context.ResolveType, context.Assets)); } } internal static AssetLoadingContext Hook_AssetLoading_Prefix(AssetLoadingParameters parameters, AssetBundle parentBundle, ref Object asset) { Object[] assets = null; AssetLoadingContext result = Hook_AssetLoading_Prefix(parameters, parentBundle, ref assets); if (assets == null || assets.Length == 0) { asset = null; return result; } if (assets.Length > 1) { XuaLogger.ResourceRedirector.Warn("Illegal behaviour by redirection handler in AssetLoadeding event. Returned more than one asset to call requiring only a single asset."); asset = assets[0]; return result; } if (assets.Length == 1) { asset = assets[0]; } return result; } internal static AssetLoadingContext Hook_AssetLoading_Prefix(AssetLoadingParameters parameters, AssetBundle bundle, ref Object[] assets) { AssetLoadingContext assetLoadingContext = new AssetLoadingContext(parameters, bundle); try { if (_isFiringAsset && (_isRecursionDisabledPermanently || !RecursionEnabled)) { return assetLoadingContext; } _isFiringAsset = true; List> prefixRedirectionsForAssetsPerCall = PrefixRedirectionsForAssetsPerCall; int count = prefixRedirectionsForAssetsPerCall.Count; for (int i = 0; i < count; i++) { PrioritizedCallback prioritizedCallback = prefixRedirectionsForAssetsPerCall[i]; if (prioritizedCallback.IsBeingCalled) { continue; } try { prioritizedCallback.IsBeingCalled = true; if (prioritizedCallback.Callback is Action action) { action(assetLoadingContext); } else if (prioritizedCallback.Callback is Action action2) { action2(assetLoadingContext); } if (assetLoadingContext.SkipRemainingPrefixes) { break; } } catch (Exception ex) { XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetLoading event."); } finally { RecursionEnabled = true; prioritizedCallback.IsBeingCalled = false; } } assets = assetLoadingContext.Assets; } catch (Exception ex2) { XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AssetLoading event."); } finally { _isFiringAsset = false; } return assetLoadingContext; } internal static AsyncAssetLoadingContext Hook_AsyncAssetLoading_Prefix(AssetLoadingParameters parameters, AssetBundle bundle, ref AssetBundleRequest request) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown AsyncAssetLoadingContext asyncAssetLoadingContext = new AsyncAssetLoadingContext(parameters, bundle); try { if (_isFiringAsset && (_isRecursionDisabledPermanently || !RecursionEnabled)) { return asyncAssetLoadingContext; } _isFiringAsset = true; List> prefixRedirectionsForAsyncAssetsPerCall = PrefixRedirectionsForAsyncAssetsPerCall; int count = prefixRedirectionsForAsyncAssetsPerCall.Count; for (int i = 0; i < count; i++) { PrioritizedCallback prioritizedCallback = prefixRedirectionsForAsyncAssetsPerCall[i]; if (prioritizedCallback.IsBeingCalled) { continue; } try { prioritizedCallback.IsBeingCalled = true; if (prioritizedCallback.Callback is Action action) { action(asyncAssetLoadingContext); } else if (prioritizedCallback.Callback is Action action2) { action2(asyncAssetLoadingContext); } if (asyncAssetLoadingContext.SkipRemainingPrefixes) { break; } } catch (Exception ex) { XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AsyncAssetLoading event."); } finally { RecursionEnabled = true; prioritizedCallback.IsBeingCalled = false; } } if (asyncAssetLoadingContext.ResolveType == AsyncAssetLoadingResolve.ThroughRequest) { request = asyncAssetLoadingContext.Request; } else { if (asyncAssetLoadingContext.ResolveType != AsyncAssetLoadingResolve.ThroughAssets) { throw new InvalidOperationException("Found invalid ResolveType on context: " + asyncAssetLoadingContext.ResolveType); } request = new AssetBundleRequest(); if (!asyncAssetLoadingContext.SkipOriginalCall) { XuaLogger.ResourceRedirector.Warn("Resolving sync over async asset load, but 'SkipOriginalCall' was not set to true. Forcing it to true."); asyncAssetLoadingContext.SkipOriginalCall = true; } } } catch (Exception ex2) { XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AsyncAssetLoading event."); } finally { _isFiringAsset = false; } return asyncAssetLoadingContext; } internal static void Hook_AssetLoaded_Postfix(AssetLoadingParameters parameters, AssetBundle parentBundle, ref Object asset) { Object[] assets = (Object[])(object)((!(asset == (Object)null)) ? new Object[1] { asset } : new Object[0]); Hook_AssetLoaded_Postfix(parameters, parentBundle, ref assets); if (assets == null || assets.Length == 0) { asset = null; } else if (assets.Length > 1) { XuaLogger.ResourceRedirector.Warn("Illegal behaviour by redirection handler in AssetLoaded event. Returned more than one asset to call requiring only a single asset."); asset = assets[0]; } else if (assets.Length == 1) { asset = assets[0]; } } internal static void Hook_AssetLoaded_Postfix(AssetLoadingParameters parameters, AssetBundle bundle, ref Object[] assets) { FireAssetLoadedEvent(parameters.ToAssetLoadedParameters(), bundle, ref assets); } internal static void Hook_ResourceLoaded_Postfix(ResourceLoadedParameters parameters, ref Object asset) { Object[] assets = (Object[])(object)((!(asset == (Object)null)) ? new Object[1] { asset } : new Object[0]); Hook_ResourceLoaded_Postfix(parameters, ref assets); if (assets == null || assets.Length == 0) { asset = null; } else if (assets.Length > 1) { XuaLogger.ResourceRedirector.Warn("Illegal behaviour by redirection handler in ResourceLoaded event. Returned more than one asset to call requiring only a single asset."); asset = assets[0]; } else if (assets.Length == 1) { asset = assets[0]; } } internal static void Hook_ResourceLoaded_Postfix(ResourceLoadedParameters parameters, ref Object[] assets) { FireResourceLoadedEvent(parameters, ref assets); } internal static void FireAssetLoadedEvent(AssetLoadedParameters parameters, AssetBundle assetBundle, ref Object[] assets) { Object[] array = assets?.ToArray(); try { AssetLoadedContext assetLoadedContext = new AssetLoadedContext(parameters, assetBundle, assets); if (_isFiringAsset && (_isRecursionDisabledPermanently || !RecursionEnabled)) { return; } _isFiringAsset = true; if (_logAllLoadedResources && assets != null) { for (int i = 0; i < assets.Length; i++) { Object val = assets[i]; if (val != (Object)null) { string uniqueFileSystemAssetPath = assetLoadedContext.GetUniqueFileSystemAssetPath(val); XuaLogger.ResourceRedirector.Debug("Loaded Asset: '" + ObjectExtensions.GetUnityType((object)val).FullName + "', Load Type: '" + parameters.LoadType.ToString() + "', Unique Path: (" + uniqueFileSystemAssetPath + ")."); } } } List>> postfixRedirectionsForAssetsPerCall = PostfixRedirectionsForAssetsPerCall; int count = postfixRedirectionsForAssetsPerCall.Count; for (int j = 0; j < count; j++) { PrioritizedCallback> prioritizedCallback = postfixRedirectionsForAssetsPerCall[j]; if (prioritizedCallback.IsBeingCalled) { continue; } try { prioritizedCallback.IsBeingCalled = true; prioritizedCallback.Callback(assetLoadedContext); if (assetLoadedContext.SkipRemainingPostfixes) { break; } } catch (Exception ex) { XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking AssetLoaded event."); } finally { RecursionEnabled = true; prioritizedCallback.IsBeingCalled = false; } } assets = assetLoadedContext.Assets; if (assetLoadedContext.SkipRemainingPostfixes || assets == null) { return; } int num = assets.Length; for (int k = 0; k < num; k++) { Object val2 = assets[k]; if (val2 != (Object)null) { AssetLoadedContext assetLoadedContext2 = new AssetLoadedContext(parameters, assetBundle, val2); List>> postfixRedirectionsForAssetsPerResource = PostfixRedirectionsForAssetsPerResource; int count2 = postfixRedirectionsForAssetsPerResource.Count; for (int l = 0; l < count2; l++) { PrioritizedCallback> prioritizedCallback2 = postfixRedirectionsForAssetsPerResource[l]; if (prioritizedCallback2.IsBeingCalled) { continue; } try { prioritizedCallback2.IsBeingCalled = true; prioritizedCallback2.Callback(assetLoadedContext2); if (assetLoadedContext2.Asset != (Object)null) { assets[k] = assetLoadedContext2.Asset; } else { XuaLogger.ResourceRedirector.Warn($"Illegal behaviour by redirection handler in AssetLoaded event. You must not remove an asset reference when hooking with behaviour {HookBehaviour.OneCallbackPerResourceLoaded}."); } if (assetLoadedContext2.SkipRemainingPostfixes) { break; } } catch (Exception ex2) { XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking AssetLoaded event."); } finally { RecursionEnabled = true; prioritizedCallback2.IsBeingCalled = false; } } } else { XuaLogger.ResourceRedirector.Error("Found unexpected null asset during AssetLoaded event."); } } } catch (Exception ex3) { XuaLogger.ResourceRedirector.Error(ex3, "An error occurred while invoking AssetLoaded event."); } finally { _isFiringAsset = false; if (array != null) { Object[] array2 = array; for (int m = 0; m < array2.Length; m++) { ExtensionDataHelper.GetOrCreateExtensionData((object)array2[m]).HasBeenRedirected = true; } } } } internal static void FireResourceLoadedEvent(ResourceLoadedParameters parameters, ref Object[] assets) { Object[] array = assets?.ToArray(); try { ResourceLoadedContext resourceLoadedContext = new ResourceLoadedContext(parameters, assets); if (_isFiringResource && (_isRecursionDisabledPermanently || !RecursionEnabled)) { return; } _isFiringResource = true; if (_logAllLoadedResources && assets != null) { for (int i = 0; i < assets.Length; i++) { Object val = assets[i]; if (val != (Object)null) { string uniqueFileSystemAssetPath = resourceLoadedContext.GetUniqueFileSystemAssetPath(val); XuaLogger.ResourceRedirector.Debug("Loaded Asset: '" + ObjectExtensions.GetUnityType((object)val).FullName + "', Load Type: '" + parameters.LoadType.ToString() + "', Unique Path: (" + uniqueFileSystemAssetPath + ")."); } } } List>> postfixRedirectionsForResourcesPerCall = PostfixRedirectionsForResourcesPerCall; int count = postfixRedirectionsForResourcesPerCall.Count; for (int j = 0; j < count; j++) { PrioritizedCallback> prioritizedCallback = postfixRedirectionsForResourcesPerCall[j]; if (prioritizedCallback.IsBeingCalled) { continue; } try { prioritizedCallback.IsBeingCalled = true; prioritizedCallback.Callback(resourceLoadedContext); if (resourceLoadedContext.SkipRemainingPostfixes) { break; } } catch (Exception ex) { XuaLogger.ResourceRedirector.Error(ex, "An error occurred while invoking ResourceLoaded event."); } finally { RecursionEnabled = true; prioritizedCallback.IsBeingCalled = false; } } assets = resourceLoadedContext.Assets; if (resourceLoadedContext.SkipRemainingPostfixes || assets == null) { return; } int num = assets.Length; for (int k = 0; k < num; k++) { Object val2 = assets[k]; if (val2 != (Object)null) { ResourceLoadedContext resourceLoadedContext2 = new ResourceLoadedContext(parameters, val2); List>> postfixRedirectionsForResourcesPerResource = PostfixRedirectionsForResourcesPerResource; int count2 = postfixRedirectionsForResourcesPerResource.Count; for (int l = 0; l < count2; l++) { PrioritizedCallback> prioritizedCallback2 = postfixRedirectionsForResourcesPerResource[l]; if (prioritizedCallback2.IsBeingCalled) { continue; } try { prioritizedCallback2.IsBeingCalled = true; prioritizedCallback2.Callback(resourceLoadedContext2); if (resourceLoadedContext2.Asset != (Object)null) { assets[k] = resourceLoadedContext2.Asset; } else { XuaLogger.ResourceRedirector.Warn($"Illegal behaviour by redirection handler in ResourceLoaded event. You must not remove an asset reference when hooking with behaviour {HookBehaviour.OneCallbackPerResourceLoaded}."); } if (resourceLoadedContext2.SkipRemainingPostfixes) { break; } } catch (Exception ex2) { XuaLogger.ResourceRedirector.Error(ex2, "An error occurred while invoking ResourceLoaded event."); } finally { RecursionEnabled = true; prioritizedCallback2.IsBeingCalled = false; } } } else { XuaLogger.ResourceRedirector.Error("Found unexpected null asset during ResourceLoaded event."); } } } catch (Exception ex3) { XuaLogger.ResourceRedirector.Error(ex3, "An error occurred while invoking ResourceLoaded event."); } finally { _isFiringResource = false; if (array != null) { Object[] array2 = array; for (int m = 0; m < array2.Length; m++) { ExtensionDataHelper.GetOrCreateExtensionData((object)array2[m]).HasBeenRedirected = true; } } } } private static void LogEventRegistration(string eventType, IEnumerable callbacks) { XuaLogger.ResourceRedirector.Debug("Registered new callback for " + eventType + "."); LogNewCallbackOrder(eventType, callbacks); } private static void LogEventUnregistration(string eventType, IEnumerable callbacks) { XuaLogger.ResourceRedirector.Debug("Unregistered callback for " + eventType + "."); LogNewCallbackOrder(eventType, callbacks); } private static void LogNewCallbackOrder(string eventType, IEnumerable callbacks) { if (!LogCallbackOrder) { return; } XuaLogger.ResourceRedirector.Debug("New callback order for " + eventType + ":"); foreach (object callback in callbacks) { XuaLogger.ResourceRedirector.Debug(callback.ToString()); } } public static void RegisterAssetBundleLoadedHook(int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback> prioritizedCallback = PrioritizedCallback.Create(action, priority); if (PostfixRedirectionsForAssetBundles.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); ListExtensions.BinarySearchInsert>>(PostfixRedirectionsForAssetBundles, prioritizedCallback); LogEventRegistration("AssetBundleLoaded", PostfixRedirectionsForAssetBundles); } public static void RegisterAssetBundleLoadedHook(Action action) { RegisterAssetBundleLoadedHook(0, action); } public static void UnregisterAssetBundleLoadedHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } PostfixRedirectionsForAssetBundles.RemoveAll((PrioritizedCallback> x) => object.Equals(x.Callback, action)); LogEventUnregistration("AssetBundleLoaded", PostfixRedirectionsForAssetBundles); } public static void RegisterAssetLoadingHook(int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority); if (PrefixRedirectionsForAssetsPerCall.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); ListExtensions.BinarySearchInsert>(PrefixRedirectionsForAssetsPerCall, prioritizedCallback); LogEventRegistration("AssetLoading", PrefixRedirectionsForAssetsPerCall); } public static void RegisterAssetLoadingHook(Action action) { RegisterAssetLoadingHook(0, action); } public static void UnregisterAssetLoadingHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrefixRedirectionsForAssetsPerCall.RemoveAll((PrioritizedCallback x) => object.Equals(x.Callback, action)); LogEventUnregistration("AssetLoading", PrefixRedirectionsForAssetsPerCall); } public static void RegisterAsyncAssetLoadingHook(int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority); if (PrefixRedirectionsForAsyncAssetsPerCall.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); ListExtensions.BinarySearchInsert>(PrefixRedirectionsForAsyncAssetsPerCall, prioritizedCallback); LogEventRegistration("AsyncAssetLoading", PrefixRedirectionsForAsyncAssetsPerCall); } public static void RegisterAsyncAssetLoadingHook(Action action) { RegisterAsyncAssetLoadingHook(0, action); } public static void UnregisterAsyncAssetLoadingHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrefixRedirectionsForAsyncAssetsPerCall.RemoveAll((PrioritizedCallback x) => object.Equals(x.Callback, action)); LogEventUnregistration("AsyncAssetLoading", PrefixRedirectionsForAsyncAssetsPerCall); } public static void RegisterAsyncAndSyncAssetLoadingHook(int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority); if (PrefixRedirectionsForAsyncAssetsPerCall.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); ListExtensions.BinarySearchInsert>(PrefixRedirectionsForAsyncAssetsPerCall, prioritizedCallback); LogEventRegistration("AsyncAssetLoading", PrefixRedirectionsForAsyncAssetsPerCall); ListExtensions.BinarySearchInsert>(PrefixRedirectionsForAssetsPerCall, prioritizedCallback); LogEventRegistration("AssetLoading", PrefixRedirectionsForAssetsPerCall); } public static void RegisterAsyncAndSyncAssetLoadingHook(Action action) { RegisterAsyncAndSyncAssetLoadingHook(0, action); } public static void UnregisterAsyncAndSyncAssetLoadingHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrefixRedirectionsForAsyncAssetsPerCall.RemoveAll((PrioritizedCallback x) => object.Equals(x.Callback, action)); LogEventUnregistration("AsyncAssetLoading", PrefixRedirectionsForAsyncAssetsPerCall); PrefixRedirectionsForAssetsPerCall.RemoveAll((PrioritizedCallback x) => object.Equals(x.Callback, action)); LogEventUnregistration("AssetLoading", PrefixRedirectionsForAssetsPerCall); } public static void RegisterAssetLoadedHook(HookBehaviour behaviour, int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback> prioritizedCallback = PrioritizedCallback.Create(action, priority); if (PostfixRedirectionsForAssetsPerCall.Contains(prioritizedCallback) || PostfixRedirectionsForAssetsPerResource.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); switch (behaviour) { case HookBehaviour.OneCallbackPerLoadCall: ListExtensions.BinarySearchInsert>>(PostfixRedirectionsForAssetsPerCall, prioritizedCallback); LogEventRegistration("AssetLoaded (" + behaviour.ToString() + ")", PostfixRedirectionsForAssetsPerCall); break; case HookBehaviour.OneCallbackPerResourceLoaded: ListExtensions.BinarySearchInsert>>(PostfixRedirectionsForAssetsPerResource, prioritizedCallback); LogEventRegistration("AssetLoaded (" + behaviour.ToString() + ")", PostfixRedirectionsForAssetsPerResource); break; } } public static void RegisterAssetLoadedHook(HookBehaviour behaviour, Action action) { RegisterAssetLoadedHook(behaviour, 0, action); } public static void UnregisterAssetLoadedHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } if (PostfixRedirectionsForAssetsPerCall.RemoveAll((PrioritizedCallback> x) => x.Callback == action) > 0) { LogEventRegistration("AssetLoaded (" + HookBehaviour.OneCallbackPerLoadCall.ToString() + ")", PostfixRedirectionsForAssetsPerCall); } if (PostfixRedirectionsForAssetsPerResource.RemoveAll((PrioritizedCallback> x) => x.Callback == action) > 0) { LogEventRegistration("AssetLoaded (" + HookBehaviour.OneCallbackPerResourceLoaded.ToString() + ")", PostfixRedirectionsForAssetsPerResource); } } public static void RegisterAssetBundleLoadingHook(int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority); if (PrefixRedirectionsForAssetBundles.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); ListExtensions.BinarySearchInsert>(PrefixRedirectionsForAssetBundles, prioritizedCallback); LogEventRegistration("AssetBundleLoading", PrefixRedirectionsForAssetBundles); } public static void RegisterAssetBundleLoadingHook(Action action) { RegisterAssetBundleLoadingHook(0, action); } public static void UnregisterAssetBundleLoadingHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrefixRedirectionsForAssetBundles.RemoveAll((PrioritizedCallback x) => object.Equals(x.Callback, action)); LogEventUnregistration("AssetBundleLoading", PrefixRedirectionsForAssetBundles); } public static void RegisterAsyncAssetBundleLoadingHook(int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority); if (PrefixRedirectionsForAsyncAssetBundles.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); ListExtensions.BinarySearchInsert>(PrefixRedirectionsForAsyncAssetBundles, prioritizedCallback); LogEventRegistration("AsyncAssetBundleLoading", PrefixRedirectionsForAsyncAssetBundles); } public static void RegisterAsyncAssetBundleLoadingHook(Action action) { RegisterAsyncAssetBundleLoadingHook(0, action); } public static void UnregisterAsyncAssetBundleLoadingHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrefixRedirectionsForAsyncAssetBundles.RemoveAll((PrioritizedCallback x) => object.Equals(x.Callback, action)); LogEventUnregistration("AsyncAssetBundleLoading", PrefixRedirectionsForAsyncAssetBundles); } public static void RegisterAsyncAndSyncAssetBundleLoadingHook(int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback prioritizedCallback = PrioritizedCallback.Create((Delegate)action, priority); if (PrefixRedirectionsForAssetBundles.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); ListExtensions.BinarySearchInsert>(PrefixRedirectionsForAssetBundles, prioritizedCallback); LogEventRegistration("AssetBundleLoading", PrefixRedirectionsForAssetBundles); ListExtensions.BinarySearchInsert>(PrefixRedirectionsForAsyncAssetBundles, prioritizedCallback); LogEventRegistration("AsyncAssetBundleLoading", PrefixRedirectionsForAsyncAssetBundles); } public static void RegisterAsyncAndSyncAssetBundleLoadingHook(Action action) { RegisterAsyncAndSyncAssetBundleLoadingHook(0, action); } public static void UnregisterAsyncAndSyncAssetBundleLoadingHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrefixRedirectionsForAssetBundles.RemoveAll((PrioritizedCallback x) => object.Equals(x.Callback, action)); LogEventUnregistration("AssetBundleLoading", PrefixRedirectionsForAssetBundles); PrefixRedirectionsForAsyncAssetBundles.RemoveAll((PrioritizedCallback x) => object.Equals(x.Callback, action)); LogEventUnregistration("AsyncAssetBundleLoading", PrefixRedirectionsForAsyncAssetBundles); } public static void RegisterResourceLoadedHook(HookBehaviour behaviour, int priority, Action action) { if (action == null) { throw new ArgumentNullException("action"); } PrioritizedCallback> prioritizedCallback = PrioritizedCallback.Create(action, priority); if (PostfixRedirectionsForResourcesPerCall.Contains(prioritizedCallback) || PostfixRedirectionsForResourcesPerResource.Contains(prioritizedCallback)) { throw new ArgumentException("This callback has already been registered.", "action"); } Initialize(); switch (behaviour) { case HookBehaviour.OneCallbackPerLoadCall: ListExtensions.BinarySearchInsert>>(PostfixRedirectionsForResourcesPerCall, prioritizedCallback); LogEventRegistration("ResourceLoaded (" + behaviour.ToString() + ")", PostfixRedirectionsForResourcesPerCall); break; case HookBehaviour.OneCallbackPerResourceLoaded: ListExtensions.BinarySearchInsert>>(PostfixRedirectionsForResourcesPerResource, prioritizedCallback); LogEventRegistration("ResourceLoaded (" + behaviour.ToString() + ")", PostfixRedirectionsForResourcesPerResource); break; } } public static void RegisterResourceLoadedHook(HookBehaviour behaviour, Action action) { RegisterResourceLoadedHook(behaviour, 0, action); } public static void UnregisterResourceLoadedHook(Action action) { if (action == null) { throw new ArgumentNullException("action"); } if (PostfixRedirectionsForResourcesPerCall.RemoveAll((PrioritizedCallback> x) => x.Callback == action) > 0) { LogEventRegistration("ResourceLoaded (" + HookBehaviour.OneCallbackPerLoadCall.ToString() + ")", PostfixRedirectionsForResourcesPerCall); } if (PostfixRedirectionsForResourcesPerResource.RemoveAll((PrioritizedCallback> x) => x.Callback == action) > 0) { LogEventRegistration("ResourceLoaded (" + HookBehaviour.OneCallbackPerResourceLoaded.ToString() + ")", PostfixRedirectionsForResourcesPerResource); } } } internal static class GeneratedInfo { public const string PROJECT_VERSION = "2.1.0"; } } namespace XUnity.ResourceRedirector.Properties { [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [DebuggerNonUserCode] [CompilerGenerated] internal class Resources { private static ResourceManager resourceMan; private static CultureInfo resourceCulture; [EditorBrowsable(EditorBrowsableState.Advanced)] internal static ResourceManager ResourceManager { get { if (resourceMan == null) { resourceMan = new ResourceManager("XUnity.ResourceRedirector.Properties.Resources", typeof(Resources).Assembly); } return resourceMan; } } [EditorBrowsable(EditorBrowsableState.Advanced)] internal static CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } internal static byte[] empty => (byte[])ResourceManager.GetObject("empty", resourceCulture); internal Resources() { } } } namespace XUnity.ResourceRedirector.Hooks { internal static class ResourceAndAssetHooks { public static readonly Type[] GeneralHooks = new Type[21] { typeof(AssetBundle_LoadFromFileAsync_Hook), typeof(AssetBundle_LoadFromFile_Hook), typeof(AssetBundle_LoadFromMemoryAsync_Hook), typeof(AssetBundle_LoadFromMemory_Hook), typeof(AssetBundle_LoadFromStreamAsync_Hook), typeof(AssetBundle_LoadFromStream_Hook), typeof(AssetBundle_mainAsset_Hook), typeof(AssetBundle_returnMainAsset_Hook), typeof(AssetBundle_Load_Hook), typeof(AssetBundle_LoadAsync_Hook), typeof(AssetBundle_LoadAll_Hook), typeof(AssetBundle_LoadAsset_Internal_Hook), typeof(AssetBundle_LoadAssetAsync_Internal_Hook), typeof(AssetBundle_LoadAssetWithSubAssets_Internal_Hook), typeof(AssetBundle_LoadAssetWithSubAssetsAsync_Internal_Hook), typeof(AssetBundleRequest_asset_Hook), typeof(AssetBundleRequest_allAssets_Hook), typeof(Resources_Load_Hook), typeof(Resources_LoadAll_Hook), typeof(Resources_GetBuiltinResource_Old_Hook), typeof(Resources_GetBuiltinResource_New_Hook) }; public static readonly Type[] SyncOverAsyncHooks = new Type[10] { typeof(AssetBundleCreateRequest_assetBundle_Hook), typeof(AssetBundleCreateRequest_DisableCompatibilityChecks_Hook), typeof(AssetBundleCreateRequest_SetEnableCompatibilityChecks_Hook), typeof(AsyncOperation_isDone_Hook), typeof(AsyncOperation_progress_Hook), typeof(AsyncOperation_priority_Hook), typeof(AsyncOperation_set_priority_Hook), typeof(AsyncOperation_allowSceneActivation_Hook), typeof(AsyncOperation_set_allowSceneActivation_Hook), typeof(AsyncOperation_Finalize_Hook) }; } internal static class AssetBundleCreateRequest_assetBundle_Hook { private delegate AssetBundle OriginalMethod(AssetBundleCreateRequest __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundleCreateRequest != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest; return AccessToolsShim.Property((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "assetBundle")?.GetGetMethod(); } private static bool Prefix(AssetBundleCreateRequest __instance, ref AssetBundle __result, ref AsyncAssetBundleLoadInfo __state) { if (ResourceRedirection.TryGetAssetBundle(__instance, out __state)) { if (__state.ResolveType == AsyncAssetBundleLoadingResolve.ThroughBundle) { __result = __state.Bundle; return false; } return true; } return true; } private static void Postfix(ref AssetBundle __result, ref AsyncAssetBundleLoadInfo __state) { if (__state == null) { return; } if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetBundleLoaded_Postfix(__state.Parameters, ref __result); } if ((Object)(object)__result != (Object)null && __state != null) { string path = __state.Parameters.Path; if (path != null) { ExtensionDataHelper.GetOrCreateExtensionData((object)__result).Path = path; } } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundle MM_Detour(AssetBundleCreateRequest __instance) { AssetBundle __result = null; AsyncAssetBundleLoadInfo __state = null; if (Prefix(__instance, ref __result, ref __state)) { __result = _original(__instance); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundleCreateRequest_DisableCompatibilityChecks_Hook { private delegate void OriginalMethod(AssetBundleCreateRequest __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest; return (object)AccessToolsShim.Method((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "SetEnableCompatibilityChecks", new Type[1] { typeof(bool) }) == null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest; return AccessToolsShim.Method((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "DisableCompatibilityChecks", new Type[0]); } private static bool Prefix(AssetBundleCreateRequest __instance) { return !ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static void MM_Detour(AssetBundleCreateRequest __instance) { if (Prefix(__instance)) { _original(__instance); } } } internal static class AssetBundleCreateRequest_SetEnableCompatibilityChecks_Hook { private delegate void OriginalMethod(AssetBundleCreateRequest __instance, bool set); private static OriginalMethod _original; private static bool Prepare(object instance) { TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest; return (object)AccessToolsShim.Method((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "SetEnableCompatibilityChecks", new Type[1] { typeof(bool) }) != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundleCreateRequest = UnityTypes.AssetBundleCreateRequest; return AccessToolsShim.Method((assetBundleCreateRequest != null) ? assetBundleCreateRequest.ClrType : null, "SetEnableCompatibilityChecks", new Type[1] { typeof(bool) }); } private static bool Prefix(AssetBundleCreateRequest __instance, bool set) { return !ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static void MM_Detour(AssetBundleCreateRequest __instance, bool set) { if (Prefix(__instance, set)) { _original(__instance, set); } } } internal static class AssetBundle_LoadFromFileAsync_Hook { private delegate AssetBundleCreateRequest OriginalMethod(string path, uint crc, ulong offset); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromFileAsync_Internal", new Type[3] { typeof(string), typeof(uint), typeof(ulong) }); if ((object)methodInfo == null) { TypeContainer assetBundle2 = UnityTypes.AssetBundle; methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromFileAsync", new Type[3] { typeof(string), typeof(uint), typeof(ulong) }); } return methodInfo; } private static bool Prefix(ref string path, ref uint crc, ref ulong offset, ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state) { AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(null, path, crc, offset, null, 0u, AssetBundleLoadType.LoadFromFile); __state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result); AssetBundleLoadingParameters parameters2 = __state.Parameters; path = parameters2.Path; crc = parameters2.Crc; offset = parameters2.Offset; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state) { ResourceRedirection.Hook_AssetBundleLoading_Postfix(__state, __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundleCreateRequest MM_Detour(string path, uint crc, ulong offset) { AssetBundleCreateRequest __result = null; AsyncAssetBundleLoadingContext __state = null; if (Prefix(ref path, ref crc, ref offset, ref __result, ref __state)) { __result = _original(path, crc, offset); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadFromFile_Hook { private delegate AssetBundle OriginalMethod(string path, uint crc, ulong offset); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromFile_Internal", new Type[3] { typeof(string), typeof(uint), typeof(ulong) }); if ((object)methodInfo == null) { TypeContainer assetBundle2 = UnityTypes.AssetBundle; methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromFile", new Type[3] { typeof(string), typeof(uint), typeof(ulong) }); } return methodInfo; } private static bool Prefix(ref string path, ref uint crc, ref ulong offset, ref AssetBundle __result, ref AssetBundleLoadingContext __state) { AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(null, path, crc, offset, null, 0u, AssetBundleLoadType.LoadFromFile); __state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result); AssetBundleLoadingParameters parameters2 = __state.Parameters; path = parameters2.Path; crc = parameters2.Crc; offset = parameters2.Offset; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundle __result, ref AssetBundleLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetBundleLoaded_Postfix(__state.Parameters, ref __result); } if ((Object)(object)__result != (Object)null && __state.Parameters.Path != null) { ExtensionDataHelper.GetOrCreateExtensionData((object)__result).Path = __state.Parameters.Path; } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundle MM_Detour(string path, uint crc, ulong offset) { AssetBundle __result = null; AssetBundleLoadingContext __state = null; if (Prefix(ref path, ref crc, ref offset, ref __result, ref __state)) { __result = _original(path, crc, offset); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadFromMemoryAsync_Hook { private delegate AssetBundleCreateRequest OriginalMethod(byte[] binary, uint crc); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromMemoryAsync_Internal", new Type[2] { typeof(byte[]), typeof(uint) }); if ((object)methodInfo == null) { TypeContainer assetBundle2 = UnityTypes.AssetBundle; methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromMemoryAsync", new Type[2] { typeof(byte[]), typeof(uint) }); } return methodInfo; } private static bool Prefix(ref byte[] binary, ref uint crc, ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state) { AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(binary, null, crc, 0uL, null, 0u, AssetBundleLoadType.LoadFromMemory); __state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result); AssetBundleLoadingParameters parameters2 = __state.Parameters; binary = parameters2.Binary; crc = parameters2.Crc; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state) { ResourceRedirection.Hook_AssetBundleLoading_Postfix(__state, __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundleCreateRequest MM_Detour(byte[] binary, uint crc) { AssetBundleCreateRequest __result = null; AsyncAssetBundleLoadingContext __state = null; if (Prefix(ref binary, ref crc, ref __result, ref __state)) { __result = _original(binary, crc); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadFromMemory_Hook { private delegate AssetBundle OriginalMethod(byte[] binary, uint crc); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromMemory_Internal", new Type[2] { typeof(byte[]), typeof(uint) }); if ((object)methodInfo == null) { TypeContainer assetBundle2 = UnityTypes.AssetBundle; methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromMemory", new Type[2] { typeof(byte[]), typeof(uint) }); } return methodInfo; } private static bool Prefix(ref byte[] binary, ref uint crc, ref AssetBundle __result, ref AssetBundleLoadingContext __state) { AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(binary, null, crc, 0uL, null, 0u, AssetBundleLoadType.LoadFromMemory); __state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result); AssetBundleLoadingParameters parameters2 = __state.Parameters; binary = parameters2.Binary; crc = parameters2.Crc; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundle __result, ref AssetBundleLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetBundleLoaded_Postfix(__state.Parameters, ref __result); } if ((Object)(object)__result != (Object)null && __state.Parameters.Path != null) { ExtensionDataHelper.GetOrCreateExtensionData((object)__result).Path = __state.Parameters.Path; } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundle MM_Detour(byte[] binary, uint crc) { AssetBundle __result = null; AssetBundleLoadingContext __state = null; if (Prefix(ref binary, ref crc, ref __result, ref __state)) { __result = _original(binary, crc); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadFromStreamAsync_Hook { private delegate AssetBundleCreateRequest OriginalMethod(Stream stream, uint crc, uint managedReadBufferSize); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromStreamAsyncInternal", new Type[3] { typeof(Stream), typeof(uint), typeof(uint) }); if ((object)methodInfo == null) { TypeContainer assetBundle2 = UnityTypes.AssetBundle; methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromStreamAsync", new Type[3] { typeof(Stream), typeof(uint), typeof(uint) }); } return methodInfo; } private static bool Prefix(ref Stream stream, ref uint crc, ref uint managedReadBufferSize, ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state) { AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(null, null, crc, 0uL, stream, managedReadBufferSize, AssetBundleLoadType.LoadFromMemory); __state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result); AssetBundleLoadingParameters parameters2 = __state.Parameters; stream = parameters2.Stream; crc = parameters2.Crc; managedReadBufferSize = parameters2.ManagedReadBufferSize; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundleCreateRequest __result, ref AsyncAssetBundleLoadingContext __state) { ResourceRedirection.Hook_AssetBundleLoading_Postfix(__state, __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundleCreateRequest MM_Detour(Stream stream, uint crc, uint managedReadBufferSize) { AssetBundleCreateRequest __result = null; AsyncAssetBundleLoadingContext __state = null; if (Prefix(ref stream, ref crc, ref managedReadBufferSize, ref __result, ref __state)) { __result = _original(stream, crc, managedReadBufferSize); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadFromStream_Hook { private delegate AssetBundle OriginalMethod(Stream stream, uint crc, uint managedReadBufferSize); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; MethodInfo methodInfo = AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadFromStreamInternal", new Type[3] { typeof(Stream), typeof(uint), typeof(uint) }); if ((object)methodInfo == null) { TypeContainer assetBundle2 = UnityTypes.AssetBundle; methodInfo = AccessToolsShim.Method((assetBundle2 != null) ? assetBundle2.ClrType : null, "LoadFromStream", new Type[3] { typeof(Stream), typeof(uint), typeof(uint) }); } return methodInfo; } private static bool Prefix(ref Stream stream, ref uint crc, ref uint managedReadBufferSize, ref AssetBundle __result, ref AssetBundleLoadingContext __state) { AssetBundleLoadingParameters parameters = new AssetBundleLoadingParameters(null, null, crc, 0uL, stream, managedReadBufferSize, AssetBundleLoadType.LoadFromMemory); __state = ResourceRedirection.Hook_AssetBundleLoading_Prefix(parameters, out __result); AssetBundleLoadingParameters parameters2 = __state.Parameters; stream = parameters2.Stream; crc = parameters2.Crc; managedReadBufferSize = parameters2.ManagedReadBufferSize; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundle __result, ref AssetBundleLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetBundleLoaded_Postfix(__state.Parameters, ref __result); } if ((Object)(object)__result != (Object)null && __state.Parameters.Path != null) { ExtensionDataHelper.GetOrCreateExtensionData((object)__result).Path = __state.Parameters.Path; } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundle MM_Detour(Stream stream, uint crc, uint managedReadBufferSize) { AssetBundle __result = null; AssetBundleLoadingContext __state = null; if (Prefix(ref stream, ref crc, ref managedReadBufferSize, ref __result, ref __state)) { __result = _original(stream, crc, managedReadBufferSize); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundle_mainAsset_Hook { private delegate Object OriginalMethod(AssetBundle __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return (object)AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "returnMainAsset", new Type[1] { typeof(AssetBundle) }) == null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Property((assetBundle != null) ? assetBundle.ClrType : null, "mainAsset")?.GetGetMethod(); } private static bool Prefix(AssetBundle __instance, ref Object __result, ref AssetLoadingContext __state) { AssetLoadingParameters parameters = new AssetLoadingParameters(null, null, AssetLoadType.LoadMainAsset); __state = ResourceRedirection.Hook_AssetLoading_Prefix(parameters, __instance, ref __result); return !__state.SkipOriginalCall; } private static void Postfix(AssetBundle __instance, ref Object __result, ref AssetLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __instance, ref __result); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object MM_Detour(AssetBundle __instance) { Object __result = null; AssetLoadingContext __state = null; if (Prefix(__instance, ref __result, ref __state)) { __result = _original(__instance); } Postfix(__instance, ref __result, ref __state); return __result; } } internal static class AssetBundle_returnMainAsset_Hook { private delegate Object OriginalMethod(AssetBundle __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return (object)AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "returnMainAsset", new Type[1] { typeof(AssetBundle) }) != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "returnMainAsset", new Type[1] { typeof(AssetBundle) }); } private static bool Prefix(AssetBundle __instance, ref Object __result, ref AssetLoadingContext __state) { AssetLoadingParameters parameters = new AssetLoadingParameters(null, null, AssetLoadType.LoadMainAsset); __state = ResourceRedirection.Hook_AssetLoading_Prefix(parameters, __instance, ref __result); return !__state.SkipOriginalCall; } private static void Postfix(AssetBundle __instance, ref Object __result, ref AssetLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __instance, ref __result); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object MM_Detour(AssetBundle __instance) { Object __result = null; AssetLoadingContext __state = null; if (Prefix(__instance, ref __result, ref __state)) { __result = _original(__instance); } Postfix(__instance, ref __result, ref __state); return __result; } } internal static class AssetBundle_Load_Hook { private delegate Object OriginalMethod(AssetBundle __instance, string name, Type type); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "Load", new Type[2] { typeof(string), typeof(Type) }); } private static bool Prefix(AssetBundle __instance, ref string name, ref Type type, ref Object __result, ref AssetLoadingContext __state) { AssetLoadingParameters parameters = new AssetLoadingParameters(name, type, AssetLoadType.LoadNamed); __state = ResourceRedirection.Hook_AssetLoading_Prefix(parameters, __instance, ref __result); AssetLoadingParameters parameters2 = __state.Parameters; name = parameters2.Name; type = parameters2.Type; return !__state.SkipOriginalCall; } private static void Postfix(AssetBundle __instance, ref Object __result, ref AssetLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __instance, ref __result); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object MM_Detour(AssetBundle __instance, string name, Type type) { Object __result = null; AssetLoadingContext __state = null; if (Prefix(__instance, ref name, ref type, ref __result, ref __state)) { __result = _original(__instance, name, type); } Postfix(__instance, ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadAsync_Hook { private delegate AssetBundleRequest OriginalMethod(AssetBundle __instance, string name, Type type); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadAsync", new Type[2] { typeof(string), typeof(Type) }); } private static bool Prefix(AssetBundle __instance, ref string name, ref Type type, ref AssetBundleRequest __result, ref AsyncAssetLoadingContext __state) { AssetLoadingParameters parameters = new AssetLoadingParameters(name, type, AssetLoadType.LoadNamed); __state = ResourceRedirection.Hook_AsyncAssetLoading_Prefix(parameters, __instance, ref __result); AssetLoadingParameters parameters2 = __state.Parameters; name = parameters2.Name; type = parameters2.Type; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundleRequest __result, ref AsyncAssetLoadingContext __state) { ResourceRedirection.Hook_AssetLoading_Postfix(__state, __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundleRequest MM_Detour(AssetBundle __instance, string name, Type type) { AssetBundleRequest __result = null; AsyncAssetLoadingContext __state = null; if (Prefix(__instance, ref name, ref type, ref __result, ref __state)) { __result = _original(__instance, name, type); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadAll_Hook { private delegate Object[] OriginalMethod(AssetBundle __instance, Type type); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadAll", new Type[1] { typeof(Type) }); } private static bool Prefix(AssetBundle __instance, ref Type type, ref Object[] __result, ref AssetLoadingContext __state) { AssetLoadingParameters parameters = new AssetLoadingParameters(null, type, AssetLoadType.LoadByType); __state = ResourceRedirection.Hook_AssetLoading_Prefix(parameters, __instance, ref __result); AssetLoadingParameters parameters2 = __state.Parameters; type = parameters2.Type; return !__state.SkipOriginalCall; } private static void Postfix(AssetBundle __instance, ref Object[] __result, ref AssetLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __instance, ref __result); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object[] MM_Detour(AssetBundle __instance, Type type) { Object[] __result = null; AssetLoadingContext __state = null; if (Prefix(__instance, ref type, ref __result, ref __state)) { __result = _original(__instance, type); } Postfix(__instance, ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadAsset_Internal_Hook { private delegate Object OriginalMethod(AssetBundle __instance, string name, Type type); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadAsset_Internal", new Type[2] { typeof(string), typeof(Type) }); } private static bool Prefix(AssetBundle __instance, ref string name, ref Type type, ref Object __result, ref AssetLoadingContext __state) { AssetLoadingParameters parameters = new AssetLoadingParameters(name, type, AssetLoadType.LoadNamed); __state = ResourceRedirection.Hook_AssetLoading_Prefix(parameters, __instance, ref __result); AssetLoadingParameters parameters2 = __state.Parameters; name = parameters2.Name; type = parameters2.Type; return !__state.SkipOriginalCall; } private static void Postfix(AssetBundle __instance, ref Object __result, ref AssetLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __instance, ref __result); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object MM_Detour(AssetBundle __instance, string name, Type type) { Object __result = null; AssetLoadingContext __state = null; if (Prefix(__instance, ref name, ref type, ref __result, ref __state)) { __result = _original(__instance, name, type); } Postfix(__instance, ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadAssetAsync_Internal_Hook { private delegate AssetBundleRequest OriginalMethod(AssetBundle __instance, string name, Type type); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadAssetAsync_Internal", new Type[2] { typeof(string), typeof(Type) }); } private static bool Prefix(AssetBundle __instance, ref string name, ref Type type, ref AssetBundleRequest __result, ref AsyncAssetLoadingContext __state) { AssetLoadingParameters parameters = new AssetLoadingParameters(name, type, AssetLoadType.LoadNamed); __state = ResourceRedirection.Hook_AsyncAssetLoading_Prefix(parameters, __instance, ref __result); AssetLoadingParameters parameters2 = __state.Parameters; name = parameters2.Name; type = parameters2.Type; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundleRequest __result, ref AsyncAssetLoadingContext __state) { ResourceRedirection.Hook_AssetLoading_Postfix(__state, __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundleRequest MM_Detour(AssetBundle __instance, string name, Type type) { AssetBundleRequest __result = null; AsyncAssetLoadingContext __state = null; if (Prefix(__instance, ref name, ref type, ref __result, ref __state)) { __result = _original(__instance, name, type); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadAssetWithSubAssets_Internal_Hook { private delegate Object[] OriginalMethod(AssetBundle __instance, string name, Type type); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadAssetWithSubAssets_Internal", new Type[2] { typeof(string), typeof(Type) }); } private static bool Prefix(AssetBundle __instance, ref string name, ref Type type, ref Object[] __result, ref AssetLoadingContext __state) { if (name == string.Empty) { AssetLoadingParameters parameters = new AssetLoadingParameters(null, type, AssetLoadType.LoadByType); __state = ResourceRedirection.Hook_AssetLoading_Prefix(parameters, __instance, ref __result); } else { AssetLoadingParameters parameters2 = new AssetLoadingParameters(name, type, AssetLoadType.LoadNamedWithSubAssets); __state = ResourceRedirection.Hook_AssetLoading_Prefix(parameters2, __instance, ref __result); } AssetLoadingParameters parameters3 = __state.Parameters; name = parameters3.Name; type = parameters3.Type; return !__state.SkipOriginalCall; } private static void Postfix(AssetBundle __instance, ref Object[] __result, ref AssetLoadingContext __state) { if (!__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __instance, ref __result); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object[] MM_Detour(AssetBundle __instance, string name, Type type) { Object[] __result = null; AssetLoadingContext __state = null; if (Prefix(__instance, ref name, ref type, ref __result, ref __state)) { __result = _original(__instance, name, type); } Postfix(__instance, ref __result, ref __state); return __result; } } internal static class AssetBundle_LoadAssetWithSubAssetsAsync_Internal_Hook { private delegate AssetBundleRequest OriginalMethod(AssetBundle __instance, string name, Type type); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundle != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundle = UnityTypes.AssetBundle; return AccessToolsShim.Method((assetBundle != null) ? assetBundle.ClrType : null, "LoadAssetWithSubAssetsAsync_Internal", new Type[2] { typeof(string), typeof(Type) }); } private static bool Prefix(AssetBundle __instance, ref string name, ref Type type, ref AssetBundleRequest __result, ref AsyncAssetLoadingContext __state) { if (name == string.Empty) { AssetLoadingParameters parameters = new AssetLoadingParameters(null, type, AssetLoadType.LoadByType); __state = ResourceRedirection.Hook_AsyncAssetLoading_Prefix(parameters, __instance, ref __result); } else { AssetLoadingParameters parameters2 = new AssetLoadingParameters(name, type, AssetLoadType.LoadNamedWithSubAssets); __state = ResourceRedirection.Hook_AsyncAssetLoading_Prefix(parameters2, __instance, ref __result); } AssetLoadingParameters parameters3 = __state.Parameters; name = parameters3.Name; type = parameters3.Type; return !__state.SkipOriginalCall; } private static void Postfix(ref AssetBundleRequest __result, ref AsyncAssetLoadingContext __state) { ResourceRedirection.Hook_AssetLoading_Postfix(__state, __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static AssetBundleRequest MM_Detour(AssetBundle __instance, string name, Type type) { AssetBundleRequest __result = null; AsyncAssetLoadingContext __state = null; if (Prefix(__instance, ref name, ref type, ref __result, ref __state)) { __result = _original(__instance, name, type); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundleRequest_asset_Hook { private delegate Object OriginalMethod(AssetBundleRequest __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AssetBundleRequest != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundleRequest = UnityTypes.AssetBundleRequest; return AccessToolsShim.Property((assetBundleRequest != null) ? assetBundleRequest.ClrType : null, "asset")?.GetGetMethod(); } private static bool Prefix(AssetBundleRequest __instance, ref Object __result, ref AsyncAssetLoadInfo __state) { if (ResourceRedirection.TryGetAssetBundleLoadInfo(__instance, out __state)) { if (__state.ResolveType == AsyncAssetLoadingResolve.ThroughAssets) { Object[] assets = __state.Assets; if (assets != null && assets.Length != 0) { __result = assets[0]; } return false; } return true; } return true; } private static void Postfix(ref Object __result, ref AsyncAssetLoadInfo __state) { if (__state != null && !__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __state.Bundle, ref __result); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object MM_Detour(AssetBundleRequest __instance) { Object __result = null; AsyncAssetLoadInfo __state = null; if (Prefix(__instance, ref __result, ref __state)) { __result = _original(__instance); } Postfix(ref __result, ref __state); return __result; } } internal static class AssetBundleRequest_allAssets_Hook { private delegate Object[] OriginalMethod(AssetBundleRequest __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { TypeContainer assetBundleRequest = UnityTypes.AssetBundleRequest; return (object)AccessToolsShim.Property((assetBundleRequest != null) ? assetBundleRequest.ClrType : null, "allAssets") != null; } private static MethodBase TargetMethod(object instance) { TypeContainer assetBundleRequest = UnityTypes.AssetBundleRequest; return AccessToolsShim.Property((assetBundleRequest != null) ? assetBundleRequest.ClrType : null, "allAssets")?.GetGetMethod(); } private static bool Prefix(AssetBundleRequest __instance, ref Object[] __result, ref AsyncAssetLoadInfo __state) { if (ResourceRedirection.TryGetAssetBundleLoadInfo(__instance, out __state)) { if (__state.ResolveType == AsyncAssetLoadingResolve.ThroughAssets) { __result = __state.Assets; return false; } return true; } return true; } private static void Postfix(ref Object[] __result, ref AsyncAssetLoadInfo __state) { if (__state != null && !__state.SkipAllPostfixes) { ResourceRedirection.Hook_AssetLoaded_Postfix(__state.Parameters, __state.Bundle, ref __result); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object[] MM_Detour(AssetBundleRequest __instance) { Object[] __result = null; AsyncAssetLoadInfo __state = null; if (Prefix(__instance, ref __result, ref __state)) { __result = _original(__instance); } Postfix(ref __result, ref __state); return __result; } } internal static class Resources_Load_Hook { private delegate Object OriginalMethod(string path, Type systemTypeInstance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.Resources != null; } private static MethodBase TargetMethod(object instance) { TypeContainer resources = UnityTypes.Resources; return AccessToolsShim.Method((resources != null) ? resources.ClrType : null, "Load", new Type[2] { typeof(string), typeof(Type) }); } private static void Postfix(string __0, Type __1, ref Object __result) { ResourceRedirection.Hook_ResourceLoaded_Postfix(new ResourceLoadedParameters(__0, __1, ResourceLoadType.LoadNamed), ref __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object MM_Detour(string path, Type systemTypeInstance) { Object __result = _original(path, systemTypeInstance); Postfix(path, systemTypeInstance, ref __result); return __result; } } internal static class Resources_LoadAll_Hook { private delegate Object[] OriginalMethod(string path, Type systemTypeInstance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.Resources != null; } private static MethodBase TargetMethod(object instance) { TypeContainer resources = UnityTypes.Resources; return AccessToolsShim.Method((resources != null) ? resources.ClrType : null, "LoadAll", new Type[2] { typeof(string), typeof(Type) }); } private static void Postfix(string __0, Type __1, ref Object[] __result) { ResourceRedirection.Hook_ResourceLoaded_Postfix(new ResourceLoadedParameters(__0, __1, ResourceLoadType.LoadByType), ref __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object[] MM_Detour(string path, Type systemTypeInstance) { Object[] __result = _original(path, systemTypeInstance); Postfix(path, systemTypeInstance, ref __result); return __result; } } internal static class Resources_GetBuiltinResource_Old_Hook { private delegate Object OriginalMethod(string path, Type systemTypeInstance); private static OriginalMethod _original; private static bool Prepare(object instance) { TypeContainer resources = UnityTypes.Resources; return (object)AccessToolsShim.Method((resources != null) ? resources.ClrType : null, "GetBuiltinResource", new Type[2] { typeof(Type), typeof(string) }) == null; } private static MethodBase TargetMethod(object instance) { TypeContainer resources = UnityTypes.Resources; return AccessToolsShim.Method((resources != null) ? resources.ClrType : null, "GetBuiltinResource", new Type[2] { typeof(string), typeof(Type) }); } private static void Postfix(string __0, Type __1, ref Object __result) { ResourceRedirection.Hook_ResourceLoaded_Postfix(new ResourceLoadedParameters(__0, __1, ResourceLoadType.LoadNamedBuiltIn), ref __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object MM_Detour(string path, Type systemTypeInstance) { Object __result = _original(path, systemTypeInstance); Postfix(path, systemTypeInstance, ref __result); return __result; } } internal static class Resources_GetBuiltinResource_New_Hook { private delegate Object OriginalMethod(Type systemTypeInstance, string path); private static OriginalMethod _original; private static bool Prepare(object instance) { TypeContainer resources = UnityTypes.Resources; return (object)AccessToolsShim.Method((resources != null) ? resources.ClrType : null, "GetBuiltinResource", new Type[2] { typeof(string), typeof(Type) }) == null; } private static MethodBase TargetMethod(object instance) { TypeContainer resources = UnityTypes.Resources; return AccessToolsShim.Method((resources != null) ? resources.ClrType : null, "GetBuiltinResource", new Type[2] { typeof(Type), typeof(string) }); } private static void Postfix(Type __0, string __1, ref Object __result) { ResourceRedirection.Hook_ResourceLoaded_Postfix(new ResourceLoadedParameters(__1, __0, ResourceLoadType.LoadNamedBuiltIn), ref __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Object MM_Detour(Type systemTypeInstance, string path) { Object __result = _original(systemTypeInstance, path); Postfix(systemTypeInstance, path, ref __result); return __result; } } internal static class AsyncOperation_isDone_Hook { private delegate bool OriginalMethod(AsyncOperation __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AsyncOperation != null; } private static MethodBase TargetMethod(object instance) { TypeContainer asyncOperation = UnityTypes.AsyncOperation; return AccessToolsShim.Property((asyncOperation != null) ? asyncOperation.ClrType : null, "isDone")?.GetGetMethod(); } private static bool Prefix(AsyncOperation __instance, ref bool __result) { if (ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance)) { __result = true; return false; } return true; } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static bool MM_Detour(AsyncOperation __instance) { bool __result = false; if (Prefix(__instance, ref __result)) { __result = _original(__instance); } return __result; } } internal static class AsyncOperation_progress_Hook { private delegate float OriginalMethod(AsyncOperation __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AsyncOperation != null; } private static MethodBase TargetMethod(object instance) { TypeContainer asyncOperation = UnityTypes.AsyncOperation; return AccessToolsShim.Property((asyncOperation != null) ? asyncOperation.ClrType : null, "progress")?.GetGetMethod(); } private static bool Prefix(AsyncOperation __instance, ref float __result) { if (ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance)) { __result = 1f; return false; } return true; } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static float MM_Detour(AsyncOperation __instance) { float __result = 0f; if (Prefix(__instance, ref __result)) { __result = _original(__instance); } return __result; } } internal static class AsyncOperation_priority_Hook { private delegate int OriginalMethod(AsyncOperation __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AsyncOperation != null; } private static MethodBase TargetMethod(object instance) { TypeContainer asyncOperation = UnityTypes.AsyncOperation; return AccessToolsShim.Property((asyncOperation != null) ? asyncOperation.ClrType : null, "priority")?.GetGetMethod(); } private static bool Prefix(AsyncOperation __instance, ref int __result) { if (ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance)) { __result = 0; return false; } return true; } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static int MM_Detour(AsyncOperation __instance) { int __result = 0; if (Prefix(__instance, ref __result)) { __result = _original(__instance); } return __result; } } internal static class AsyncOperation_set_priority_Hook { private delegate void OriginalMethod(AsyncOperation __instance, int value); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AsyncOperation != null; } private static MethodBase TargetMethod(object instance) { TypeContainer asyncOperation = UnityTypes.AsyncOperation; return AccessToolsShim.Property((asyncOperation != null) ? asyncOperation.ClrType : null, "priority")?.GetSetMethod(); } private static bool Prefix(AsyncOperation __instance) { return !ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static void MM_Detour(AsyncOperation __instance, int value) { if (Prefix(__instance)) { _original(__instance, value); } } } internal static class AsyncOperation_allowSceneActivation_Hook { private delegate bool OriginalMethod(AsyncOperation __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AsyncOperation != null; } private static MethodBase TargetMethod(object instance) { TypeContainer asyncOperation = UnityTypes.AsyncOperation; return AccessToolsShim.Property((asyncOperation != null) ? asyncOperation.ClrType : null, "allowSceneActivation")?.GetGetMethod(); } private static bool Prefix(AsyncOperation __instance, ref bool __result) { if (ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance)) { __result = true; return false; } return true; } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static bool MM_Detour(AsyncOperation __instance) { bool __result = false; if (Prefix(__instance, ref __result)) { __result = _original(__instance); } return __result; } } internal static class AsyncOperation_set_allowSceneActivation_Hook { private delegate void OriginalMethod(AsyncOperation __instance, bool value); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AsyncOperation != null; } private static MethodBase TargetMethod(object instance) { TypeContainer asyncOperation = UnityTypes.AsyncOperation; return AccessToolsShim.Property((asyncOperation != null) ? asyncOperation.ClrType : null, "allowSceneActivation")?.GetSetMethod(); } private static bool Prefix(AsyncOperation __instance) { return !ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static void MM_Detour(AsyncOperation __instance, bool value) { if (Prefix(__instance)) { _original(__instance, value); } } } internal static class AsyncOperation_Finalize_Hook { private delegate void OriginalMethod(AsyncOperation __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.AsyncOperation != null; } private static MethodBase TargetMethod(object instance) { TypeContainer asyncOperation = UnityTypes.AsyncOperation; if (asyncOperation == null) { return null; } return asyncOperation.ClrType.GetMethod("Finalize", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic); } private static bool Prefix(AsyncOperation __instance) { return !ResourceRedirection.ShouldBlockAsyncOperationMethods(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static void MM_Detour(AsyncOperation __instance) { if (Prefix(__instance)) { _original(__instance); } } } } namespace XUnity.ResourceRedirector.Examples { internal class TextureReplacementPlugin { private void Awake() { ResourceRedirection.RegisterAssetLoadedHook(HookBehaviour.OneCallbackPerResourceLoaded, 0, AssetLoaded); } public void AssetLoaded(AssetLoadedContext context) { Object asset = context.Asset; Texture2D val = (Texture2D)(object)((asset is Texture2D) ? asset : null); if (val != null) { context.Asset = (Object)(object)val; context.Complete(); } } } internal class AssetBundleRedirectorPlugin { private class AssetBundleRedirectorSyncOverAsyncPlugin { private void Awake() { ResourceRedirection.EnableSyncOverAsyncAssetLoads(); ResourceRedirection.RegisterAsyncAndSyncAssetBundleLoadingHook(1000, AssetBundleLoading); } public void AssetBundleLoading(IAssetBundleLoadingContext context) { if (!File.Exists(context.Parameters.Path)) { string normalizedPath = context.GetNormalizedPath(); string text = Path.Combine("mods", normalizedPath); if (File.Exists(text)) { AssetBundle bundle = AssetBundle.LoadFromFile(text); context.Bundle = bundle; context.Complete(skipRemainingPrefixes: true, true); } } } } private class SmartAssetBundleRedirectorSyncOverAsyncPlugin { private void Awake() { ResourceRedirection.EnableSyncOverAsyncAssetLoads(); ResourceRedirection.RegisterAsyncAndSyncAssetBundleLoadingHook(1000, AssetBundleLoading); } public void AssetBundleLoading(IAssetBundleLoadingContext context) { if (File.Exists(context.Parameters.Path)) { return; } string normalizedPath = context.GetNormalizedPath(); string text = Path.Combine("mods", normalizedPath); if (File.Exists(text)) { if (context is AsyncAssetBundleLoadingContext asyncAssetBundleLoadingContext) { AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(text); asyncAssetBundleLoadingContext.Request = request; } else { AssetBundle bundle = AssetBundle.LoadFromFile(text); context.Bundle = bundle; } context.Complete(skipRemainingPrefixes: true, true); } } } private void Awake() { ResourceRedirection.RegisterAssetBundleLoadingHook(1000, AssetBundleLoading); ResourceRedirection.RegisterAsyncAssetBundleLoadingHook(1000, AsyncAssetBundleLoading); } public void AssetBundleLoading(AssetBundleLoadingContext context) { if (!File.Exists(context.Parameters.Path)) { string normalizedPath = context.GetNormalizedPath(); string text = Path.Combine("mods", normalizedPath); if (File.Exists(text)) { AssetBundle bundle = AssetBundle.LoadFromFile(text); context.Bundle = bundle; context.Complete(skipRemainingPrefixes: true, true); } } } public void AsyncAssetBundleLoading(AsyncAssetBundleLoadingContext context) { if (!File.Exists(context.Parameters.Path)) { string normalizedPath = context.GetNormalizedPath(); string text = Path.Combine("mods", normalizedPath); if (File.Exists(text)) { AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(text); context.Request = request; context.Complete(skipRemainingPrefixes: true, true); } } } } } namespace XUnity.ResourceRedirector.Constants { internal static class EnvironmentEx { internal static readonly string LoweredCurrentDirectory = Paths.GameRoot.ToLowerInvariant(); } public static class PluginData { public const string Identifier = "gravydevsupreme.xunity.resourceredirector"; public const string Name = "XUnity Resource Redirector"; public const string Version = "2.1.0"; } }