0
0
mirror of https://github.com/sp-tarkov/modules.git synced 2025-02-13 09:50:43 -05:00
modules/project/Aki.Custom/Patches/EasyAssetsPatch.cs

156 lines
6.1 KiB
C#
Raw Normal View History

2023-03-03 18:52:31 +00:00
using Aki.Reflection.Patching;
using Diz.Jobs;
using Diz.Resources;
using JetBrains.Annotations;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Build.Pipeline;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Aki.Common.Utils;
2023-03-03 18:52:31 +00:00
using Aki.Custom.Models;
using Aki.Custom.Utils;
using DependencyGraph = DependencyGraph<IEasyBundle>;
using Aki.Reflection.Utils;
2023-03-03 18:52:31 +00:00
namespace Aki.Custom.Patches
{
public class EasyAssetsPatch : ModulePatch
{
private static readonly FieldInfo _bundlesField;
static EasyAssetsPatch()
{
_bundlesField = typeof(EasyAssets).GetField($"{EasyBundleHelper.Type.Name.ToLowerInvariant()}_0", PatchConstants.PrivateFlags);
2023-03-03 18:52:31 +00:00
}
public EasyAssetsPatch()
{
_ = nameof(IEasyBundle.SameNameAsset);
_ = nameof(IBundleLock.IsLocked);
_ = nameof(BundleLock.MaxConcurrentOperations);
_ = nameof(DependencyGraph.GetDefaultNode);
}
protected override MethodBase GetTargetMethod()
{
return typeof(EasyAssets).GetMethods(PatchConstants.PublicDeclaredFlags).SingleCustom(IsTargetMethod);
2023-03-03 18:52:31 +00:00
}
private static bool IsTargetMethod(MethodInfo mi)
{
var parameters = mi.GetParameters();
2023-07-07 15:01:45 +01:00
return (parameters.Length == 6
&& parameters[0].Name == "bundleLock"
&& parameters[1].Name == "defaultKey"
2023-03-03 18:52:31 +00:00
&& parameters[4].Name == "shouldExclude");
}
[PatchPrefix]
private static bool PatchPrefix(ref Task __result, EasyAssets __instance, [CanBeNull] IBundleLock bundleLock, string defaultKey, string rootPath,
string platformName, [CanBeNull] Func<string, bool> shouldExclude, [CanBeNull] Func<string, Task> bundleCheck)
{
__result = Init(__instance, bundleLock, defaultKey, rootPath, platformName, shouldExclude, bundleCheck);
return false;
}
private static async Task Init(EasyAssets instance, [CanBeNull] IBundleLock bundleLock, string defaultKey, string rootPath, string platformName, [CanBeNull] Func<string, bool> shouldExclude, Func<string, Task> bundleCheck)
2023-03-03 18:52:31 +00:00
{
2023-07-20 13:11:09 +01:00
// platform manifest
var path = $"{rootPath.Replace("file:///", string.Empty).Replace("file://", string.Empty)}/{platformName}/";
var filepath = path + platformName;
var jsonfile = filepath + ".json";
var manifest = File.Exists(jsonfile)
? await GetManifestJson(jsonfile)
: await GetManifestBundle(filepath);
// create bundles array from obfuscated type
var bundleNames = manifest.GetAllAssetBundles()
.Union(BundleManager.Bundles.Keys)
.ToArray();
2023-07-20 13:11:09 +01:00
var bundles = (IEasyBundle[])Array.CreateInstance(EasyBundleHelper.Type, bundleNames.Length);
// create bundle lock
2023-07-20 13:11:09 +01:00
if (bundleLock == null)
2023-03-03 18:52:31 +00:00
{
2023-07-20 13:11:09 +01:00
bundleLock = new BundleLock(int.MaxValue);
}
// create bundle of obfuscated type
2023-07-20 13:11:09 +01:00
for (var i = 0; i < bundleNames.Length; i++)
{
bundles[i] = (IEasyBundle)Activator.CreateInstance(EasyBundleHelper.Type, new object[]
{
bundleNames[i],
path,
manifest,
bundleLock,
bundleCheck
});
2023-07-20 13:11:09 +01:00
await JobScheduler.Yield(EJobPriority.Immediate);
}
// create dependency graph
instance.Manifest = manifest;
2023-07-20 13:11:09 +01:00
_bundlesField.SetValue(instance, bundles);
instance.System = new DependencyGraph(bundles, defaultKey, shouldExclude);
2023-03-03 18:52:31 +00:00
}
// NOTE: used by:
// - EscapeFromTarkov_Data/StreamingAssets/Windows/cubemaps
// - EscapeFromTarkov_Data/StreamingAssets/Windows/defaultmaterial
// - EscapeFromTarkov_Data/StreamingAssets/Windows/dissonancesetup
// - EscapeFromTarkov_Data/StreamingAssets/Windows/Doge
// - EscapeFromTarkov_Data/StreamingAssets/Windows/shaders
2023-03-03 18:52:31 +00:00
private static async Task<CompatibilityAssetBundleManifest> GetManifestBundle(string filepath)
{
var manifestLoading = AssetBundle.LoadFromFileAsync(filepath);
await manifestLoading.Await();
var assetBundle = manifestLoading.assetBundle;
var assetLoading = assetBundle.LoadAllAssetsAsync();
await assetLoading.Await();
return (CompatibilityAssetBundleManifest)assetLoading.allAssets[0];
}
private static async Task<CompatibilityAssetBundleManifest> GetManifestJson(string filepath)
{
var text = VFS.ReadTextFile(filepath);
2023-03-03 18:52:31 +00:00
/* we cannot parse directly as <string, BundleDetails>, because...
[Error : Unity Log] JsonSerializationException: Expected string when reading UnityEngine.Hash128 type, got 'StartObject' <>. Path '['assets/content/weapons/animations/simple_animations.bundle'].Hash', line 1, position 176.
...so we need to first convert it to a slimmed-down type (BundleItem), then convert back to BundleDetails.
*/
var raw = JsonConvert.DeserializeObject<Dictionary<string, BundleItem>>(text);
var converted = raw.ToDictionary(GetPairKey, GetPairValue);
2023-03-03 18:52:31 +00:00
// initialize manifest
2023-03-03 18:52:31 +00:00
var manifest = ScriptableObject.CreateInstance<CompatibilityAssetBundleManifest>();
manifest.SetResults(converted);
2023-03-03 18:52:31 +00:00
return manifest;
}
2023-07-20 13:11:09 +01:00
public static string GetPairKey(KeyValuePair<string, BundleItem> x)
2023-03-03 18:52:31 +00:00
{
2023-07-20 13:11:09 +01:00
return x.Key;
}
2023-03-03 18:52:31 +00:00
2023-07-20 13:11:09 +01:00
public static BundleDetails GetPairValue(KeyValuePair<string, BundleItem> x)
{
return new BundleDetails
2023-03-03 18:52:31 +00:00
{
2023-07-20 13:11:09 +01:00
FileName = x.Value.FileName,
Crc = x.Value.Crc,
Dependencies = x.Value.Dependencies
};
2023-03-03 18:52:31 +00:00
}
}
}