diff --git a/AssetStudioCLI/Exporter.cs b/AssetStudioCLI/Exporter.cs index 72e2985..3c26296 100644 --- a/AssetStudioCLI/Exporter.cs +++ b/AssetStudioCLI/Exporter.cs @@ -10,10 +10,13 @@ namespace AssetStudioCLI { internal static class Exporter { + private static readonly HashSet ExportPathHashSet = new HashSet(System.StringComparer.OrdinalIgnoreCase); + private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export") { var fileName = FixFileName(item.Text); var filenameFormat = CLIOptions.o_filenameFormat.Value; + var canOverwrite = CLIOptions.f_overwriteExisting.Value; switch (filenameFormat) { case FilenameFormat.AssetName_PathID: @@ -24,17 +27,18 @@ namespace AssetStudioCLI break; } fullPath = Path.Combine(dir, fileName + extension); - if (!File.Exists(fullPath)) + if (ExportPathHashSet.Add(fullPath)) { - Directory.CreateDirectory(dir); - return true; + if (CanWrite(fullPath, dir, canOverwrite)) + { + return true; + } } - if (filenameFormat == FilenameFormat.AssetName) + else if (filenameFormat == FilenameFormat.AssetName) { fullPath = Path.Combine(dir, fileName + item.UniqueID + extension); - if (!File.Exists(fullPath)) + if (CanWrite(fullPath, dir, canOverwrite)) { - Directory.CreateDirectory(dir); return true; } } @@ -42,6 +46,14 @@ namespace AssetStudioCLI return false; } + private static bool CanWrite(string fullPath, string dir, bool canOverwrite) + { + if (!canOverwrite && File.Exists(fullPath)) + return false; + Directory.CreateDirectory(dir); + return true; + } + private static bool ExportVideoClip(AssetItem item, string exportPath) { var m_VideoClip = (VideoClip)item.Asset; @@ -387,5 +399,10 @@ namespace AssetStudioCLI ? Path.GetRandomFileName() : Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_')); } + + public static void ClearHash() + { + ExportPathHashSet.Clear(); + } } } diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index 1ea1c5e..91a0e56 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -93,6 +93,7 @@ namespace AssetStudioCLI.Options public static Option o_groupAssetsBy; public static Option o_filenameFormat; public static Option o_outputFolder; + public static Option f_overwriteExisting; public static Option o_displayHelp; //logger public static Option o_logLevel; @@ -254,6 +255,15 @@ namespace AssetStudioCLI.Options optionExample: "", optionHelpGroup: HelpGroups.General ); + f_overwriteExisting = new GroupedOption + ( + optionDefaultValue: false, + optionName: "-r, --overwrite-existing", + optionDescription: "(Flag) If specified, Studio will overwrite existing files during asset export/dump\n", + optionExample: "", + optionHelpGroup: HelpGroups.General, + isFlag: true + ); o_displayHelp = new GroupedOption ( optionDefaultValue: false, @@ -678,6 +688,11 @@ namespace AssetStudioCLI.Options switch (flag) { + case "-r": + case "--overwrite-existing": + f_overwriteExisting.Value = true; + flagIndexes.Add(i); + break; case "--l2d-search-by-filename": if (o_workMode.Value != WorkMode.Live2D) { @@ -1403,7 +1418,8 @@ namespace AssetStudioCLI.Options if (o_workMode.Value != WorkMode.Info) { sb.AppendLine($"# Asset Group Option: {o_groupAssetsBy}"); - sb.AppendLine($"# Filename format: {o_filenameFormat}"); + sb.AppendLine($"# Filename Format: {o_filenameFormat}"); + sb.AppendLine($"# Overwrite Existing Files: {f_overwriteExisting}"); } if (o_workMode.Value == WorkMode.Export) { diff --git a/AssetStudioCLI/ParallelExporter.cs b/AssetStudioCLI/ParallelExporter.cs index c66c6d4..75cf504 100644 --- a/AssetStudioCLI/ParallelExporter.cs +++ b/AssetStudioCLI/ParallelExporter.cs @@ -10,7 +10,7 @@ namespace AssetStudioCLI { internal static class ParallelExporter { - private static ConcurrentDictionary savePathHash = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary ExportPathDict = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); public static bool ExportTexture2D(AssetItem item, string exportPath, out string debugLog) { @@ -184,6 +184,7 @@ namespace AssetStudioCLI { var fileName = FixFileName(item.Text); var filenameFormat = CLIOptions.o_filenameFormat.Value; + var canOverwrite = CLIOptions.f_overwriteExisting.Value; switch (filenameFormat) { case FilenameFormat.AssetName_PathID: @@ -194,17 +195,18 @@ namespace AssetStudioCLI break; } fullPath = Path.Combine(dir, fileName + extension); - if (savePathHash.TryAdd(fullPath.ToLower(), true) && !File.Exists(fullPath)) + if (ExportPathDict.TryAdd(fullPath, true)) { - Directory.CreateDirectory(dir); - return true; + if (CanWrite(fullPath, dir, canOverwrite)) + { + return true; + } } - if (filenameFormat == FilenameFormat.AssetName) + else if (filenameFormat == FilenameFormat.AssetName) { fullPath = Path.Combine(dir, fileName + item.UniqueID + extension); - if (!File.Exists(fullPath)) + if (CanWrite(fullPath, dir, canOverwrite)) { - Directory.CreateDirectory(dir); return true; } } @@ -212,6 +214,14 @@ namespace AssetStudioCLI return false; } + private static bool CanWrite(string fullPath, string dir, bool canOverwrite) + { + if (!canOverwrite && File.Exists(fullPath)) + return false; + Directory.CreateDirectory(dir); + return true; + } + public static bool ParallelExportConvertFile(AssetItem item, string exportPath, out string debugLog) { switch (item.Type) @@ -237,7 +247,7 @@ namespace AssetStudioCLI public static void ClearHash() { - savePathHash.Clear(); + ExportPathDict.Clear(); } } } diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 8f02f15..bc4e733 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -761,6 +761,7 @@ namespace AssetStudioCLI } Console.Write($"Exported [{exportedCount}/{toExportCount}]\r"); } + Exporter.ClearHash(); Parallel.ForEach(toParallelExportAssetDict, new ParallelOptions { MaxDegreeOfParallelism = parallelExportCount }, toExportAsset => { diff --git a/AssetStudioGUI/ExportOptions.Designer.cs b/AssetStudioGUI/ExportOptions.Designer.cs index ba488e1..b1da2fc 100644 --- a/AssetStudioGUI/ExportOptions.Designer.cs +++ b/AssetStudioGUI/ExportOptions.Designer.cs @@ -82,6 +82,7 @@ this.exportAllNodes = new System.Windows.Forms.CheckBox(); this.eulerFilter = new System.Windows.Forms.CheckBox(); this.optionTooltip = new System.Windows.Forms.ToolTip(this.components); + this.overwriteExistingFiles = new System.Windows.Forms.CheckBox(); this.groupBox1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.parallelExportUpDown)).BeginInit(); this.panel1.SuspendLayout(); @@ -96,7 +97,7 @@ // OKbutton // this.OKbutton.BackColor = System.Drawing.SystemColors.ButtonFace; - this.OKbutton.Location = new System.Drawing.Point(460, 430); + this.OKbutton.Location = new System.Drawing.Point(460, 448); this.OKbutton.Name = "OKbutton"; this.OKbutton.Size = new System.Drawing.Size(75, 23); this.OKbutton.TabIndex = 4; @@ -108,7 +109,7 @@ // this.Cancel.BackColor = System.Drawing.SystemColors.ButtonFace; this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.Cancel.Location = new System.Drawing.Point(541, 430); + this.Cancel.Location = new System.Drawing.Point(541, 448); this.Cancel.Name = "Cancel"; this.Cancel.Size = new System.Drawing.Size(75, 23); this.Cancel.TabIndex = 5; @@ -120,6 +121,7 @@ // this.groupBox1.AutoSize = true; this.groupBox1.BackColor = System.Drawing.SystemColors.Menu; + this.groupBox1.Controls.Add(this.overwriteExistingFiles); this.groupBox1.Controls.Add(this.parallelExportMaxLabel); this.groupBox1.Controls.Add(this.parallelExportCheckBox); this.groupBox1.Controls.Add(this.parallelExportUpDown); @@ -135,7 +137,7 @@ this.groupBox1.Controls.Add(this.converttexture); this.groupBox1.Location = new System.Drawing.Point(12, 13); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(316, 272); + this.groupBox1.Size = new System.Drawing.Size(316, 280); this.groupBox1.TabIndex = 1; this.groupBox1.TabStop = false; this.groupBox1.Text = "Export"; @@ -144,7 +146,7 @@ // this.parallelExportMaxLabel.AutoSize = true; this.parallelExportMaxLabel.ForeColor = System.Drawing.SystemColors.ControlDarkDark; - this.parallelExportMaxLabel.Location = new System.Drawing.Point(260, 221); + this.parallelExportMaxLabel.Location = new System.Drawing.Point(260, 244); this.parallelExportMaxLabel.Name = "parallelExportMaxLabel"; this.parallelExportMaxLabel.Size = new System.Drawing.Size(33, 13); this.parallelExportMaxLabel.TabIndex = 13; @@ -156,7 +158,7 @@ this.parallelExportCheckBox.AutoSize = true; this.parallelExportCheckBox.Checked = true; this.parallelExportCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; - this.parallelExportCheckBox.Location = new System.Drawing.Point(6, 219); + this.parallelExportCheckBox.Location = new System.Drawing.Point(6, 242); this.parallelExportCheckBox.Name = "parallelExportCheckBox"; this.parallelExportCheckBox.Size = new System.Drawing.Size(203, 17); this.parallelExportCheckBox.TabIndex = 11; @@ -167,7 +169,7 @@ // // parallelExportUpDown // - this.parallelExportUpDown.Location = new System.Drawing.Point(211, 218); + this.parallelExportUpDown.Location = new System.Drawing.Point(211, 241); this.parallelExportUpDown.Maximum = new decimal(new int[] { 8, 0, @@ -214,7 +216,7 @@ this.exportSpriteWithAlphaMask.AutoSize = true; this.exportSpriteWithAlphaMask.Checked = true; this.exportSpriteWithAlphaMask.CheckState = System.Windows.Forms.CheckState.Checked; - this.exportSpriteWithAlphaMask.Location = new System.Drawing.Point(6, 150); + this.exportSpriteWithAlphaMask.Location = new System.Drawing.Point(6, 173); this.exportSpriteWithAlphaMask.Name = "exportSpriteWithAlphaMask"; this.exportSpriteWithAlphaMask.Size = new System.Drawing.Size(205, 17); this.exportSpriteWithAlphaMask.TabIndex = 8; @@ -226,7 +228,7 @@ this.openAfterExport.AutoSize = true; this.openAfterExport.Checked = true; this.openAfterExport.CheckState = System.Windows.Forms.CheckState.Checked; - this.openAfterExport.Location = new System.Drawing.Point(6, 196); + this.openAfterExport.Location = new System.Drawing.Point(6, 219); this.openAfterExport.Name = "openAfterExport"; this.openAfterExport.Size = new System.Drawing.Size(137, 17); this.openAfterExport.TabIndex = 10; @@ -238,7 +240,7 @@ this.restoreExtensionName.AutoSize = true; this.restoreExtensionName.Checked = true; this.restoreExtensionName.CheckState = System.Windows.Forms.CheckState.Checked; - this.restoreExtensionName.Location = new System.Drawing.Point(6, 63); + this.restoreExtensionName.Location = new System.Drawing.Point(6, 86); this.restoreExtensionName.Name = "restoreExtensionName"; this.restoreExtensionName.Size = new System.Drawing.Size(275, 17); this.restoreExtensionName.TabIndex = 5; @@ -276,7 +278,7 @@ this.convertAudio.AutoSize = true; this.convertAudio.Checked = true; this.convertAudio.CheckState = System.Windows.Forms.CheckState.Checked; - this.convertAudio.Location = new System.Drawing.Point(6, 173); + this.convertAudio.Location = new System.Drawing.Point(6, 196); this.convertAudio.Name = "convertAudio"; this.convertAudio.Size = new System.Drawing.Size(213, 17); this.convertAudio.TabIndex = 9; @@ -290,7 +292,7 @@ this.panel1.Controls.Add(this.tojpg); this.panel1.Controls.Add(this.topng); this.panel1.Controls.Add(this.tobmp); - this.panel1.Location = new System.Drawing.Point(18, 111); + this.panel1.Location = new System.Drawing.Point(18, 134); this.panel1.Name = "panel1"; this.panel1.Size = new System.Drawing.Size(279, 33); this.panel1.TabIndex = 7; @@ -352,7 +354,7 @@ this.converttexture.AutoSize = true; this.converttexture.Checked = true; this.converttexture.CheckState = System.Windows.Forms.CheckState.Checked; - this.converttexture.Location = new System.Drawing.Point(6, 87); + this.converttexture.Location = new System.Drawing.Point(6, 110); this.converttexture.Name = "converttexture"; this.converttexture.Size = new System.Drawing.Size(116, 17); this.converttexture.TabIndex = 6; @@ -368,7 +370,7 @@ this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodPanel); this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodLabel); this.l2dGroupBox.Controls.Add(this.l2dForceBezierCheckBox); - this.l2dGroupBox.Location = new System.Drawing.Point(12, 275); + this.l2dGroupBox.Location = new System.Drawing.Point(12, 291); this.l2dGroupBox.Name = "l2dGroupBox"; this.l2dGroupBox.Size = new System.Drawing.Size(316, 149); this.l2dGroupBox.TabIndex = 2; @@ -490,7 +492,7 @@ this.groupBox2.Controls.Add(this.eulerFilter); this.groupBox2.Location = new System.Drawing.Point(328, 13); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(289, 411); + this.groupBox2.Size = new System.Drawing.Size(289, 427); this.groupBox2.TabIndex = 3; this.groupBox2.TabStop = false; this.groupBox2.Text = "Fbx"; @@ -498,7 +500,7 @@ // fbxResetButton // this.fbxResetButton.BackColor = System.Drawing.SystemColors.ButtonFace; - this.fbxResetButton.Location = new System.Drawing.Point(208, 368); + this.fbxResetButton.Location = new System.Drawing.Point(208, 384); this.fbxResetButton.Name = "fbxResetButton"; this.fbxResetButton.Size = new System.Drawing.Size(75, 23); this.fbxResetButton.TabIndex = 21; @@ -763,6 +765,16 @@ this.eulerFilter.Text = "EulerFilter"; this.eulerFilter.UseVisualStyleBackColor = true; // + // overwriteExistingFiles + // + this.overwriteExistingFiles.AutoSize = true; + this.overwriteExistingFiles.Location = new System.Drawing.Point(6, 63); + this.overwriteExistingFiles.Name = "overwriteExistingFiles"; + this.overwriteExistingFiles.Size = new System.Drawing.Size(130, 17); + this.overwriteExistingFiles.TabIndex = 14; + this.overwriteExistingFiles.Text = "Overwrite existing files"; + this.overwriteExistingFiles.UseVisualStyleBackColor = true; + // // ExportOptions // this.AcceptButton = this.OKbutton; @@ -770,7 +782,7 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.SystemColors.Menu; this.CancelButton = this.Cancel; - this.ClientSize = new System.Drawing.Size(628, 461); + this.ClientSize = new System.Drawing.Size(628, 483); this.Controls.Add(this.l2dGroupBox); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); @@ -856,5 +868,6 @@ private System.Windows.Forms.ListBox uvTypesListBox; private System.Windows.Forms.Label uvBindingsLabel; private System.Windows.Forms.Button fbxResetButton; + private System.Windows.Forms.CheckBox overwriteExistingFiles; } } \ No newline at end of file diff --git a/AssetStudioGUI/ExportOptions.cs b/AssetStudioGUI/ExportOptions.cs index 11a519f..835a221 100644 --- a/AssetStudioGUI/ExportOptions.cs +++ b/AssetStudioGUI/ExportOptions.cs @@ -15,6 +15,7 @@ namespace AssetStudioGUI InitializeComponent(); assetGroupOptions.SelectedIndex = Properties.Settings.Default.assetGroupOption; filenameFormatComboBox.SelectedIndex = Properties.Settings.Default.filenameFormat; + overwriteExistingFiles.Checked = Properties.Settings.Default.overwriteExistingFiles; restoreExtensionName.Checked = Properties.Settings.Default.restoreExtensionName; converttexture.Checked = Properties.Settings.Default.convertTexture; exportSpriteWithAlphaMask.Checked = Properties.Settings.Default.exportSpriteWithMask; @@ -42,6 +43,7 @@ namespace AssetStudioGUI { Properties.Settings.Default.assetGroupOption = assetGroupOptions.SelectedIndex; Properties.Settings.Default.filenameFormat = filenameFormatComboBox.SelectedIndex; + Properties.Settings.Default.overwriteExistingFiles = overwriteExistingFiles.Checked; Properties.Settings.Default.restoreExtensionName = restoreExtensionName.Checked; Properties.Settings.Default.convertTexture = converttexture.Checked; Properties.Settings.Default.exportSpriteWithMask = exportSpriteWithAlphaMask.Checked; diff --git a/AssetStudioGUI/Exporter.cs b/AssetStudioGUI/Exporter.cs index 2c6446d..b7a6be9 100644 --- a/AssetStudioGUI/Exporter.cs +++ b/AssetStudioGUI/Exporter.cs @@ -9,10 +9,13 @@ namespace AssetStudioGUI { internal static class Exporter { + private static readonly HashSet ExportPathHashSet = new HashSet(System.StringComparer.OrdinalIgnoreCase); + private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export") { var fileName = FixFileName(item.Text); var filenameFormatIndex = Properties.Settings.Default.filenameFormat; + var canOverwrite = Properties.Settings.Default.overwriteExistingFiles; switch (filenameFormatIndex) { case 1: //assetName@pathID @@ -23,17 +26,18 @@ namespace AssetStudioGUI break; } fullPath = Path.Combine(dir, fileName + extension); - if (!File.Exists(fullPath)) + if (ExportPathHashSet.Add(fullPath)) { - Directory.CreateDirectory(dir); - return true; + if (CanWrite(fullPath, dir, canOverwrite)) + { + return true; + } } - if (filenameFormatIndex == 0) //assetName + else if (filenameFormatIndex == 0) //assetName { fullPath = Path.Combine(dir, fileName + item.UniqueID + extension); - if (!File.Exists(fullPath)) + if (CanWrite(fullPath, dir, canOverwrite)) { - Directory.CreateDirectory(dir); return true; } } @@ -41,6 +45,14 @@ namespace AssetStudioGUI return false; } + private static bool CanWrite(string fullPath, string dir, bool canOverwrite) + { + if (!canOverwrite && File.Exists(fullPath)) + return false; + Directory.CreateDirectory(dir); + return true; + } + private static bool ExportVideoClip(AssetItem item, string exportPath) { var m_VideoClip = (VideoClip)item.Asset; @@ -349,5 +361,10 @@ namespace AssetStudioGUI ? Path.GetRandomFileName() : Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_')); } + + public static void ClearHash() + { + ExportPathHashSet.Clear(); + } } } diff --git a/AssetStudioGUI/ParallelExport.cs b/AssetStudioGUI/ParallelExport.cs index af7fe23..0143d12 100644 --- a/AssetStudioGUI/ParallelExport.cs +++ b/AssetStudioGUI/ParallelExport.cs @@ -9,7 +9,7 @@ namespace AssetStudioGUI { internal static class ParallelExporter { - private static ConcurrentDictionary savePathHash = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary ExportPathDict = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); public static bool ExportTexture2D(AssetItem item, string exportPath, out string debugLog) { @@ -183,6 +183,7 @@ namespace AssetStudioGUI { var fileName = FixFileName(item.Text); var filenameFormatIndex = Properties.Settings.Default.filenameFormat; + var canOverwrite = Properties.Settings.Default.overwriteExistingFiles; switch (filenameFormatIndex) { case 1: //assetName@pathID @@ -193,17 +194,18 @@ namespace AssetStudioGUI break; } fullPath = Path.Combine(dir, fileName + extension); - if (savePathHash.TryAdd(fullPath.ToLower(), true) && !File.Exists(fullPath)) + if (ExportPathDict.TryAdd(fullPath, true)) { - Directory.CreateDirectory(dir); - return true; + if (CanWrite(fullPath, dir, canOverwrite)) + { + return true; + } } - if (filenameFormatIndex == 0) //assetName + else if (filenameFormatIndex == 0) //assetName { fullPath = Path.Combine(dir, fileName + item.UniqueID + extension); - if (!File.Exists(fullPath)) + if (CanWrite(fullPath, dir, canOverwrite)) { - Directory.CreateDirectory(dir); return true; } } @@ -211,6 +213,14 @@ namespace AssetStudioGUI return false; } + private static bool CanWrite(string fullPath, string dir, bool canOverwrite) + { + if (!canOverwrite && File.Exists(fullPath)) + return false; + Directory.CreateDirectory(dir); + return true; + } + public static bool ParallelExportConvertFile(AssetItem item, string exportPath, out string debugLog) { switch (item.Type) @@ -236,7 +246,7 @@ namespace AssetStudioGUI public static void ClearHash() { - savePathHash.Clear(); + ExportPathDict.Clear(); } } } diff --git a/AssetStudioGUI/Properties/Settings.Designer.cs b/AssetStudioGUI/Properties/Settings.Designer.cs index 7e015d7..65694ad 100644 --- a/AssetStudioGUI/Properties/Settings.Designer.cs +++ b/AssetStudioGUI/Properties/Settings.Designer.cs @@ -334,5 +334,17 @@ namespace AssetStudioGUI.Properties { this["decompressToDisk"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool overwriteExistingFiles { + get { + return ((bool)(this["overwriteExistingFiles"])); + } + set { + this["overwriteExistingFiles"] = value; + } + } } } diff --git a/AssetStudioGUI/Properties/Settings.settings b/AssetStudioGUI/Properties/Settings.settings index 67f11d6..6ec4ac2 100644 --- a/AssetStudioGUI/Properties/Settings.settings +++ b/AssetStudioGUI/Properties/Settings.settings @@ -80,5 +80,8 @@ False + + False + \ No newline at end of file diff --git a/AssetStudioGUI/Studio.cs b/AssetStudioGUI/Studio.cs index e7c2ec6..c6da6e8 100644 --- a/AssetStudioGUI/Studio.cs +++ b/AssetStudioGUI/Studio.cs @@ -677,6 +677,7 @@ namespace AssetStudioGUI Progress.Report(++i, toExportCount); } + Exporter.ClearHash(); Parallel.ForEach(toParallelExportAssetDict, new ParallelOptions { MaxDegreeOfParallelism = parallelExportCount }, (toExportAsset, loopState) => { @@ -896,7 +897,8 @@ namespace AssetStudioGUI Logger.Info($"Exporting {gameObject.m_Name}"); try { - ExportGameObject(gameObject, exportPath, animationList); + var modelExportPath = Path.Combine(exportPath, gameObject.m_Name) + Path.DirectorySeparatorChar; + ExportGameObject(gameObject, modelExportPath, animationList); Logger.Info($"Finished exporting {gameObject.m_Name}"); } catch (Exception ex)