From d0635813e5088efd9cc799002001ba190c0cac14 Mon Sep 17 00:00:00 2001 From: flibber-hk <76987839+flibber-hk@users.noreply.github.com> Date: Tue, 27 Jan 2026 21:08:43 +0000 Subject: [PATCH] initial implementation --- AssetHelper/AssetHelper.csproj | 2 +- AssetHelper/Core/BundleMetadata.cs | 5 ++-- .../Plugin/LoadingPage/LoadingScreen.cs | 23 +++++++++++++++ .../Plugin/LoadingPage/MemoryWatcher.cs | 29 +++++++++++++++++++ AssetHelper/Plugin/StartupOverrideManager.cs | 9 ++++++ AssetHelper/packages.lock.json | 6 ++-- 6 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 AssetHelper/Plugin/LoadingPage/MemoryWatcher.cs diff --git a/AssetHelper/AssetHelper.csproj b/AssetHelper/AssetHelper.csproj index c5052cf..649c4a7 100644 --- a/AssetHelper/AssetHelper.csproj +++ b/AssetHelper/AssetHelper.csproj @@ -71,7 +71,7 @@ - + diff --git a/AssetHelper/Core/BundleMetadata.cs b/AssetHelper/Core/BundleMetadata.cs index ed6a0e6..2a4fb2d 100644 --- a/AssetHelper/Core/BundleMetadata.cs +++ b/AssetHelper/Core/BundleMetadata.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using AssetHelperLib.IO; using AssetsTools.NET; using AssetsTools.NET.Extra; using Silksong.AssetHelper.Internal; @@ -113,8 +114,8 @@ internal static List DetermineDirectDepsInternal(string bundleName, out AssetsManager mgr = new(); string sceneBundlePath = Path.Combine(AssetPaths.BundleFolder, bundleFile); - using MemoryStream ms = new(File.ReadAllBytes(sceneBundlePath)); - BundleFileInstance bun = mgr.LoadBundleFile(ms, sceneBundlePath); + using RentedFileArray rfa = new(sceneBundlePath); + BundleFileInstance bun = mgr.LoadBundleFile(rfa.Stream, sceneBundlePath); AssetsFileInstance afileInst = mgr.LoadAssetsFileFromBundle(bun, 0, false); AssetsFile afile = afileInst.file; diff --git a/AssetHelper/Plugin/LoadingPage/LoadingScreen.cs b/AssetHelper/Plugin/LoadingPage/LoadingScreen.cs index 485df11..d3c3772 100644 --- a/AssetHelper/Plugin/LoadingPage/LoadingScreen.cs +++ b/AssetHelper/Plugin/LoadingPage/LoadingScreen.cs @@ -108,6 +108,29 @@ void Awake() subtextRect.anchoredPosition = new Vector2(0, -45); } +#if DEBUG + { + GameObject memTextObj = new("MemText"); + memTextObj.transform.SetParent(_canvasObject.transform); + Text _memText = memTextObj.AddComponent(); + + _memText.font = Resources.GetBuiltinResource("Arial.ttf"); + _memText.text = string.Empty; + _memText.fontSize = 20; + _memText.alignment = TextAnchor.MiddleCenter; + _memText.color = Color.white; + + RectTransform memtextRect = _memText.rectTransform; + memtextRect.anchorMin = new Vector2(0.5f, 0.5f); + memtextRect.anchorMax = new Vector2(0.5f, 0.5f); + memtextRect.pivot = new Vector2(0.5f, 1f); + memtextRect.sizeDelta = new Vector2(800, 100); + memtextRect.anchoredPosition = new Vector2(0, -90); + + memTextObj.AddComponent(); + } +#endif + // For testing _statusText.text = "Loading..."; } diff --git a/AssetHelper/Plugin/LoadingPage/MemoryWatcher.cs b/AssetHelper/Plugin/LoadingPage/MemoryWatcher.cs new file mode 100644 index 0000000..121c2bb --- /dev/null +++ b/AssetHelper/Plugin/LoadingPage/MemoryWatcher.cs @@ -0,0 +1,29 @@ +using System; +using UnityEngine; +using UnityEngine.UI; + +namespace Silksong.AssetHelper.Plugin.LoadingPage; + + +/// +/// Unscientific class to watch memory usage. +/// +[RequireComponent(typeof(Text))] +internal class MemoryWatcher : MonoBehaviour +{ + private long maxSoFar = 0; + + private Text _text; + + void Awake() + { + _text = GetComponent(); + } + + void Update() + { + long mem = GC.GetTotalMemory(forceFullCollection: false); + maxSoFar = mem > maxSoFar ? mem : maxSoFar; + _text.text = $"Memory: {mem:E}\nMax {maxSoFar:E}"; + } +} diff --git a/AssetHelper/Plugin/StartupOverrideManager.cs b/AssetHelper/Plugin/StartupOverrideManager.cs index ce61a8d..def8d8e 100644 --- a/AssetHelper/Plugin/StartupOverrideManager.cs +++ b/AssetHelper/Plugin/StartupOverrideManager.cs @@ -1,6 +1,8 @@ using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; +using AssetHelperLib.IO; using MonoDetour.HookGen; using Silksong.AssetHelper.Core; using Silksong.AssetHelper.Plugin.LoadingPage; @@ -43,6 +45,9 @@ private static IEnumerator WrapStartManagerStart(StartManager self, IEnumerator // This should already be the case, but we should check just in case it matters. yield return new WaitUntil(() => AddressablesData.IsAddressablesLoaded); + // Assign the shared array pool for IO at the start of the procedure + RentedFileArray.Pool = ArrayPool.Create(250 * 1024 * 1024, 5); + LoadingScreen screen = LoadingScreenExtensions.Create(); bool failed = false; @@ -98,6 +103,10 @@ private static IEnumerator WrapStartManagerStart(StartManager self, IEnumerator // Even if there was an error, still let them into the game normally UObject.Destroy(screen); + + // Clear the pool now that it's no longer in use; in theory the GC can reclaim it/when if it wants. + RentedFileArray.Pool = null; + yield return null; yield return original; diff --git a/AssetHelper/packages.lock.json b/AssetHelper/packages.lock.json index e1d4f48..7901cb8 100644 --- a/AssetHelper/packages.lock.json +++ b/AssetHelper/packages.lock.json @@ -4,9 +4,9 @@ ".NETStandard,Version=v2.1": { "AssetHelperLib": { "type": "Direct", - "requested": "[0.10.1, )", - "resolved": "0.10.1", - "contentHash": "qRX+I2d6T0WVcJrxPV7bBlGD37B1Eg5GAo36+72lXOJqgHjhnJrgOcnqtwm9vRaOaBfnzMV3f8+myTioLeT9cw==" + "requested": "[0.11.0, )", + "resolved": "0.11.0", + "contentHash": "1YIHnp3S+gBLa1NzFTtSmMFA+zT7D0mCgCPqPhVa4pv5CKpJQgSiZPeiRxzMDvDMK0sdGa6O6/Uuh1pPIrBYlw==" }, "AssetsTools.NET": { "type": "Direct",