Jeremy Pritts 85172b7393
File system improvements (#1936)
* WIP file system improvements

* Switch to a hierarchial virtual file system

* EnumerateFiles and EnumerateDirectories

* Change import code to use FileSystem

* Use FileSystem when loading assemblies

* Use FileSystem in MonoManager initialization

* Remove set method for PlatformGameStructure::RootPath

* Renaming cleanup
2025-09-13 15:17:41 -07:00

160 lines
5.2 KiB
C#

using AssetRipper.Assets.Bundles;
using AssetRipper.Export.UnityProjects.Configuration;
using AssetRipper.Export.UnityProjects.PathIdMapping;
using AssetRipper.Export.UnityProjects.Project;
using AssetRipper.Export.UnityProjects.Scripts;
using AssetRipper.Import.Configuration;
using AssetRipper.Import.Logging;
using AssetRipper.Import.Structure;
using AssetRipper.Processing;
using AssetRipper.Processing.AnimatorControllers;
using AssetRipper.Processing.Assemblies;
using AssetRipper.Processing.AudioMixers;
using AssetRipper.Processing.Editor;
using AssetRipper.Processing.Prefabs;
using AssetRipper.Processing.Scenes;
using AssetRipper.Processing.ScriptableObject;
using AssetRipper.Processing.Textures;
namespace AssetRipper.Export.UnityProjects;
public class ExportHandler
{
protected LibraryConfiguration Settings { get; }
public ExportHandler(LibraryConfiguration settings)
{
Settings = settings;
}
public GameData Load(IReadOnlyList<string> paths, FileSystem fileSystem)
{
if (paths.Count == 1)
{
Logger.Info(LogCategory.Import, $"Attempting to read files from {paths[0]}");
}
else
{
Logger.Info(LogCategory.Import, $"Attempting to read files from {paths.Count} paths...");
}
GameStructure gameStructure = GameStructure.Load(paths, fileSystem, Settings);
GameData gameData = GameData.FromGameStructure(gameStructure);
Logger.Info(LogCategory.Import, "Finished reading files");
return gameData;
}
public void Process(GameData gameData)
{
Logger.Info(LogCategory.Processing, "Processing loaded assets...");
foreach (IAssetProcessor processor in GetProcessors())
{
processor.Process(gameData);
}
Logger.Info(LogCategory.Processing, "Finished processing assets");
}
protected virtual IEnumerable<IAssetProcessor> GetProcessors()
{
// Assembly processors
yield return new AttributePolyfillGenerator();
yield return new MonoExplicitPropertyRepairProcessor();
yield return new ObfuscationRepairProcessor();
yield return new ForwardingAssemblyGenerator();
if (Settings.ImportSettings.ScriptContentLevel == ScriptContentLevel.Level1)
{
yield return new MethodStubbingProcessor();
}
yield return new NullRefReturnProcessor(Settings.ImportSettings.ScriptContentLevel);
yield return new UnmanagedConstraintRecoveryProcessor();
if (Settings.ProcessingSettings.RemoveNullableAttributes)
{
yield return new NullableRemovalProcessor();
}
if (Settings.ProcessingSettings.PublicizeAssemblies)
{
yield return new SafeAssemblyPublicizingProcessor();
}
yield return new RemoveAssemblyKeyFileAttributeProcessor();
yield return new InternalsVisibileToPublicKeyRemover();
yield return new SceneDefinitionProcessor();
yield return new MainAssetProcessor();
yield return new AnimatorControllerProcessor();
yield return new AudioMixerProcessor();
yield return new EditorFormatProcessor(Settings.ProcessingSettings.BundledAssetsExportMode);
//Static mesh separation goes here
yield return new LightingDataProcessor();//Needs to be after static mesh separation
yield return new PrefabProcessor();
yield return new SpriteProcessor();
yield return new ScriptableObjectProcessor();
}
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}...");
Logger.Info(LogCategory.Export, $"Game files have these Unity versions:{GetListOfVersions(gameData.GameBundle)}");
Logger.Info(LogCategory.Export, $"Exporting to Unity version {gameData.ProjectVersion}");
Settings.ExportRootPath = outputPath;
Settings.SetProjectSettings(gameData.ProjectVersion);
ProjectExporter projectExporter = new(Settings, gameData.AssemblyManager);
BeforeExport(projectExporter);
projectExporter.DoFinalOverrides(Settings);
projectExporter.Export(gameData.GameBundle, Settings, fileSystem);
Logger.Info(LogCategory.Export, "Finished exporting assets");
foreach (IPostExporter postExporter in GetPostExporters())
{
postExporter.DoPostExport(gameData, Settings, fileSystem);
}
Logger.Info(LogCategory.Export, "Finished post-export");
static string GetListOfVersions(GameBundle gameBundle)
{
return string.Join(' ', gameBundle
.FetchAssetCollections()
.Select(c => c.Version)
.Distinct()
.Select(v => v.ToString()));
}
}
protected virtual void BeforeExport(ProjectExporter projectExporter)
{
}
protected virtual IEnumerable<IPostExporter> GetPostExporters()
{
yield return new ProjectVersionPostExporter();
yield return new PackageManifestPostExporter();
yield return new StreamingAssetsPostExporter();
yield return new DllPostExporter();
yield return new PathIdMapExporter();
}
public GameData LoadAndProcess(IReadOnlyList<string> paths, FileSystem fileSystem)
{
GameData gameData = Load(paths, fileSystem);
Process(gameData);
return gameData;
}
public void LoadProcessAndExport(IReadOnlyList<string> inputPaths, string outputPath, FileSystem fileSystem)
{
GameData gameData = LoadAndProcess(inputPaths, fileSystem);
Export(gameData, outputPath, fileSystem);
}
public void ThrowIfSettingsDontMatch(LibraryConfiguration settings)
{
if (Settings != settings)
{
throw new ArgumentException("Settings don't match");
}
}
}