0
0
mirror of https://github.com/sp-tarkov/modules.git synced 2025-02-13 05:30:43 -05:00
modules/project/SPT.Custom/Utils/EasyBundleHelper.cs
2024-05-21 19:10:17 +01:00

137 lines
4.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using SPT.Reflection.Utils;
using UnityEngine;
using BindableState = BindableState<Diz.DependencyManager.ELoadState>;
namespace SPT.Custom.Utils
{
public class EasyBundleHelper
{
private const BindingFlags NonPublicInstanceFlags = BindingFlags.Instance | BindingFlags.NonPublic;
private static readonly FieldInfo _pathField;
private static readonly FieldInfo _keyWithoutExtensionField;
private static readonly FieldInfo _bundleLockField;
private static readonly PropertyInfo _dependencyKeysProperty;
private static readonly PropertyInfo _keyProperty;
private static readonly PropertyInfo _loadStateProperty;
private static readonly MethodInfo _loadingCoroutineMethod;
private readonly object _instance;
public static readonly Type Type;
static EasyBundleHelper()
{
_ = nameof(IBundleLock.IsLocked);
_ = nameof(BindableState.Bind);
Type = PatchConstants.EftTypes.SingleCustom(x => !x.IsInterface && x.GetProperty("SameNameAsset", PatchConstants.PublicDeclaredFlags) != null);
_pathField = Type.GetField("string_1", NonPublicInstanceFlags);
_keyWithoutExtensionField = Type.GetField("string_0", NonPublicInstanceFlags);
_bundleLockField = Type.GetFields(NonPublicInstanceFlags).FirstOrDefault(x => x.FieldType == typeof(IBundleLock));
_dependencyKeysProperty = Type.GetProperty("DependencyKeys");
_keyProperty = Type.GetProperty("Key");
_loadStateProperty = Type.GetProperty("LoadState");
// Function with 0 params and returns task (usually method_0())
var possibleMethods = Type.GetMethods(PatchConstants.PublicDeclaredFlags).Where(x => x.GetParameters().Length == 0 && x.ReturnType == typeof(Task)).ToArray();
if (possibleMethods.Length > 1)
{
throw new Exception($"Unable to find the Loading Coroutine method as there are multiple possible matches: {string.Join(",", possibleMethods.Select(x => x.Name))}");
}
if (possibleMethods.Length == 0)
{
throw new Exception("Unable to find the Loading Coroutine method as there are no matches");
}
_loadingCoroutineMethod = possibleMethods.Single();
}
public EasyBundleHelper(object easyBundle)
{
_instance = easyBundle;
}
public IEnumerable<string> DependencyKeys
{
get
{
return (IEnumerable<string>)_dependencyKeysProperty.GetValue(_instance);
}
set
{
_dependencyKeysProperty.SetValue(_instance, value);
}
}
public IBundleLock BundleLock
{
get
{
return (IBundleLock)_bundleLockField.GetValue(_instance);
}
set
{
_bundleLockField.SetValue(_instance, value);
}
}
public string Path
{
get
{
return (string)_pathField.GetValue(_instance);
}
set
{
_pathField.SetValue(_instance, value);
}
}
public string Key
{
get
{
return (string)_keyProperty.GetValue(_instance);
}
set
{
_keyProperty.SetValue(_instance, value);
}
}
public BindableState LoadState
{
get
{
return (BindableState)_loadStateProperty.GetValue(_instance);
}
set
{
_loadStateProperty.SetValue(_instance, value);
}
}
public string KeyWithoutExtension
{
get
{
return (string)_keyWithoutExtensionField.GetValue(_instance);
}
set
{
_keyWithoutExtensionField.SetValue(_instance, value);
}
}
public Task LoadingCoroutine(Dictionary<string, AssetBundle> bundles)
{
return (Task)_loadingCoroutineMethod.Invoke(_instance, new object[] { bundles });
}
}
}