diff --git a/AssetStudioCLI/Exporter.cs b/AssetStudioCLI/Exporter.cs index 9214716..90260b1 100644 --- a/AssetStudioCLI/Exporter.cs +++ b/AssetStudioCLI/Exporter.cs @@ -315,6 +315,31 @@ namespace AssetStudioCLI m_VideoClip.m_VideoData.WriteData(exportFullPath.Replace(".dat", "_data.dat")); } break; + case MonoBehaviour m_MonoBehaviour when CLIOptions.f_rawByteArrayFromMono.Value: + var reader = m_MonoBehaviour.reader; + reader.Reset(); + var assetData = reader.ReadBytes(28); //PPtr m_GameObject, m_Enabled, PPtr + var assetNameLen = reader.ReadInt32(); + reader.Position -= 4; + var assetNameBytes = reader.ReadBytes(assetNameLen + 4); + if (assetNameLen > 0) + reader.AlignStream(); + var arrayLen = reader.ReadInt32(); + if (arrayLen <= 0 || arrayLen > reader.Remaining) + break; + using (var outStream = new FileStream(exportFullPath.Replace(".dat", "_extracted.dat"), FileMode.Create)) + { + reader.BaseStream.CopyTo(outStream, size: arrayLen); + } + using (var outStream = new FileStream(exportFullPath, FileMode.Create)) + { + outStream.Write(assetData, 0, assetData.Length); + outStream.Write(assetNameBytes, 0, assetNameBytes.Length); + if (reader.Remaining > 0) + reader.BaseStream.CopyTo(outStream, size: reader.Remaining); + } + Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; } File.WriteAllBytes(exportFullPath, item.Asset.GetRawData()); diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index 007a4c4..8f94c2f 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -128,6 +128,7 @@ namespace AssetStudioCLI.Options public static Option f_decompressToDisk; public static Option f_notRestoreExtensionName; public static Option f_avoidLoadingViaTypetree; + public static Option f_rawByteArrayFromMono; public static Option f_loadAllAssets; static CLIOptions() @@ -557,6 +558,15 @@ namespace AssetStudioCLI.Options optionHelpGroup: HelpGroups.Advanced, isFlag: true ); + f_rawByteArrayFromMono = new GroupedOption + ( + optionDefaultValue: false, + optionName: "--raw-array", + optionDescription: "(Flag) If specified, Studio will try to extract raw byte array from MonoBehaviour assets\n(Only for ExportRaw mode)\n", + optionExample: "", + optionHelpGroup: HelpGroups.Advanced, + isFlag: true + ); f_loadAllAssets = new GroupedOption ( optionDefaultValue: false, @@ -741,6 +751,16 @@ namespace AssetStudioCLI.Options f_avoidLoadingViaTypetree.Value = true; flagIndexes.Add(i); break; + case "--raw-array": + if (o_workMode.Value != WorkMode.ExportRaw) + { + Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{flag.Color(brightYellow)}] flag. This flag is not suitable for the current working mode [{o_workMode.Value}].\n"); + ShowOptionDescription(f_rawByteArrayFromMono, isFlag: true); + return; + } + f_rawByteArrayFromMono.Value = true; + flagIndexes.Add(i); + break; case "--load-all": switch (o_workMode.Value) { @@ -1431,6 +1451,10 @@ namespace AssetStudioCLI.Options sb.AppendLine($"# Restore TextAsset Extension: {!f_notRestoreExtensionName.Value}"); sb.AppendLine($"# Max Parallel Export Tasks: {o_maxParallelExportTasks}"); } + if (o_workMode.Value == WorkMode.ExportRaw) + { + sb.AppendLine($"# Extract Raw Byte Array From MonoBehaviour: {f_rawByteArrayFromMono}"); + } sb.AppendLine(ShowCurrentFilter()); sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); sb.AppendLine($"# Assembly Path: \"{o_assemblyPath}\""); diff --git a/AssetStudioGUI/ExportOptions.Designer.cs b/AssetStudioGUI/ExportOptions.Designer.cs index d4c8863..fd2c254 100644 --- a/AssetStudioGUI/ExportOptions.Designer.cs +++ b/AssetStudioGUI/ExportOptions.Designer.cs @@ -32,6 +32,7 @@ this.OKbutton = new System.Windows.Forms.Button(); this.Cancel = new System.Windows.Forms.Button(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.rawByteArrayFromMono = new System.Windows.Forms.CheckBox(); this.overwriteExistingFiles = new System.Windows.Forms.CheckBox(); this.parallelExportMaxLabel = new System.Windows.Forms.Label(); this.parallelExportCheckBox = new System.Windows.Forms.CheckBox(); @@ -97,7 +98,7 @@ // OKbutton // this.OKbutton.BackColor = System.Drawing.SystemColors.ButtonFace; - this.OKbutton.Location = new System.Drawing.Point(460, 448); + this.OKbutton.Location = new System.Drawing.Point(460, 459); this.OKbutton.Name = "OKbutton"; this.OKbutton.Size = new System.Drawing.Size(75, 23); this.OKbutton.TabIndex = 4; @@ -109,7 +110,7 @@ // this.Cancel.BackColor = System.Drawing.SystemColors.ButtonFace; this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.Cancel.Location = new System.Drawing.Point(541, 448); + this.Cancel.Location = new System.Drawing.Point(541, 459); this.Cancel.Name = "Cancel"; this.Cancel.Size = new System.Drawing.Size(75, 23); this.Cancel.TabIndex = 5; @@ -121,6 +122,7 @@ // this.groupBox1.AutoSize = true; this.groupBox1.BackColor = System.Drawing.SystemColors.Menu; + this.groupBox1.Controls.Add(this.rawByteArrayFromMono); this.groupBox1.Controls.Add(this.overwriteExistingFiles); this.groupBox1.Controls.Add(this.parallelExportMaxLabel); this.groupBox1.Controls.Add(this.parallelExportCheckBox); @@ -137,11 +139,21 @@ 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, 280); + this.groupBox1.Size = new System.Drawing.Size(316, 303); this.groupBox1.TabIndex = 1; this.groupBox1.TabStop = false; this.groupBox1.Text = "Export"; // + // rawByteArrayFromMono + // + this.rawByteArrayFromMono.AutoSize = true; + this.rawByteArrayFromMono.Location = new System.Drawing.Point(6, 267); + this.rawByteArrayFromMono.Name = "rawByteArrayFromMono"; + this.rawByteArrayFromMono.Size = new System.Drawing.Size(290, 17); + this.rawByteArrayFromMono.TabIndex = 15; + this.rawByteArrayFromMono.Text = "Raw: Extract raw byte array from MonoBehaviour assets"; + this.rawByteArrayFromMono.UseVisualStyleBackColor = true; + // // overwriteExistingFiles // this.overwriteExistingFiles.AutoSize = true; @@ -380,7 +392,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, 291); + this.l2dGroupBox.Location = new System.Drawing.Point(12, 304); this.l2dGroupBox.Name = "l2dGroupBox"; this.l2dGroupBox.Size = new System.Drawing.Size(316, 149); this.l2dGroupBox.TabIndex = 2; @@ -502,7 +514,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, 427); + this.groupBox2.Size = new System.Drawing.Size(289, 440); this.groupBox2.TabIndex = 3; this.groupBox2.TabStop = false; this.groupBox2.Text = "Fbx"; @@ -510,7 +522,7 @@ // fbxResetButton // this.fbxResetButton.BackColor = System.Drawing.SystemColors.ButtonFace; - this.fbxResetButton.Location = new System.Drawing.Point(208, 384); + this.fbxResetButton.Location = new System.Drawing.Point(208, 398); this.fbxResetButton.Name = "fbxResetButton"; this.fbxResetButton.Size = new System.Drawing.Size(75, 23); this.fbxResetButton.TabIndex = 21; @@ -782,7 +794,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, 483); + this.ClientSize = new System.Drawing.Size(628, 494); this.Controls.Add(this.l2dGroupBox); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); @@ -869,5 +881,6 @@ private System.Windows.Forms.Label uvBindingsLabel; private System.Windows.Forms.Button fbxResetButton; private System.Windows.Forms.CheckBox overwriteExistingFiles; + private System.Windows.Forms.CheckBox rawByteArrayFromMono; } } \ No newline at end of file diff --git a/AssetStudioGUI/ExportOptions.cs b/AssetStudioGUI/ExportOptions.cs index 835a221..ccc9286 100644 --- a/AssetStudioGUI/ExportOptions.cs +++ b/AssetStudioGUI/ExportOptions.cs @@ -29,7 +29,8 @@ namespace AssetStudioGUI parallelExportUpDown.Value = taskCount <= 0 ? maxParallelTasks : Math.Min(taskCount, maxParallelTasks); parallelExportMaxLabel.Text += maxParallelTasks; parallelExportCheckBox.Checked = Properties.Settings.Default.parallelExport; - + rawByteArrayFromMono.Checked = Properties.Settings.Default.rawByteArrayFromMono; + l2dModelGroupComboBox.SelectedIndex = (int)Properties.Settings.Default.l2dModelGroupOption; l2dAssetSearchByFilenameCheckBox.Checked = Properties.Settings.Default.l2dAssetSearchByFilename; var defaultMotionMode = Properties.Settings.Default.l2dMotionMode.ToString(); @@ -53,6 +54,7 @@ namespace AssetStudioGUI Properties.Settings.Default.openAfterExport = openAfterExport.Checked; Properties.Settings.Default.parallelExport = parallelExportCheckBox.Checked; Properties.Settings.Default.parallelExportCount = (int)parallelExportUpDown.Value; + Properties.Settings.Default.rawByteArrayFromMono = rawByteArrayFromMono.Checked; Properties.Settings.Default.l2dModelGroupOption = (CubismLive2DExtractor.Live2DModelGroupOption)l2dModelGroupComboBox.SelectedIndex; Properties.Settings.Default.l2dAssetSearchByFilename = l2dAssetSearchByFilenameCheckBox.Checked; diff --git a/AssetStudioGUI/Exporter.cs b/AssetStudioGUI/Exporter.cs index 42268bf..271efe1 100644 --- a/AssetStudioGUI/Exporter.cs +++ b/AssetStudioGUI/Exporter.cs @@ -276,6 +276,30 @@ namespace AssetStudioGUI m_VideoClip.m_VideoData.WriteData(exportFullPath.Replace(".dat", "_data.dat")); } break; + case MonoBehaviour m_MonoBehaviour when Properties.Settings.Default.rawByteArrayFromMono: + var reader = m_MonoBehaviour.reader; + reader.Reset(); + var assetData = reader.ReadBytes(28); //PPtr m_GameObject, m_Enabled, PPtr + var assetNameLen = reader.ReadInt32(); + reader.Position -= 4; + var assetNameBytes = reader.ReadBytes(assetNameLen + 4); + if (assetNameLen > 0) + reader.AlignStream(); + var arrayLen = reader.ReadInt32(); + if (arrayLen <= 0 || arrayLen > reader.Remaining) + break; + using (var outStream = new FileStream(exportFullPath.Replace(".dat", "_extracted.dat"), FileMode.Create)) + { + reader.BaseStream.CopyTo(outStream, size: arrayLen); + } + using (var outStream = new FileStream(exportFullPath, FileMode.Create)) + { + outStream.Write(assetData, 0, assetData.Length); + outStream.Write(assetNameBytes, 0, assetNameBytes.Length); + if (reader.Remaining > 0) + reader.BaseStream.CopyTo(outStream, size: reader.Remaining); + } + return true; } File.WriteAllBytes(exportFullPath, item.Asset.GetRawData()); return true; diff --git a/AssetStudioGUI/Properties/Settings.Designer.cs b/AssetStudioGUI/Properties/Settings.Designer.cs index 86d69a6..a9a86b7 100644 --- a/AssetStudioGUI/Properties/Settings.Designer.cs +++ b/AssetStudioGUI/Properties/Settings.Designer.cs @@ -358,5 +358,17 @@ namespace AssetStudioGUI.Properties { this["meshLazyLoad"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool rawByteArrayFromMono { + get { + return ((bool)(this["rawByteArrayFromMono"])); + } + set { + this["rawByteArrayFromMono"] = value; + } + } } } diff --git a/AssetStudioGUI/Properties/Settings.settings b/AssetStudioGUI/Properties/Settings.settings index 65bc0b1..cb25a17 100644 --- a/AssetStudioGUI/Properties/Settings.settings +++ b/AssetStudioGUI/Properties/Settings.settings @@ -86,5 +86,8 @@ True + + False + \ No newline at end of file