using AssetRipper.Assets;
using AssetRipper.Assets.Bundles;
using AssetRipper.Export.UnityProjects.AnimatorControllers;
using AssetRipper.Export.UnityProjects.Audio;
using AssetRipper.Export.UnityProjects.AudioMixers;
using AssetRipper.Export.UnityProjects.Configuration;
using AssetRipper.Export.UnityProjects.Meshes;
using AssetRipper.Export.UnityProjects.Miscellaneous;
using AssetRipper.Export.UnityProjects.Models;
using AssetRipper.Export.UnityProjects.NavMeshes;
using AssetRipper.Export.UnityProjects.PathIdMapping;
using AssetRipper.Export.UnityProjects.Project;
using AssetRipper.Export.UnityProjects.Project.Exporters.Engine;
using AssetRipper.Export.UnityProjects.Scripts;
using AssetRipper.Export.UnityProjects.Shaders;
using AssetRipper.Export.UnityProjects.Terrains;
using AssetRipper.Export.UnityProjects.Textures;
using AssetRipper.Export.UnityProjects.TypeTrees;
using AssetRipper.Import.Configuration;
using AssetRipper.Import.Logging;
using AssetRipper.Import.Structure;
using AssetRipper.IO.Files;
using AssetRipper.IO.Files.SerializedFiles;
using AssetRipper.Processing;
using AssetRipper.Processing.AnimatorControllers;
using AssetRipper.Processing.Assemblies;
using AssetRipper.Processing.AudioMixers;
using AssetRipper.Processing.PrefabOutlining;
using AssetRipper.Processing.Scenes;
using AssetRipper.Processing.StaticMeshes;
using AssetRipper.Processing.Textures;
using AssetRipper.SourceGenerated.Classes.ClassID_1;
using AssetRipper.SourceGenerated.Classes.ClassID_1113;
using AssetRipper.SourceGenerated.Classes.ClassID_114;
using AssetRipper.SourceGenerated.Classes.ClassID_115;
using AssetRipper.SourceGenerated.Classes.ClassID_117;
using AssetRipper.SourceGenerated.Classes.ClassID_128;
using AssetRipper.SourceGenerated.Classes.ClassID_152;
using AssetRipper.SourceGenerated.Classes.ClassID_156;
using AssetRipper.SourceGenerated.Classes.ClassID_187;
using AssetRipper.SourceGenerated.Classes.ClassID_188;
using AssetRipper.SourceGenerated.Classes.ClassID_2;
using AssetRipper.SourceGenerated.Classes.ClassID_21;
using AssetRipper.SourceGenerated.Classes.ClassID_213;
using AssetRipper.SourceGenerated.Classes.ClassID_238;
using AssetRipper.SourceGenerated.Classes.ClassID_240;
using AssetRipper.SourceGenerated.Classes.ClassID_244;
using AssetRipper.SourceGenerated.Classes.ClassID_272;
using AssetRipper.SourceGenerated.Classes.ClassID_273;
using AssetRipper.SourceGenerated.Classes.ClassID_28;
using AssetRipper.SourceGenerated.Classes.ClassID_3;
using AssetRipper.SourceGenerated.Classes.ClassID_43;
using AssetRipper.SourceGenerated.Classes.ClassID_48;
using AssetRipper.SourceGenerated.Classes.ClassID_49;
using AssetRipper.SourceGenerated.Classes.ClassID_687078895;
using AssetRipper.SourceGenerated.Classes.ClassID_72;
using AssetRipper.SourceGenerated.Classes.ClassID_83;
using System.Text;
namespace AssetRipper.Export.UnityProjects
{
public class Ripper
{
private GameStructure? gameStructure;
public Ripper() : this(new()) { }
public Ripper(LibraryConfiguration configuration)
{
Settings = configuration;
}
public bool IsLoaded => gameStructure != null;
public GameStructure GameStructure
{
[MemberNotNull(nameof(gameStructure))]
get
{
ThrowIfGameStructureIsNull();
return gameStructure;
}
}
///
/// Needs to be set before loading assets to ensure predictable behavior
///
public LibraryConfiguration Settings { get; }
public void ResetData()
{
gameStructure?.Dispose();
gameStructure = null;
}
[MemberNotNull(nameof(gameStructure))]
public GameStructure Load(IReadOnlyList paths)
{
ResetData();
if (paths.Count == 1)
{
Logger.Info(LogCategory.General, $"Attempting to read files from {paths[0]}");
}
else
{
Logger.Info(LogCategory.General, $"Attempting to read files from {paths.Count} paths...");
}
gameStructure = GameStructure.Load(paths, Settings);
Logger.Info(LogCategory.General, "Finished reading files");
Logger.Info(LogCategory.General, "Processing assemblies...");
if (Settings.ScriptContentLevel == ScriptContentLevel.Level1)
{
new MethodStubbingProcessor().Process(GameStructure.AssemblyManager);
}
Logger.Info(LogCategory.General, "Processing loaded assets...");
UnityVersion version = gameStructure.FileCollection.GetMaxUnityVersion();
foreach (IAssetProcessor processor in GetProcessors())
{
processor.Process(GameStructure.FileCollection, version);
}
Logger.Info(LogCategory.General, "Finished processing assets");
return GameStructure;
IEnumerable GetProcessors()
{
yield return new SceneDefinitionProcessor();
yield return new MainAssetProcessor();
yield return new LightingDataProcessor();
yield return new AnimatorControllerProcessor();
yield return new AudioMixerProcessor();
yield return new EditorFormatProcessor(Settings.BundledAssetsExportMode, GameStructure.AssemblyManager);
if (Settings.EnableStaticMeshSeparation)
{
yield return new StaticMeshProcessor();
}
if (Settings.EnablePrefabOutlining)
{
yield return new PrefabOutliningProcessor();
}
yield return new PrefabProcessor();
yield return new SpriteProcessor();
}
}
public IEnumerable FetchLoadedAssets()
{
return GameStructure.FileCollection.FetchAssets();
}
[MemberNotNull(nameof(gameStructure))]
private void ThrowIfGameStructureIsNull()
{
if (gameStructure == null)
{
throw new NullReferenceException("GameStructure cannot be null");
}
}
[MemberNotNull(nameof(gameStructure))]
public void ExportProject(string exportPath, Action? onBeforeExport = null) => ExportProject(exportPath, CoreConfiguration.DefaultFilter, onBeforeExport);
[MemberNotNull(nameof(gameStructure))]
public void ExportProject(string exportPath, Func filter, Action? onBeforeExport)
{
Logger.Info(LogCategory.Export, $"Attempting to export assets to {exportPath}...");
ThrowIfGameStructureIsNull();
Logger.Info(LogCategory.Export, "Starting export");
Logger.Info(LogCategory.Export, $"Game files have these Unity versions:{GetListOfVersions(gameStructure.FileCollection)}");
UnityVersion version = gameStructure.FileCollection.GetMaxUnityVersion();
Logger.Info(LogCategory.Export, $"Exporting to Unity version {version}");
Settings.ExportRootPath = exportPath;
Settings.Filter = filter;
Settings.SetProjectSettings(version, BuildTarget.NoTarget, TransferInstructionFlags.NoTransferInstructionFlags);
{
ProjectExporter projectExporter = new();
onBeforeExport?.Invoke(projectExporter);
InitializeExporters(projectExporter);
projectExporter.Export(gameStructure.FileCollection, Settings);
}
Logger.Info(LogCategory.Export, "Finished exporting assets");
foreach (IPostExporter postExporter in GetPostExporters())
{
postExporter.DoPostExport(this);
}
Logger.Info(LogCategory.Export, "Finished post-export");
static string GetListOfVersions(GameBundle gameBundle)
{
StringBuilder sb = new();
foreach (UnityVersion version in gameBundle.FetchAssetCollections().Select(s => s.Version).Distinct())
{
sb.Append(' ');
sb.Append(version.ToString());
}
return sb.ToString();
}
static IEnumerable GetPostExporters()
{
yield return new ProjectVersionPostExporter();
yield return new PackageManifestPostExporter();
yield return new StreamingAssetsPostExporter();
yield return new TypeTreeExporter();
yield return new DllPostExporter();
yield return new PathIdMapExporter();
}
}
private void InitializeExporters(ProjectExporter projectExporter)
{
OverrideNormalExporters(projectExporter);
if (!Settings.IgnoreEngineAssets)
{
OverrideEngineExporters(projectExporter);
}
}
private void OverrideNormalExporters(ProjectExporter projectExporter)
{
//Yaml Exporters
YamlStreamedAssetExporter streamedAssetExporter = new();
projectExporter.OverrideExporter(streamedAssetExporter);
projectExporter.OverrideExporter(streamedAssetExporter);//ICubemap also by inheritance
projectExporter.OverrideExporter(streamedAssetExporter);
projectExporter.OverrideExporter(streamedAssetExporter);
projectExporter.OverrideExporter(streamedAssetExporter);
//Miscellaneous exporters
projectExporter.OverrideExporter(new TextAssetExporter(Settings));
FontAssetExporter fontAssetExporter = new FontAssetExporter();
projectExporter.OverrideExporter(fontAssetExporter);
projectExporter.OverrideExporter(fontAssetExporter);
projectExporter.OverrideExporter(new MovieTextureAssetExporter());
VideoClipExporter videoClipExporter = new();
projectExporter.OverrideExporter(videoClipExporter);
projectExporter.OverrideExporter(videoClipExporter);
//Texture exporters
TextureAssetExporter textureExporter = new(Settings);
projectExporter.OverrideExporter(textureExporter); //Texture2D and Cubemap
projectExporter.OverrideExporter(textureExporter);
if (Settings.SpriteExportMode == SpriteExportMode.Yaml)
{
YamlSpriteExporter spriteExporter = new();
projectExporter.OverrideExporter(spriteExporter);
projectExporter.OverrideExporter(spriteExporter);
}
//Texture Array exporters
if (Settings.Version.IsGreaterEqual(2020, 2))
{
TextureArrayAssetExporter textureArrayExporter = new(Settings);
projectExporter.OverrideExporter(textureArrayExporter);
projectExporter.OverrideExporter(textureArrayExporter);
projectExporter.OverrideExporter(textureArrayExporter);
}
//Shader exporters
projectExporter.OverrideExporter(Settings.ShaderExportMode switch
{
ShaderExportMode.Yaml => new YamlShaderExporter(),
ShaderExportMode.Disassembly => new ShaderDisassemblyExporter(),
ShaderExportMode.Decompile => new USCShaderExporter(),
_ => new DummyShaderTextExporter(),
});
projectExporter.OverrideExporter(new SimpleShaderExporter());
//Audio exporters
projectExporter.OverrideExporter(new YamlAudioExporter());
if (Settings.AudioExportFormat == AudioExportFormat.Native)
{
projectExporter.OverrideExporter(new NativeAudioExporter());
}
if (AudioClipExporter.IsSupportedExportFormat(Settings.AudioExportFormat))
{
projectExporter.OverrideExporter(new AudioClipExporter(Settings));
}
//AudioMixer exporters
AudioMixerExporter audioMixerExporter = new();
projectExporter.OverrideExporter(audioMixerExporter);
projectExporter.OverrideExporter(audioMixerExporter);
projectExporter.OverrideExporter(audioMixerExporter);
projectExporter.OverrideExporter(audioMixerExporter);
//Mesh and Model exporters
if (Settings.MeshExportFormat == MeshExportFormat.Glb)
{
projectExporter.OverrideExporter(new GlbMeshExporter());
GlbModelExporter glbModelExporter = new();
projectExporter.OverrideExporter(glbModelExporter);
projectExporter.OverrideExporter(glbModelExporter);
projectExporter.OverrideExporter(glbModelExporter);
}
//Terrain and NavMesh exporters
switch (Settings.TerrainExportMode)
{
case TerrainExportMode.Heatmap:
projectExporter.OverrideExporter(new TerrainHeatmapExporter(Settings));
break;
case TerrainExportMode.Mesh:
projectExporter.OverrideExporter(new TerrainMeshExporter());
projectExporter.OverrideExporter(new GlbNavMeshExporter());
break;
default:
TerrainYamlExporter terrainYamlExporter = new();
projectExporter.OverrideExporter(terrainYamlExporter);
projectExporter.OverrideExporter(terrainYamlExporter);
break;
}
//Script exporters
projectExporter.OverrideExporter(Settings.ScriptExportMode switch
{
ScriptExportMode.DllExportWithoutRenaming => new AssemblyDllExporter(GameStructure.AssemblyManager),
_ => new ScriptExporter(GameStructure.AssemblyManager, Settings),
});
//Animator Controller
projectExporter.OverrideExporter(new AnimatorControllerExporter());
}
private void OverrideEngineExporters(ProjectExporter projectExporter)
{
EngineAssetExporter engineExporter = new(Settings);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
projectExporter.OverrideExporter(engineExporter);
}
}
}