From af1daafb9627e59d721ef32041b1e0a2f8f1f03e Mon Sep 17 00:00:00 2001
From: Chloe Christley <734133+chloelcdev@users.noreply.github.com>
Date: Sun, 27 Apr 2025 14:07:11 -0400
Subject: [PATCH 01/16] Add Dependencies for AssetBundle things
(MelonLoaderAssembliesPath) \UnityEngine.Il2CppAssetBundleManager.dll
(MonoAssembliesPath) \UnityEngine.AssetBundleModule.dll
---
S1API/S1API.csproj | 1 +
1 file changed, 1 insertion(+)
diff --git a/S1API/S1API.csproj b/S1API/S1API.csproj
index a28f1c2d..f9460115 100644
--- a/S1API/S1API.csproj
+++ b/S1API/S1API.csproj
@@ -41,6 +41,7 @@
+
From 064053b261a1333ab4ed0d876de2165fc8d0e0df Mon Sep 17 00:00:00 2001
From: Chloe Christley <734133+chloelcdev@users.noreply.github.com>
Date: Sun, 27 Apr 2025 14:09:00 -0400
Subject: [PATCH 02/16] Create AssetBundleHelper.cs
---
S1API/AssetBundles/AssetBundleHelper.cs | 54 +++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 S1API/AssetBundles/AssetBundleHelper.cs
diff --git a/S1API/AssetBundles/AssetBundleHelper.cs b/S1API/AssetBundles/AssetBundleHelper.cs
new file mode 100644
index 00000000..9bc95837
--- /dev/null
+++ b/S1API/AssetBundles/AssetBundleHelper.cs
@@ -0,0 +1,54 @@
+using System;
+using System.IO;
+using System.Reflection;
+using UnityEngine;
+
+
+namespace S1API.AssetBundles
+{
+
+ public static class AssetBundleHelper
+ {
+#if IL2CPP
+ ///
+ /// Loads an Il2Cpp AssetBundle from an embedded resource stream by name.
+ ///
+ /// The full embedded resource name (including namespace path).
+ /// The loaded Il2CppAssetBundle, or throws on failure.
+ public static Il2CppAssetBundle GetAssetBundleFromStream(string resourceName)
+ {
+ // Attempt to find the embedded resource in the executing assembly
+ var assembly = Assembly.GetExecutingAssembly();
+ using (Stream stream = assembly.GetManifestResourceStream(resourceName))
+ {
+ if (stream == null)
+ throw new Exception($"Embedded resource '{resourceName}' not found in {assembly.FullName}."); // hoping these throws will be melon/bepinex-agnostic
+
+ // Read the stream into a byte array
+ byte[] data = new byte[stream.Length];
+ stream.Read(data, 0, data.Length);
+
+ // Load the AssetBundle from memory
+ var bundle = Il2CppAssetBundleManager.LoadFromMemory(data);
+ if (bundle == null)
+ throw new Exception($"Failed to load AssetBundle from memory: {resourceName}");
+
+ return bundle;
+ }
+ }
+#else
+ public static AssetBundle GetAssetBundleFromStream(string resourceName)
+ {
+ // Attempt to find the embedded resource in the executing assembly
+ var assembly = Assembly.GetExecutingAssembly();
+
+ var stream = assembly.GetManifestResourceStream(resourceName);
+
+ return AssetBundle.LoadFromStream(stream);
+ }
+#endif
+
+
+ }
+
+}
From b60479f030b8ac8f5b89ff6984af4e0393274d4d Mon Sep 17 00:00:00 2001
From: Chloe Christley <734133+chloelcdev@users.noreply.github.com>
Date: Sun, 27 Apr 2025 12:25:20 -0400
Subject: [PATCH 03/16] Turned AssetBundleHelper into AssetLoader, added
WrappedAssetBundle
also added WrappedAssetBundleRequest
---
S1API/AssetBundles/AssetBundleHelper.cs | 54 -------
S1API/AssetBundles/AssetLoader.cs | 94 +++++++++++
S1API/AssetBundles/WrappedAssetBundle.cs | 192 +++++++++++++++++++++++
3 files changed, 286 insertions(+), 54 deletions(-)
delete mode 100644 S1API/AssetBundles/AssetBundleHelper.cs
create mode 100644 S1API/AssetBundles/AssetLoader.cs
create mode 100644 S1API/AssetBundles/WrappedAssetBundle.cs
diff --git a/S1API/AssetBundles/AssetBundleHelper.cs b/S1API/AssetBundles/AssetBundleHelper.cs
deleted file mode 100644
index 9bc95837..00000000
--- a/S1API/AssetBundles/AssetBundleHelper.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System;
-using System.IO;
-using System.Reflection;
-using UnityEngine;
-
-
-namespace S1API.AssetBundles
-{
-
- public static class AssetBundleHelper
- {
-#if IL2CPP
- ///
- /// Loads an Il2Cpp AssetBundle from an embedded resource stream by name.
- ///
- /// The full embedded resource name (including namespace path).
- /// The loaded Il2CppAssetBundle, or throws on failure.
- public static Il2CppAssetBundle GetAssetBundleFromStream(string resourceName)
- {
- // Attempt to find the embedded resource in the executing assembly
- var assembly = Assembly.GetExecutingAssembly();
- using (Stream stream = assembly.GetManifestResourceStream(resourceName))
- {
- if (stream == null)
- throw new Exception($"Embedded resource '{resourceName}' not found in {assembly.FullName}."); // hoping these throws will be melon/bepinex-agnostic
-
- // Read the stream into a byte array
- byte[] data = new byte[stream.Length];
- stream.Read(data, 0, data.Length);
-
- // Load the AssetBundle from memory
- var bundle = Il2CppAssetBundleManager.LoadFromMemory(data);
- if (bundle == null)
- throw new Exception($"Failed to load AssetBundle from memory: {resourceName}");
-
- return bundle;
- }
- }
-#else
- public static AssetBundle GetAssetBundleFromStream(string resourceName)
- {
- // Attempt to find the embedded resource in the executing assembly
- var assembly = Assembly.GetExecutingAssembly();
-
- var stream = assembly.GetManifestResourceStream(resourceName);
-
- return AssetBundle.LoadFromStream(stream);
- }
-#endif
-
-
- }
-
-}
diff --git a/S1API/AssetBundles/AssetLoader.cs b/S1API/AssetBundles/AssetLoader.cs
new file mode 100644
index 00000000..4f0da8da
--- /dev/null
+++ b/S1API/AssetBundles/AssetLoader.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+using System.Reflection;
+using UnityEngine;
+
+namespace S1API.AssetBundles
+{
+
+ public static class AssetLoader
+ {
+#if IL2CPP
+ ///
+ /// Loads an Il2Cpp AssetBundle from an embedded resource stream by name.
+ ///
+ /// The full embedded resource name (including namespace path).
+ /// The loaded Il2CppAssetBundle, or throws on failure.
+ public static WrappedAssetBundle GetAssetBundleFromStream(string fullResourceName)
+ {
+ try
+ {
+ // Attempt to find the embedded resource in the executing assembly
+ var assembly = Assembly.GetExecutingAssembly();
+ using (Stream stream = assembly.GetManifestResourceStream(fullResourceName))
+ {
+ if (stream == null)
+ throw new Exception($"Embedded resource '{fullResourceName}' not found in {assembly.FullName}."); // hoping these throws will be melon/bepinex-agnostic
+
+ // Read the stream into a byte array
+ byte[] data = new byte[stream.Length];
+ stream.Read(data, 0, data.Length);
+
+ // Load the AssetBundle from memory
+ Il2CppAssetBundle bundle = Il2CppAssetBundleManager.LoadFromMemory(data);
+ if (bundle == null)
+ throw new Exception($"Failed to load AssetBundle from memory: {fullResourceName}");
+
+ return new(bundle);
+ }
+ }
+ catch (Exception ex)
+ {
+ // Handle exceptions as needed
+ Debug.LogError($"Error loading AssetBundle from stream: {ex.Message}");
+ throw;
+ }
+ }
+#else
+ public static WrappedAssetBundle GetAssetBundleFromStream(string fullResourceName)
+ {
+ // Attempt to find the embedded resource in the executing assembly
+ var assembly = Assembly.GetExecutingAssembly();
+
+ var stream = assembly.GetManifestResourceStream(fullResourceName);
+
+ return new(AssetBundle.LoadFromStream(stream));
+ }
+#endif
+
+ ///
+ ///
+ /// No need to type the assembly just the path stuff.
+ ///
+ /// Example if carassetbundle is in subfolder /bundles/:
+ ///
+ /// GameObject myCar = Instantiate(EasyLoad("bundles.carassetbundle", "MyCarGameObject"));
+ ///
+ ///
+ public static T EasyLoad(string bundle_name, string object_name) where T : UnityEngine.Object
+ {
+ return EasyLoad(bundle_name, object_name, Assembly.GetExecutingAssembly(), out _);
+ }
+
+ public static T EasyLoad(string bundle_name, string object_name, out WrappedAssetBundle bundle) where T : UnityEngine.Object
+ {
+ return EasyLoad(bundle_name, object_name, Assembly.GetExecutingAssembly(), out bundle);
+ }
+
+ public static T EasyLoad(string bundle_name, string object_name, Assembly assemblyOverride) where T : UnityEngine.Object
+ {
+ return EasyLoad(bundle_name, object_name, assemblyOverride, out _);
+ }
+
+ public static T EasyLoad(string bundle_name, string object_name, Assembly assemblyOverride, out WrappedAssetBundle bundle) where T : UnityEngine.Object
+ {
+ // Get the asset bundle from the assembly
+ bundle = GetAssetBundleFromStream($"{assemblyOverride.GetName().Name}.{bundle_name}");
+
+ // Load the asset from the bundle
+ return bundle.LoadAsset(object_name);
+ }
+
+ }
+
+}
diff --git a/S1API/AssetBundles/WrappedAssetBundle.cs b/S1API/AssetBundles/WrappedAssetBundle.cs
new file mode 100644
index 00000000..bc5cbcfc
--- /dev/null
+++ b/S1API/AssetBundles/WrappedAssetBundle.cs
@@ -0,0 +1,192 @@
+using UnityEngine;
+
+#if IL2CPP
+using Type = Il2CppSystem.Type;
+using AssetBundle = UnityEngine.Il2CppAssetBundle;
+using AssetBundleRequest = UnityEngine.Il2CppAssetBundleRequest;
+#endif
+
+
+namespace S1API.AssetBundles
+{
+
+ ///
+ /// Works just like the AssetBundle type, it's just a proxy, but will use Il2CppAssetBundle if it needs to so you don't have to worry about it.
+ ///
+ public class WrappedAssetBundle
+ {
+ public bool isStreamedAssetBundle => _realBundle.isStreamedSceneAssetBundle;
+
+ public Object mainAsset => _realBundle.mainAsset;
+
+
+ public AssetBundle _realBundle;
+
+ public WrappedAssetBundle(AssetBundle realBundle)
+ {
+ _realBundle = realBundle;
+ }
+
+
+ public bool Contains(string name)
+ {
+ return _realBundle.Contains(name);
+ }
+
+ public string[] AllAssetNames()
+ {
+ return GetAllAssetNames();
+ }
+
+ public string[] GetAllAssetNames()
+ {
+ return _realBundle.GetAllAssetNames();
+ }
+
+ public string[] AllScenePaths()
+ {
+ return GetAllScenePaths();
+ }
+
+ public string[] GetAllScenePaths()
+ {
+ return _realBundle.GetAllScenePaths();
+ }
+
+ public Object Load(string name)
+ {
+ return LoadAsset(name);
+ }
+
+ public Object LoadAsset(string name)
+ {
+ return this.LoadAsset