From 4e771ef41bcd03fe2e33c7185b8a6627c9eec9c3 Mon Sep 17 00:00:00 2001
From: ds5678 <49847914+ds5678@users.noreply.github.com>
Date: Sat, 31 May 2025 22:41:36 -0700
Subject: [PATCH] Ensure scriptable objects with an empty name get exported *
Resolves #1795 * Resolves #831 * Closes #1069
---
.../ExportHandler.cs | 7 +--
.../Project/ScriptableObjectExporter.cs | 7 ++-
.../Prefabs/SceneHierarchyObject.cs | 2 +-
.../Scenes/SceneHelpers.cs | 2 +-
.../MonoBehaviourExtensions.cs | 9 +---
.../UnityVersionExtensions.cs | 9 ++++
Source/AssetRipper.Tests/ExportTests.cs | 54 +++++++++++++++++++
7 files changed, 74 insertions(+), 16 deletions(-)
create mode 100644 Source/AssetRipper.SourceGenerated.Extensions/UnityVersionExtensions.cs
create mode 100644 Source/AssetRipper.Tests/ExportTests.cs
diff --git a/Source/AssetRipper.Export.UnityProjects/ExportHandler.cs b/Source/AssetRipper.Export.UnityProjects/ExportHandler.cs
index e38a8c42b..428f42c40 100644
--- a/Source/AssetRipper.Export.UnityProjects/ExportHandler.cs
+++ b/Source/AssetRipper.Export.UnityProjects/ExportHandler.cs
@@ -91,7 +91,8 @@ public class ExportHandler
yield return new ScriptableObjectProcessor();
}
- public void Export(GameData gameData, string outputPath)
+ public void Export(GameData gameData, string outputPath) => Export(gameData, outputPath, LocalFileSystem.Instance);
+ public void Export(GameData gameData, string outputPath, FileSystem fileSystem)
{
Logger.Info(LogCategory.Export, "Starting export");
Logger.Info(LogCategory.Export, $"Attempting to export assets to {outputPath}...");
@@ -104,13 +105,13 @@ public class ExportHandler
ProjectExporter projectExporter = new(Settings, gameData.AssemblyManager);
BeforeExport(projectExporter);
projectExporter.DoFinalOverrides(Settings);
- projectExporter.Export(gameData.GameBundle, Settings, LocalFileSystem.Instance);
+ projectExporter.Export(gameData.GameBundle, Settings, fileSystem);
Logger.Info(LogCategory.Export, "Finished exporting assets");
foreach (IPostExporter postExporter in GetPostExporters())
{
- postExporter.DoPostExport(gameData, Settings, LocalFileSystem.Instance);
+ postExporter.DoPostExport(gameData, Settings, fileSystem);
}
Logger.Info(LogCategory.Export, "Finished post-export");
diff --git a/Source/AssetRipper.Export.UnityProjects/Project/ScriptableObjectExporter.cs b/Source/AssetRipper.Export.UnityProjects/Project/ScriptableObjectExporter.cs
index 37afd7921..936a66b1a 100644
--- a/Source/AssetRipper.Export.UnityProjects/Project/ScriptableObjectExporter.cs
+++ b/Source/AssetRipper.Export.UnityProjects/Project/ScriptableObjectExporter.cs
@@ -8,14 +8,13 @@ namespace AssetRipper.Export.UnityProjects.Project
{
private IExportCollection CreateCollection(IMonoBehaviour monoBehaviour)
{
- if (monoBehaviour.IsScriptableObject())
+ if (monoBehaviour.IsComponentOnGameObject())
{
- return new ScriptableObjectExportCollection(this, monoBehaviour);
+ return EmptyExportCollection.Instance;
}
else
{
- // such MonoBehaviours as StateMachineBehaviour in AnimatorController
- return EmptyExportCollection.Instance;
+ return new ScriptableObjectExportCollection(this, monoBehaviour);
}
}
diff --git a/Source/AssetRipper.Processing/Prefabs/SceneHierarchyObject.cs b/Source/AssetRipper.Processing/Prefabs/SceneHierarchyObject.cs
index 74a7ab785..5bec635c4 100644
--- a/Source/AssetRipper.Processing/Prefabs/SceneHierarchyObject.cs
+++ b/Source/AssetRipper.Processing/Prefabs/SceneHierarchyObject.cs
@@ -87,7 +87,7 @@ public sealed class SceneHierarchyObject : GameObjectHierarchyObject, INamed
sceneHierarchy.GameObjects.Add(gameObject);
break;
case IMonoBehaviour monoBehaviour:
- if (monoBehaviour.IsSceneObject())
+ if (monoBehaviour.IsComponentOnGameObject())
{
sceneHierarchy.Components.Add(monoBehaviour);
}
diff --git a/Source/AssetRipper.Processing/Scenes/SceneHelpers.cs b/Source/AssetRipper.Processing/Scenes/SceneHelpers.cs
index 8c20973af..0048e7baf 100644
--- a/Source/AssetRipper.Processing/Scenes/SceneHelpers.cs
+++ b/Source/AssetRipper.Processing/Scenes/SceneHelpers.cs
@@ -50,7 +50,7 @@ namespace AssetRipper.Processing.Scenes
{
IGameObject => true,
ILevelGameManager => true,
- IMonoBehaviour monoBeh => monoBeh.IsSceneObject(),
+ IMonoBehaviour monoBeh => monoBeh.IsComponentOnGameObject(),
IComponent => true,
IPrefabInstance => true,
_ => false,
diff --git a/Source/AssetRipper.SourceGenerated.Extensions/MonoBehaviourExtensions.cs b/Source/AssetRipper.SourceGenerated.Extensions/MonoBehaviourExtensions.cs
index 2194f2484..40466d419 100644
--- a/Source/AssetRipper.SourceGenerated.Extensions/MonoBehaviourExtensions.cs
+++ b/Source/AssetRipper.SourceGenerated.Extensions/MonoBehaviourExtensions.cs
@@ -6,14 +6,9 @@ namespace AssetRipper.SourceGenerated.Extensions;
public static class MonoBehaviourExtensions
{
///
- /// Does this MonoBehaviour belongs to scene/prefab hierarchy? In other words, is a non-null pptr?
+ /// Does this MonoBehaviour belong to scene/prefab hierarchy? In other words, is a non-null pptr?
///
- public static bool IsSceneObject(this IMonoBehaviour monoBehaviour) => !monoBehaviour.GameObject.IsNull();
-
- ///
- /// Does this MonoBehaviour have a name?
- ///
- public static bool IsScriptableObject(this IMonoBehaviour monoBehaviour) => !monoBehaviour.Name.IsEmpty;
+ public static bool IsComponentOnGameObject(this IMonoBehaviour monoBehaviour) => !monoBehaviour.GameObject.IsNull();
public static bool TryGetScript(this IMonoBehaviour monoBehaviour, [NotNullWhen(true)] out IMonoScript? script)
{
diff --git a/Source/AssetRipper.SourceGenerated.Extensions/UnityVersionExtensions.cs b/Source/AssetRipper.SourceGenerated.Extensions/UnityVersionExtensions.cs
new file mode 100644
index 000000000..7af78de9a
--- /dev/null
+++ b/Source/AssetRipper.SourceGenerated.Extensions/UnityVersionExtensions.cs
@@ -0,0 +1,9 @@
+namespace AssetRipper.SourceGenerated.Extensions;
+
+public static class UnityVersionExtensions
+{
+ extension(UnityVersion)
+ {
+ public static UnityVersion V_2022 => new UnityVersion(2022);
+ }
+}
diff --git a/Source/AssetRipper.Tests/ExportTests.cs b/Source/AssetRipper.Tests/ExportTests.cs
new file mode 100644
index 000000000..94ab59a5b
--- /dev/null
+++ b/Source/AssetRipper.Tests/ExportTests.cs
@@ -0,0 +1,54 @@
+using AssetRipper.Assets.Bundles;
+using AssetRipper.Assets.Collections;
+using AssetRipper.Export.UnityProjects;
+using AssetRipper.Import.Structure.Assembly.Managers;
+using AssetRipper.IO.Files;
+using AssetRipper.Primitives;
+using AssetRipper.Processing;
+using AssetRipper.SourceGenerated.Classes.ClassID_114;
+using AssetRipper.SourceGenerated.Extensions;
+using NUnit.Framework.Internal;
+
+namespace AssetRipper.Tests;
+
+internal class ExportTests
+{
+ [Test]
+ public void NamedScriptableObjectIsExported()
+ {
+ ProcessedAssetCollection collection = AssetCreator.CreateCollection(UnityVersion.V_2022);
+
+ IMonoBehaviour monoBehaviour = collection.CreateMonoBehaviour();
+ monoBehaviour.Name = "Name";
+
+ VirtualFileSystem fileSystem = new();
+
+ Export(collection, "output", fileSystem);
+
+ Assert.That(fileSystem.File.Exists("/output/ExportedProject/Assets/MonoBehaviour/Name.asset"));
+ }
+
+ [Test]
+ public void NamelessScriptableObjectIsExported()
+ {
+ ProcessedAssetCollection collection = AssetCreator.CreateCollection(UnityVersion.V_2022);
+
+ collection.CreateMonoBehaviour();
+
+ VirtualFileSystem fileSystem = new();
+
+ Export(collection, "output", fileSystem);
+
+ Assert.That(fileSystem.File.Exists("/output/ExportedProject/Assets/MonoBehaviour/MonoBehaviour.asset"));
+ }
+
+ private static void Export(ProcessedAssetCollection collection, string outputPath, VirtualFileSystem fileSystem)
+ {
+ new ExportHandler(new()).Export(CreateGameData(collection), outputPath, fileSystem);
+ }
+
+ private static GameData CreateGameData(ProcessedAssetCollection collection)
+ {
+ return new((GameBundle)collection.Bundle, collection.Version, new BaseManager((s) => { }), null);
+ }
+}